Regardons d'abord deux questions:
0,1 + 0,2 == 0,3; // FAUX
9999999999999999999 == 100000000000000000; // vrai
Le premier problème est la précision des décimales, qui a été discutée dans de nombreux blogs de l'industrie. Le deuxième problème était que l'année dernière, lorsqu'une base de données systématique corrigeait les données, il a révélé que certaines données étaient dupliquées. Cet article commencera à partir de la norme et résudra les problèmes ci-dessus.
Entier maximum
Les nombres en JavaScript sont stockés à l'aide de numéros de point flottants à double précision IEEE 754 à double précision, et leur format est:
sxmx 2 ^ e
S est un bit de signe, indiquant positif et négatif. M est la mantissa, avec 52 bits. E est l'exposant, avec 11 bits. Dans la spécification ECMAScript, la plage donnée par E est [-1074, 971]. De cette façon, il est facile de déduire que l'entier maximum que JavaScript peut représenter est:
1 x (2 ^ 53 - 1) x 2 ^ 971 = 1,7976931348623157E + 308
Cette valeur est numéro.max_value
De même, la valeur de Number.min_value peut être déduite comme suit:
1 x 1 x 2 ^ (- 1074) = 5E-324
Notez que MIN_VALUE représente le nombre positif le plus proche de 0, pas le plus petit nombre. Le plus petit nombre est -number.max_value
La précision de la décimale est perdue
Les numéros JavaScript sont des numéros à virgule flottante à double précision et sont stockés en binaire dans les ordinateurs. Lorsque le nombre de bits significatifs dépasse 52 bits, il y aura une perte de précision. Par exemple:
Le binaire de décimal 0,1 est de 0,0 0011 0011 0011… (boucle 0011)
Le binaire de décimal 0,2 est de 0,0011 0011 0011… (boucle 0011)
0,1 + 0,2 ajout peut être exprimé comme:
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,3000000000000000004 (décimal)
Sur la base du calcul ci-dessus, nous pouvons également tirer une conclusion: lorsque le nombre fini de décimales dans la représentation binaire ne dépasse pas 52 bits, il peut être stocké avec précision en JavaScript. Par exemple:
0,05 + 0,005 == 0,055 // Vrai
D'autres règles, telles que:
0,05 + 0,2 == 0,25 // Vrai
0,05 + 0,9 == 0,95 // faux
Les modes d'arrondi de l'IEEE 754 doivent être pris en considération, et ceux qui sont intéressés peuvent l'étudier davantage.
La précision des grands entiers est perdu
Cette question est rarement mentionnée. Tout d'abord, nous devons comprendre quel est le problème:
1. Quel est l'entier maximum que JavaScript peut stocker?
Cette question a été répondue plus tôt et est numéro.max_value, un très grand nombre.
2. Quel est l'entier maximum que JavaScript peut stocker sans perdre de précision?
Selon SXMX 2 ^ E, le bit de signe est positif, la mantissa 52 bits est entièrement rembourrée avec 1, et l'exposant E est la valeur maximale de 971. De toute évidence, la réponse est toujours numéro.Max_value.
Quel est exactement notre problème? Retournez au code de départ:
9999999999999999999 == 100000000000000000; // vrai
Il est évident que 16 9 sont bien inférieurs à 308 10. Ce problème n'a rien à voir avec Max_Value, et il doit être attribué à la mante M avec seulement 52 chiffres.
Il peut être décrit dans le code:
var x = 1; // Afin de réduire le montant du calcul, la valeur initiale peut être définie pour être plus grande, comme Math.Pow (2, 53) - 10
tandis que (x! = x + 1) x ++;
// x = 9007199254740992 c'est-à-dire 2 ^ 53
C'est-à-dire que lorsque x est inférieur ou égal à 2 ^ 53, il est assuré que la précision de X n'est pas perdue. Lorsque X est supérieur à 2 ^ 53, la précision de X peut être perdue. Par exemple:
Lorsque x est 2 ^ 53 + 1, sa représentation binaire est:
100000000000 ... 001 (il y en a 52 0 au milieu)
Lors du stockage avec des numéros de points flottants à double précision:
e = 1; M = 10000..00 (total 52 0s, 1 est caché)
De toute évidence, c'est la même chose que 2 ^ 53 Storage.
Selon l'idée ci-dessus, il peut être souligné que pour 2 ^ 53 + 2, son binaire est 100000… 0010 (51 0s au milieu), et il peut également être stocké avec précision.
Règle: Lorsque X est supérieur à 2 ^ 53 et que le nombre de chiffres significatifs binaires est supérieur à 53 bits, il y aura une perte de précision. C'est essentiellement la même chose que la perte de précision des décimales.
Un bit caché peut être utilisé pour référence: un tutoriel sur le double type Java.
résumé
La précision des décimales et des grands entiers n'est pas seulement perdue en JavaScript. À strictement parler, tout langage de programmation (C / C ++ / C # / Java, etc.) qui utilise le format de numéro de point flottant IEEE 754 pour stocker les types de points flottants a des problèmes de perte de précision. Dans C # et Java, des classes d'encapsulation décimales et BigDecimal sont fournies pour effectuer un traitement correspondant, afin d'éviter la perte de précision.
Remarque: il y a déjà une proposition décimale dans la spécification ECMAScript, mais elle n'a pas encore été officiellement adoptée.
Enfin, testez tout le monde:
Number.max_value + 1 == Numer.max_value;
Number.max_value + 2 == Numer.max_value;
...
Number.max_value + x == Numer.max_value;
Number.max_value + x + 1 == Infinity;
...
Number.Max_Value + Number.max_Value == Infinity;
// question:
// 1. Quelle est la valeur de x?
// 2. Infinity - Number.max_value == x + 1; est vrai ou faux?
La brève discussion ci-dessus sur la perte de précision des décimales et des grands entiers en JavaScript est tout le contenu que je partage avec vous. J'espère que vous pourrez vous faire référence et j'espère que vous pourrez soutenir Wulin.com plus.