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
タイガーホークT3 ベース
ベストアンサー1
なぜ
x**4.0
もっと早くx**4
Python 3 と比べて* ?
Python 3int
オブジェクトは、任意のサイズをサポートするように設計された本格的なオブジェクトです。そのため、Cレベルではこのように扱われる(すべての変数がPyLongObject *
型として宣言されているのを見てくださいlong_pow
)。これにより、指数計算もはるかに簡単になります。よりトリッキーそして退屈なob_digit
それを実行するには、値を表すために使用する配列を操作する必要があるためです。(勇敢な人のための源。- 見る:Python での大きな整数のメモリ割り当てを理解する詳細はPyLongObject
s をご覧ください。
Pythonfloat
オブジェクトは、逆に、変形できるCdouble
型(PyFloat_AsDouble
)と操作を実行できますこれらのネイティブタイプを使用する。これは素晴らしい関連するエッジケースをチェックした後、Pythonはプラットホームを使う'pow
(Cの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
、および はC としてのiw
元の です。PyFloatObject
double
参考までに言うと、
2.7.13
私にとって Python は 1 倍2~3
高速で、逆の動作を示します。
前の事実また説明しているPython 2 と 3 の間の相違点について、興味深いのでこのコメントにも触れておこうと思いました。
Python 2 では、 Python 3 のオブジェクトint
とは異なる古いオブジェクトを使用しています( 3.x のすべてのオブジェクトは 型です)。Python 2 では、オブジェクトの値 (または、サフィックス を使用する場合) によって区別されます。int
int
PyLongObject
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'>
、Python 2 で呼び出しx
内に名前をラップすると (基本的にPython 3 のように使用するように強制すると)、速度の向上は消えます。long
long_pow
# <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
1 つのスニペットはを に変換しますが、もう 1 つは変換しません (@pydsinger が指摘したように)、このキャストが速度低下の原因ではないことに注意してくださいlong
。 の実装は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 にのみ適用されます。他の実装では動作が異なる場合があります。