anhero / JsonBox

This is a JSON C++ library. It can write and read JSON files with ease and speed.
MIT License
115 stars 60 forks source link

JsonBox::Value uses insufficient precision when outputting Doubles to a JSON stream #18

Closed kevpatt closed 9 years ago

kevpatt commented 10 years ago

JavaScript uses IEEE 754 double-precision binary floating point internally for representation of all numbers. This is a 64-bit floating point type that is identical to C++ "double".

When writing a JsonBox::Value containing a double to a stream, the stream precision should be set to 17, which is the maximum number of resolvable decimal digits that can be represented by an IEEE 754 number. This is the only way to preserve all the original precision of the stored number and avoid rounding off the digits of even relatively small numbers. Since JavaScript uses "double" natively for all numbers, it only makes sense to preserve the full precision of these numbers in JSON.

Here is a patch to correct the issue:

--- src/Value.cpp   2013-05-23 17:38:30.000000000 -0400
+++ src/new/Value.cpp   2014-01-28 11:58:32.000000000 -0500
@@ -1080,7 +1080,12 @@
            break;

        case Value::DOUBLE:
-           output << v.getDouble();
+           {
+               std::streamsize p = output.precision();
+               output.precision(17);
+               output << v.getDouble();
+               output.precision(p);
+           }
            break;

        case Value::OBJECT:
kevpatt commented 10 years ago

BTW, this will not create longer numbers in the output unless the stored number actually needs the extra digits. It will also not induce pointless "zero-padding". The default stream behavior is to use only the number of digits required, up to the maximum specified by precision().