2015-04-23 13 views
5

मैं jsoncpp का उपयोग कर JSON फ़ाइल से पढ़ रहा हूं। जब मैं फ़ाइल पर वापस लिखता हूं, तो मेरे फ्लोट वैल्यू थोड़ा दूर होते हैं। परीक्षण के लिए, मैंने फ़ाइल को जेसन :: वैल्यू पर पार्स करने का निर्णय लिया और फिर उस मान को फ़ाइल में वापस लिखें। मैं इसे एक जैसा दिखने की उम्मीद करता हूं, लेकिन इसके बजाय फ्लोट वैल्यू अलग-अलग हैं।Jsoncpp फ़्लोट मानों को गलत तरीके से लिख रहा है

उदाहरण:

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

आप देख सकते हैं कि 0.25 परिवर्तन नहीं किया है, भले ही अन्य तैरता के सभी किया:

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

के रूप में लिखते हैं। कोई विचार क्या हो रहा है?

+0

कुछ फ़्लोटिंग पॉइंट मानों को बाइनरी में बिल्कुल दर्शाया जा सकता है और कुछ नहीं कर सकते हैं। जो आप देख रहे हैं वह आपके मूल्यों का सबसे नज़दीकी प्रतिनिधित्व है। –

+0

फ़्लोटिंग पॉइंट नंबर सटीक नहीं हैं। वे सीमित स्मृति में सबसे अच्छा प्रतिनिधित्व कर रहे हैं। पीएस 0.25 बाइनरी में काम करने के साथ एक चौथाई-सारांश है ;-) –

+0

स्पष्टीकरण के लिए धन्यवाद। क्या इससे बचने का कोई तरीका है? – SFBA26

उत्तर

2

यह वास्तव में फ़्लोटिंग पॉइंट नंबर पार्सिंग/प्रिंटिंग कार्यान्वयन का मुद्दा है। हालांकि फ्लोटिंग पॉइंट नंबर केवल कुछ दशमलव संख्याओं का प्रतिनिधित्व कर सकते हैं (0.25 ~ 2^64 में से एक है), निकटतम द्विआधारी प्रतिनिधित्व के लिए स्ट्रिंग प्रस्तुति को पार्स करना आवश्यक है। फ़्लोटिंग पॉइंट प्रिंट करते समय, (अधिमानतः सबसे छोटा) स्ट्रिंग प्रस्तुति मुद्रित करना भी आवश्यक है जिसे द्विआधारी प्रतिनिधित्व में बहाल किया जा सकता है।

मैं मानता हूं कि मैंने जेसनसीपीपी की जांच नहीं की है ताकि यह देखने के लिए कि कोई समाधान है या नहीं।

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 दोनों पार्स और मुद्रण एल्गोरिदम आंतरिक रूप से लागू किया लेकिन जैसा कि मैंने RapidJSON के लेखक हूँ, मैं कैसे RapidJSON इस के लिए यह देखने की कोशिश की। सामान्य परिशुद्धता पार्सिंग में अधिकतम 3 यूएलपी त्रुटियां होंगी, लेकिन पूर्ण परिशुद्धता पार्सिंग ध्वज (kParseFullPrecisionFlag) के साथ यह हमेशा निकटतम प्रतिनिधित्व के लिए पार्स कर सकती है। मुद्रण भाग Grisu2 एल्गोरिदम लागू किया। यह हमेशा सटीक परिणाम उत्पन्न करता है, और 99% से अधिक समय सबसे छोटा (इष्टतम) होता है।

वास्तव में, strtod() और sprintf(..., "%.17g", ...) का उपयोग करके भी इस समस्या को हल कर सकते हैं। लेकिन वे मौजूदा सी/सी ++ मानक पुस्तकालय में बहुत धीमे हैं। उदाहरण के लिए, मैंने double प्रिंट करने के लिए benchmark किया है। तो रैपिडजसन में हमने अपने स्वयं के अनुकूलित हेडर-केवल समाधान लागू किए।

+3

आपकी प्रतिक्रिया के लिए धन्यवाद। दुर्भाग्य से, मैंने मूल कोड नहीं लिखा था और अब रैपिडजसन पर स्विच करने में बहुत देर हो चुकी है। मैंने जेएसओएन को लिखने से पहले फ्लोट्स को कन्वर्ट करने के लिए to_string का उपयोग करने का प्रयास किया, लेकिन सहेजे गए मानों को पढ़ने के दौरान मुझे एक त्रुटि मिली .AFFatat()। तो मुझे लगता है कि एकमात्र विकल्प स्ट्रिंग में कनवर्ट करना है जब स्ट्रिंग के रूप में लिखना और पढ़ना, फिर फ्लोट में कनवर्ट करना। – SFBA26

संबंधित मुद्दे