Programing

Python 3에서 x ** 4.0이 x ** 4보다 빠른 이유는 무엇입니까?

lottogame 2020. 6. 1. 07:41
반응형

Python 3에서 x ** 4.0이 x ** 4보다 빠른 이유는 무엇입니까?


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

나는 그것이 어떻게 작동하는지보기 위해 제기 한 힘을 변경하려고 시도했습니다. 예를 들어 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 은 루프 외부에서는 발생하지 않는다고 지적했습니다. 나는 확인하고 상황은 (내가 본 것에서) 베이스 가 올라갈 때만 발생합니다 . 그것에 대한 아이디어가 있습니까?


x**4.0 빨리 보다는 x**4파이썬 3 * ?

파이썬 3 int객체는 임의의 크기를 지원하도록 설계된 본격적인 객체입니다. 그 사실 때문에 C 수준에서 그대로 처리됩니다 (모든 변수가 PyLongObject *유형으로 선언되는 방법 참조 long_pow). 이것은 또한 지수 훨씬 더하게 까다 하고 지루한을 당신이 함께 놀러 할 필요가 있기 때문에 ob_digit그것을 수행하기 위해 그 값을 표현하기 위해 사용하는 배열입니다. ( 출처 용감한합니다. - 참조 : 파이썬에서 큰 정수에 대한 이해 메모리 할당 에 대한 자세한 내용은 PyLongObject.들)

float반대로 파이썬 객체는 (를 사용하여 ) C 유형 으로 변환수 있으며 이러한 기본 유형을 사용하여 작업을 수행 할 수 있습니다 . 이것은 대단한 관련 에지 경우에 확인 후, 그것은 파이썬을 허용하기 때문에 플랫폼 '를 사용 ( C의 입니다 ) 실제 지수를 처리하는 :doublePyFloat_AsDoublepowpow

/* 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); 

iviw우리의 원래있는 PyFloatObjectC 등의 double의.

그만한 가치가있는 것은 : Python 2.7.13for me는 2~3더 빠르며 반대 행동을 보여줍니다.

이전의 사실 은 또한 파이썬 2와 3의 불일치를 설명 하므로 흥미 롭기 때문에이 의견도 다루겠다고 생각했습니다.

Python 2에서는 Python 3 intint객체 와 다른 오래된 객체를 사용하고 있습니다 ( int3.x의 모든 객체는 PyLongObject유형 임). Python 2에는 객체의 값에 따라 (또는 접미사를 사용하는 경우) 구별되는 것이 있습니다 L/l.

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

<type 'int'>여기 참조는 같은 일을 수행 float의 수행을 가 안전하게 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'>비교에의 <type 'int'>당신은, 랩 된 경우의 xA의 이름 long(기본적으로 사용하도록 강제 파이썬 2에서 전화를 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

메모를 받아, 그 한 조각을 변환하는 비록 intlong(@pydsinger가 가리키는 아웃과 같은) 다른 하나는하지 않지만,이 캐스트는 둔화 뒤에 기여 힘이 아니다. 의 구현입니다 long_pow. (본문 만 long(x)시간 ).

[...] 루프 외부에서는 발생하지 않습니다. [...] 그것에 대한 아이디어가 있습니까?

이것은 CPython의 들여다 보는 구멍 최적화 프로그램으로 상수를 접습니다. 지수 결과를 찾기위한 실제 계산이없고 값만로드되므로 두 경우 모두 동일한 정확한 타이밍을 얻습니다.

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

Identical byte-code is generated for '4 ** 4.' with the only difference being that the LOAD_CONST loads the float 256.0 instead of the int 256:

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

So the times are identical.


*All of the above apply solely for CPython, the reference implementation of Python. Other implementations might perform differently.


If we look at the bytecode, we can see that the expressions are purely identical. The only difference is a type of a constant that will be an argument of BINARY_POWER. So it's most certainly due to an int being converted to a floating point number down the line.

>>> 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

Update: let's take a look at Objects/abstract.c in the CPython source code:

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

PyNumber_Power calls ternary_op, which is too long to paste here, so here's the link.

It calls the nb_power slot of x, passing y as an argument.

Finally, in float_pow() at line 686 of Objects/floatobject.c we see that arguments are converted to a C double right before the actual operation:

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);
    ...

Because one is correct, another is approximation.

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

참고URL : https://stackoverflow.com/questions/42355194/why-is-x4-0-faster-than-x4-in-python-3

반응형