See this code:

```
<html>
<head>
<script src="http://www.json.org/json2.js" type="text/javascript"></script>
<script type="text/javascript">
var jsonString = '{"id":714341252076979033,"type":"FUZZY"}';
var jsonParsed = JSON.parse(jsonString);
console.log(jsonString, jsonParsed);
</script>
</head>
<body>
</body>
</html>
```

When I see my console in Firefox 3.5, the value of jsonParsed is:

```
Object id=714341252076979100 type=FUZZY
```

I.e the number is rounded. Tried different values, the same outcome (number rounded).

I also don't get its rounding rules. 714341252076979136 is rounded to 714341252076979200, whereas 714341252076979135 is rounded to 714341252076979100.

**EDIT:** See first comment below. Apparently this is not about JSON, but something about JavaScript number handling. But the question remains:

Why is this happening?

What you're seeing here is actually the effect of two roundings. Numbers in ECMAScript are internally represented double-precision floating-point. When `id`

is set to `714341252076979033`

(`0x9e9d9958274c359`

in hex), it actually is assigned the nearest representable double-precision value, which is `714341252076979072`

(`0x9e9d9958274c380`

). When you print out the value, it is being rounded to 15 significant decimal digits, which gives `14341252076979100`

.

You're overflowing the capacity of JavaScript's number type, see §8.5 of the spec for details. Those IDs will need to be strings.

IEEE-754 double-precision floating point (the kind of number JavaScript uses) can't precisely represent **all** numbers (of course). Famously, `0.1 + 0.2 == 0.3`

is false. That can affect whole numbers just like it affects fractional numbers; it starts once you get above 9,007,199,254,740,991 (`Number.MAX_SAFE_INTEGER`

).

Beyond `Number.MAX_SAFE_INTEGER + 1`

(`9007199254740992`

), the IEEE-754 floating-point format can no longer represent every consecutive integer. `9007199254740991 + 1`

is `9007199254740992`

, but `9007199254740992 + 1`

is **also** `9007199254740992`

because `9007199254740993`

cannot be represented in the format. The next that can be is `9007199254740994`

. Then `9007199254740995`

can't be, but `9007199254740996`

can.

The reason is we've run out of bits, so we no longer have a 1s bit; the lowest-order bit now represents multiples of 2. Eventually, if we keep going, we lose that bit and only work in multiples of 4. And so on.

Your values are *well* above that threshold, and so they get rounded to the nearest representable value.

If you're curious about the bits, here's what happens: An IEEE-754 binary double-precision floating-point number has a sign bit, 11 bits of exponent (which defines the overall scale of the number, as a power of 2 [because this is a binary format]), and 52 bits of significand (but the format is so clever it gets 53 bits of precision out of those 52 bits). How the exponent is used is complicated (described here), but in **very** vague terms, if we add one to the exponent, the value of the significand is doubled, since the exponent is used for powers of 2 (again, caveat there, it's not direct, there's cleverness in there).

So let's look at the value `9007199254740991`

(aka, `Number.MAX_SAFE_INTEGER`

):

+??????????????????????????????????????????????????????????????? sign bit / +???????+?????????????????????????????????????????????????????? exponent / / | +?????????????????????????????????????????????????+? significand / / | / | 0 10000110011 1111111111111111111111111111111111111111111111111111 = 9007199254740991 (Number.MAX_SAFE_INTEGER)

That exponent value, `10000110011`

, means that every time we add one to the significand, the number represented goes up by 1 (the whole number 1, we lost the ability to represent fractional numbers much earlier).

But now that significand is full. To go past that number, we have to increase the exponent, which means that if we add one to the significand, the value of the number represented goes up by 2, not 1 (because the exponent is applied to 2, the base of this binary floating point number):

+??????????????????????????????????????????????????????????????? sign bit / +???????+?????????????????????????????????????????????????????? exponent / / | +?????????????????????????????????????????????????+? significand / / | / | 0 10000110100 0000000000000000000000000000000000000000000000000000 = 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)

Well, that's okay, because `9007199254740991 + 1`

is `9007199254740992`

anyway. But! We can't represent `9007199254740993`

. We've run out of bits. If we add just 1 to the significand, it adds 2 to the value:

+??????????????????????????????????????????????????????????????? sign bit / +???????+?????????????????????????????????????????????????????? exponent / / | +?????????????????????????????????????????????????+? significand / / | / | 0 10000110100 0000000000000000000000000000000000000000000000000001 = 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)

The format just cannot represent odd numbers anymore as we increase the value, the exponent is too big.

Eventually, we run out of significand bits again and have to increase the exponent, so we end up only being able to represent multiples of 4. Then multiples of 8. Then multiples of 16. And so on.

It is not caused by this json parser. Just try to enter 714341252076979033 to fbug's console. You'll see the same 714341252076979100.

See this blog post for details: http://www.exploringbinary.com/print-precision-of-floating-point-integers-varies-too

JavaScript uses double precision floating point values, ie a total precision of 53 bits, but you need

```
ceil(lb 714341252076979033) = 60
```

bits to exactly represent the value.

The nearest exactly representable number is `714341252076979072`

(write the original number in binary, replace the last 7 digits with `0`

and round up because the highest replaced digit was `1`

).

You'll get `714341252076979100`

instead of this number because `ToString()`

as described by ECMA-262, §9.8.1 works with powers of ten and in 53 bit precision all these numbers are equal.

The problem is that your number requires a greater precision than JavaScript has.

Can you send the number as a string? Separated in two parts?

JavaScript can only handle exact whole numbers up to about 9000 million million (that's 9 with 15 zeros). Higher than that and you get garbage. Work around this by using strings to hold the numbers. If you need to do math with these numbers, write your own functions or see if you can find a library for them: I suggest the former as I don't like the libraries I've seen. To get you started, see two of my functions at another answer.

©2020 All rights reserved.