C++
फ्लोटिंग प्वाइंट अंकगणित
खोज…
फ्लोटिंग पॉइंट नंबर अजीब हैं
लगभग हर एक प्रोग्रामर जो पहली गलती करता है, वह मान लेता है कि यह कोड इरादा के अनुसार काम करेगा:
float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
total += a;
}
नौसिखिए प्रोग्रामर मानता है कि यह हर एक नंबर को 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99
की सीमा में परिणाम देगा, परिणाम 199
यह गणितीय रूप से सही उत्तर देने के लिए होगा।
दो चीजें होती हैं जो इसे असत्य बनाती हैं:
- जैसा कि लिखा गया कार्यक्रम कभी समाप्त नहीं होता है।
a
कभी नहीं के बराबर हो जाता है2
, और पाश कभी नहीं समाप्त हो जाता है। - अगर हम लूप लॉजिक को फिर से लिखने के लिए
a < 2
को चेक करते हैं, तो लूप समाप्त हो जाता है, लेकिन कुल अंत199
से कुछ अलग है। IEEE754-आज्ञाकारी मशीनों पर, यह अक्सर लगभग201
बजाय योग करेगा।
ऐसा होने का कारण यह है कि फ़्लोटिंग पॉइंट नंबर उनके निर्धारित मानों के अनुमोदन का प्रतिनिधित्व करते हैं ।
शास्त्रीय उदाहरण निम्नलिखित गणना है:
double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
//This never prints on IEEE754-compliant machines
std::cout << "This Computer is Magic!" << std::endl;
else
std::cout << "This Computer is pretty normal, all things considered." << std::endl;
यद्यपि हम जो प्रोग्रामर देखते हैं वह बेस 10 में लिखे गए तीन नंबर होते हैं, जो कंपाइलर (और अंतर्निहित हार्डवेयर) बाइनरी नंबर होते हैं। क्योंकि 0.1
, 0.2
, और 0.3
से सही विभाजन की आवश्यकता होती है 10
एक आधार -2 में एक आधार -10 प्रणाली में काफी आसान है जो, लेकिन असंभव सिस्टम-इन नंबरों, अनिश्चित स्वरूपों में संग्रहीत किया जा करने के लिए कैसे संख्या समान 1/3
को बेस -10 में imprecise फॉर्म 0.333333333333333...
में संग्रहित किया जाना है।
//64-bit floats have 53 digits of precision, including the whole-number-part.
double a = 0011111110111001100110011001100110011001100110011001100110011010; //imperfect representation of 0.1
double b = 0011111111001001100110011001100110011001100110011001100110011010; //imperfect representation of 0.2
double c = 0011111111010011001100110011001100110011001100110011001100110011; //imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that this is not quite equal to the "canonical" 0.3!