2012-07-17 39 views
30

बस मस्ती के लिए और क्योंकि यह वास्तव में आसान था, मैं Grafting numbers उत्पन्न करने के लिए एक छोटी कार्यक्रम में लिखा है, लेकिन चल बिन्दु परिशुद्धता समस्याओं के कारण यह बड़ा उदाहरण में से कुछ नहीं मिल रहा है।पाइथन फ्लोटिंग पॉइंट मनमाने ढंग से सटीक उपलब्ध है?

def isGrafting(a): 
    for i in xrange(1, int(ceil(log10(a))) + 2): 
    if a == floor((sqrt(a) * 10**(i-1)) % 10**int(ceil(log10(a)))): 
     return 1 

a = 0 
while(1): 
    if (isGrafting(a)): 
    print "%d %.15f" % (a, sqrt(a)) 
    a += 1 

यह कोड कम से कम एक ज्ञात ग्राफ्टिंग नंबर याद करता है। 9999999998 => 99999.99998999999999949999999994999999999374999999912... यह 10**5 से गुणा करने के बाद अतिरिक्त परिशुद्धता छोड़ रहा है।

>>> a = 9999999998 
>>> sqrt(a) 
99999.99999 
>>> a == floor((sqrt(a) * 10**(5)) % 10**int(ceil(log10(a)))) 
False 
>>> floor((sqrt(a) * 10**(5)) % 10**int(ceil(log10(a)))) 
9999999999.0 
>>> print "%.15f" % sqrt(a) 
99999.999989999996615 
>>> print "%.15f" % (sqrt(a) * 10**5) 
9999999999.000000000000000 

तो मैं अगर यह मेरे सीपीयू किसी भी तरह चल बिन्दु संख्या या अजगर छोटा था देखने के लिए एक छोटी सी ++ प्रोग्राम लिखा था।

#include <cstdio> 
#include <cmath> 
#include <stdint.h> 

int main() 
{ 
    uint64_t a = 9999999998; 
    printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e4, sqrt((double)a)*1e5, sqrt((double)a)*1e6); 
    a = 999999999998; 
    printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e5, sqrt((double)a)*1e6, sqrt((double)a)*1e7); 
    a = 99999999999998; 
    printf("%ld %.15f %.15f %.15f %.15f\n", a, sqrt((double)a), sqrt((double)a)*1e6, sqrt((double)a)*1e7, sqrt((double)a)*1e8); 
    return 0; 
} 

कौन सा आउटपुट:

9999999998 99999.999989999996615 999999999.899999976158142 9999999999.000000000000000 99999999990.000000000000000 
999999999998 999999.999998999992386 99999999999.899993896484375 999999999999.000000000000000 9999999999990.000000000000000 
99999999999998 9999999.999999899417162 9999999999999.900390625000000 99999999999999.000000000000000 999999999999990.000000000000000 

तो यह चल बिन्दु परिशुद्धता की सीमा के खिलाफ लगता है कि मैं चल रहा हूँ कठिन और सीपीयू शेष बिट बंद काटना है, क्योंकि यह सोचता है कि शेष अंतर फ्लोटिंग पॉइंट त्रुटि है। क्या Python के तहत इस के आसपास काम करने का कोई तरीका है? या मुझे सी में जाने और जीएमपी या कुछ का उपयोग करने की ज़रूरत है?

+1

परिमेय संख्याओं पर सटीक गणित प्रदर्शन करने के लिए, [ 'fractions' मॉड्यूल] (https://docs.python.org/3/library/fractions.html) इस्तेमाल किया जा सकता । 'Mpmath' के लिए – jfs

उत्तर

31

मानक पुस्तकालय में, decimal मॉड्यूल आप जो खोज रहे हैं हो सकता है। इसके अलावा, मुझे काफी उपयोगी होने के लिए mpmath मिला है। documentation (, अन्यथा मैं कुछ उदाहरण को सत्यापित करने और उन्हें पोस्ट करेंगे दुर्भाग्य से मेरे कार्यालय कंप्यूटर mpmath स्थापित नहीं है) के साथ-साथ कई महान उदाहरण है।

decimal मॉड्यूल के बारे में एक चेतावनी, हालांकि। मॉड्यूल में सरल गणितीय परिचालनों के लिए कई अंतर्निहित फ़ंक्शन शामिल हैं (उदा। sqrt), लेकिन इन फ़ंक्शंस के परिणाम हमेशा संबंधित परिशुद्धता पर math या अन्य मॉड्यूल में संबंधित फ़ंक्शन से मेल नहीं खाते हैं (हालांकि वे अधिक सटीक हो सकते हैं)। उदाहरण के लिए,

from decimal import * 
import math 

getcontext().prec = 30 
num = Decimal(1)/Decimal(7) 

print(" math.sqrt: {0}".format(Decimal(math.sqrt(num)))) 
print("decimal.sqrt: {0}".format(num.sqrt())) 

अजगर 3.2.3 में, यह पहली दो पंक्तियों

math.sqrt: 0.37796447300922719758631274089566431939601898193359375 
decimal.sqrt: 0.377964473009227227214516536234 
actual value: 0.3779644730092272272145165362341800608157513118689214 

जो के रूप में कहा गया है आउटपुट, वास्तव में आप क्या उम्मीद करेंगे नहीं है, और आप देख सकते हैं कि उच्च परिशुद्धता, कम परिणाम मिलते हैं। ध्यान दें कि decimal मॉड्यूल के बाद से इसे और अधिक बारीकी से मेल खाता है actual value, इस उदाहरण में अधिक सटीकता है।

+2

+1। दशमलव संख्याओं का उपयोग करने में समस्या यह है कि आप दशमलव वस्तुओं पर गणित कार्यों के तरीके में ज्यादा कुछ नहीं कर सकते हैं, इसलिए यदि आप बस इसके आसपास खेल रहे हैं तो यह काफी सीमित है। – DSM

+0

@DSM मैं सहमत हूं। मैंने केवल साधारण समस्याओं के लिए 'mpmath' का उपयोग किया है, लेकिन फिर भी, मुझे यह एक अच्छा, ठोस पैकेज मिला है। –

+1

बस स्पष्ट होने के लिए - मुझे पूरा यकीन है कि 'math.sqrt' बनाम 'decimal.sqrt()' के आपके परीक्षण में,' math.sqrt' द्वारा उत्पादित परिणाम _less_ सही है, बाइनरी-टू के कारण -डिसीमल रूपांतरण। 'दशमलव। डीसीमल (math.sqrt (num) ** 2) * 7' बनाम' दशमलव। दशमलव (num.sqrt() ** 2) * 7' के आउटपुट पर विचार करें। – senderle

7

आप floatingpoint के बजाय Decimal साथ की कोशिश कर सकते हैं।

5

पायथन में कोई अंतर्निहित मनमानी-सटीक फ्लोट नहीं है, लेकिन तीसरे पक्ष के पायथन पैकेज हैं जो जीएमपी का उपयोग करते हैं: gmpy और PyGMP

8

इस विशेष समस्या के लिए, decimal जाने का एक शानदार तरीका है, क्योंकि यह दशमलव अंकों को टुपल्स के रूप में संग्रहीत करता है!

>>> a = decimal.Decimal(9999999998) 
>>> a.as_tuple() 
DecimalTuple(sign=0, digits=(9, 9, 9, 9, 9, 9, 9, 9, 9, 8), exponent=0) 

आप एक संपत्ति है कि स्वाभाविक रूप से सबसे दशमलव संकेतन में व्यक्त की तलाश कर रहे हैं, यह एक द्विआधारी प्रतिनिधित्व उपयोग करने के लिए थोड़ा पागल है।विकिपीडिया पृष्ठ आपको संकेत नहीं है कि कितने "गैर ग्राफ्टिंग अंक" दिखाई दे सकते हैं "कलम बांधने का काम अंक" शुरू होने से पहले लिंक है, तो यह आप निर्दिष्ट कर सकते हैं:

>>> def isGrafting(dec, max_offset=5): 
...  dec_digits = dec.as_tuple().digits 
...  sqrt_digits = dec.sqrt().as_tuple().digits 
...  windows = [sqrt_digits[o:o + len(dec_digits)] for o in range(max_offset)] 
...  return dec_digits in windows 
... 
>>> isGrafting(decimal.Decimal(9999999998)) 
True 
>>> isGrafting(decimal.Decimal(77)) 
True 

मुझे लगता है कि एक अच्छा मौका का परिणाम नहीं है Decimal.sqrt() बाइनरी प्रतिनिधित्व और दशमलव प्रतिनिधित्व के बीच रूपांतरण की वजह से math.sqrt() के परिणामस्वरूप, कम से कम इसके लिए अधिक सटीक होगा। , निम्नलिखित पर विचार करें उदाहरण के लिए:

>>> num = decimal.Decimal(1)/decimal.Decimal(7) 
>>> decimal.Decimal(math.sqrt(num) ** 2) * 7 
Decimal('0.9999999999999997501998194593') 
>>> decimal.Decimal(num.sqrt() ** 2) * 7 
Decimal('1.000000000000000000000000000')