静かなる名辞

pythonとプログラミングのこと



【python】べき乗とべき根の計算

 べき乗はx^n、べき根は\sqrt[n]{x}です。2乗とかsqrtくらいはわかっても、n乗根あたりになるとすぐ出てこないという人も多いのでは?

 目次

スポンサーリンク



組み込み関数powを使う方法

 powという組み込み関数があります。まあ、要は達します。

>>> pow(2, 10)
1024
>>> pow(0.5, 10)
0.0009765625
>>> pow(1.5, 3.5)
4.133513940946613

 見たところ浮動小数点でも大丈夫。

 ドキュメントによると、第三引数を指定することで「x の y 乗に対する z の剰余」を計算できるそうですが、何に使えるのでしょうかね・・・。

2. 組み込み関数 — Python 3.6.5 ドキュメント

べき乗演算子を使う方法

 まったく同じことが演算子でもできます。

>>> 2**10
1024
>>> 0.5**10
0.0009765625
>>> 1.5**3.5
4.133513940946613

 powは必要なのでしょうか。powを多用すると式がごちゃごちゃするので、こちらを使いたいです。

 ただ、罠があるようです。

Python のべき乗演算子に潜む罠 | CUBE SUGAR STORAGE

 単項演算子の-などと組み合わせる場合、べき乗演算子が先に評価されます。どういうこと? と思うかもしれませんが、要するに

>>> -1**2  # WTF!?
-1
>>> -(1**2)  # つまりはこういうこと
-1
>>> (-1)**2  # 本当に欲しかったもの
1

 思い通りの結果を得たければカッコを多用すべきであり、そうするとなんかpowでも良いような気もしてきます。

numpyに頼る方法

 np.powerがあります。

>>> np.power(2, 10)
1024
>>> np.power(0.5, 10)
0.0009765625
>>> np.power(1.5, 3.5)
4.133513940946613

 見たところ、型の取扱も含めてほぼ同じ。まあ、これを単体で使うメリットは特に感じません。numpy配列を相手にするなら、ありかも(ただしnumpy配列にべき乗演算子を使うという選択肢もある)。なお、片方が配列で片方がスカラー、とか配列同士、というケースでは、

>>> import numpy as np
>>> np.power([1,2,3], 2)
array([1, 4, 9])
>>> np.power(2, [1,2,3])
array([2, 4, 8])
>>> np.power([1,2,3], [4,5,6])
array([  1,  32, 729])

 こんな扱いになります。特に難しいことはないです。

n乗根について

 n乗根(べき根)がわからなかった人は、\sqrt[2]{x} = x^\frac{1}{2}を思い出しましょう。

>>> 2**10  # べき乗(10乗)
1024
>>> 1024**(1/10)  # べき根(10乗根)
2.0

 小数のべき乗が計算できれば、べき根も計算できるということです。

どれが速いの?

 timeitで簡単に比較してみます。私はIPython使いではないので、モジュールimportで使います。

>>> import numpy as np
>>> import timeit
>>> timeit.timeit(lambda : [[x**y for y in range(30)] for x in range(30)], number=1000)
0.37399847699998645
>>> timeit.timeit(lambda : [[pow(x,y) for y in range(30)] for x in range(30)], number=1000)
0.4485901359998934
>>> timeit.timeit(lambda : [[np.power(x,y) for y in range(30)] for x in range(30)], number=1000)
1.3186961119999978

 スカラーに対してはべき乗演算子一択。

 numpy配列だと、べき乗演算子とnp.powerはどちらが上でしょうか。

>>> timeit.timeit(lambda : np.arange(1000)**np.arange(1000), number=100000)
1.4120757860000595
>>> timeit.timeit(lambda : np.power(np.arange(1000), np.arange(1000)), number=100000)
1.402805570000055

 そもそも冗談みたいに速いんですが(numberに注目)、速度差自体は計測誤差レベル。一番コアな部分は同じ処理なのでしょう。

まとめ

 ま、べき乗演算子ですべてまかなえるので、罠に気をつけて使えば良いと思いました。

 あと、numpyすごいなぁ・・・