Veamos primero dos preguntas:
0.1 + 0.2 == 0.3; // FALSO
99999999999999999999 == 10000000000000000000; // verdadero
El primer problema es la precisión de los decimales, que se ha discutido en muchos blogs de la industria. El segundo problema fue que el año pasado, cuando una base de datos sistemática estaba corrigiendo los datos, descubrió que algunos datos estaban duplicados. Este artículo comenzará desde la norma y resumirá los problemas anteriores.
Entero máximo
Los números en JavaScript se almacenan utilizando números de punto flotante de doble precisión IEEE 754 de doble precisión de 64 bits, y su formato es:
sxmx 2^e
S es un bit de signo, que indica positivo y negativo. M es la Mantissa, con 52 bits. E es el exponente, con 11 bits. En la especificación de ECMAScript, el rango dado por E es [-1074, 971]. De esta manera, es fácil deducir que el entero máximo que JavaScript puede representar es:
1 x (2^53 - 1) x 2^971 = 1.7976931348623157E+308
Este valor es número.max_value
Del mismo modo, el valor del número.min_value se puede deducir como:
1 x 1 x 2^(-1074) = 5e-324
Tenga en cuenta que Min_Value representa el número positivo más cercano a 0, no el número más pequeño. El número más pequeño es -number.max_value
La precisión del decimal se pierde
Los números de JavaScript son números de punto flotante de doble precisión y se almacenan en binarias en computadoras. Cuando el número de bits significativos excede los 52 bits, habrá pérdida de precisión. Por ejemplo:
El binario de decimal 0.1 es 0.0 0011 0011 0011 ... (bucle 0011)
El binario de decimal 0.2 es 0.0011 0011 0011 ... (bucle 0011)
0.1 + 0.2 La adición se puede expresar como:
e = -4; M = 1.10011001100 ... 1100 (52 bits)
+ e = -3; M = 1.10011001100 ... 1100 (52 bits)
----------------------------------------------------------------------------------------------------------------------------
e = -3; M = 0.11001100110 ... 0110
+ e = -3; M = 1.10011001100 ... 1100
----------------------------------------------------------------------------------------------------------------------------
e = -3; M = 10.01100110011 ... 001
----------------------------------------------------------------------------------------------------------------------------
= 0.01001100110011 ... 001
= 0.300000000000000000004 (decimal)
Según el cálculo anterior, también podemos sacar una conclusión: cuando el número finito de decimales decimales en la representación binaria no excede los 52 bits, se puede almacenar con precisión en JavaScript. Por ejemplo:
0.05 + 0.005 == 0.055 // Verdadero
Otras reglas, como:
0.05 + 0.2 == 0.25 // Verdadero
0.05 + 0.9 == 0.95 // falso
Se deben considerar los modos de redondeo de IEEE 754, y aquellos que están interesados pueden estudiarlo.
La precisión de los enteros abiertos se pierde
Raramente se menciona esta pregunta. Primero, tenemos que averiguar cuál es el problema:
1. ¿Cuál es el entero máximo que JavaScript puede almacenar?
Esta pregunta ha sido respondida anteriormente, y es Number.max_Value, un número muy grande.
2. ¿Cuál es el entero máximo que JavaScript puede almacenar sin perder precisión?
Según SXMX 2^e, el bit de signo es positivo, la mantissa de 52 bits está completamente acolchada con 1, y el exponente E es el valor máximo de 971. Obviamente, la respuesta aún es número.max_value.
¿Cuál es exactamente nuestro problema? Vuelve al código de inicio:
99999999999999999999 == 10000000000000000000; // verdadero
Es obvio que 16 9 son mucho menos que 308 10s. Este problema no tiene nada que ver con max_value, y debe atribuirse a la mantis m con solo 52 dígitos.
Se puede describir en el código:
var x = 1; // Para reducir la cantidad de cálculo, el valor inicial puede establecerse para ser mayor, como Math.Pow (2, 53) - 10
while (x! = x+1) x ++;
// x = 9007199254740992, es decir, 2^53
Es decir, cuando X es menor o igual a 2^53, se asegura que la precisión de X no se pierda. Cuando X es mayor que 2^53, la precisión de X puede perderse. Por ejemplo:
Cuando x es 2^53 + 1, su representación binaria es:
100000000000000 ... 001 (hay 52 0s en el medio)
Al almacenar con números de punto flotante de doble precisión:
E = 1; M = 10000..00 (total 52 0s, 1 está oculto)
Obviamente, esto es lo mismo que el almacenamiento 2^53.
Según la idea anterior, se puede describir que para 2^53 + 2, su binario es 100000 ... 0010 (51 0s en el medio), y también se puede almacenar con precisión.
Regla: Cuando X es mayor que 2^53 y el número de dígitos significativos binarios es mayor que 53 bits, habrá pérdida de precisión. Esto es esencialmente lo mismo que la pérdida de precisión de los decimales.
El bit oculto se puede usar para referencia: un tutorial sobre Java Double Type.
resumen
La precisión de los decimales y los enteros grandes no solo se pierde en JavaScript. Estrictamente hablando, cualquier lenguaje de programación (c/c ++/c#/java, etc.) que usa el formato de número de punto flotante IEEE 754 para almacenar tipos de puntos flotantes tiene problemas de pérdida de precisión. En C# y Java, se proporcionan clases de encapsulación decimales y bigdecimales para realizar el procesamiento correspondiente, para evitar la pérdida de precisión.
Nota: Ya hay una propuesta decimal en la especificación de Ecmascript, pero aún no se ha adoptado oficialmente.
Finalmente, prueba a todos:
Número.max_value + 1 == numer.max_value;
Number.max_value + 2 == numer.max_value;
...
Número.max_value + x == numer.max_value;
Número.max_value + x + 1 == Infinity;
...
Número.max_value + number.max_value == Infinity;
// pregunta:
// 1. ¿Cuál es el valor de x?
// 2. Infinity - Number.max_value == x + 1; ¿Es verdadero o falso?
La breve discusión anterior sobre la pérdida de precisión de decimales e enteros abiertos en JavaScript es todo el contenido que comparto con usted. Espero que pueda darle una referencia y espero que pueda apoyar más a Wulin.com.