43 votes

Pourquoi deux nombres différents sont-ils égaux en JavaScript?

J'ai été déconner avec une console JavaScript, quand j'ai soudain décidé d'essayer ceci:

0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

Étonnamment, ils sont égaux: Strange output

Pourquoi se produit-il? Ils sont clairement différents numéros (même l' 0xFFFF...FFFF est un chiffre plus courte)

Si j'ajoute un F de la 0xFFFF...FF, ils ne sont pas égaux: 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF Even stranger output

Est-ce un comportement attendu?

50voto

p.s.w.g Points 81433

Tous les numéros sont en JavaScript représenté en interne par 64-bits des nombres à virgule flottante (voir §4.3.19 de la spécification). Cela signifie qu'il peut exactement représenter chaque nombre entier compris entre 0 jusqu'à 9007199254740992 (valeur hexadécimale 0x20000000000000). Tous les entiers supérieurs (ou de moins que la contrepartie négative) peut avoir besoin d'être arrondi au plus proche d'une valeur approximative.

Observer:

9007199254740992 === 9007199254740993
> true

Cependant, les deux nombres sont arrondis à l'suffisamment différentes des valeurs approximatives encore évaluer à différentes valeurs lorsque vous les comparez. Par exemple:

9007199254740992 === 9007199254740994
> false

C'est ce que vous avez vu dans le deuxième extrait de l'endroit où vous ajoutez un autre F chiffre.

28voto

Luis Masuelli Points 2518

0x100000000000000 == 0xFFFFFFFFFFFFFF donne truealors que 0x10000000000000 == 0xFFFFFFFFFFFFF donne false. Donc, la première est la "limite", de dire.

Nous allons analyser les chiffres: 52 bits pour 0xFFFFFFFFFFFFF et un bit supplémentaire pour 0x10000000000000 dans la représentation interne.

EDIT: Numéros d'une telle ampleur ne sont pas représentés par de longs ints, mais en double precission flotteurs. C'est parce qu' ils dépassent les 32 bits de la représentation d'un entier de valeur de chaque chiffre dans le code javascript est représenté comme IEEE754 en virgule flottante double précision.

Lorsque vous représentez tout IEEE754 Double Precission FP Nombre en interne, vous obtenez:

0111 1111 1111 2222
2222 2222 2222 2222
2222 2222 2222 2222
2222 2222 2222 2222

Où (0) est le bit de signe, (1) les bits d'exposant, et (2) les bits de la mantisse.

Si vous comparez en JavaScript 0.5 == 5 * 0.1 , vous obtiendrez true , même lorsque ladite opération a flottant imprecission (c'est à dire vous obtenez une erreur). Donc, Javascript tolère une petite erreur dans les opérations à virgule flottante afin d'opérations comme celles qui donnent le vrai, le bon sens dit.

Edit - Il y a quelque chose de mal, j'ai écrit à propos de la Mantisse: Oui, tous les Mantisse commence par 1 (il est dit que ces mantisse normalisée), MAIS qu' 1 n'est pas stockée dans un normalisée nombre (différente de zéro chaque exposant a seulement les nombres normalisés. mantissas pour les nombres en exposant 000 0000 0000 ne suivent pas cette règle). Cela signifie que chaque mantisse normalisée a 52 explicite bits, et une implicite 1.

Maintenant: que sur les 52 bits? Notez que le 0xFF... a 52 bits de longueur. Cela signifie qu'il sera stocké sous la forme: 0 pour le signe (c'est positif), 52 pour l'exposant et 52 "1" chiffres de la mantisse (voir une note finale au pied de cette réponse). Depuis un "1" est implicite, nous allons stocker 51 "1" et "0".

0100 0011 0010 1111
1111 1111 1111 1111
1111 1111 1111 1111
1111 1111 1111 1110

(exponent 1075 corresponds to actual exponent 52)

ET l'autre numéro a 53 bits: un "1" et 52 "0". Depuis le premier "1" est implicite, il sera stocké comme:

0100 0011 0100 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

(exponent 1076 corresponds to actual exponent 53)

Maintenant, il est temps de comparer les valeurs. Ils comparent en égalité de conditions: d'abord nous prenons signe et l'exposant à la comparaison. Si elles sont égales, nous considérons que la mantisse.

Comparaison se déroule ici en considérant une petite erreur tolérée comme un produit de l'arrondissement. Ces epsilon est pris en compte (epsilon est sur =2^-53) et FP ALU détecte que, relativement, ces chiffres ne diffèrent que dans de telles epsilon, de sorte qu'ils semblent les mêmes que dans ce contexte (il ya beaucoup de fois où ce n'est pas vous sauver en cas d' 0.3 == 0.2 + 0.1, en cours de chacune des trois nombres binaires non-représentable, contrairement à 0.5 qui est, et peut tolérer une erreur contre 0.1 + 0.4).

Remarque à Propos de la mantisse et de la FP de la représentation: La Mantisse est toujours, sur le plan conceptuel, inférieur à 1. Si vous voulez représenter un nombre plus élevé, vous devez le concevoir à l'aide d'un exposant. Exemples:

  • 0.5 est représenté comme 0.5 * 2 ^ 0 (tenir compte du droit de priorité des opérateurs dans les mathématiques).
  • 1 est représenté non pas comme 1 * 2 ^ 0 depuis la mantisse est toujours inférieur à 1, de sorte que la représentation sera 0.5 * 2 ^ 1.
  • De 65 ans, qui a représentation binaire comme 1000001, seront stockés en tant que (65/128) * 2 ^ 7.

Ces nombres sont représentés en (rappelez-vous: le premier "1" est implicite puisque ces exposants sont pour les nombres normalisés):

0011 1111 1111 0000
... more 0 digits

(exponent 1023 stands for actual exponent 0, mantissa in binary repr. is 0.1, and the first "1" is implicit).

0100 0000 0000 0000
... more 0 digits

(exponent 1024 stands for actual exponent 1, mantissa in binary repr. is 0.1, and the first "1" is implicit).

et

0100 0000 0110 0000
0100 0000 0000 0000

(exponent 1030 stands for actual exponent 7, mantissa in binary repr. is 0.1000001, and since the first "1" is implicit, it is stored as 0000 0100 0000...)

Remarque à Propos de l'exposant: Baisse de precission peut être réalisé en permettant des exposants négatifs: les Exposants semblent positive -non signé - mais la réalité est que vous devez soustraire 1023 (appelé "biais") à ce nombre pour obtenir le réel de l'exposant (exposant "1" correspond en réalité à 2^(-1022)). La traduction de cette à 10 en fonction de la puissance, de la plus faible exposant est -308 pour les nombres décimaux (en prenant également en compte la mantisse possition comme je le montrerai plus tard). Le plus faible nombre positif est:

0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0001

qui est: (1 * 2^-52) * 2^-1023 étant le premier -52 donné par la mantisse et l'-1023 par l'exposant. La finale est: 1 * 2^(-1075), qui va vers le 10^-308 toujours dit.

Le plus bas de l'exposant est - 000 0000 0000 correspondant (-1023). Il y a une règle: Chaque mantisse doit commencer par la (implicite) "1" ou avoir de l'exposant. De l'autre côté, le plus haut exposant pourrait être 111 1111 1111, mais l'exposant est réservé aux pseudonumbers:

0111 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

correspond à +l'Infini, tandis que:

1111 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0000

correspond à l'Infini, et le tout avec un motif différent de zéro mantisse, comme:

?111 1111 1111 0000
0000 0000 0000 0000
0000 0000 0000 0000
0000 0000 0000 0001

correspondent à la valeur NaN (pas un nombre; idéal pour représenter des trucs comme log(-1) ou 0/0). En fait, je ne suis pas sûr de ce que mantissas sont utilisés pour NaN (soit calme ou de signalisation NaN). Le point d'interrogation remplace n'importe quel bit.

3voto

Salman A Points 60620

La suite hexa décimal nombre:

0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

est stocké en tant que norme IEEE 754 valeur float:

1.3407807929942597e+154

Vous ajoutez 1 à ce nombre, et il devient:

0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

ce qui est également stockées en tant que:

1.3407807929942597e+154

Les deux numéros sont se situent en dehors de la plage de numéros qui peuvent être représentés avec précision par le Nombre JavaScript (ref). Dans l'exemple ci-dessus, les deux numéros finissent par avoir la même représentation interne, d'où ils sont, en quelque sorte, de l'égalité.

Rappel: il ne faut pas comparer des nombres à virgule flottante à l'aide de l'opérateur d'égalité (ref).

2voto

djechlin Points 18051

Ceci est évidemment débordement ou arrondi. Calculez mathématiquement la magnitude des nombres et comparez-les au plus grand nombre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X