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의 입니다 ) 실제 지수를 처리하는 :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
우리의 원래있는 PyFloatObject
C 등의 double
의.
그만한 가치가있는 것은 : Python
2.7.13
for me는2~3
더 빠르며 반대 행동을 보여줍니다.
이전의 사실 은 또한 파이썬 2와 3의 불일치를 설명 하므로 흥미 롭기 때문에이 의견도 다루겠다고 생각했습니다.
Python 2에서는 Python 3 int
의 int
객체 와 다른 오래된 객체를 사용하고 있습니다 ( int
3.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'>
당신은, 랩 된 경우의 x
A의 이름 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
메모를 받아, 그 한 조각을 변환하는 비록 int
에 long
(@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
'Programing' 카테고리의 다른 글
JavaScript에서 왜 2 == [2]입니까? (0) | 2020.06.01 |
---|---|
빌드 유형이 제품 맛과 다른 이유는 무엇입니까? (0) | 2020.06.01 |
WAR에서 주석을 사용하여 서블릿 필터 실행 순서를 정의하는 방법 (0) | 2020.06.01 |
파이썬에서 중첩 된 try / except 블록이 좋은 프로그래밍 습관입니까? (0) | 2020.06.01 |
NumPy 2d 배열의 슬라이스 또는 nxn 배열에서 mxm 하위 행렬을 어떻게 추출합니까 (n> m)? (0) | 2020.06.01 |