2

pythonを使用して、フォームのオブジェクトの対数を計算する必要があります

log( 1 - n0 - n1*1j)

ここで、n0 と n1 は非常に小さい数値 ~ 1.0e-27 で、1j は虚数です。

cmath.log を使用すると間違った答えが返される

print cmath.log( 1.0 -  1e-27 - 1.0e-27j )
(5e-55-1e-27j)

mpmath を使用すると、正しい結果を得ることができますが、引数を正しく表現した場合に限ります

import mpmath as mp
mp.prec = 100
print mp.log(   mp.mpc(1.0) -  mp.mpc(0.00000000000000000000000001)  - mp.mpc(real='0.0', imag='1.0e-27') )

与える

(-1.0000389695486766657204483072e-26 - 1.00000000000000000000000001e-27j)

(これが正解です)一方

print mp.log(  mp.mpc(0.99999999999999999999999999)  - mp.mpc(real='0.0', imag='1.0e-27') )

与える

(5.0e-55 - 1.0e-27j)

何が起きてる?cmath.log() を使用するだけで正しい答えを得ることができますか?

4

2 に答える 2

3

Python は、一般に倍精度と呼ばれる IEEE binary64 標準を使用して、浮動小数点数を表します。binary64 の精度は 10 進数で約 15 桁しかありません。15 桁を超える数値は正確に表すことができません。ここでわかるように:

>>> 1 - 1e-27
1.0

精度の損失により1 - 1e-27、ちょうど に丸められます1.0。より高度な数学ライブラリには、入力した数値より 1 大きい対数を計算する関数が用意されています。たとえば、numpyで:

>>> numpy.log1p(-1e-27-1e-27j)
-1e-27j

...残念ながらこれ間違っています。それは私を驚かせました。なぜそうなったのかわかりません。次善の策は、おそらく mpmath のような任意精度の数学ライブラリを使用することです。浮動小数点数ではなく文字列で任意精度の数値を初期化してください。浮動小数点リテラルを使用すると、任意精度ライブラリが機能する前に、大量の精度が失われます。

于 2014-01-16T11:29:12.717 に答える
1

double 形式の精度は、10 進数で約 15 桁です。cmath.log()あなたのケースでは、大きさの数値(1.とあなたの小さな数)があまりにも異なるため、精度が失われます。

アルゴリズムに高速性が必要ない場合は、Taylor 級数を に使用できますlog(1+x)。すなわち:

log(1+x) = x - x**2/2 + x**3/3 + ...

さらに精度を上げるために、 Kahan summation algorithmを実装できます。

次の式を使用することもできます。

log(1+x) = math.log1p(x) + 1j*cmath.phase(1+x),

ここでmath.log1p、小さな x の対数を正確に計算します。

于 2014-01-16T12:02:03.273 に答える