2009-05-08 12 views
21

मैं हाल ही में पता चला कि x**.5 और math.sqrt(x) हमेशा पायथन में एक ही परिणाम का उत्पादन नहीं करते:जो अधिक सटीक है, x **। 5 या math.sqrt (x)?

Python 2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)] 
on win32 
>>> 8885558**.5 - math.sqrt(8885558) 
-4.5474735088646412e-13 

10 ** 7 नीचे सभी पूर्णांकों जाँच हो रही है, दो तरीकों नमूनों की लगभग ठीक 0.1% के लिए अलग-अलग परिणाम का उत्पादन किया, बड़ी संख्या के लिए त्रुटि (धीरे-धीरे) बढ़ने के आकार के साथ।

तो सवाल यह है कि कौन सी विधि अधिक सटीक है?

+0

क्या आप "त्रुटि दर" से क्या मतलब समझ सकते हैं? –

+0

वर्ग रूट की गणना करने के दो तरीके 10 ** 7 से नीचे 10,103 संख्याओं के समान परिणाम नहीं देते हैं। (या लगभग 0.1%) –

+2

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

उत्तर

26

न तो एक अधिक सटीक है, वे दोनों बराबर भागों में वास्तविक जवाब से अलग:

>>> (8885558**0.5)**2 
8885557.9999999981 
>>> sqrt(8885558)**2 
8885558.0000000019 

>>> 2**1023.99999999999 
1.7976931348498497e+308 

>>> (sqrt(2**1023.99999999999))**2 
1.7976931348498495e+308 
>>> ((2**1023.99999999999)**0.5)**2 
1.7976931348498499e+308 

>>> ((2**1023.99999999999)**0.5)**2 - 2**1023.99999999999 
1.9958403095347198e+292 
>>> (sqrt(2**1023.99999999999))**2 - 2**1023.99999999999 
-1.9958403095347198e+292 

http://mail.python.org/pipermail/python-list/2003-November/238546.html

गणित मॉड्यूल मंच सी लिपट पुस्तकालय गणित कार्यों वही नाम; math.pow() सबसे उपयोगी है यदि आपको सी सी एक्सटेंशन सी के pow() पर कॉल करने के साथ उच्च संगतता की आवश्यकता है (या बस चाहते हैं)।

__builtin__.pow() पायथन के इन्फ़िक्स के कार्यान्वयन ** ऑपरेटर, और जटिल नंबर, असीम पूर्णांक शक्तियों के साथ भी सौदों, और मॉड्यूलर घातांक (सी pow() उन में से किसी को संभाल नहीं करता है) है।

** अधिक पूर्ण है। math.sqrt शायद एसक्यूआरटी का सी कार्यान्वयन है जो शायद pow से संबंधित है।

+2

आधिकारिक स्रोत के लिंक के लिए +1 :) –

+7

'sqrt' आईईईई 754 द्वारा परिभाषित बुनियादी परिचालनों में से एक है। इसे 'पाउ' के कॉल के रूप में सीधे लागू नहीं किया जाना चाहिए, और मूल संचालन के रूप में इसे सही गोल करना चाहिए ('पाउ' के सामान्य कार्यान्वयन में लंबे शॉट से नहीं है)। –

+3

'(8885558 ** 0.5)' और 'sqrt (8885558)' ** के संबंधित वर्गों को कंप्यूटिंग करने के लिए बिजली/वर्ग रूट ** के समान परिशुद्धता पर फ्लोटिंग-पॉइंट में ** और उम्मीद है कि गणना के परिणाम के बारे में कुछ भी बताने के लिए अधिक सटीक मूर्ख है। यह निष्कर्ष निकाला है कि "वे दोनों बराबर भागों में वास्तविक उत्तर से अलग हो जाते हैं" हंसते हैं: फ़्लोटिंग-पॉइंट में गणना की गई उनके वर्ग 8885558.0 से प्रत्येक 1ULP तक भिन्न होती हैं। –

10

दोनों पाउ फ़ंक्शन और math.sqrt() फ़ंक्शन दोनों परिणामों की गणना कर सकते हैं जो डिफ़ॉल्ट फ़्लोट प्रकार स्टोर कर सकते हैं उससे अधिक सटीक हैं। मुझे लगता है कि आप जो त्रुटियां देख रहे हैं वह फ़ंक्शन की त्रुटियों की बजाय फ़्लोटिंग पॉइंट गणित की सीमाओं का परिणाम है। इसके अलावा, जब से 7 अंकों की वर्ग रूट लेते समय ~ 10^(- 13) का अंतर होता है? यहां तक ​​कि सबसे सटीक भौतिकी गणनाओं के लिए शायद ही कभी कई महत्वपूर्ण अंक की आवश्यकता होती है ...

math.sqrt() का उपयोग करने का एक अन्य कारण यह है कि इसे पढ़ने और समझना आसान होता है, जो आमतौर पर चीजों को एक निश्चित तरीके से करने का एक अच्छा कारण है।

+0

इस प्रश्न का उत्तर गति के बारे में आपकी टिप्पणी का खंडन करेगा: http: // stackoverflow।कॉम/प्रश्न/327002/पायथन-जो-तेज़-एक्स -5-या-गणित-वर्गमीटर –

+0

मेरा एक दोस्त वास्तव में आज पहले इस पर बेंचमार्क किया गया, और निष्कर्ष निकाला कि math.sqrt() तेज़ था। यह एक परियोजना यूलर गणना के संदर्भ में था। मैंने अपनी विधि की जांच किए बिना अपने शब्द पर भरोसा किया, ताकि दावा गलत हो। फिर भी, यह जंगली रूप से असंभव लगता है कि math.sqrt() धीमा हो जाएगा। अगर ऐसा होता, तो उन्होंने इसे पाउ() के बदले में क्यों लागू नहीं किया? –

+0

"पाउ()" के मामले में ... मैं थोड़ा थक गया हूँ। :) –

4

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

नोट: स्पष्टीकरण के लिए, Python 3.0 में sqrt तेज है। यह पायथन के पुराने संस्करणों में धीमा है। Which is faster in Python: x**.5 or math.sqrt(x)? पर जेएफ सेबेस्टियन माप देखें।

+0

क्या आप मेरे लिए आखिरी वाक्य को स्पष्ट कर सकते हैं? –

+0

गति के बारे में आपका बिंदु गलत है। ** 0.5 एसक्यूआरटी से वास्तव में तेज़ है। – Unknown

+0

पायथन 3.0 में नहीं। – Brian

1

मुझे वही व्यवहार नहीं मिलता है। शायद त्रुटि मंच विशिष्ट है?

 
Python 2.5.2 (r252:60911, Mar 10 2008, 15:14:55) 
[GCC 3.3.5 (propolice)] on openbsd4 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import math 
>>> math.sqrt(8885558) - (8885558**.5) 
0.0 
>>> (8885558**.5) - math.sqrt(8885558) 
0.0 
+0

मुझे डर था कि यह मामला हो सकता है - मैंने कहीं पढ़ा है कि math.sqrt सीधे सी कार्यान्वयन में पारित किया गया है, लेकिन मुझे अभी संदर्भ नहीं मिल रहा है। –

+0

मैं परिणाम की पुष्टि कर सकता हूं। –

+0

बेन: मुझे इसे दस्तावेज नहीं मिल रहा है, लेकिन यह कम से कम पायथन 2.5 के लिए सच है: http://tinyurl.com/omvudo – Ken

3

इसका कारण यह है मैं अलग परिणाम प्राप्त प्लेटफ़ॉर्म-विशिष्ट बात किसी तरह का हो गया है:

Python 2.5.1 (r251:54863, Jan 13 2009, 10:26:13) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin 
>>> 8885558**.5 - math.sqrt(8885558) 
0.0 

अजगर का कौन-सा संस्करण उपयोग कर रहे हैं और क्या ओएस amd64 पर मैं इस मिल सकता है?

मेरा अनुमान है कि इसमें पदोन्नति और कास्टिंग के साथ कुछ करना है। दूसरे शब्दों में, चूंकि आप 8885558 ** कर रहे हैं। 5, 8885558 को एक फ्लोट में पदोन्नत किया जाना है। यह सब ऑपरेटिंग सिस्टम, प्रोसेसर, और पायथन के संस्करण के आधार पर अलग-अलग संभाला जाता है। अस्थायी बिंदु अंकगणित की अद्भुत दुनिया में आपका स्वागत है। :-)

+0

"पायथन 2.6.1 (आर 261: 67517, 4 दिसंबर 2008, 16:51:00) [एमएससी v.1500 32 बिट (इंटेल)] win32 पर " –

+0

दिलचस्प। शायद यह किसी प्रकार का 32 बिट बनाम 64 बिट मुद्दा है? मैं और दूसरा व्यक्ति जिसने अलग-अलग परिणाम प्राप्त किए हैं, दोनों 64-बिट ओएस का उपयोग कर रहे हैं। या यह एक बीएसडी चीज हो सकती है। मैं मैक ओएस एक्स का उपयोग कर रहा हूं। –

+0

मुझे 32-बिट लिनक्स पर भी 0.0 मिलता है (पायथन 2.5.2)। –

6

उपयोग decimal अधिक सटीक वर्ग जड़ों को खोजने के लिए:

>>> import decimal 
>>> decimal.getcontext().prec = 60 
>>> decimal.Decimal(8885558).sqrt() 
Decimal("2980.86531061032678789963529280900544861029083861907705317042") 
3

मैं विन XP अजगर 2.5.1 पर आप के साथ एक ही मुद्दा मिल गया है, जबकि मैं पर 32-बिट Gentoo अजगर 2.5.4 नहीं है। यह सी पुस्तकालय कार्यान्वयन का मामला है।

अब, जीत पर, math.sqrt(8885558)**28885558.0000000019 देता है, जबकि (8885558**.5)**28885557.9999999981, जो एक ही एप्सिलॉन के लिए राशि लगते देता है।

मैं कहता हूं कि कोई वास्तव में यह नहीं कह सकता कि कौन सा "बेहतर" विकल्प है।

1

सिद्धांत में math.sqrt में उच्च परिशुद्धता होना चाहिए तो math.pow। वर्ग जड़ों [0] की गणना करने के लिए न्यूटन की विधि देखें। हालांकि पाइथन फ्लोट (या सी डबल) के दशमलव अंकों की संख्या में सीमा शायद अंतर को मुखौटा करेगी।

[0] http://en.wikipedia.org/wiki/Integer_square_root

0

मैं एक ही परीक्षण किया और एक ही परिणाम, 10000000. से बाहर 10103 मतभेद यह विंडोज में अजगर 2.7 उपयोग कर रहा था मिल गया।

अंतर गोल करने में से एक है। मेरा मानना ​​है कि जब दो परिणाम भिन्न होते हैं, तो यह केवल एक ULP है जो एक फ्लोट के लिए सबसे छोटा संभव अंतर है। सच्चा उत्तर दोनों के बीच है, लेकिन float में इसका प्रतिनिधित्व करने की क्षमता नहीं है और इसे गोल किया जाना चाहिए।

जैसा कि किसी अन्य उत्तर में बताया गया है, decimal module का उपयोग float से बेहतर सटीकता प्राप्त करने के लिए किया जा सकता है। मैंने इसे सही त्रुटि का बेहतर विचार प्राप्त करने के लिए उपयोग किया, और सभी मामलों में sqrt**0.5 से अधिक था। हालांकि बहुत ज्यादा नहीं!

>>> s1 = sqrt(8885558) 
>>> s2 = 8885558**0.5 
>>> s3 = decimal.Decimal(8885558).sqrt() 
>>> s1, s2, s3 
(2980.865310610327, 2980.8653106103266, Decimal('2980.865310610326787899635293')) 
>>> s3 - decimal.Decimal(s1) 
Decimal('-2.268290468226740188598632812E-13') 
>>> s3 - decimal.Decimal(s2) 
Decimal('2.2791830406379010009765625E-13') 
संबंधित मुद्दे