왜 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
반대로 Python 객체는 (를 사용하여 ) 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
동일한 바이트 코드는 int 대신 float 를 로드 '4 ** 4.'
한다는 점만 다릅니다 .LOAD_CONST
256.0
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
따라서 시간은 동일합니다.
* 위의 모든 내용은 Python의 참조 구현 인 CPython에만 적용됩니다. 다른 구현은 다르게 수행 될 수 있습니다.
답변
바이트 코드를 보면 표현식이 완전히 동일하다는 것을 알 수 있습니다. 유일한 차이점은의 인수가 될 상수 유형입니다 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 소스 코드 에서 Objects / 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
인자로.
마지막으로 Objects / floatobject.c의float_pow()
686 행에서 인수가 실제 작업 직전에 C로 변환되는 것을 볼 수 있습니다.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);
...
답변
하나는 정확하기 때문에 다른 것은 근사치입니다.
>>> 334453647687345435634784453567231654765 ** 4.0
1.2512490121794596e+154
>>> 334453647687345435634784453567231654765 ** 4
125124901217945966595797084130108863452053981325370920366144
719991392270482919860036990488994139314813986665699000071678
41534843695972182197917378267300625