web-dev-qa-db-ja.com

python x。** y vs math.pow(x、y)の指数

Math.powまたは**演算子を使用する方が効率的ですか?いつ他を使用する必要がありますか?

これまでのところ、x**yintまたはfloatを返すことができます。10進数を使用する場合、関数powはfloatを返します

import math

print math.pow(10, 2)

print 10. ** 2
40
user3084006

べき乗演算子_**_を使用すると、関数呼び出しのオーバーヘッドがないため、高速になります。 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_がこのプロパティを保証します。

例について考えてみましょう:ijの2つの数値があり、それらが浮動小数点数か整数かはわかりません。ただし、_i^j_の浮動小数点結果が必要です。では、どのようなオプションがありますか?

  • 少なくとも1つの引数をfloatに変換してから_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_を使用してもそれはできません。

78
poke

プロトコルのみ:**演算子は 組み込み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

いくつかのオンライン例

4
Wolf

まあ、彼らは本当に異なるタスクのためです。

整数演算が必要な場合は、pow(2つの引数を持つx ** yと同等)を使用します。

そして、どちらかの引数がフロートで、フロート出力が必要な場合は、math.powを使用します。

powmath.powの違いに関する議論については、これを参照してください question

3
wim

_**_はmath.pow()よりも確かに高速ですが、例のような単純な2次関数が必要な場合は、製品を使用する方がさらに高速です。

_10.*10.
_

より速くなります

_10.**2
_

違いはそれほど大きくなく、1つの操作(timeitを使用)では気付かれませんが、操作の数が多い場合は重要になる可能性があります。

2
KDhoore