12

My problem is really simple but I'm not sure if there's a "native" solution using JSON.parse.

I receive this string from an API :

{ "key" : -922271061845347495 }

When I'm using JSON.parse on this string, it turns into this object:

{ "key" : -922271061845347500 }

As you can see, the parsing stops when the number is too long (you can check this behavior here). It has only 15 exact digits, the last one is rounded and those after are set to 0. Is there a "native" solution to keep the exact value ? (it's an ID so I can't round it)

I know I can use regex to solve this problem but I'd prefer to use a "native" method if it exists.

Salman A
  • 262,204
  • 82
  • 430
  • 521
Simon
  • 1,679
  • 4
  • 21
  • 37
  • Try with, `{ "key" : "-922271061845347495" }` – Jashwant May 17 '12 at 07:25
  • 1
    This offers several answers: [stack overflow thread][1] [1]: http://stackoverflow.com/questions/209869/what-is-the-accepted-way-to-send-64-bit-values-over-json – Paul Jowett May 17 '12 at 07:52
  • Thanks, I probably didn't search with the good keywords, reason why i didn't find those explanations. As a solution, I am sending data as string and casting them into number on API side, in this way the db keeps on using Integers as IDs. – Simon May 17 '12 at 08:13

2 Answers2

17

Your assumption that the parsing stops after certain digits is incorrect.

It says here:

In JavaScript all numbers are floating-point numbers. JavaScript uses the standard 8 byte IEEE floating-point numeric format, which means the range is from:

±1.7976931348623157 x 10308 - very large, and ±5 x 10-324 - very small.

As JavaScript uses floating-point numbers the accuracy is only assured for integers between: -9007199254740992 (-253) and 9007199254740992 (253)

You number lies outside the "accurate" range hence it is converted to the nearest representation of the JavaScript number. Any attempt to evaluate this number (using JSON.parse, eval, parseInt) will cause data loss. I therefore recommend that you pass the key as a string. If you do not control the API, file a feature request.

Salman A
  • 262,204
  • 82
  • 430
  • 521
  • This doesn't actually answer the question, though. "Is there a native solution to keep the exact value?" – Andrew Leach May 17 '12 at 07:38
  • The native solution would be to write your own JSON parser that parses numbers as strings. – Salman A May 17 '12 at 08:00
  • @Salman A : Thanks for your explanations and advises. I will probably wait a little before making my own parser and sending keys as strings then parsing them into number on api side. – Simon May 17 '12 at 08:16
  • @G4llic4: the solution actually depends on whether you control the API or not. If you do, go ahead and change `key` to a string (assuming that you do not need to do any _math_ on it). – Salman A May 17 '12 at 08:27
  • As i have to preserve api efficiency I will still use Number. The client will send the ID as a string and I will cast it into Number on api side. – Simon May 17 '12 at 08:39
4

The number is too big to be parsed correctly.

One solution is:

  1. Preprocessing your string from API to convert it into string before parsing.
  2. Preform normal parsing
  3. Optionally, you could convert it back into number for your own purpose.

Here is the RegExp to convert all numbers in your string (proceeded with :) into strings:

 // convert all number fields into strings to maintain precision
 // : 922271061845347495, => : "922271061845347495",
 stringFromApi = stringFromApi.replace(/:\s*(-?\d+),/g, ': "$1",');

Regex explanation:

  • \s* any number of spaces
  • -? one or zero '-' symbols (negative number support)
  • \d+ one or more digits
  • (...) will be put in the $1 variable
Fortega
  • 19,463
  • 14
  • 75
  • 113
  • Careful with this, it won't catch numbers at the end of an object (since there won't be a comma) – sham Apr 27 '22 at 12:35