Paste JSON. This page lexes the raw text itself, computes the exact decimal value of every number literal with BigInt arithmetic, computes the exact value of the IEEE 754 double your parser will produce, and reports the difference. It ranks findings by whether the value survives a round trip, not by whether the value is exact.
Headline finding
The obvious check for this is String(JSON.parse(x)) !== x: parse it, print it back, compare the text. It reports nothing for any of the three literals below, and all three change value. They are 17 to 19 digit IDs ending in round digits, which is what you receive when an upstream JavaScript service already round-tripped a bigint through a double before handing it to you.
Computed in this browser when the page loaded, from these three literals only. Nothing above is stored in the page as text.
Nothing leaves the browser. Large documents are audited in full; only the rendered tables are capped, and the cap always prints the real total.
Findings are ordered by round-trip survival: whether the bytes you pasted come back out the other side, and whether the value behind them is the value you sent.
1.0, 1e2, 1.500, -0. These are what the naive heuristic reports as damage. One row with a count.Every audit runs two engines over the same literals and prints both answers.
String(JSON.parse(x)) !== x, spelled exactly that way, run per literal.The summary prints how many literals the exact engine says changed, how many of those the naive engine misses, and how many literals the naive engine flags whose value did not change at all. Every one of those counts comes from the document you pasted.
For every literal whose value changed, the exact engine also checks that the double is the correctly rounded nearest one, by verifying in BigInt that twice the absolute error is at most one ulp. That check is reported per document rather than assumed, because the double being compared against is the one this browser produced, which is the one your JavaScript code will see.
RFC 8259, section 6, Numbers. Quoted verbatim:
This specification allows implementations to set limits on the range and precision of numbers accepted.
Note that when such software is used, numbers that are integers and are in the range [-(2**53)+1, (2**53)-1] are interoperable in the sense that implementations will agree exactly on their numeric values.
A JSON number such as 1E400 or 3.141592653589793238462643383279 may indicate potential interoperability problems, since it suggests that the software that created it expects receiving software to have greater capabilities for numeric magnitude and precision than is widely available.
Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted.
Leading zeros are not allowed.
The grammar itself carries no magnitude or precision bound. The repetition operators are unbounded, so an arbitrarily long integer part, fraction part and exponent are all well formed JSON. RFC 8259, section 6, quoted verbatim:
number = [ minus ] int [ frac ] [ exp ]
decimal-point = %x2E ; .
digit1-9 = %x31-39 ; 1-9
e = %x65 / %x45 ; e E
exp = e [ minus / plus ] 1*DIGIT
frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )
minus = %x2D ; -
plus = %x2B ; +
zero = %x30 ; 0
Source: https://www.rfc-editor.org/rfc/rfc8259#section-6. That is why the grammar lane on this page is reported separately from the value lane: a literal can be perfectly legal JSON and still be a value your parser cannot hold, and a literal can be rejected by a strict parser while its value is exactly representable.