Why are two different numbers equal in JavaScript?

I was talking to the JavaScript console when I suddenly decided to try the following:

0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

Surprisingly, they are equal: Strange output

Why is this happening? They have clearly different numbers (even 0xFFFF...FFFF is one digit shorter)

If I add F to 0xFFFF...FF , they are not equal 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF : Even stranger output

Is this the expected behavior?

+43
javascript numbers
07 Aug '14 at 19:25
source share
4 answers

All JavaScript numbers are internally represented by 64-bit floating point numbers (see Β§4.3.19 of the specification). This means that it can accurately represent every integer from 0 to 9007199254740992 (the hexadecimal value is 0x20000000000000 ). Any integers greater than this (or less than the negative counterpart) may need to be rounded to the nearest approximate value.

Note:

 9007199254740992 === 9007199254740993 > true 

However, two numbers, rounded to fairly different approximate values, are still evaluated by different values ​​when comparing them. For example:

 9007199254740992 === 9007199254740994 > false 

This is what you see in the second snippet, where you add another digit F

+51
Aug 07 '14 at 19:29
source share

0x100000000000000 == 0xFFFFFFFFFFFFFF gives true while 0x10000000000000 == 0xFFFFFFFFFFFFF gives false . So the first is the "limit", say.

Analyze the numbers: 52 bits for 0xFFFFFFFFFFFFF and one extra bit for 0x10000000000000 in the internal representation.

EDIT . Numbers of this magnitude are not represented by long integers, but by double floats. This is because they outperform the 32-bit representation of an integer value . Each number in javascript is represented as an IEEE754 double precision floating point.

When you introduce the IEEE754 Double Precision FP Number , you get:

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

Where (0) is the sign bit, (1) the exponent bits, and (2) the mantissa bit.

If you compare in JavaScript 0.5 == 5 * 0.1 , you will get true even if this operation has a floating value (i.e. you will get some error). Therefore, Javascript makes a small mistake in floating point operations, so operations like this give true, as common sense says.

Change I wrote something wrong about Mantissa: Yes, each Mantissa starts with 1 (they say that such a mantissa is normalized), BUT that 1 not stored in a normalized number (each nonzero exponent has only normalized numbers. Mantissas for numbers with exponent 000 0000 0000 does not follow this rule). This means that each normalized mantissa has 52 explicit bits and an implicit 1 .

Now: what about 52 bits? Note that the size 0xFF ... has a length of 52 bits. This means that it will be saved as: 0 for the sign (positive), 52 for the exponent, and 52 "1" digits in the mantissa (see the Final Note at the foot of this answer). Since one "1" is implicit, we will store 51 "1" and one "0".

 0100 0011 0010 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1110 (exponent 1075 corresponds to actual exponent 52) 

And the other number has 53 bits: one is β€œ1” and 52 is β€œ0”. Since the first "1" is implicit, it will be stored as:

 0100 0011 0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 (exponent 1076 corresponds to actual exponent 53) 

Now it's time to compare the values. They will compare in equal conditions: first we take the sign and the exponent for comparison. If they are equal, we consider the mantissa.

This compares the comparison, given that a small error carries over as a product of rounding. Such epsilon is taken into account (epsilon is about = 2 ^ -53), and FP ALU detects that these numbers differ only in such epsilon, so they seem to be equal only in this context (often this does not save you, as in the case of 0.3 == 0.2 + 0.1 , being each of the three numbers binary-unrepresentative, in contrast to 0.5 , which is, and can tolerate an error with respect to 0.1 + 0.4 ).

Note About the representation of the mantissa and FP: The mantissa is always, conceptually, below 1. If you want to represent a larger number, you must represent it using a power indicator. Examples:

  • 0.5 is represented as 0.5 * 2 ^ 0 (consider the correct operator priority in mathematics).
  • 1 is not represented as 1 * 2 ^ 0 , since the mantissa is always less than 1, so the representation will be 0.5 * 2 ^ 1 .
  • 65, which has a binary representation as 1000001, will be saved as (65/128) * 2 ^ 7 .

These numbers are represented as (remember: the first "1" is implicit, since these indicators are for normalized numbers):

 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). 

and

 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...) 

Note about the exponent: a lower precession can be achieved by providing negative indicators: The indicators seem positive - do not match, but the reality is that you have to subtract 1023 (called the β€œbias”) to this number to get the actual indicator (this means that the indicator "1" actually corresponds to 2 ^ (- 1022)). Translating this to a 10-level power, the lowest figure is -308 for decimal numbers (also considering the possibility of mantissa, as I will show later). Least Positive Number:

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

which: (1 * 2^-52) * 2^-1023 is the first -52 given by the mantissa and -1023. The last of them: 1 * 2 ^ (- 1075), which goes in the direction 10 ^ -308, is always said.

The lowest value of 000 0000 0000 corresponds to (-1023). There is a rule: each mantissa should begin with (implicit) "1" or have this indicator. On the other hand, the highest metric might be 111 1111 1111 , but this metric is reserved for special aliases:

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

corresponds to + infinity, and:

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

matches -Infinity, and any pattern with a non-zero mantissa, for example:

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

correspond to NaN (not a number ideal for representing things like log (-1) or 0/0). Actually, I'm not sure which mantissa are used for NaN (either silent or signaling NaN). The question mark indicates any bit.

+28
Aug 07 '14 at 19:42
source share

The following hexadecimal number:

 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 

stored as the default value of the IEEE 754 float:

 1.3407807929942597e+154 

You add 1 to this number and it becomes:

 0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 

which is also saved as:

 1.3407807929942597e+154 

Both numbers are outside the range of numbers that can be exactly represented by a JavaScript number ( ref ). In the above example, both numbers end with the same internal representation, therefore, they are equal, equal.

Reminder: Do not compare floating point numbers using the equality operator ( ref ).

+4
Aug 12 '14 at 17:33
source share

This is obviously overflow or rounding. Mathematically work out the magnitude of the numbers and check against the largest number.

+2
Aug 7 '14 at 19:29
source share



All Articles