言い換えれば、2つのアスタリスクの後ろには何がありますか?それは単に数をx倍するだけですか、それとも何か他のものですか?フォローアップの質問として、2 ** 3または2 * 2 * 2と書く方が良いですか。 C++では、関数を呼び出すため、単純な計算にはpow()を使用しない方がよいと聞いたので質問しています。
内部に興味がある場合は、命令を逆アセンブルして、マップ先のCPythonバイトコードを取得します。 Python3の使用:
»»» def test():
return 2**3
...:
»»» dis.dis(test)
2 0 LOAD_CONST 3 (8)
3 RETURN_VALUE
OK、これで入力時に計算が完了し、結果が保存されたようです。 2 * 2 * 2とまったく同じCPythonバイトコードを取得します(自由に試してみてください)。したがって、定数に評価される式の場合、同じ結果が得られ、それは問題ではありません。
変数の力が必要な場合はどうなりますか?
これで、2つの異なるバイトコードが得られます。
»»» def test(n):
return n ** 3
»»» dis.dis(test)
2 0 LOAD_FAST 0 (n)
3 LOAD_CONST 1 (3)
6 BINARY_POWER
7 RETURN_VALUE
vs.
»»» def test(n):
return n * 2 * 2
....:
»»» dis.dis(test)
2 0 LOAD_FAST 0 (n)
3 LOAD_CONST 1 (2)
6 BINARY_MULTIPLY
7 LOAD_CONST 1 (2)
10 BINARY_MULTIPLY
11 RETURN_VALUE
さて、問題はもちろんですが、BINARY_MULTIPLYはBINARY_POWER操作よりも速いですか?
それを試す最良の方法は、timeitを使用することです。 IPythonを使用します%timeit
魔法。乗算の出力は次のとおりです。
%timeit test(100)
The slowest run took 15.52 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 163 ns per loop
そして力のために
The slowest run took 5.44 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 473 ns per loop
代表的な入力に対してこれを繰り返すことをお勧めしますが、経験的には乗算の方が速いように見えます(ただし、出力の分散に関する前述の警告に注意してください)。
さらに内部が必要な場合は、CPythonコードを掘り下げることをお勧めします。
2番目のものは数値に対して少し速いですが、最初のものと比較して利点は非常に低いです:読みやすさ。時間に追われていて、そのような最適化を行うようにプレッシャーをかけられている場合、pythonはおそらく使用すべき言語ではありませんです。
注:数字以外の場合:
a ** bは次のように変換されます
a.__pow__(b)
一方、a * a * aはへの呼び出しです
a.__mul__(a.__mul__(a))
import time
s = time.time()
for x in xrange(1,1000000):
x**5
print "done in ", time.time() - s
s = time.time()
for x in xrange(1,1000000):
x*x*x*x*x
print "done in ", time.time() - s
私のマシンの歩留まりについて:
done in 0.975429058075
done in 0.260419845581
[Finished in 1.2s]
率直に言って、乗算は少し速いです。
>>timeit.timeit('[i*i*i*i for i in range(100)]', number=10000)
0.262529843304
>>timeit.timeit('[i**4 for i in range(100)]', number=10000)
0.31143438383
ただし、2つのオプションから1つを選択する場合は、速度だけを考慮する必要はありません。たとえば、2の20乗を計算するときに簡単なことは何ですか?単に2**20
または20回繰り返して乗算タスクを実行するforループを使用していますか?
_**
_演算子は、内部的に反復関数(組み込みのpow()
( Python docs )と同じセマンティクス)を使用します。これは、とにかくその関数を呼び出すだけであることを意味します。 )。
したがって、パワーを知っていてハードコーディングできる場合は、_2*2*2
_を使用すると_2**3
_よりも少し速くなる可能性があります。これは関数とは少し関係がありますが、パフォーマンスの主な問題はループを使用することだと思います。
_2**3
_のような単純なものである場合、読みやすいコードを読みにくいコードに置き換えるのはまだかなりばかげていることに注意してください。パフォーマンスの向上はせいぜい最小限です。
から ドキュメント :
パワー演算子は、左側の単項演算子よりも緊密に結合します。右側の単項演算子よりも緊密に結合しません。構文は次のとおりです。
_power ::= primary ["**" u_expr]
_
したがって、括弧なしの累乗演算子と単項演算子のシーケンスでは、演算子は右から左に評価されます(これにより、オペランドの評価順序は制約されません)。_
-1**2
_は_-1
_になります。累乗演算子は、組み込みの
pow()
関数と同じセマンティクスを持ち、2つの引数を指定して呼び出されると、左の引数が右の引数の累乗になります。
これは、Pythonでは、_2**2**3
_が2**(2**3) = 2**8 = 256
として評価されることを意味します。
数学では、積み重ねられた指数は上から下に適用されます。この方法で行われなかった場合は、指数の乗算が得られます。
_(((2**3)**4)**5) = 2**(3*4*5)
_
乗算を行うだけの方が少し速いかもしれませんが、読みにくくなります。