सामग्री पर जाएँ
Topos Uranos

सारांश

किसी प्रोग्राम की दशमलव वाली संख्याएँ गणित की वास्तविक संख्याएँ नहीं हैं: वे उन परिमेय संख्याओं का एक परिमित उपसमुच्चय हैं जिनका हर दो की कोई घात है, और जो भी मान इस उपसमुच्चय में नहीं आता, उसकी जगह उसमें आने वाला सबसे निकट का मान ले लेता है। यह पाठ अध्ययन करता है कि एक फ़्लोटिंग-पॉइंट संख्या 64 बिट (चिह्न, घातांक और मैंटिसा) में कैसे रखी जाती है, क्यों 0.10.1 का कोई सटीक निरूपण नहीं है और उसकी जगह कौन-सा मान आता है, float और double में कितने अंक सुरक्षित हैं, पूर्णांकन की त्रुटियाँ कैसे संचित होती हैं, दो वास्तविक संख्याओं की तुलना == से क्यों नहीं की जाती और एक औचित्यपूर्ण सहनसीमा से कैसे की जाती है, और अनंत तथा अ-संख्या क्या हैं, जिन्हें यह प्रारूप उन परिणामों के लिए आरक्षित रखता है जो समाते नहीं या जिनका अस्तित्व नहीं है।

अधिगम उद्देश्य

  1. समझाना कि 0.10.1 का कोई सटीक द्विआधारी निरूपण क्यों नहीं है और उसकी जगह कौन-सा मान रखा जाता है।
  2. बार-बार के योगों में और बहुत भिन्न परिमाण वाली संख्याओं के योग में पूर्णांकन के प्रभाव का पूर्वानुमान करना।
  3. वास्तविक संख्याओं की तुलना == के बजाय एक उपयुक्त सहनसीमा से करना, और सहनसीमा के चुनाव का औचित्य बताना।
  4. आवश्यक परिशुद्धता के अनुसार float और double में से चुनना, और अनंत तथा अ-संख्या को पहचानना।

आधार 2 में वैज्ञानिक संकेतन

पाठ पूर्णांक और उनका निरूपण ने दिखाया कि nn बिट का एक पूर्णांक ठीक 2n2^n क्रमागत मानों को निरूपित करता है। लेकिन दशमलव वाली संख्याएँ एक अलग कठिनाई खड़ी करती हैं: किन्हीं भी दो वास्तविक संख्याओं के बीच अनंत अन्य संख्याएँ होती हैं, और बिटों की कोई भी परिमित संख्या उन सबमें भेद नहीं कर सकती। आज के सभी कंप्यूटर जो हल अपनाते हैं, वह वही है जिसका उपयोग विज्ञान बहुत बड़े या बहुत छोटे परिमाण लिखने के लिए करता है: वैज्ञानिक संकेतन। आधार 10 में पृथ्वी से सूर्य की औसत दूरी 1.496×10111.496 \times 10^{11} मीटर लिखी जाती है; इस संख्या का एक चिह्न है, कुछ सार्थक अंक हैं (मैंटिसा, 1.4961.496) और आधार की एक घात है (घातांक, 1111), जो बताता है कि दशमलव बिंदु कहाँ आता है। यदि ऐसा है, तो अंकों की एक नियत संख्या से बहुत भिन्न कोटि के परिमाण ढके जा सकते हैं, इस मूल्य पर कि हर परिमाण के केवल पहले अंक रखे जाते हैं।

कंप्यूटर यही काम आधार 2 में करता है। शून्य से भिन्न हर संख्या एक ही तरीके से इस रूप में लिखी जाती है

x=(−1)s×1.m1m2m3…m52 (2)×2ex = (-1)^{s} \times 1.m_1 m_2 m_3 \ldots m_{52} \, {}_{(2)} \times 2^{e}

जहाँ ss चिह्न है (धनात्मक के लिए 0, ऋणात्मक के लिए 1), 1.m1m2…1.m_1 m_2 \ldots द्विआधारी में लिखा मैंटिसा है, जिसका पहला अंक सदा 1 होता है, और ee घातांक है। पहले अंक के सदा 1 होने का एक व्यावहारिक परिणाम है: उसे रखने की आवश्यकता नहीं होती, और जो बिट बचता है वह परिशुद्धता के काम आता है। फ़्लोटिंग-पॉइंट नाम ठीक इसी रूप का वर्णन करता है: दशमलव बिंदु अंकों के बीच किसी नियत स्थान पर नहीं रहता, बल्कि घातांक के अनुसार “तैरता” है।

C++ का प्रकार double सभी वर्तमान कंपाइलरों में अंतरराष्ट्रीय स्तर पर मानकीकृत 64 बिट के डबल-प्रिसिज़न बाइनरी प्रारूप का उपयोग करता है: चिह्न के लिए 1 बिट, घातांक के लिए 11 बिट और मैंटिसा के लिए 52 बिट, पहले अंक के बिना। घातांक खिसकाकर रखा जाता है: 11 बिट के फ़ील्ड में e+1023e + 1023 रहता है, जिससे वह फ़ील्ड घातांकों के लिए, जो −1022-1022 से 10231023 तक हैं, 1 से 2046 तक के अचिह्नित मान रखता है (फ़ील्ड के मान 0 और 2047 शून्य, बहुत छोटी संख्याओं, अनंत और अ-संख्या के लिए आरक्षित हैं, जिन्हें पाठ के अंत में देखा जाएगा)। प्रकार float 32 बिट के सिंगल-प्रिसिज़न प्रारूप का उपयोग करता है: चिह्न के लिए 1, घातांक के लिए 8 और मैंटिसा के लिए 23।

एक double के बिट देखे जा सकते हैं। नीचे दिया गया प्रोग्राम std::bit_cast का उपयोग करता है, जो हेडर <bit> से आता है और संख्या के 64 बिटों को, किसी को बदले बिना, 64 बिट के एक अचिह्नित पूर्णांक के रूप में फिर से पढ़ता है; यहाँ इसे और समझाए बिना, मेमोरी में झाँकने के एक उपकरण की तरह उपयोग किया गया है। फ़ॉर्मैट विनिर्देश {:064b} उस पूर्णांक को द्विआधारी में 64 अंकों के साथ लिखता है, जैसा इससे पहले के पाठ में हुआ था, और {:016X} षोडशआधारी में 16 अंकों के साथ।

C++ प्रोग्राम
#include <bit>#include <cstdint>#include <print>​int main(){    const double tenth{0.1};    // संख्या के 64 बिट, एक अचिह्नित पूर्णांक के रूप में पढ़े गए।    const std::uint64_t bits{std::bit_cast<std::uint64_t>(tenth)};    std::println("{:064b}", bits);    std::println("{:016X}", bits);}
आउटपुट
00111111101110011001100110011001100110011001100110011001100110103FB999999999999A
उदाहरण0.1 के 64 बिट

चित्र प्रोग्राम द्वारा लिखे गए 64 बिटों को समूहों में बाँटता है और उन्हें फ़ील्ड-दर-फ़ील्ड पढ़ता है।

प्रमाण

  1. 1+11+52=641 + 11 + 52 = 64

    64 बिट, षोडशआधारी में 3FB999999999999A। ये बाएँ से दाएँ पढ़े जाते हैं: चिह्न का 1 बिट, घातांक के 11 और मैंटिसा के 52।

  2. s=0s = 0

    चिह्न 0 है: संख्या धनात्मक है।

  3. e=1019−1023=−4e = 1019 - 1023 = -4

    घातांक का फ़ील्ड, द्विआधारी में 0111111101101111111011, 1019 के बराबर है; उसमें से खिसकाव, 1023, घटाया जाता है, और घातांक −4-4 आता है।

  4. m≈1.6000000000000000888m \approx 1.6000000000000000888

    मैंटिसा, उस आरंभिक 1 के साथ जो रखा नहीं जाता, द्विआधारी में 1.1001100110011…10101.1001100110011\ldots1010 है: समूह 10011001 दोहराता है और अंतिम समूह, 10101010, ऊपर की ओर पूर्णांकित है। इसका मान लगभग 1.60000000000000008881.6000000000000000888 है।

  5. x=0.1000000000000000055511…≠0.1x = 0.1000000000000000055511\ldots \neq 0.1

    रखी गई संख्या +1.6000000000000000888×2−4+1.6000000000000000888 \times 2^{-4} है, अर्थात् 0.1000000000000000055511…0.1000000000000000055511\ldots: 0.10.1 के बहुत निकट, पर 0.10.1 नहीं।