1

I have recently discovered a strange JS snippet, however I'm not sure if it's a bug or there is some logic for it.

Try this number: 9000000022903136*8* Alert it, console.log it, assign it to a variable. You will get the value 9000000022903136*0*. The question is why? Is it a bug?

I have also noticed that you get 90000000229031360 from 90000000229031352 to 90000000229031368, for 90000000229031351 you get 90000000229031340, for 90000000229031369 you get 90000000229031369.

This happens on : Chrome, FF, Node.js

Silviu Burcea
  • 5,103
  • 1
  • 29
  • 43
  • 1
    JavaScript stores *every* number as a float internally, including integers. You're just losing precision. – Blender Oct 23 '13 at 05:44
  • Is there a way to avoid losing precision? Is there something like BigInteger in Java or something with higher precision? – Silviu Burcea Oct 23 '13 at 05:49
  • Google "bigint javascript". There's nothing built-in. – Blender Oct 23 '13 at 05:50
  • possible duplicate of [Is JavaScript's Floating-Point Math Broken?](http://stackoverflow.com/questions/588004/is-javascripts-floating-point-math-broken) – Peter O. Oct 23 '13 at 05:58
  • @PeterO.Actually, this is not a duplicate. The problems are related, because I just found out that JS numbers are stored as floating point, but it's not the same thing for sure. – Silviu Burcea Oct 23 '13 at 06:02

2 Answers2

3

Well, numbers in computers are limited (mostly). What you see here is the classic overflow of a floaty/doubly stored number, which can hold a number of digits, and the exponent of it, for instance (the actual implementation differs, of course):

123 is stored as [1 2 3], exponent 2. 1.23 is stored as [1 2 3], exponent 0.

So, 90000000229031368 is stored as:

[9 0 0 0 0 0 0 0 2 2 9 0 3 1 3 6], exponent 16. And as you can see, there is no more room for the last 8 digit, so it is set when you read it.

The other examples might seem contradictory, but keep in mind that the computer does not store those digits in base 10, but base 2.

Read more on this subject with the keywords: Float floating-point (e.g. on Wikipedia).

thriqon
  • 2,458
  • 17
  • 23
  • Thank you for the nice explanation, I wasn't aware that integers in JS are not really integers. – Silviu Burcea Oct 23 '13 at 06:03
  • @SilviuBurcea There are no integers in JS yet. There's a single Number type, and its IEEE 64-bit floating point (often called "IEEE double"). There are proposals to add real integer types to the language, or at least real 64-bit integers. – Boris Zbarsky Oct 23 '13 at 06:48
3

That's because javascript numbers are 64 bit floats.

Floating point numbers have 2 parts - the fractional part which defines the "value" of the number and the exponent part which defines how far to the left or right of the decimal point the number should be shifted.

To illustrate how this work I'll be using an imaginary floating point number format that is decimal based instead of binary:

Let's define our imaginary format as 8 character floats - that is the number must be stored within 8 characters. Lets partition our format to have 6 characters as the fractional part and 2 characters as the exponent:

   _ _ _ _ _ _ _ _
  |_ _|_ _ _ _ _ _|  <--- 8 char float
exponent   fractional

For ease of discussion, let's invent a syntax to describe the format:

exponent,fractional

So for example, the number 128 can be stored as 0,128 and PI can be stored as -5,314159 (the decimal point shifted to the left by 5 places).

The PI case above is how programmers first encounter floating point numbers - they need to work with fractional numbers instead of simple integers. But the floating point format also has another feature - it can store numbers bigger than the space allocated for the fractional part!

For example, what if we want to store the number 987654321 in our imaginary 8char floating point format? It's more than 6 characters! Well, we'd do it like this: 2,9876543. That is, we store the most significant digits and shift the decimal point 2 spaces to the right.

If we try to read that number, what well get is 987654300. We've lost the least significant digits! Hmm.. sounds familiar.

In the case of javascript, the format is IEEE 754 64bit binary floating point. It has 52 bits allocated for the fractional part (53 if you include the sign bit). Which means that for numbers of up to 52 bits it behaves just like an integer. Any larger and it will begin sacrificing the least significant bits (not digits, bits, so the rounding may appear odd to us humans).

See this wikipedia article for more details on how 64bit floats work: http://en.wikipedia.org/wiki/Double_precision_floating-point_format

slebetman
  • 109,858
  • 19
  • 140
  • 171