0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

指数と対数を組み合わせた等式の評価について

Posted at

Introduction

 正整数は素因数分解によって、たとえば $18 = 2 \times 3^2$ のように、素数の正整数乗の積として一意に表すことができます。
 一方、指数に実数を許すと、この表現は一意ではなくなります。実際、$18 = 2^{1+\log_2 3} \times 3 = 2 \times 3 \times 5^{\log_5 3}$ のように、無数の表し方が存在します。
 このように、指数に実数、特に対数(logarithm)を用いた場合に、2つの異なる表現が等しいかどうかを判定するプログラムを、PythonのSymPyを使って簡単に作ってみました。しかし、意外にも正しく評価できないケースがあったため、今回この記事を書くに至りました。

Summary

以下では具体的な実例を扱いますが、全体像をつかんでいただくため、先にサマリーをまとめます。

  • 指数と対数を組み合わせた等式が、正しく評価できない場合がありました
  • 実例では前処理を工夫することで、正しく評価できる例を示しました
  • ただし、これらは実例に対するadhocな前処理方法であり、すべての等式に適用できるわけではありません
  • 等式評価を汎用的に行える便利なライブラリがあれば、ぜひ知りたいです

Example

以下の$x,y$が等しいことを確かめよ

$x=2^{\log_6 18}$

$y=3^{(2+\log_3 2) \cdot \log_6 2}$

Codes

sympyを使っています。$\log$関数の引数は(真数、底)の順番であることに注意して下さい。

from sympy import log, simplify, N, Eq
x=2**(log(18,6))
y=3**((2+log(2,3))*log(2,6))

評価1

$x,y$と、等号評価「==」と、sympyの等号評価「equals」、「Eq」(simplify付き)の結果を表示します。

equalsは代数的に等しいかを評価し、Eqは2式が等しければTrueを返しますが基本的には(Falseであれば)等式そのものを返します。

print("x:: {}".format(x))
print("y:: {}".format(y))

print("x==y:: {}".format(x==y))
print("sympy.x.equals(y):: {}".format(x.equals(y)))
print("sympy.Eq(x,y).simplify():: {}".format(Eq(x,y).simplify()))

結果は、Falseです。

x:: 2**(log(3)/log(6) + 1)
y:: 3**((log(2)/log(3) + 2)*log(2)/log(6))
x==y:: False
sympy.x.equals(y):: False
sympy.Eq(x,y).simplify():: Eq(2**(log(3)/log(6) + 1), 3**(log(2)*log(18)/(log(3)*log(6))))

評価2(simplify)

次に$x,y$をsimplifyで整理してみます。

#数式を整理する
x=simplify(x)
y=simplify(y)

ここで$y$の式は少し整理されましたが、やはりFalseとなりました。なお、equalsでNoneと表示されているのは判定不能だそうです。

x:: 2**(log(3)/log(6) + 1)
y:: 3**(log(2)*log(18)/(log(3)*log(6)))
x==y:: False
sympy.x.equals(y):: None
sympy.Eq(x,y).simplify():: Eq(2**(log(3)/log(6) + 1), 3**(log(2)*log(18)/(log(3)*log(6))))

評価3(差分を取ってからsimplify)

$x,y$をそれぞれ整理するよりも、差分を取ってから式を整理すると、上手く0になることもあるので試してみました。

#xとyの差分をとって、0になるか確かめる
x=x-y
y=0

やはりここでもFalse、Noneとなってしまいます。

x:: -3**(log(2)*log(18)/(log(3)*log(6))) + 2**(log(18)/log(6))
y:: 0
x==y:: False
sympy.x.equals(y):: None
sympy.Eq(x,y).simplify():: Eq(-3**(log(2)*log(18)/(log(3)*log(6))) + 2**(log(3)/log(6) + 1), 0)

評価4(log_2 をとってから評価)

式が複雑過ぎて評価出来ない可能性があるので、少なくとも$x$の式を簡単にできるように$\log_2$を取ってみます。

#両辺のlog_2を取ると、途端に正解する
x=log(x,2)
y=log(y,2)

これでやっと、Trueと評価されました。ただし、「==」はFalseと評価されています。

x:: log(2**(log(3)/log(6) + 1))/log(2)
y:: log(3**((log(2)/log(3) + 2)*log(2)/log(6)))/log(2)
x==y:: False
sympy.x.equals(y):: True
sympy.Eq(x,y).simplify():: True

評価5(log_2 をとり、simplifyをしてから評価)

評価4に加えて、さらに両辺をsiplifyで整理してから評価します。

#両辺のlog_2を取ると、途端に正解する
x=log(x,2)
y=log(y,2)

#数式を整理する
x=simplify(x)
y=simplify(y)

ついに、$x,y$の式が一致しました。
これで「==」もTrueを返します。

x:: log(3)/log(6) + 1
y:: log(3)/log(6) + 1
x==y:: True
sympy.x.equals(y):: True
sympy.Eq(x,y).simplify():: True

評価6(数値的一致を見る)

sympyのNを用いて数値計算します。

ここでは、一番最初に定義した$x,y$の式をそのまま計算させています。

#数値計算する
x=N(x)
y=N(y)

計算方法や順序によっては誤差が出るので、本来は完全に0と一致するとは限りませんが、今回は完全一致したようです。

x:: 3.05918465698377
y:: 3.05918465698377
x==y:: True
sympy.x.equals(y):: True
sympy.Eq(x,y).simplify():: True

Conclusion

前述のSummaryのとおりです

それでは良きPythonライフを!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?