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


164

से x**4.0तेज क्यों है x**4? मैं 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

मैंने अपने द्वारा उठाए गए शक्ति को देखने की कोशिश की कि यह कैसे काम करता है, और उदाहरण के लिए अगर मैं 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 ने बताया कि यह लूप के बाहर नहीं होता है। मैंने जाँच की और स्थिति केवल तब होती है (जब मैंने देखा है) जब आधार उठाया जा रहा है। उस के बारे में कोई विचार?


11
इसके लायक यह है: मेरे लिए अजगर 2.7.13 एक कारक 2 ~ 3 तेज है, और उलटा व्यवहार दिखाता है: एक पूर्णांक घातांक एक फ्लोटिंग पॉइंट घातांक से तेज है।

4
@ आगे, मैं 14 usec के लिए x**4.0और 3.9 के लिए मिला है x**4
ढाबा

जवाबों:


161

पायथन 3 * की तुलना में x**4.0 तेज़ क्यों है ?x**4

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

अजगर floatवस्तुओं, इसके विपरीत, एक सी प्रकार में परिवर्तित किया जा सकता है double(उपयोग करके 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हमारे मूल हैं ।PyFloatObjectdouble

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

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

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

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

<type 'int'>आप यहाँ देख एक ही बात करता है floatरों करना इसे सुरक्षित रूप से एक सी में परिवर्तित हो जाती, 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'>एस की तुलना में सुस्त कैसे हैं <type 'int'>, यदि आप पायथन 2 xमें एक longकॉल में नाम लपेटते हैं (अनिवार्य long_powरूप से इसे पायथन 3 में उपयोग करने के लिए मजबूर करते हैं ), गति लाभ गायब हो जाता है:

# <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जबकि दूसरा नहीं (जैसा कि @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.'जाता है जो कि int के बजाय LOAD_CONSTफ्लोट को लोड करता है :256.0256

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

तो समय समान हैं।


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


जो कुछ भी है, यह एक से अधिक लूप से संबंधित है range, समय के रूप में केवल **ऑपरेशन ही पूर्णांक और फ़्लोट के बीच कोई अंतर नहीं देता है।
२१:४3 पर बाघभक्त ३

अंतर केवल तब दिखता है जब एक चर को देखते हुए ( 4**4बस के रूप में तेजी से होता है 4**4.0), और यह जवाब उस पर बिल्कुल नहीं छूता है।
टाइगरहॉक 3

1
लेकिन, स्थिरांक @ TigerhawkT3 ( dis(compile('4 ** 4', '', 'exec'))) से जुड़ जाएंगे, इसलिए समय बिलकुल एक जैसा होना चाहिए ।
दिमित्रिस फासारकिस हिलियार्ड

आपकी अंतिम समयसीमा यह बताती है कि आप जो कहते हैं वह नहीं दिखाते हैं। long(x)**2.अभी भी long(x)**24-5 के कारक से तेज है । (
डाउनवॉटर में से

3
@ mbomb007 <type 'long'>पायथन 3 में प्रकार का उन्मूलन शायद भाषा को सरल बनाने के लिए किए गए प्रयासों द्वारा समझाया गया है। यदि आपके पास पूर्णांकों का प्रतिनिधित्व करने के लिए एक प्रकार हो सकता है, तो यह दो से अधिक प्रबंधनीय है (और आवश्यक होने पर एक से दूसरे में परिवर्तित होने के बारे में चिंता करना, उपयोगकर्ताओं को भ्रमित होना आदि)। गति का लाभ उसके लिए गौण है। PEP 237 का औचित्य खंड भी कुछ अधिक जानकारी प्रदान करता है।
दिमित्री फासरकिस हिलियार्ड

25

यदि हम bytecode को देखते हैं, तो हम देख सकते हैं कि भाव शुद्ध रूप से समान हैं। एकमात्र अंतर एक प्रकार का स्थिर है जो एक तर्क होगा BINARY_POWER। तो यह निश्चित रूप intसे लाइन के नीचे एक फ्लोटिंग पॉइंट नंबर में परिवर्तित होने के कारण है ।

>>> def func(n):
...    return n**4
... 
>>> def func1(n):
...    return n**4.0
... 
>>> from dis import dis
>>> dis(func)
  2           0 LOAD_FAST                0 (n)
              3 LOAD_CONST               1 (4)
              6 BINARY_POWER
              7 RETURN_VALUE
>>> dis(func1)
  2           0 LOAD_FAST                0 (n)
              3 LOAD_CONST               1 (4.0)
              6 BINARY_POWER
              7 RETURN_VALUE

अपडेट: आइए CPython स्रोत कोड में ऑब्जेक्ट्स / abstract.c पर एक नज़र डालें :

PyObject *
PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
{
    return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
}

PyNumber_Powerकॉल ternary_op, जो यहां पेस्ट करने के लिए बहुत लंबा है, इसलिए यहां लिंक दिया गया है

यह तर्क के रूप nb_powerमें x, के स्लॉट को कॉल करता yहै।

अंत में, ऑब्जेक्ट्स / फ्लोटोबोजेसीfloat_pow() की लाइन 686 पर हम देखते हैं कि तर्क वास्तविक ऑपरेशन से ठीक पहले सी में बदल जाते हैं :double

static PyObject *
float_pow(PyObject *v, PyObject *w, PyObject *z)
{
    double iv, iw, ix;
    int negate_result = 0;

    if ((PyObject *)z != Py_None) {
        PyErr_SetString(PyExc_TypeError, "pow() 3rd argument not "
            "allowed unless all arguments are integers");
        return NULL;
    }

    CONVERT_TO_DOUBLE(v, iv);
    CONVERT_TO_DOUBLE(w, iw);
    ...

1
@ जीन-फ्रांस्वा फाबरे का मानना ​​है कि यह लगातार तह करने के कारण है।
दिमित्री फासरकिस हिलियार्ड

2
मुझे लगता है कि एक रूपांतरण है और वे अलग-अलग तरीके से संभाले नहीं हैं, "सबसे निश्चित रूप से" एक स्रोत के बिना थोड़ा सा खिंचाव है।
miradulo

1
@ मिच - विशेष रूप से, इस विशेष कोड में, उन दो परिचालनों के निष्पादन समय में कोई अंतर नहीं है। अंतर केवल ओपी के लूप के साथ उत्पन्न होता है। यह उत्तर निष्कर्ष पर जा रहा है।
टाइगरहॉकट 3

2
आप केवल तभी क्यों देख रहे हैं float_powजब वह धीमे मामले के लिए भी नहीं चल रहा है?
user2357112

2
@ TigerhawkT3: 4**4और 4**4.0स्थिर हो जाओ। यह एक पूरी तरह से अलग प्रभाव है।
user2357112

-1

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

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

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

1
स्पष्टीकरण के लिए धन्यवाद। ठीक है, मैंने वास्तव में सोचा था कि यह स्पष्ट है कि संख्याओं की गणना केवल 12 या उससे अधिक अंकों की गणना करना है, उन सभी की गणना करने के लिए। सब के बाद, हम क्यों अनुमानों का उपयोग करने का एकमात्र कारण यह है कि वे गणना करने के लिए तेज हैं, है ना?
वेकी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.