2013-05-16 19 views
8

हाल ही में, मैं पोस्ट पढ़ रहा था:समझौता: डबल या कुछ भी नहीं

int main() 
{ 
    double x = 1e8; 
    while(x > 0) 
    { 
     --x; 
    } 
} 

मान लें कि इस कोड को चलाता है: Double or Nothing from GOTW by Herb Sutter मैं एक छोटे से निम्नलिखित कार्यक्रम के विवरण के साथ उलझन में हूँ कुछ मशीन में 1 सेकंड। मैं इस बिंदु से सहमत हूं कि इस तरह का कोड मूर्खतापूर्ण है।

हालांकि, इस मुद्दे के बारे में विवरण के अनुसार अगर हम xfloat से double को बदलने के लिए, तो कुछ compilers पर, यह कंप्यूटर हमेशा के लिए चलते रहेंगे। स्पष्टीकरण मानक से निम्नलिखित उद्धरण पर आधारित है।

खंड सी ++ मानक के 3.9.1/8 से हवाला देते हुए:

रहे हैं तीन चल बिन्दु प्रकार: नाव, डबल, और लंबे समय तक डबल। प्रकार डबल कम से कम उतना सटीक प्रदान करता है जितना कि फ्लोट के रूप में, और लंबे समय तक डबल डबल के रूप में कम से कम सटीकता प्रदान करता है। प्रकार फ्लोट के मानों का सेट डबल प्रकार के मानों के सेट का एक सबसेट है; प्रकार डबल के मानों का सेट लंबे प्रकार के मानों के सेट का एक सबसेट है।

कोड के लिए सवाल यह है:

आप कब तक यदि आप "फ्लोट" बदल "डबल" यह लेने के लिए उम्मीद करेंगे? क्यूं कर?

यहाँ विवरण दिया है:

यह शायद या तो के बारे में 1 सेकंड ले जाएगा (एक विशेष कार्यान्वयन तैरता पर कुछ हद तक तेजी के रूप में तेजी से, या डबल्स की तुलना में कुछ धीमी हो सकती है,), या हमेशा के लिए , फ्लोट के आधार पर 0 से 1e8 समेत सभी पूर्णांक मानों का प्रतिनिधित्व कर सकते हैं या नहीं।

मानक से उपरोक्त उद्धरण का अर्थ है कि ऐसे मूल्य हो सकते हैं जिन्हें डबल द्वारा दर्शाया जा सकता है लेकिन इसे एक फ्लोट द्वारा प्रदर्शित नहीं किया जा सकता है। विशेष रूप से, कुछ लोकप्रिय प्लेटफार्मों और कंपाइलरों पर, डबल [0,1e8] में सभी पूर्णांक मानों का बिल्कुल प्रतिनिधित्व कर सकते हैं लेकिन फ्लोट नहीं कर सकता है।

क्या होगा यदि फ्लोट 0 से 1e8 तक सभी पूर्णांक मानों का बिल्कुल प्रतिनिधित्व नहीं कर सकता है? फिर संशोधित कार्यक्रम उल्टी गिनती शुरू कर देंगे, लेकिन अंत में एक मूल्य के एन जो नहीं दर्शाया जा सकता तक पहुंच जाएगा और जिसके लिए एन 1 == N (अपर्याप्त फ्लोटिंग प्वाइंट परिशुद्धता के कारण) ... और

मेरा सवाल है:

यदि फ्लोट 1e8 का प्रतिनिधित्व करने में भी सक्षम नहीं है, तो हमें float x = 1e8 प्रारंभ करने पर पहले से ही अतिप्रवाह होना चाहिए; तो हम कंप्यूटर को हमेशा के लिए कैसे चलेंगे?

मैं यहाँ एक सरल उदाहरण की कोशिश की है (हालांकि double नहीं लेकिन int)

#include <iostream> 

int main() 
{ 
    int a = 4444444444444444444; 
    std::cout << "a " << a << std::endl; 
    return 0; 
} 
It outputs: a -1357789412 

इसका मतलब यह है कि अगर संकलक int प्रकार के साथ दी गई संख्या का प्रतिनिधित्व करने में सक्षम नहीं है, यह अतिप्रवाह का परिणाम देगा।

तो क्या मैंने गलत पढ़ा? मुझे क्या याद आया? double से float अपरिभाषित व्यवहार बदल रहा है?

धन्यवाद!

उत्तर

9

कुंजी शब्द "बिल्कुल" है।

float1e8 का प्रतिनिधित्व कर सकता है, यहां तक ​​कि बिल्कुल, जब तक कि आपके पास 0kप्रकार का एक सनकी नहीं है। लेकिन इसका मतलब यह नहीं है कि यह सभी छोटे मूल्यों का बिल्कुल प्रतिनिधित्व कर सकता है, उदाहरण के लिए, आमतौर पर 2^25+1 = 33554433, जिसे परिशुद्धता के 26 बिट की आवश्यकता होती है, को float (आमतौर पर, जिसमें 23 + 1 बिट परिशुद्धता है) में बिल्कुल प्रतिनिधित्व नहीं किया जा सकता है, न ही 2^25-1 = 33554431, जो परिशुद्धता के 25 बिट की जरूरत है।

इन नंबरों की

दोनों तो 2^25 = 33554432 के रूप में प्रतिनिधित्व, और फिर

33554432.0f - 1 == 33554432.0f 

इच्छा पाश कर रहे हैं। (आप पहले एक लूप हिट करेंगे, लेकिन उसमें एक अच्छा दशमलव प्रतिनिधित्व है;)

पूर्णांक अंकगणित में, आपके पास x - 1 != x सभी x के लिए है, लेकिन फ्लोटिंग पॉइंट अंकगणित में नहीं है।

ध्यान दें कि float में केवल सामान्य 23 + 1 बिट्स सटीक होने के बावजूद लूप भी समाप्त हो सकता है, क्योंकि मानक फ्लोटिंग पॉइंट कंप्यूटेशंस को प्रकार की तुलना में अधिक सटीकता से बाहर करने की अनुमति देता है, और यदि गणना है पर्याप्त रूप से अधिक सटीकता (उदाहरण के लिए सामान्य double 52 + 1 बिट्स के साथ) पर प्रदर्शन किया जाता है, प्रत्येक घटाव x बदल जाएगा।

+0

अच्छी जानकारी के लिए धन्यवाद, लेकिन मेरा सवाल यह है कि अगर शुरुआती समय में ओवरफ्लो हो तो क्यों लूप भी शुरू होगा? – taocp

+2

@taocp आपके पास प्रारंभिकरण पर ओवरफ़्लो नहीं है। फ़्लोटिंग पॉइंट प्रारूप लगातार * सटीक * होते हैं जब तक आप उच्च मान पर नहीं जाते हैं जब तक कि आप + 1. # INF तक नहीं पहुंच जाते। अनंत पर संचालन, और # एनएएन कानूनी हैं, अपरिभाषित नहीं हैं। हालांकि उनके पास अप्रत्याशित परिणाम हो सकते हैं। [आईईईई -754 मानक] (https://en.wikipedia.org/wiki/IEEE_floating_point) पर एक नज़र डालें –

+0

@indeterminatelyately आह, इसके लिए बहुत बहुत धन्यवाद। – taocp

0

इस सरल संशोधन का प्रयास करें जो लगातार x मानों के मूल्य को cout करता है।

#include <iostream> 
using namespace std; 

int main() 
{ 
    float x = 1e8; 
    while(x > 0) 
    { 
     cout << x << endl; 
     --x; 
    } 
} 
नाव के कुछ कार्यान्वयन आपको लगता है कि नाव के मूल्यों या उस क्षेत्र में 1e8 में फंस रहे हैं, देखेंगे पर

। यह फ्लोट स्टोर्स नंबरों के रास्ते के कारण है। फ़्लोट (और न ही सीमित सीमित प्रतिनिधित्व कर सकते हैं) सभी संभावित दशमलव मानों का प्रतिनिधित्व कर सकते हैं, इसलिए जब आप फ्लोट में बहुत बड़े मूल्यों से निपटते हैं तो आपके पास अनिवार्य रूप से एक दशमलव होता है, जो कुछ शक्तियों में लगाया जाता है। खैर, यदि यह दशमलव मान किसी मान में समाप्त होता है जहां अंतिम बिट ड्रॉप हो जाता है, तो इसका मतलब है कि यह गोलाकार हो जाता है। जो आप समाप्त करते हैं वह वह मान है जो नीचे घटता है (फिर बैक अप)।

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