पायथन में कौन सा तेज है: x **। 5 या math.sqrt (x)?


187

मैं कुछ समय से यह सोच रहा था। जैसा कि शीर्षक कहता है, जो तेज है, वास्तविक कार्य या बस आधी शक्ति तक बढ़ा रहा है?

अपडेट करें

यह समय से पहले अनुकूलन का मामला नहीं है। यह केवल एक सवाल है कि अंतर्निहित कोड वास्तव में कैसे काम करता है। पायथन कोड कैसे काम करता है इसका सिद्धांत क्या है?

मैंने गुइडो वैन रोसुम को एक ईमेल कारण भेजा है जो मैं वास्तव में इन तरीकों में अंतर जानना चाहता था।

मेरी ई - मेल:

पायथन में एक वर्गमूल करने के लिए कम से कम 3 तरीके हैं: math.sqrt, '**' ऑपरेटर और पॉव (x, .5)। मैं इनमें से प्रत्येक के कार्यान्वयन में अंतर के रूप में उत्सुक हूं। जब दक्षता की बात आती है जो बेहतर है?

उनकी प्रतिक्रिया:

पाउ और ** बराबर हैं; math.sqrt जटिल संख्या और C sqrt () फ़ंक्शन के लिंक के लिए काम नहीं करता है। जैसा कि एक तेज है, मुझे पता नहीं है ...


81
यह कमाल है कि Guido ईमेल का जवाब देता है।
इवान फॉसमार्क

3
इवान, मुझे आश्चर्य हुआ कि मुझे एक प्रतिक्रिया मिली
नोप

11
मुझे नहीं लगता कि यह एक बुरा सवाल है। उदाहरण के लिए, x * x, x ** 2 की तुलना में पूर्ण 10 गुना तेज है। पठनीयता इस स्थिति में एक टॉसअप है, इसलिए फास्ट तरीके से क्यों नहीं?
टीएम।

12
केसी, मैं आपके साथ "प्रीमेच्योर ऑप्टिमाइज़ेशन" चीज़ पर हूँ। :) आपका प्रश्न मेरे लिए समय से पहले के अनुकूलन जैसा नहीं लगता है: इसमें कोई जोखिम नहीं है कि कोई भी संस्करण आपके कोड को तोड़ता है। जब आप math.sqrt () पर pow () चुनते हैं तो यह बेहतर होता है कि आप क्या करते हैं (निष्पादन समय के संदर्भ में)।
एरिक ओ लेबिगॉट

8
यह समय से पहले का अनुकूलन नहीं है, बल्कि समय से पहले के पीसेमाइजेशन (रेफरी नंबर 28, सी ++ कोडिंग मानकों, ए। एलेक्सैंडरेस्क्यू) से परहेज करता है। यदि math.sqrtएक अधिक अनुकूलित दिनचर्या है (जैसा कि यह है) और इरादे को और अधिक स्पष्ट रूप से व्यक्त करता है, तो इसे हमेशा प्राथमिकता दी जानी चाहिए x**.5। यह जानने के लिए कि आप क्या लिखते हैं, यह समय से पहले अनुकूलन नहीं है, और उस विकल्प को चुना जो तेज है और अधिक कोड स्पष्टता प्रदान करता है। यदि हां, तो आपको समान रूप से अच्छी तरह से बहस करने की आवश्यकता है कि आपने अन्य विकल्पों को क्यों चुना।
11

जवाबों:


89

math.sqrt(x)की तुलना में काफी तेज है x**0.5

import math
N = 1000000
%%timeit
for i in range(N):
    z=i**.5

10 लूप, सर्वश्रेष्ठ 3: 156 एमएस प्रति लूप

%%timeit
for i in range(N):
    z=math.sqrt(i)

10 लूप, सर्वश्रेष्ठ 3: 91.1 एमएस प्रति लूप

पायथन 3.6.9 ( नोटबुक ) का उपयोग करना ।


मैंने अब इसे 3 बार codepad.org पर चलाया है और सभी तीन बार () बी () की तुलना में बहुत तेज है।
जेरेमी रुटेन

10
मानक समयबद्ध मॉड्यूल आपका मित्र है। जब निष्पादन समय को मापने की बात आती है तो यह आम नुकसान से बचता है!
एरिक ओ लेबिगॉट

1
आपकी स्क्रिप्ट के परिणाम इस प्रकार हैं: zoltan @ host: ~ $ python2.5 p.py 0.183226 सेकंड लिया गया। 0.155829 सेकंड zoltan @ होस्ट लिया: ~ $ python2.4 p.py 0.181142 सेकंड लिया गया 0.153742 सेकंड zoltan @ host: ~ $ python2 python2.6 p.py 0.157436 सेकंड लिया गया 0.093905 सेकंड का समय लिया लक्ष्य प्रणाली: Ubuntu Linux CPU: Intel (R) Core (TM) 2 डुओ CPU T9600 @ 2.80GHz जैसा कि आप देख सकते हैं कि मुझे अलग-अलग परिणाम मिले हैं। इसके अनुसार आपका उत्तर सामान्य नहीं है।
zoli2k

2
कोडपैड एक महान सेवा है, लेकिन समय प्रदर्शन के लिए भयानक है, मेरा मतलब है कि कौन जानता है कि किसी निश्चित समय में सर्वर कितना व्यस्त होगा। प्रत्येक रन संभावित रूप से बहुत अलग परिणाम दे सकता है
adamJLev

1
मैंने Linux पर py32, py31, py30, py27, py26, pypy, jython, py25, py24 दुभाषियों के लिए x **। 5 बनाम sqrt (x) की प्रदर्शन तुलना जोड़ी है। gist.github.com/783011
jfs

19
  • अनुकूलन का पहला नियम: यह मत करो
  • दूसरा नियम: यह मत करो , अभी तक

यहाँ कुछ समय है (अजगर 2.5.2, विंडोज):

$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
1000000 loops, best of 3: 0.445 usec per loop

$ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
1000000 loops, best of 3: 0.574 usec per loop

$ python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
1000000 loops, best of 3: 0.727 usec per loop

यह परीक्षण दिखाता है कि x**.5की तुलना में थोड़ा तेज है sqrt(x)

अजगर 3.0 के लिए परिणाम विपरीत है:

$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
1000000 loops, best of 3: 0.803 usec per loop

$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
1000000 loops, best of 3: 0.695 usec per loop

$ \Python30\python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
1000000 loops, best of 3: 0.761 usec per loop

math.sqrt(x)हमेशा x**.5किसी अन्य मशीन (उबंटू, पायथन 2.6 और 3.1) की तुलना में तेज़ होता है :

$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
10000000 loops, best of 3: 0.173 usec per loop
$ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
10000000 loops, best of 3: 0.115 usec per loop
$ python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
10000000 loops, best of 3: 0.158 usec per loop
$ python3.1 -mtimeit -s"from math import sqrt; x = 123" "x**.5"
10000000 loops, best of 3: 0.194 usec per loop
$ python3.1 -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
10000000 loops, best of 3: 0.123 usec per loop
$ python3.1 -mtimeit -s"import math; x = 123" "math.sqrt(x)"
10000000 loops, best of 3: 0.157 usec per loop

10

आप वास्तव में कितने वर्गमूल हैं? क्या आप पायथन में कुछ 3 डी ग्राफिक्स इंजन लिखने की कोशिश कर रहे हैं? यदि नहीं, तो कोड के साथ क्यों जाना जाता है जो कोड से अधिक गूढ़ है जिसे पढ़ना आसान है? समय अंतर किसी को भी कम से कम मैं किसी भी आवेदन मैं सकता है के बारे में नोटिस सकता है। मैं वास्तव में आपके सवाल का मतलब नहीं है, लेकिन ऐसा लगता है कि आप समय से पहले अनुकूलन के साथ बहुत दूर जा रहे हैं।


16
मुझे नहीं लगता कि मैं समय से पहले अनुकूलन कर रहा हूं। यह 2 अलग-अलग तरीकों से निर्णय लेने का एक सरल प्रश्न है, जो औसतन, तेज होगा।
नहीं

2
किबी: यह निश्चित रूप से एक वैध प्रश्न है, लेकिन मैं स्टैक ओवरफ्लो पर आपके प्रश्नों की संख्या के बारे में आपके निराशा को साझा करता हूं, जिसका अर्थ है कि पूछने वाला सभी प्रकार के समय से पहले अनुकूलन का प्रदर्शन कर रहा है। यह निश्चित रूप से प्रत्येक भाषा के लिए पूछे जाने वाले प्रश्नों का एक बड़ा प्रतिशत है।
एली कोर्टराइट

2
क्या math.sqrt (x) x ** 0.5 की तुलना में पढ़ना आसान है? मुझे लगता है कि वे दोनों स्पष्ट रूप से वर्गमूल हैं ... कम से कम यदि आप वैसे भी अजगर से परिचित हैं। मानक अजगर संचालकों को कॉल न करें जैसे ** "गुप्त" सिर्फ इसलिए कि आप अजगर से परिचित नहीं हैं।
टीएम।

5
मुझे नहीं लगता कि ** ऑपरेटर गुप्त है। मुझे लगता है कि वर्ग 0.5 को प्राप्त करने की विधि के रूप में घातांक 0.5 के लिए कुछ बढ़ाकर उन लोगों के लिए थोड़ा गूढ़ है जो अपने गणित पर नहीं रखते हैं।
किबी

13
क्या होगा अगर वह पायथन में 3 डी इंजन बना रहा है?
क्रिस बर्ट-ब्राउन

9

इन माइक्रो-बेंचमार्क में, math.sqrtधीमी होगी, क्योंकि sqrtगणित नामस्थान में देखने के लिए थोड़ा समय लगता है । आप इसे थोड़ा सुधार सकते हैं

 from math import sqrt

फिर भी, समय के माध्यम से कुछ बदलावों को चलाने के लिए, थोड़ा (4-5%) प्रदर्शन लाभ दिखाते हैं x**.5

दिलचस्प है, कर रहा है

 import math
 sqrt = math.sqrt

गति में 1% के अंतर के साथ, बहुत कम सांख्यिकीय महत्व के साथ, इसे और भी अधिक बढ़ाया।


मैं किबी को दोहराऊंगा, और कहूंगा कि यह शायद एक समयपूर्व अनुकूलन है।


7

अजगर 2.6 में (float).__pow__() फ़ंक्शन सी फ़ंक्शन का उपयोग करता है pow()और फ़ंक्शन सी math.sqrt()फ़ंक्शन का उपयोग करता है sqrt()

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

का उपयोग करते हुए की गति में अंतर .**या math.sqrtद्वारा रैपर सी कार्यों के आसपास का इस्तेमाल किया और गति दृढ़ता से / सी संकलक प्रणाली पर इस्तेमाल किया अनुकूलन झंडे पर निर्भर करता है कारण होता है।

संपादित करें:

यहाँ मेरी मशीन पर क्लाउडीयू के एल्गोरिदम के परिणाम हैं। मुझे अलग परिणाम मिले:

zoltan@host:~$ python2.4 p.py 
Took 0.173994 seconds
Took 0.158991 seconds
zoltan@host:~$ python2.5 p.py 
Took 0.182321 seconds
Took 0.155394 seconds
zoltan@host:~$ python2.6 p.py 
Took 0.166766 seconds
Took 0.097018 seconds

4

इसके लायक क्या है (जिम का जवाब देखें)। मेरी मशीन पर, अजगर 2.5 चला रहा है:

PS C:\> python -m timeit -n 100000 10000**.5
100000 loops, best of 3: 0.0543 usec per loop
PS C:\> python -m timeit -n 100000 -s "import math" math.sqrt(10000)
100000 loops, best of 3: 0.162 usec per loop
PS C:\> python -m timeit -n 100000 -s "from math import sqrt" sqrt(10000)
100000 loops, best of 3: 0.0541 usec per loop

4

क्लाउडीयू के कोड का उपयोग करते हुए, मेरी मशीन पर भी "गणित आयात sqrt से" x **। 5 तेज है, लेकिन psyco.full () sqrt (x) का उपयोग करके बहुत तेज हो जाता है, कम से कम 200%


3

सबसे अधिक संभावना math.sqrt (x), क्योंकि यह वर्गाकार रूटिंग के लिए अनुकूलित है।

बेंचमार्क आपको वह उत्तर प्रदान करेगा जिसकी आप तलाश कर रहे हैं।


3

किसी ने क्वेक 3 से "फास्ट न्यूटन-रफसन स्क्वायर रूट" के बारे में टिप्पणी की ... मैंने इसे ctypes के साथ लागू किया, लेकिन यह देशी संस्करणों की तुलना में सुपर धीमी है। मैं कुछ अनुकूलन और वैकल्पिक कार्यान्वयन का प्रयास करने जा रहा हूं।

from ctypes import c_float, c_long, byref, POINTER, cast

def sqrt(num):
 xhalf = 0.5*num
 x = c_float(num)
 i = cast(byref(x), POINTER(c_long)).contents.value
 i = c_long(0x5f375a86 - (i>>1))
 x = cast(byref(i), POINTER(c_float)).contents.value

 x = x*(1.5-xhalf*x*x)
 x = x*(1.5-xhalf*x*x)
 return x * num

यहां संरचना का उपयोग करने का एक और तरीका है, ctypes संस्करण की तुलना में लगभग 3.6x तेज़ी से निकलता है, लेकिन फिर भी सी की गति 1/10 है।

from struct import pack, unpack

def sqrt_struct(num):
 xhalf = 0.5*num
 i = unpack('L', pack('f', 28.0))[0]
 i = 0x5f375a86 - (i>>1)
 x = unpack('f', pack('L', i))[0]

 x = x*(1.5-xhalf*x*x)
 x = x*(1.5-xhalf*x*x)
 return x * num

1

क्लाउडीयू के परिणाम मेरे से अलग हैं। मैं एक पुराने P4 2.4Ghz मशीन पर उबंटू में अजगर 2.6 का उपयोग कर रहा हूं ... यहां मेरे परिणाम हैं:

>>> timeit1()
Took 0.564911 seconds
>>> timeit2()
Took 0.403087 seconds
>>> timeit1()
Took 0.604713 seconds
>>> timeit2()
Took 0.387749 seconds
>>> timeit1()
Took 0.587829 seconds
>>> timeit2()
Took 0.379381 seconds

sqrt मेरे लिए लगातार तेज़ है ... यहां तक ​​कि Codepad.org अब इस बात से सहमत प्रतीत होता है कि स्थानीय संदर्भ में sqrt, अधिक तेज़ है ( http://codepad.org/6trzcM3j )। कोडपैड वर्तमान में पायथन 2.5 चला रहा है। शायद वे 2.4 या पुराने का उपयोग कर रहे थे जब क्लॉडु ने पहली बार उत्तर दिया था?

वास्तव में, यहां तक ​​कि arg (i) के स्थान पर math.sqrt (i) का उपयोग करते हुए, मैं अभी भी sqrt के लिए बेहतर समय प्राप्त करता हूं। इस मामले में timeit2 () ने मेरी मशीन पर 0.53 और 0.55 सेकंड का समय लिया, जो अभी भी timeit1 के 0.56-0.60 आंकड़ों से बेहतर है।

मैं कहता हूँ, आधुनिक पायथन पर, math.sqrt का उपयोग करें और निश्चित रूप से इसे स्थानीय संदर्भ में लाएं, जैसे कि somevar = math.sqrt या गणित आयात sqrt के साथ।


1

के लिए अनुकूलन करने के लिए पायथोनिक बात पठनीयता है। इसके लिए मुझे लगता है कि इसका स्पष्ट उपयोग हैsqrt फ़ंक्शन का सबसे अच्छा है। कहा कि, चलो प्रदर्शन की जांच वैसे भी करते हैं।

मैंने पायथन 3 के लिए क्लाउडीयू के कोड को अपडेट किया और गणना को दूर करना भी असंभव बना दिया (कुछ अच्छा पायथन कंपाइलर भविष्य में कर सकता है):

from sys import version
from time import time
from math import sqrt, pi, e

print(version)

N = 1_000_000

def timeit1():
  z = N * e
  s = time()
  for n in range(N):
    z += (n * pi) ** .5 - z ** .5
  print (f"Took {(time() - s):.4f} seconds to calculate {z}")

def timeit2():
  z = N * e
  s = time()
  for n in range(N):
    z += sqrt(n * pi) - sqrt(z)
  print (f"Took {(time() - s):.4f} seconds to calculate {z}")

def timeit3(arg=sqrt):
  z = N * e
  s = time()
  for n in range(N):
    z += arg(n * pi) - arg(z)
  print (f"Took {(time() - s):.4f} seconds to calculate {z}")

timeit1()
timeit2()
timeit3()

परिणाम अलग-अलग होते हैं, लेकिन एक नमूना आउटपुट होता है:

3.6.6 (default, Jul 19 2018, 14:25:17) 
[GCC 8.1.1 20180712 (Red Hat 8.1.1-5)]
Took 0.3747 seconds to calculate 3130485.5713865166
Took 0.2899 seconds to calculate 3130485.5713865166
Took 0.2635 seconds to calculate 3130485.5713865166

इसे स्वयं आज़माएं।


0

समस्या SQRMINSUM मैंने हाल ही में हल किया है एक बड़े डेटासेट पर बार-बार वर्गमूल की गणना करने की आवश्यकता होती है। मेरे इतिहास में सबसे पुरानी 2 प्रस्तुतियाँ , इससे पहले कि मैंने अन्य अनुकूलन किए हैं, केवल ~ 0.5 को sqrt () के साथ बदलकर भिन्न होता है, इस प्रकार PyPy में 3.74 से 0.51 के रनटाइम को कम करता है। यह लगभग दो बार पहले से ही बड़े पैमाने पर 400% सुधार है जिसे क्लाउडीयू ने मापा।


0

बेशक, अगर कोई शाब्दिक रूप से काम कर रहा है और उसे निरंतर मूल्य की आवश्यकता है, तो पायथन रनटाइम, संकलन समय पर मूल्य की पूर्व-गणना कर सकता है, यदि यह ऑपरेटरों के साथ लिखा गया है - इस मामले में प्रत्येक संस्करण को प्रोफाइल करने की आवश्यकता नहीं है:

In [77]: dis.dis(a)                                                                                                                       
  2           0 LOAD_CONST               1 (1.4142135623730951)
              2 RETURN_VALUE

In [78]: def a(): 
    ...:     return 2 ** 0.5 
    ...:                                                                                                                                  

In [79]: import dis                                                                                                                       

In [80]: dis.dis(a)                                                                                                                       
  2           0 LOAD_CONST               1 (1.4142135623730951)
              2 RETURN_VALUE

-3

यदि आप math.py में गए और अपने प्रोग्राम में "sqrt" फ़ंक्शन को कॉपी किया तो इससे भी अधिक तेज़ क्या होगा। आपके प्रोग्राम को math.py खोजने में समय लगता है, फिर इसे खोलें, वह फ़ंक्शन ढूंढें जिसे आप खोज रहे हैं, और फिर अपने प्रोग्राम में वापस लाएं। यदि वह फ़ंक्शन "लुकअप" चरणों के साथ और भी तेज है, तो फ़ंक्शन को खुद ही तेजी से चलना होगा। शायद आपका समय आधे में कट जाएगा। संक्षेप में:

  1. Math.py पर जाएं
  2. फ़ंक्शन का पता लगाएं "sqrt"
  3. इसे कॉपी करें
  4. अपने प्रोग्राम में sqrt खोजक के रूप में पेस्ट करें।
  5. यह समय है।

1
यह काम नहीं करेगा; stackoverflow.com/q/18857355/3004881 देखें । मूल प्रश्न में उद्धरण पर भी ध्यान दें जो कहता है कि यह सी फ़ंक्शन का लिंक है। इसके अलावा, फ़ंक्शन के स्रोत कोड की प्रतिलिपि बनाना कैसे अलग हो सकता है from math import sqrt?
डैन गेट्ज़

यह नहीं होगा, मैंने कहा कि सिर्फ यह स्पष्ट करने के लिए कि दोनों कार्यों को कॉल करने में क्या अंतर था।
PyGuy
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.