python - पायथन 3 में x** 4 से x** 4.0 अधिक तेज़ क्यों है?




performance python-3.x (2)

x**4.0 से x**4.0 अधिक तेज़ क्यों है? मैं CPython 3.5.2 का उपयोग कर रहा हूं।

$ python -m timeit "for x in range(100):" " x**4.0"
  10000 loops, best of 3: 24.2 usec per loop

$ python -m timeit "for x in range(100):" " x**4"
  10000 loops, best of 3: 30.6 usec per loop

मैंने अपने द्वारा जुटाई गई शक्ति को बदलने की कोशिश की कि यह कैसे काम करता है, और उदाहरण के लिए अगर मैं x को 10 या 16 की शक्ति तक बढ़ाता हूं, तो यह 30 से 35 तक उछल रहा है, लेकिन अगर मैं 10.0 को एक नाव के रूप में बढ़ा रहा हूं, तो यह चल रहा है लगभग 24.1 ~ 4।

मुझे लगता है कि यह 2 के फ्लोट रूपांतरण और शक्तियों के साथ कुछ करने के लिए हो सकता है, लेकिन मैं वास्तव में नहीं जानता।

मैंने देखा कि दोनों मामलों में 2 की शक्तियां तेज हैं, मुझे लगता है कि दुभाषिया / कंप्यूटर के लिए उन गणनाएं अधिक देशी / आसान हैं। लेकिन फिर भी, तैरने के साथ यह लगभग नहीं चल रहा है। 2.0 => 24.1~4 & 128.0 => 24.1~4 लेकिन 2 => 29 & 128 => 62

TigerhawkT3 ने बताया कि यह लूप के बाहर नहीं होता है। मैंने जाँच की और स्थिति केवल तब होती है (जो मैंने देखा है) जब आधार उठाया जा रहा है। उस के बारे में कोई विचार?


पायथन 3 * में x**4 से x**4.0 अधिक तेज़ क्यों है?

पायथन 3 int ऑब्जेक्ट एक पूर्ण आकार की वस्तु हैं जो एक मनमाने आकार का समर्थन करने के लिए डिज़ाइन किया गया है; उस तथ्य के कारण, उन्हें सी स्तर पर इस तरह संभाला जाता है (देखें कि कैसे सभी चर को PyLongObject * long_pow में टाइप किया long_pow )। यह भी उनके घातांक को बहुत अधिक पेचीदा और थकाऊ बनाता है क्योंकि आपको इसे निष्पादित करने के लिए इसके मूल्य का प्रतिनिधित्व करने के लिए उपयोग करने वाले ob_digit सरणी के साथ खेलने की आवश्यकता है। ( बहादुर के लिए स्रोत। देखें: PyLongObject s पर अधिक के लिए अजगर में बड़े पूर्णांकों के लिए स्मृति आवंटन को समझना ।)

अजगर float ऑब्जेक्ट्स, इसके विपरीत, एक सी double प्रकार में परिवर्तित किया जा सकता है ( PyFloat_AsDouble का उपयोग PyFloat_AsDouble ) और उन मूल प्रकारों का उपयोग करके ऑपरेशन किए जा सकते हैं। यह बहुत अच्छा है , क्योंकि प्रासंगिक किनारे के मामलों की जाँच के बाद, यह पायथन को वास्तविक घातांक को संभालने के लिए प्लेटफ़ॉर्म के pow ( सी का pow , यानी ) का उपयोग करने की अनुमति देता है:

/* Now iv and iw are finite, iw is nonzero, and iv is
 * positive and not equal to 1.0.  We finally allow
 * the platform pow to step in and do the rest.
 */
errno = 0;
PyFPE_START_PROTECT("pow", return NULL)
ix = pow(iv, iw); 

जहां iv और iw हमारे मूल PyFloatObject जो सी double एस हैं।

इसके लायक क्या है: मेरे लिए अजगर 2.7.13 एक कारक 2~3 तेज है, और उलटा व्यवहार दिखाता है।

पिछला तथ्य भी पायथन 2 और 3 के बीच विसंगति की व्याख्या करता है, इसलिए मैंने सोचा कि मैं इस टिप्पणी को भी संबोधित करूंगा क्योंकि यह दिलचस्प है।

Python 2 में, आप पुरानी int ऑब्जेक्ट का उपयोग कर रहे हैं जो Python 3 में int ऑब्जेक्ट से अलग है (3.x में सभी int ऑब्जेक्ट PyLongObject प्रकार के हैं)। पायथन 2 में, एक अंतर है जो वस्तु के मूल्य पर निर्भर करता है (या, यदि आप प्रत्यय का उपयोग करते हैं तो L/l :

# Python 2
type(30)  # <type 'int'>
type(30L) # <type 'long'>

<type 'int'> आप यहां देखते हैं कि वही काम float s करता है , यह सुरक्षित रूप से C long में परिवर्तित हो जाता है जब इस पर घातांक किया जाता है ( int_pow संकलक को 'रजिस्टर में' डालने के लिए संकेत देता है यदि यह कर सकता है इसलिए, ताकि फर्क पड़ सके ):

static PyObject *
int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
{
    register long iv, iw, iz=0, ix, temp, prev;
/* Snipped for brevity */    

यह एक अच्छी गति हासिल करने की अनुमति देता है।

यह देखने के लिए कि <type 'long'> s की तुलना में कितनी सुस्त है, अगर आप Python 2 में एक long कॉल में x नाम को लपेटते हैं (अनिवार्य रूप से इसे Python 3 की तरह long_pow का उपयोग करने के लिए मजबूर करते हैं,) गति लाभ गायब हो जाता है:

# <type 'int'>
(python2)  python -m timeit "for x in range(1000):" " x**2"       
10000 loops, best of 3: 116 usec per loop
# <type 'long'> 
(python2)  python -m timeit "for x in range(1000):" " long(x)**2"
100 loops, best of 3: 2.12 msec per loop

ध्यान दें, हालांकि एक स्निपेट int को long समय long बदल देता है, जबकि दूसरा नहीं (जैसा कि @pydsinger द्वारा बताया गया है), यह कास्ट मंदी के पीछे योगदान करने वाला बल नहीं है। long_pow का कार्यान्वयन है। (समय केवल देखने के लिए long(x) साथ बयान)।

[...] यह लूप के बाहर नहीं होता है। [...] इस बारे में कोई विचार?

यह आपके लिए स्थिरांक को तह करते हुए सीपीथॉन का पीपहोल आशावादी है। आप या तो मामले के समान सटीक समय प्राप्त करते हैं क्योंकि घातांक के परिणाम को खोजने के लिए कोई वास्तविक गणना नहीं है, केवल मूल्यों का लोडिंग:

dis.dis(compile('4 ** 4', '', 'exec'))
  1           0 LOAD_CONST               2 (256)
              3 POP_TOP
              4 LOAD_CONST               1 (None)
              7 RETURN_VALUE

'4 ** 4.' लिए समान बाइट-कोड जेनरेट किया गया है एकमात्र अंतर यह है कि LOAD_CONST अंतर 256 बजाय फ्लोट 256.0 लोड करता है:

dis.dis(compile('4 ** 4.', '', 'exec'))
  1           0 LOAD_CONST               3 (256.0)
              2 POP_TOP
              4 LOAD_CONST               2 (None)
              6 RETURN_VALUE

इसलिए समय समान हैं।

* उपरोक्त सभी केवल अजगर के संदर्भ कार्यान्वयन, सीपीथॉन के लिए लागू होते हैं। अन्य कार्यान्वयन अलग तरीके से प्रदर्शन कर सकते हैं।


क्योंकि एक सही है, दूसरा सन्निकटन है।

>>> 334453647687345435634784453567231654765 ** 4.0
1.2512490121794596e+154
>>> 334453647687345435634784453567231654765 ** 4
125124901217945966595797084130108863452053981325370920366144
719991392270482919860036990488994139314813986665699000071678
41534843695972182197917378267300625





python-internals