2015-04-23 44 views
5

我正在使用jsoncpp從JSON文件中讀取數據。當我回寫該文件時,我的浮點值稍微偏離。爲了測試,我決定將文件解析爲Json :: Value,然後將該值寫回文件。我希望它看起來一樣,但是浮動值是不同的。Jsoncpp錯誤地寫入浮動值

例子:

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

這樣寫道:

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

你可能會注意到,0.25沒有改變,即使其他所有的花車一樣。任何想法這裏發生了什麼?

+0

某些浮點值可以用二進制精確表示,有些浮點值不能。你所看到的是你的價值觀的最接近的表現。 –

+0

浮點數不準確。他們是有限記憶中的最佳表現。 PS 0.25是與二進制工作相關的四分之一summat ;-) –

+0

感謝您的澄清。無論如何要避免這種情況? – SFBA26

回答

2

這實際上是一個浮點數解析/打印實現的問題。儘管浮點數只能精確地表示一些十進制數(0.25是〜2^64之一),但有必要將字符串表示法解析爲最接近的二進制表示形式。在打印浮點時,還需要打印可以恢復爲二進制表示的(最好是最短的)字符串表示。

我承認我沒有調查JsonCPP,看看是否有解決方案。但正如我的RapidJSON作者,我想看看RapidJSON如何執行此:

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(); 

而結果:

{ 
    "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++標準庫中要慢得多。例如,我已經完成了benchmark的打印double。所以在RapidJSON中,我們實現了自己的優化頭標解決方案。

+3

感謝您的回覆。不幸的是,我沒有編寫原始代碼,現在切換到RapidJSON爲時已晚。我嘗試使用to_string在寫入JSON之前轉換浮點數,但在使用.AsFloat()讀取保存的值時出現錯誤。所以我認爲我唯一的選擇是在寫入時將字符串轉換爲字符串,並將其讀取爲字符串,然後轉換爲浮點型。 – SFBA26