Jsoncpp写错误的浮动值 [英] Jsoncpp writing float values incorrectly

查看:999
本文介绍了Jsoncpp写错误的浮动值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用jsoncpp从JSON文件读取数据。当我回写到文件时,我的浮点值稍微偏离。为了测试,我决定将文件解析为Json :: Value,然后将该值写回文件。我希望它看起来是一样的,但是浮动值是不同的。




$参数
{
MinXValue:0.1,
MaxXValue:0.15,
MinYValue:0.25,
MaxYValue:1.1,$ b $MinObjectSizeValue:1

$ / code $ / pre

写作:

<$

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



<你可能会注意到,尽管所有其他的花车都做了,但0.25并没有改变。任何想法是什么在这里?

解决方案

它实际上是一个浮点数解析/打印实现的问题。尽管浮点数只能精确地表示一些十进制数(0.25是〜2 ^ 64之一),但是有必要将字符串表示法解析为最接近的二进制表示形式。当打印浮点时,还需要打印(最好是最短的)字符串表示形式,以便将其恢复为二进制表示形式。



我承认我没有调查JsonCPP来看看是否有解决方案。但是,因为我是 RapidJSON 的作者,所以我试着看看RapidJSON是如何执行的:


$ b $

  const char json [] = 
{
\MinXValue \:0.1,
\MaxXValue \:0.15,
\MinYValue \:0.25,
\MaxYValue \:1.1,
\MinObjectSizeValue \:1
};

使用namespace rapidjson;

文件d;
d.Parse(json);

StringBuffer sb;
PrettyWriter< StringBuffer>作家(SB);
d。接受(作家);

std :: cout<< sb.GetString();

结果:
$ b $

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

RapidJSON在内部实现了解析和打印算法。正常的精度解析将有最多3个ULP错误,但是具有完全精度解析标志( kParseFullPrecisionFlag ),它总是可以解析到最近的表示。打印部分实现了Grisu2算法。它总是产生一个确切的结果,超过99%的时间是最短的(最佳)。



实际上,使用 strtod() sprintf(...,%.17g,...)也可以解决这个问题。但是在目前的C / C ++标准库中它们要慢得多。例如,我已经完成了基准,以打印 double 。因此,在RapidJSON中,我们实现了自己的优化头标解决方案。


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

Example:

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

writes as:

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

You may notice that 0.25 did not change, even though all of the other floats did. Any idea what's going on here?

解决方案

It is actually an issue of floating point number parsing/printing implementation. Although floating point numbers can only represent some decimal numbers exactly (0.25 is one of ~2^64), it is necessary to parse a string representation to the nearest binary representation. When printing floating point, it is also necessary to print the (preferably the shortest) string representation which can be restored to the binary representation.

I admit that I had not investigate JsonCPP to see if there is a solution for this. But as 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 internally. Normal precision parsing will have maximum 3 ULP errors, but with full precision parsing flag (kParseFullPrecisionFlag) it can always parse to nearest representation. The printing part implemented Grisu2 algorithm. It does always generate an exact result, and more than 99% of time to be shortest (optimal).

Actually, using strtod() and sprintf(..., "%.17g", ...) can solve this problem too. But they are much slower in current C/C++ standard library. For example, I have done a benchmark for printing double. So in RapidJSON we implemented its own optimized header-only solutions.

这篇关于Jsoncpp写错误的浮动值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆