3

I was looking at Number.isInteger() on MDN. I came upon this example -

Number.isInteger(5.000000000000001); // false

I changed the value to 5.0000000000000001 and if I execute the same method on the console, the result is:

Number.isInteger(5.0000000000000001); // true

Also 5.0000000000000001 === 5 comes out to be true.

Can someone please explain what's happening here?

Tushar Arora
  • 966
  • 2
  • 7
  • 21
  • 1
    [IEEE floating point](https://en.wikipedia.org/wiki/IEEE_754) – Matt Ellen May 24 '19 at 09:01
  • 3
    [Is floating point math broken?](https://stackoverflow.com/questions/588004) – adiga May 24 '19 at 09:01
  • 1
    @Tushar: For numbers around 5 (just above 2**2), JavaScript’s Number format uses increments of 2**−50. The .000000000000001 of 5.000000000000001 is about 1.1259 of those increments, so, when 5.000000000000001 is converted to the Number format, the low 1 digit contributes one increment to the value. With one more zero, the .0000000000000001 of .0000000000000001 is about .11259 of those increments. So, when 5.0000000000000001 is converted to the Number format, that low 1 digit results in no additional increments. The result is 5. – Eric Postpischil May 24 '19 at 12:23
  • @EricPostpischil — Please don't answer in the comments. It's barely readable. – Quentin May 24 '19 at 13:31
  • 1
    @EricPostpischil Thank you for elaborating on that. Now that the duplicate tag has been removed, could you add this as an answer? – Tushar Arora May 24 '19 at 13:36
  • @Quentin: There was not an alternative at the time; the question had been improperly marked as a duplicate. – Eric Postpischil May 24 '19 at 17:27
  • @Jamiec: This is not a duplicate of [that question](https://stackoverflow.com/questions/56289197/can-anyone-please-elaborate-number-precision-and-overflow-in-javascript). This question requests elaboration of the precision, which is not covered in the other question. Please do not promiscuously mark questions as duplicates of that question. – Eric Postpischil May 24 '19 at 17:28

1 Answers1

3

JavaScript uses the IEEE-754 basic 64-bit binary floating-point format. In this format, every finite number is expressed as an integer M times a power of 2, 2E. The magnitude of M must be less than 253, and E may be from −1074 to 971. (The more common description scales M and E differently, so that M has fraction bits instead of being an integer, but this is equivalently mathematically.)

For the number 5.000000000000001, the most precisely it can be represented is to use E = −50, because this makes M as large as will fit, about 5•250 = 1.25•252. If we made E one smaller, M would have to be about 1.25•253, which exceeds the 253 limit.

So, given E = −50, we want 5.000000000000001 = M•2−50, which means M = 5.000000000000001•250 = 5•250 + .000000000000001•250. Obviously the first term, 5•250, is an integer. The second term, .000000000000001•250, is about 1.1259. So, when converting 5.000000000000001 to JavaScript’s Number format, we need to make M an integer, so we have to round 1.1259 to 1. The result is M = 5•250 + 1, so the number is (5•250 + 1)•2−50 = 5.00000000000000088817841970012523233890533447265625.

On the other hand, when we have 5.0000000000000001, with one more zero, we have 5.0000000000000001•250 = 5•250 + .0000000000000001•250. In this case, the second term, .0000000000000001•250, is about .11259. So, when converting 5.0000000000000001 to JavaScript’s Number format, we have to round .11259 to 0, so the number is ((5•250)•2−50 = 5.

Eric Postpischil
  • 141,624
  • 10
  • 138
  • 247