javascript - que - operadores relacionales
¿Por qué el operador de módulo devuelve el número fraccionario en javascript? (7)
¿Por qué el 49.90 % 0.10
en JavaScript devuelve 0.09999999999999581
? Esperaba que fuera 0.
Dejaré esto aquí para referencia futura, pero aquí hay una función útil que puede manejar más precisamente el Remainder (ya que JS no tiene un operador de módulo ) que implique flotantes.
function floatSafeRemainder(val, step){
var valDecCount = (val.toString().split(''.'')[1] || '''').length;
var stepDecCount = (step.toString().split(''.'')[1] || '''').length;
var decCount = valDecCount > stepDecCount? valDecCount : stepDecCount;
var valInt = parseInt(val.toFixed(decCount).replace(''.'',''''));
var stepInt = parseInt(step.toFixed(decCount).replace(''.'',''''));
return (valInt % stepInt) / Math.pow(10, decCount);
}
$(function() {
function floatSafeModulus(val, step) {
var valDecCount = (val.toString().split(''.'')[1] || '''').length;
var stepDecCount = (step.toString().split(''.'')[1] || '''').length;
var decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount;
var valInt = parseInt(val.toFixed(decCount).replace(''.'', ''''));
var stepInt = parseInt(step.toFixed(decCount).replace(''.'', ''''));
return (valInt % stepInt) / Math.pow(10, decCount);
}
$("#form").submit(function(e) {
e.preventDefault();
var safe = ''Invalid'';
var normal = ''Invalid'';
var var1 = parseFloat($(''#var1'').val());
var var2 = parseFloat($(''#var2'').val());
if (!isNaN(var1) && !isNaN(var2)) {
safe = floatSafeModulus(var1, var2);
normal = var1 % var2
}
$(''#safeResult'').text(safe);
$(''#normalResult'').text(normal);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="form" novalidate>
<div>
<input type="number" id="var1">%
<input type="number" id="var2">
</div>
<div>safe: <span id="safeResult"></span><div>
<div>normal (%): <span id="normalResult"></span></div>
<input type="submit" value="try it out">
</form>
Eche un vistazo a los puntos flotantes y sus desventajas: un número como 0.1
no se puede guardar correctamente como coma flotante, por lo que siempre habrá tales problemas. Tome sus números * 10 o * 100 y haga los cálculos con enteros en su lugar.
El número de Javascript usa "IEEE de doble precisión" para almacenar los valores. Son incapaces de almacenar todos los números decimales exactamente. El resultado no es cero debido al error de redondeo al convertir el número decimal a binario.
49.90 = 49.89999999999999857891452848...
0.10 = 0.10000000000000000555111512...
Por lo tanto, el piso (49.90 / 0.10) es solo 498, y el resto será 0.09999 ....
Parece que estás usando números para almacenar la cantidad de dólares. No haga esto , ya que las operaciones de punto flotante propagan y amplifican el error de redondeo. Almacene el número como la cantidad de centavos en su lugar. El entero se puede representar exactamente, y 4990 % 10
devolverá 0.
Esta no es una respuesta perfecta, pero funciona.
function format_float_bug(num)
{
return parseFloat( num.toFixed(15) );
}
puedes usarlo de la siguiente manera
format_float_bug(4990 % 10);
porque debajo del número (49.89999999999999857891452848) los primeros 15 lugares decimales son como 9999999
Porque JavaScript usa matemáticas de punto flotante que siempre conduce a errores de redondeo.
Si necesita un resultado exacto con dos decimales, multiplique sus números por 100
antes de la operación y luego vuelva a dividirlos después:
var result = ( 4990 % 10 ) / 100;
Redondea si es necesario.
http://en.wikipedia.org/wiki/Modulo_operation No te enojes. Modulo se usa con enteros ^^ Entonces los valores flotantes ocurren algunos errores.
Porque
El punto flotante no puede almacenar todos los valores decimales exactamente. Por lo tanto, al usar formatos de coma flotante siempre habrá errores de redondeo en los valores de entrada. Los errores en las entradas de curso dan como resultado errores en la salida. En el caso de una función discreta u operador, puede haber una gran diferencia en la salida alrededor del punto donde la función u operador es discreto. El operador de modula es discreto y su caso es claramente un ejemplo de este problema.
Entrada y salida para valores de coma flotante
Por lo tanto, al usar variables de coma flotante, siempre debe tener en cuenta esto. Y cualquier salida que desee de un cálculo con puntos flotantes siempre debe formatearse / acondicionarse antes de mostrar con esto en mente.
Cuando solo se usan funciones continuas y operadores, el redondeo a la precisión deseada a menudo servirá (no trunque). Las características de formato estándar utilizadas para convertir flotadores a cadenas generalmente lo harán por usted.
Para tener una salida correcta basada en la precisión esperada de las entradas y la precisión de salida deseada, también debe
- Redondee las entradas a la precisión esperada o asegúrese de que no se puedan ingresar valores con mayor precisión.
- Agregue un pequeño valor a las salidas antes de redondear / formatearlas que sea menor o igual a 1/4 de la precisión deseada y mayor que el error máximo esperado causado por errores de redondeo en la entrada y durante el cálculo. Si eso no es posible, la combinación de la precisión del tipo de datos utilizado no es suficiente para entregar la precisión de salida deseada para su cálculo.
Estas 2 cosas a menudo no se hacen y en la mayoría de los casos las diferencias causadas por no hacerlas son demasiado pequeñas para ser importantes para la mayoría de los usuarios, pero ya tenía un proyecto donde los usuarios no aceptaban la salida sin esas correcciones.
Funciones o operadores discretos (como modula)
Cuando se trata de operadores o funciones discretos, es posible que se requieran correcciones adicionales para garantizar que el resultado sea el esperado. Redondear y agregar pequeñas correcciones antes del redondeo no puede resolver el problema.
Es posible que se requiera una verificación / corrección especial en los resultados del cálculo intermedio, inmediatamente después de aplicar la función discreta u operador.
Caso específico de esta pregunta
En este caso, espera una entrada con una cierta precisión, por lo que es posible corregir la salida para el impacto de errores de redondeo que son mucho más pequeños que la precisión deseada.
Si decimos que la precisión de su tipo de datos es e.
Su entrada no se almacenará como los valores a y b que ingresó, sino como un * (1 +/- e) yb * (1 +/- e)
El resultado de una división a * (1 +/- e) por b * (1 +/- e) daría como resultado (a / b) (1 +/- 2e).
La función de modula tiene que truncar el resultado y multiplicarse nuevamente. Entonces el resultado será (a / b b) (1 +/- 3e) = a (1 +/- 3e) dando como resultado un error de a * 3e.
El mod agrega a * e al posible error de a * 3e debido a la resta de 2 valores con posibles errores de a * 3e y a * e.
Por lo tanto, debe verificar que el error total posible a * 4e sea menor que la precisión deseada y, si se cumple esa condición y el resultado no difiere más de b que ese error máximo posible, puede reemplazarlo de manera segura por 0.
Mejor evitar tener el problema
A menudo es más eficiente evitar estos problemas utilizando tipos de datos (formatos enteros o de punto fijo) para cálculos como este que pueden almacenar la entrada esperada sin errores de redondeo. Un ejemplo de esto es que nunca debe usar valores de coma flotante para cálculos financieros.