Node.js का REPL खोलकर 0.1 + 0.2 टाइप करके देखिए — 0.3 की जगह जवाब मिलता है 0.30000000000000004। यह किसी एक भाषा की गड़बड़ी नहीं है — यह इस बात का सीधा नतीजा है कि IEEE 754 स्टैंडर्ड फ़्रैक्शनल नंबर को बाइनरी में कैसे दर्शाता है, और यही रिज़ल्ट Python, Java, PHP जैसी लगभग हर उस भाषा में दिखता है जो इस स्टैंडर्ड पर बनी है।
फ़्लोटिंग-पॉइंट नंबर के तीन हिस्से
IEEE 754 के हिसाब से एक नंबर तीन कॉम्पोनेंट के तौर पर स्टोर होता है: साइन (पॉज़िटिव या नेगेटिव), मैंटिसा (नंबर के मायने रखने वाले अंक), और एक्सपोनेंट (वह पावर जिससे दशमलव बिंदु शिफ़्ट होता है)। यह साइंटिफ़िक नोटेशन जैसा है: 1.5 × 10², बस बाइनरी में।
0.1 को बाइनरी में सटीक क्यों नहीं दर्शाया जा सकता
डेसिमल में 0.1, बाइनरी में एक अनंत फ़्रैक्शन है (कुछ वैसे ही जैसे डेसिमल में 1/3 अनंत होता है)। कंप्यूटर सिर्फ़ मैंटिसा के सीमित बिट स्टोर करता है, इसलिए नंबर को नज़दीकी दर्शाने लायक़ वैल्यू पर राउंड कर दिया जाता है — और यही राउंडिंग दिखने वाली "एरर" पैदा करती है।
यह असल में कहाँ नुक़सान पहुँचाता है: शॉपिंग कार्ट और बिलिंग
अगर किसी ई-कॉमर्स चेकआउट पेज पर हर आइटम की क़ीमत को साधारण float के तौर पर जोड़ा जाए, तो कई आइटम के बाद टोटल अपेक्षित रक़म से कुछ पैसे इधर-उधर हो सकता है — हर जोड़ में हल्का-सा राउंडिंग होता है, और यह ग़लती कैंसल होने की बजाय जमा होती जाती है। इसी वजह से पेमेंट सिस्टम आमतौर पर रुपयों की जगह पैसे को इंटीजर में गिनते हैं, या float/double की बजाय ख़ास decimal टाइप इस्तेमाल करते हैं।
यह किस काम आता है
- फ़ाइनेंशियल या साइंटिफ़िक कैलकुलेशन में अप्रत्याशित राउंडिंग एरर को समझना और डायग्नोज़ करना।
- किसी ख़ास फ़्लोटिंग-पॉइंट नंबर का सटीक बाइनरी रिप्रेज़ेंटेशन देखना।
- किसी साथी या स्टूडेंट को समझाना कि फ़्रैक्शनल नंबर की सटीक बराबरी के लिए तुलना करना एक बुरी प्रैक्टिस क्यों है।
ज़ीरो के पास सबनॉर्मल नंबर
जब किसी नंबर की वैल्यू सामान्य रिप्रेज़ेंटेशन (जो इम्प्लिसिट 1 से शुरू होने वाले सिग्निफ़िकेंड पर आधारित है) के लिए बहुत छोटी हो, तो IEEE 754 सबनॉर्मल (डीनॉर्मलाइज़्ड) मोड में चला जाता है, जहाँ यह इम्प्लिसिट 1 हटा दिया जाता है — इससे और भी छोटी वैल्यू वाले नंबर को अचानक ज़ीरो पर पहुँचने के बजाय धीरे-धीरे प्रिसीज़न खोते हुए दर्शाया जा सकता है। ज़ीरो की तरफ़ यह "स्मूद" शिफ़्ट अचानक ज़ीरो हो जाने से बेहतर है, लेकिन कुछ प्रोसेसर पर सबनॉर्मल कैलकुलेशन सामान्य कैलकुलेशन से काफ़ी धीमी होती है।