2014-01-16 39 views
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()才能得到正確的答案嗎?

+1

「正確的答案」在我看來似乎在實際中偏離了一個數量級。 [Wolfram Alpha](http://www.wolframalpha.com/input/?i=log1p%28-1e-27-1e-27i%29)和我的直覺都表明實際部分應該更接近'-1e -27'。 – user2357112

+0

我認爲,如果它只比9.99e-27更小,那它就大於1。 – egoburnswell

+2

'0.00000000000000000000000001'是'1e-26',而不是'1e-27'。你爲什麼不用字符串初始化它,比如'mp.mpc(real ='0.0',imag ='1.0e-27')'? – user2357112

回答

3

Python使用IEEE binary64標準(通常稱爲雙精度)來表示浮點數。 binary64只有大約15位十進制數字的精度;超過15位數字的數字不能準確表示。正如你可以在這裏看到:

>>> 1 - 1e-27 
1.0 

精度損失導致1 - 1e-27四捨五入到剛剛1.0。更復雜的數學庫提供的函數可以計算1的對數,而不是輸入的數字。例如,在numpy

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

...不幸的是錯誤。這讓我感到驚訝。我不知道爲什麼會發生。下一個最好的選擇可能是使用像mpmath這樣的任意精度的數學庫。確保使用字符串初始化任意精度數字,而不是使用浮點數。如果您使用浮點文字,則在任意精度庫進場前您將失去大量精度。

1

雙格式具有大約15位十進制數的精度。 cmath.log()在你的情況下會失去精確度,因爲它在數量級上的總和(1.和你的小數)是不同的。

如果你的算法不需要高速,你可以使用泰勒級數爲log(1+x)。即:

日誌(1 + X)= X - X ** 2/2 + X ** 3/3 + ...

對於可以實現Kahan summation algorithm更加精確。

也可以使用下式:

日誌(1 + X)= math.log1p(X)+ 1J * cmath.phase(1 + x)中,

其中math.log1p計算對數正是爲了小x。

+0

這裏,由於'x〜1e-26',一階近似log(1 + x)= x'給出的精度高達'〜1e-52',這可能就足夠了。 – aland