python对数错误地计算了非常小的复数

python对数错误地计算了非常小的复数,python,complex-numbers,logarithm,mpmath,natural-logarithm,Python,Complex Numbers,Logarithm,Mpmath,Natural Logarithm,我需要使用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) -

我需要使用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') )
给予

(哪个是正确答案) 鉴于

给予

这是怎么回事?
仅使用cmath.log()就可以得到正确的答案吗

Python使用IEEE binary64标准(通常称为双精度)来表示浮点数。binary64只有大约15位小数精度;超过15位的数字无法准确表示。正如你在这里看到的:

>>> 1 - 1e-27
1.0
精度损失导致
1-1e-27
四舍五入到
1.0
。更复杂的数学库提供了计算1的对数比输入的数字多的函数。例如,在:


…不幸的是,这也是错误的。这让我很惊讶。我不知道为什么会这样。下一个最佳选择可能是使用任意精度的数学库,如mpmath。确保用字符串而不是浮点数初始化任意精度的数字。如果使用浮点文本,在任意精度库发挥作用之前,将丢失大量精度。

Python使用IEEE binary64标准(通常称为双精度)来表示浮点数。binary64只有大约15位小数精度;超过15位的数字无法准确表示。正如你在这里看到的:

>>> 1 - 1e-27
1.0
精度损失导致
1-1e-27
四舍五入到
1.0
。更复杂的数学库提供了计算1的对数比输入的数字多的函数。例如,在:


…不幸的是,这也是错误的。这让我很惊讶。我不知道为什么会这样。下一个最佳选择可能是使用任意精度的数学库,如mpmath。确保用字符串而不是浮点数初始化任意精度的数字。如果使用浮点文字,在任意精度库发挥作用之前,将损失大量精度。

双精度格式的精度约为15位小数
cmath.log()
在您的情况下会丢失精度,因为它在数量级(1.和您的小数字)上的总和太不同

如果你的算法不需要高速,你可以用泰勒级数来计算。即:

日志(1+x)=x-x**2/2+x**3/3+

您可以实现更高的精度

您还可以使用以下公式:

对数(1+x)=数学对数1p(x)+1j*cmath.相位(1+x)


其中
math.log1p
精确计算小x的对数。

双精度格式的精度约为15位小数
cmath.log()
在您的情况下会丢失精度,因为它在数量级(1.和您的小数字)上的总和太不同

如果你的算法不需要高速,你可以用泰勒级数来计算。即:

日志(1+x)=x-x**2/2+x**3/3+

您可以实现更高的精度

您还可以使用以下公式:

对数(1+x)=数学对数1p(x)+1j*cmath.相位(1+x)


其中
math.log1p
精确计算小x的对数。

在我看来,“正确答案”在实部似乎偏离了一个数量级。我的直觉都表明,真实的部分应该更接近
-1e-27
。如果它比1小,它就比1大,我想它会像9.99e-27。
0.00000000000000000000000001
1e-26
,而不是
1e-27
。你为什么不用一个字符串来初始化它,比如
mp.mpc(real='0.0',imag='1.0e-27')
?如果初始化为'mp.log(mp.mpc(real='0.99999999999999999999',imag='-1.0e-27'),你是对的,它确实给出了正确的答案。在我看来,“正确答案”在真实部分似乎偏离了一个数量级。我的直觉都表明,真实的部分应该更接近
-1e-27
。如果它比1小,它就比1大,我想它会像9.99e-27。
0.00000000000000000000000001
1e-26
,而不是
1e-27
。你为什么不用一个字符串初始化它,比如
mp.mpc(real='0.0',imag='1.0e-27')
?如果初始化为'mp.log(mp.mpc(real='0.99999999999999999999',imag='-1.0e-27'),你是对的,它给出了正确的答案。这里,由于
x~1e-26
,一阶近似值
log(1+x)=x
给出的精度高达
~1e-52
,这可能足够了。这里,由于
x~1e-26
,一阶近似
log(1+x)=x
给出的精度高达
~1e-52
,这可能足够了。
(5.0e-55 - 1.0e-27j)
>>> 1 - 1e-27
1.0
>>> numpy.log1p(-1e-27-1e-27j)
-1e-27j