Jsoncpp writes float values ​​incorrectly

I am reading from a JSON file using jsoncpp. When I write back to the file, my floating point values ​​are a bit off. For testing, I decided to parse the file to Json :: Value, and then write that value back to the file. I expect it to look the same, but the float values ​​are different instead.

Example:

"Parameters": { "MinXValue": 0.1, "MaxXValue": 0.15, "MinYValue": 0.25, "MaxYValue": 1.1, "MinObjectSizeValue": 1 } 

is written as:

 "Parameters": { "MinXValue": 0.10000000000000001, "MaxXValue": 0.14999999999999999, "MinYValue": 0.25, "MaxYValue": 1.1000000238418579, "MinObjectSizeValue": 1 } 

You may notice that 0.25 has not changed, although all other floats. Any idea what is going on here?

+6
source share
1 answer

Actually, this is the problem of implementing parsing floating point numbers. Although floating point numbers can accurately represent only some decimal numbers (0.25 is one of ~ 2 ^ 64), you need to parse the string representation to the nearest binary representation. When printing with floating point, you must also print a (preferably shortest) string representation, which can be restored in binary representation.

I admit that I did not research JsonCPP to see if there is a solution for this. But since I am the author of RapidJSON , I tried to see how RapidJSON performs for this:

 const char json[] = "{" "\"MinXValue\": 0.1," "\"MaxXValue\": 0.15," "\"MinYValue\": 0.25," "\"MaxYValue\": 1.1," "\"MinObjectSizeValue\": 1" "}"; using namespace rapidjson; Document d; d.Parse(json); StringBuffer sb; PrettyWriter<StringBuffer> writer(sb); d.Accept(writer); std::cout << sb.GetString(); 

And the result:

 { "MinXValue": 0.1, "MaxXValue": 0.15, "MinYValue": 0.25, "MaxYValue": 1.1, "MinObjectSizeValue": 1 } 

RapidJSON implemented both parsing and printing algorithms. Conventional parsing will have a maximum of 3 ULP errors, but with the full precision parsing flag ( kParseFullPrecisionFlag ), it can always parse to the nearest view. In terms of printing, the Grisu2 algorithm is implemented. It always generates an accurate result and more than 99% of the time will be the shortest (optimal).

Actually, using strtod() and sprintf(..., "%.17g", ...) can also solve this problem. But in the current C / C ++ standard library, they are much slower. For example, I made a benchmark to print double . Thus, in RapidJSON we implemented our own optimized header-only solutions.

+2
source

Source: https://habr.com/ru/post/985817/


All Articles