2012-04-29 18 views
7

मैं जब मैं अंक मान चल और उन्हें 1.फ़्लोटिंग पॉइंट जोड़ और गुणात्मक सहयोगी है?

cout << ((0.7 + 0.2 + 0.1)==1)<<endl;  //output is 0 
cout << ((0.7 + 0.1 + 0.2)==1)<<endl;  //output is 1 

की तुलना क्यों इन मूल्यों को अलग बाहर आएगा तीन जोड़ने था एक समस्या थी?

+0

आपका उदाहरण कोड * कम्यूटिटीविटी *, * * सहयोगी * में भिन्न नहीं है। एसोसिएटिविटी का प्रदर्शन करने वाला एक संस्करण '(0.7 + (0.1 + 0.2))' –

+0

@MattMcNabb: + एक बाइनरी ऑपरेशन होगा। फ्लोटिंग-पॉइंट ऑपरेंड के साथ, यह कम्यूटेटिव है लेकिन सहयोगी नहीं है। इस प्रकार, यदि आपके पास दो अभिव्यक्तियां हैं जो विभिन्न परिणामों का उत्पादन करती हैं, तो आप केवल कम्यूटिटीविटी लागू करके दूसरे से एक नहीं बना सकते हैं। – tmyklebu

+0

@tmyklebu ठीक है, इसलिए यह सहयोगीता की जांच करता है अगर केवल यह ज्ञात है कि कम्यूटिटीविटी है। (सी ++ मानक कम्यूटिटी की गारंटी के लिए प्रकट नहीं होता है)। –

उत्तर

10

फ़्लोटिंग पॉइंट जोड़ आवश्यक नहीं है। यदि आप उस क्रम को बदलते हैं जिसमें आप चीजें जोड़ते हैं, तो यह परिणाम बदल सकता है।

विषय पर मानक पेपर What Every Computer Scientist Should Know about Floating Point Arithmetic है। यह निम्नलिखित उदाहरण देता है:

एक और ग्रे क्षेत्र कोष्ठक की व्याख्या से संबंधित है। राउंडऑफ त्रुटियों के कारण, बीजगणित के सहयोगी कानून फ्लोटिंग-पॉइंट संख्याओं के लिए जरूरी नहीं हैं। उदाहरण के लिए, अभिव्यक्ति (x + y) + z में x + (y + z) की तुलना में एक बिल्कुल अलग उत्तर है जब x = 1e30, y = -1e30 और z = 1 (यह पूर्व मामले में 1 है, बाद में 0)।

5

क्या वर्तमान में लोकप्रिय मशीनों और सॉफ्टवेयर के साथ होने की संभावना है, यह है:

संकलक इनकोडिंग .7 के रूप में 0x1.6666666666666p -1 (इस हेक्साडेसिमल अंक 1.6666666666666 की शक्ति के लिए 2 से गुणा है -1), .2 0x1.999999999999ap-3 के रूप में, और .1 0x1.999999999999ap-4 के रूप में। इनमें से प्रत्येक फ़्लोटिंग-पॉइंट में प्रतिनिधित्व करने योग्य संख्या है जो आपके द्वारा लिखे गए दशमलव अंकों के सबसे नज़दीक है।

ध्यान दें कि इनमें से प्रत्येक हेक्साडेसिमल फ्लोटिंग-पॉइंट स्थिरांक में इसके महत्व में 53 बिट्स हैं ("अंश" भाग, जिसे अक्सर मंथिसा कहा जाता है)। महत्व के लिए हेक्साडेसिमल अंक में "1" और तेरह अधिक हेक्साडेसिमल अंक (चार बिट्स प्रत्येक, 52 कुल, 53 "1" सहित 53) हैं, जो 64-बिट बाइनरी फ़्लोटिंग के लिए आईईईई -754 मानक प्रदान करता है, बिंदु संख्या।

चलो .7 और .2: 0x1.6666666666666p-1 और 0x1.999999999999ap-3 के लिए संख्याएं जोड़ें। सबसे पहले, पहले मैच के लिए दूसरे नंबर के एक्सपोनेंट को स्केल करें। ऐसा करने के लिए, हम एक्सपोनेंट को 4 से गुणा करेंगे ("पी -3" को "पी -1" में बदलना) और 1/4 तक महत्व को गुणा करें, 0x0.66666666666668p-1 दे रहे हैं। फिर 0x1.6666666666666p-1 और 0x0.66666666666668p-1 जोड़ें, 0x1.ccccccccccccc8p-1 दे रहा है। ध्यान दें कि इस संख्या में 53 बिट्स से अधिक महत्व हैं: अवधि के बाद "8" 14 वां अंक है। फ़्लोटिंग-पॉइंट इस बिट्स के साथ परिणाम नहीं लौटा सकता है, इसलिए इसे निकटतम प्रतिनिधित्व करने योग्य संख्या में गोल किया जाना चाहिए। इस मामले में, दो संख्याएं हैं जो बराबर हैं, 0x1.cccccccccccccp-1 और 0x1.ccccccccccccdp-1। जब कोई टाई होती है, तो महत्व के सबसे निचले हिस्से में शून्य वाला नंबर उपयोग किया जाता है। "सी" भी है और "डी" विषम है, इसलिए "सी" का उपयोग किया जाता है। जोड़ का अंतिम परिणाम 0x1.cccccccccccccp-1 है।

अगला, उसमें .1 (0x1.999999999999ap-4) के लिए संख्या जोड़ें। फिर, हम एक्सपोनेंट मैच बनाने के लिए स्केल करते हैं, इसलिए 0x1.999999999999ap-4 0x.33333333333334p-1 बन जाता है। फिर 0x1.cccccccccccccp-1 में जोड़ें, 0x1.fffffffffffff4p-1 दे रहा है। गोल करने के लिए कि 53 बिट्स 0x1.fffffffffffffp-1 देता है, और यह ".7 + .2 + .1" का अंतिम परिणाम है।

अब ".7 + .1 + .2" पर विचार करें। ".7 + .1" के लिए, 0x1.6666666666666p-1 और 0x1.999999999999ap-4 जोड़ें। याद रखें कि बाद वाले को 0x.33333333333334p-1 तक स्केल किया गया है। फिर सटीक योग 0x1.9 99 99 99 99 99 99 4 पी -1 है। गोल करने से 53 बिट्स 0x1.999 99 99 99 99 99-1 देता है।

फिर .2 (0x1.999999999999ap-3) के लिए संख्या जोड़ें, जो 0x0.66666666666668p-1 तक स्केल किया गया है। सटीक राशि 0x2.00000000000008p-1 है। फ़्लोटिंग-पॉइंट के महत्व हमेशा 1 के साथ शुरू करने के लिए स्केल किए जाते हैं (विशेष मामलों को छोड़कर: शून्य, अनंतता, और प्रतिनिधित्व करने योग्य सीमा के नीचे बहुत छोटी संख्या), इसलिए हम इसे 0x1.00000000000004p0 पर समायोजित करते हैं।अंत में, हम 0 बिट 1.0000000000000p0 देकर 53 बिट्स तक पहुंचते हैं।

इस प्रकार, गोलाकार होने पर होने वाली त्रुटियों के कारण, ".7 + .2 + .1" 0x1.fffffffffffffp-1 (1 से थोड़ा कम), और ".7 + .1 +2" रिटर्न देता है 0x1.0000000000000p0 (बिल्कुल 1)।

1

फ़्लोटिंग पॉइंट गुणा सी या सी ++ में सहयोगी नहीं है।

सबूत:

#include<stdio.h> 
#include<time.h> 
#include<stdlib.h> 
using namespace std; 
int main() { 
    int counter = 0; 
    srand(time(NULL)); 
    while(counter++ < 10){ 
     float a = rand()/100000; 
     float b = rand()/100000; 
     float c = rand()/100000; 

     if (a*(b*c) != (a*b)*c){ 
      printf("Not equal\n"); 
     } 
    } 
    printf("DONE"); 
    return 0; 
} 

इस कार्यक्रम में, समय का लगभग 30%, (a*b)*c नहीं a*(b*c) के बराबर है।

+3

या 0% समय यदि 'RAND_MAX <100000'! –

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