views:

488

answers:

6

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:

WTF?

+3  A: 

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

thorn
Thanks for linking to my article, but it only explains half the problem -- the PRINTING of the internally rounded value. Even if javascript let you print the whole thing, it would still be wrong -- it would be the nearest representable double-precision value, as explained by others below.
Rick Regan
+4  A: 

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

T.J. Crowder
Wow, I never knew the ECMA site was so ugly.
cdmckay
+2  A: 

Your problem is that your numer requires a greater precission than javascript has.

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

voyager
+8  A: 

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.

Stephen Canon
+2  A: 

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.

Christoph
+1  A: 

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.

Robert L