なぜx**4.0
速くよりx**4
Pythonの3の*?
Python 3 int
オブジェクトは、任意のサイズをサポートするように設計された本格的なオブジェクトです。そのため、それらはCレベルでそのように処理されます(すべての変数がPyLongObject *
型として宣言される方法を参照してくださいlong_pow
)。また、これを実行するには、値を表すために使用する配列をいじる必要があるため、指数の計算がより複雑で面倒になりますob_digit
。(勇敢な人々のためのソース。-参照:PyLongObject
sの詳細については、Pythonでの長整数のメモリ割り当てを理解する。)
float
逆に、Python オブジェクトは(を使用して)Cの型に変換でき、操作はこれらのネイティブの型を使用して実行できます。これは素晴らしいです、関連するエッジケースをチェックした後、それをするのPythonを許可する、なぜならプラットフォームを使用する(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
のです。
それだけの価値2.7.13
があるのですが、私にとってPython は1倍2~3
高速で、逆の振る舞いを示します。
前の事実はPython 2とPython 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'>
sと<type 'int'>
sの比較の低さを確認するために、Python 2の呼び出しでx
名前をラップした場合long
(本質的にlong_pow
は、Python 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
1つのスニペットはint
to 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
同一のバイトコードが生成されますが'4 ** 4.'
、唯一の違いは、がintではなくLOAD_CONST
float 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にのみ適用されます。他の実装は異なる動作をする場合があります。