Math.powまたは**演算子を使用する方が効率的ですか?いつ他を使用する必要がありますか?
これまでのところ、x**y
はint
またはfloat
を返すことができます。10進数を使用する場合、関数pow
はfloatを返します
import math
print math.pow(10, 2)
print 10. ** 2
べき乗演算子_**
_を使用すると、関数呼び出しのオーバーヘッドがないため、高速になります。 Pythonコードを逆アセンブルすると、これを見ることができます:
_>>> dis.dis('7. ** i')
1 0 LOAD_CONST 0 (7.0)
3 LOAD_NAME 0 (i)
6 BINARY_POWER
7 RETURN_VALUE
>>> dis.dis('pow(7., i)')
1 0 LOAD_NAME 0 (pow)
3 LOAD_CONST 0 (7.0)
6 LOAD_NAME 1 (i)
9 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
12 RETURN_VALUE
>>> dis.dis('math.pow(7, i)')
1 0 LOAD_NAME 0 (math)
3 LOAD_ATTR 1 (pow)
6 LOAD_CONST 0 (7)
9 LOAD_NAME 2 (i)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 RETURN_VALUE
_
_7. ** 5
_のような定数式は実際にコンパイル時に評価されるため、ここでは指数として変数i
を使用していることに注意してください。
さて、実際には、この違いはそれほど重要ではありません。タイミングを計るとわかるように:
_>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255
_
したがって、pow
と_math.pow
_は約2倍遅いですが、あまり気にしないほど十分に高速です。べき乗をボトルネックとして実際に識別できない限り、明確さが低下した場合、一方の方法をもう一方よりも選択する理由はありません。 pow
は統合されたモジュロ演算などを提供するため、これは特に当てはまります。
Alfeは上記のコメントで良い質問をしました。
timeit
は、すべての場合で_math.pow
_が_**
_より遅いことを示しています。とにかくmath.pow()
とは何ですか?誰かがそれがどんな利点があるのか考えていますか?
_math.pow
_の組み込みpow
とべき乗演算子_**
_の大きな違いは、それがalwaysであることです。 floatセマンティクスを使用します。そのため、何らかの理由で、結果としてフロートが返されるようにする場合は、_math.pow
_がこのプロパティを保証します。
例について考えてみましょう:i
とj
の2つの数値があり、それらが浮動小数点数か整数かはわかりません。ただし、_i^j
_の浮動小数点結果が必要です。では、どのようなオプションがありますか?
i ** j
_を実行できます。i ** j
_を実行し、結果をfloatに変換できます(i
またはj
がfloatの場合、float指数は自動的に使用されるため、結果は同じです)。math.pow
_を使用できます。それで、これをテストしましょう:
_>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439
_
ご覧のとおり、_math.pow
_は実際には高速です!考えてみると、関数呼び出しのオーバーヘッドもなくなりました。他のすべての選択肢ではfloat()
を呼び出す必要があるからです。
さらに、カスタムタイプに特別な_**
_(および___pow__
_)メソッドを実装することで、___rpow__
_およびpow
の動作をオーバーライドできることに注意する価値があります。 (何らかの理由で)そうしたくない場合は、_math.pow
_を使用してもそれはできません。
プロトコルのみ:**
演算子は 組み込みpow
関数 を呼び出します。最初の2つの引数が整数型の場合、オプションの3番目の引数(モジュラス)を受け入れます。
したがって、べき乗から剰余を計算する場合は、組み込み関数を使用してください。 math.pow
は間違った結果を与える可能性があります。
import math
base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)
これを実行すると、0.0
最初のケースでは、13は奇数であるため、明らかに真ではありません(したがって、そのすべての整数乗)。 math.pow
バージョンは、エラーを引き起こす限られた精度を使用します。
公平を期すために、math.pow
ははるかに高速です。
import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("pow(2, 100)")
出力として得られるものは次のとおりです。
0.240936803195
1.4775809183
いくつかのオンライン例
math.pow
)pow
を使用するとパフォーマンスが低下します)pow
を使用するとパフォーマンスが若干低下します)まあ、彼らは本当に異なるタスクのためです。
整数演算が必要な場合は、pow
(2つの引数を持つx ** y
と同等)を使用します。
そして、どちらかの引数がフロートで、フロート出力が必要な場合は、math.pow
を使用します。
pow
とmath.pow
の違いに関する議論については、これを参照してください question 。
_**
_はmath.pow()
よりも確かに高速ですが、例のような単純な2次関数が必要な場合は、製品を使用する方がさらに高速です。
_10.*10.
_
より速くなります
_10.**2
_
違いはそれほど大きくなく、1つの操作(timeit
を使用)では気付かれませんが、操作の数が多い場合は重要になる可能性があります。