2013-02-25 99 views
11

क्या कोई मुझे यहां हुड के नीचे क्या चल रहा है, इसे अनपैक करने में मदद कर सकता है?यहां राउंड ऑफ त्रुटि की प्रकृति क्या है?

>>> 1e16 + 1. 
1e+16 
>>> 1e16 + 1.1 
1.0000000000000002e+16 

मैं 64-बिट पायथन 2.7 पर हूं। सबसे पहले, मुझे लगता है कि फ्लोट के लिए केवल 15 की सटीकता है कि यह सिर्फ गोल-ऑफ त्रुटि है। सच्चा फ़्लोटिंग-पॉइंट उत्तर

10000000000000000.999999.... 

और दशमलव को कुछ हद तक लापता हो सकता है। लेकिन दूसरा परिणाम मुझे इस समझ पर सवाल करता है और वास्तव में 1 का प्रतिनिधित्व नहीं किया जा सकता है? कोई विचार?

[संपादित करें: बस स्पष्ट करने के लिए। मैं किसी भी तरह से सुझाव नहीं दे रहा हूं कि उत्तर "गलत" हैं। जाहिर है, वे सही हैं, क्योंकि, वे ठीक हैं। मैं बस समझने की कोशिश कर रहा हूं क्यों।]

+4

0,1 द्विआधारी चल बिंदु में असीम दोहराता, दशमलव में 1/3 की तरह थोड़े। –

+0

मुझे यह पता है, लेकिन मुझे समझ में नहीं आता कि इससे गोल-बंद व्यवहार का प्रदर्शन कैसे होगा। – jseabold

+1

यह भी ध्यान दें कि Python 2.6 और इससे पहले के परिणाम अलग होंगे। 2.7 में सबसे कम संभव दशमलव स्ट्रिंग दिखाने के लिए एक सुविधा शामिल है (http://docs.python.org/2/whatsnew/2.7.html#other-language-changes)। 2.6 के साथ, पहला परिणाम '10000000000000000.0' –

उत्तर

9

यह बस जितना हो सके उतना करीब है।

फ़्लोटिंग हेक्स में 1e16 0x4341c37937e08000 है।

1e16 + 2 0x4341c37937e08001 है।

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

+0

धन्यवाद है। एक सवाल। हेक्साडेसिमल क्यों?प्रतिनिधित्व की आसानी या क्या कुछ अंतर्निहित कारण है कि अंतर्निहित अंकगणित हेक्साडेसिमल में है? मुझे गहराई से खोदने की ज़रूरत होगी, मुझे लगता है कि एक भी संख्या (इस उदाहरण से परे) के दौर को समझने के लिए। – jseabold

+1

@jseabold हेक्साडेसिमल एक पावर ऑफ -2 बेस है, जिसका अर्थ यह है कि हेक्साडेसिमल में एक संख्या "दोहराना दशमलव" (वास्तव में दशमलव नहीं) है, और केवल-अगर यह बाइनरी में भी दोहराया जा रहा है, जो इसके लिए भ्रम से बचाता है विषय। –

+0

फ़्लोटिंग पॉइंट इसकी सटीकता को बदलता है क्योंकि संख्या की परिमाण में परिवर्तन होता है। बहुत छोटी संख्या के लिए, यह कमजोर भिन्नताओं का प्रतिनिधित्व कर सकते हैं। बहुत बड़ी संख्या के लिए, गोल करने वाली त्रुटि बहुत बड़ी हो सकती है - लेकिन महत्वपूर्ण बात यह है कि यह अभी भी प्रदर्शित होने वाली संख्याओं के सापेक्ष छोटा सा है। राउंडिंग त्रुटि बढ़ती है क्योंकि मान स्वयं करते हैं। – StilesCrisis

5

10^16 = 0x002386f26fc10000 एक डबल परिशुद्धता फ्लोटिंग पॉइंट नंबर के रूप में बिल्कुल प्रतिनिधित्व योग्य है। अगला प्रतिनिधित्व करने योग्य संख्या 1e16 + 2 है। 1e16 + 1 सही ढंग से 1e16 तक गोल किया गया है, और 1e16 + 1.1 सही ढंग से 1e16 + 2 तक गोल किया गया है। इस सी कार्यक्रम के उत्पादन की जाँच करें:

#include <stdio.h> 
#include <math.h> 
#include <stdint.h> 

int main() 
{ 
    uint64_t i = 10000000000000000ULL; 
    double a = (double)i; 
    double b = nextafter(a,1.0e20); // next representable number 
    printf("I=0x%016llx\n",i); // 10^16 in hex 
    printf("A=%a (%.4f)\n",a,a); // double representation 
    printf("B=%a (%.4f)\n",b,b); // next double 
} 

आउटपुट:

I=0x002386f26fc10000 
A=0x1.1c37937e08p+53 (10000000000000000.0000) 
B=0x1.1c37937e08001p+53 (10000000000000002.0000) 
+0

यह मेरे लिए संकलित नहीं करता है? (मैं कोई सी विशेषज्ञ नहीं हूं।) [** संपादित करें ** बहुत जल्द स्पोक करें। जी ++ जीसीसी का उपयोग करने की आवश्यकता नहीं है।] धन्यवाद। – jseabold

3

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

> (integer-decode-float 1.0d0) 
4503599627370496 
-52 
1 

यही है, अगर हम एक पूर्णांक रूप significand में संग्रहीत मूल्य पर विचार, यह 2 उपलब्ध की अधिकतम शक्ति है (4503599627370496 = 2^52), छोटा (2^-52)। (यह 0 के एक्सपोनेंट के साथ 1 के रूप में संग्रहीत नहीं है क्योंकि यह महत्व के लिए आसान है और बाईं ओर शून्य नहीं है, और यह हमें बाएं 1 बिट का प्रतिनिधित्व करने और अधिक सटीकता रखने की अनुमति देता है। इस फ़ॉर्म में नंबर नहीं कहा जाता है denormal।)

चलिए 1e16 देखें।

> (integer-decode-float 1d16) 
5000000000000000 
1 
1 

यहां हमारे पास प्रतिनिधित्व (5000000000000000) * 2^1 है। ध्यान दें कि एक अच्छा दौर दशमलव संख्या होने के बावजूद, 2 की शक्ति नहीं है; ऐसा इसलिए है क्योंकि 1e16 2 की शक्ति नहीं है। हर बार जब आप 10 से गुणा करते हैं, तो आप 2 और 5 से गुणा कर रहे हैं; 2 से गुणा करने से केवल एक्सपोनेंट बढ़ रहा है, लेकिन 5 से गुणा करना एक "वास्तविक" गुणा है, और यहां हमने 5 बार गुणा किया है।

5000000000000000 = 10001110000110111100100110111111000001000000000000000 (base 2) 

का निरीक्षण करें कि यह एक 53-बिट बाइनरी संख्या है, उसके बाद से दो तैरता एक 53-बिट significand है के रूप में यह होना चाहिए।

लेकिन स्थिति को समझने की कुंजी यह है कि एक्सपोनेंट 1 है। (एक्सपोनेंट छोटा होना एक संकेत है कि हम परिशुद्धता की सीमाओं के करीब आ रहे हैं।) इसका मतलब है कि फ्लोट वैल्यू 2^1 = 2 है बार यह महत्व है।

अब, क्या होता है जब हम इस नंबर में 1 जोड़ने का प्रतिनिधित्व करने का प्रयास करते हैं? खैर, हमें उसी पैमाने पर 1 का प्रतिनिधित्व करने की आवश्यकता है। लेकिन इस संख्या में हम जो छोटा बदलाव कर सकते हैं वह बिल्कुल 2 है, क्योंकि महत्व का कम से कम महत्वपूर्ण महत्व मूल्य 2 है!

है यही कारण है, अगर हम significand को बढ़ा देते, छोटी संभव परिवर्तन करने, हम

5000000000000001 = 10001110000110111100100110111111000001000000000000001 (base 2) 

हो और जब हम प्रतिपादक लागू होते हैं, हम 2 * 5000000000000001 = 10000000000000002 मिलता है, जो वास्तव में मूल्य आप मनाया है । आपके पास केवल 10000000000000000 या 10000000000000002 हो सकते हैं, और 10000000000000001.1 बाद के के करीब है।

(ध्यान दें कि यहां समस्या यह भी नहीं है कि दशमलव संख्या बाइनरी में सटीक नहीं है! यहां कोई द्विआधारी "दोहराना decimals" नहीं है, और महत्व के दाहिने सिरे पर 0 बिट्स हैं - यह बस है आपके इनपुट के बड़े करीने से सिर्फ न्यूनतम बिट से परे हो जाता है)

3
numpy के साथ

, आप और अगले बड़े छोटे प्रदर्शनीय आईईईई चल बिन्दु संख्या देख सकते हैं:।

>>> import numpy as np 
>>> huge=1e100 
>>> tiny=1e-100 
>>> np.nextafter(1e16,huge) 
10000000000000002.0 
>>> np.nextafter(1e16,tiny) 
9999999999999998.0 

तो:

>>> (np.nextafter(1e16,huge)-np.nextafter(1e16,tiny))/2.0 
2.0 

और:

>>> 1.1>2.0/2 
True 

इसलिए 1e16 + 1.1 सही ढंग से 10000000000000002,0

के अगले बड़े आईईईई प्रदर्शनीय संख्या के लिए गोल है के रूप में है:

>>> 1e16+1.0000000000000005 
1.0000000000000002e+16 

और 1e16- (कुछ 1 तुलना में थोड़ा बड़ा) अगले छोटे आईईईई नंबर पर 2 से नीचे चला गया है:

>>> 1e16-1.0000000000000005 
9999999999999998.0 

ध्यान रखें कि 32 बिट बनाम 64 बिट पायथन अप्रासंगिक है। यह IEEE format का आकार है जो महत्वपूर्ण है। यह भी ध्यान रखें कि संख्या की परिमाण जितनी बड़ी होगी, ईपीएसलॉन मान (मूल रूप से दो अगले बड़े और छोटे आईईईई मानों के बीच प्रसार) changes

साथ ही आप बिट्स में देख सकते हैं:

>>> def f_to_bits(f): return struct.unpack('<Q', struct.pack('<d', f))[0] 
... 
>>> def bits_to_f(bits): return struct.unpack('<d', struct.pack('<Q', bits))[0] 
... 
>>> bits_to_f(f_to_bits(1e16)+1) 
1.0000000000000002e+16 
>>> bits_to_f(f_to_bits(1e16)-1) 
9999999999999998.0 
+0

मुझे इसके बाद के बारे में कैसे पता नहीं चला। फिनफो ऑब्जेक्ट्स के साथ मिलकर यह बहुत आसान है। धन्यवाद। – jseabold

+0

इसके बाद यह बहुत बुरा है पाइथन गणित पुस्तकालय का हिस्सा नहीं है, लेकिन [इसे आसानी से जोड़ा जाता है।] (Http://stackoverflow.com/a/6163157/298607) – dawg