我正在使用numpy.log 1p函数来计算非常小的复数的log(1 + x)值,并且得到了意想不到的结果.

我预计输出实际上应该等于函数输入.而在下面的简单例子中,情况似乎并非如此.

np.log1p(1e-14 * (1 + 1j))
Out[75]: (9.992007221626358e-15+9.9999999999999e-15j)
np.log1p(1e-15 * (1 + 1j))
Out[76]: (1.110223024625156e-15+9.999999999999989e-16j)
np.log1p(1e-16 * (1 + 1j))
Out[77]: 1e-16j

scipy.special中的log 1p函数似乎工作正常,但不幸的是,我需要使用numpy函数(用于numba).

我目前在Python 3.10.10上使用numpy版本1.26.4

np.__version__
Out[78]: '1.26.4'

推荐答案

numpy docs人说:

对于实值输入,log 1 p对于x很小以至于1 + x == 1的浮点精度也是准确的.

这似乎是一种间接的方式,表明他们"放弃"了复杂的输入.事实上,在普通Python(没有cmath.log1p)中,在Windows上:

>>> import cmath
>>> p = 1e-14 * (1 + 1j)
>>> p
(1e-14+1e-14j)
>>> cmath.log(1 + p)
(9.992007221626409e-15+9.9999999999999e-15j)

这与你得到的非常接近.所以看起来复杂cnumpy.log1p(c)确实是在调用numpy.log()之前将1.0添加到c.

结果"应该"接近p - p**2/2p如此小(仅log(1+p)p=0左右的泰勒展开式的前两项):

>>> p - p**2/2
(1e-14+9.9999999999999e-15j)

这本质上是由mpmath扩展模块交付的:

>>> import mpmath
>>> p = mpmath.mpc(1, 1) * 1e-14
>>> p
mpc(real='1.0e-14', imag='1.0e-14')
>>> mpmath.log1p(p)
mpc(real='1.0e-14', imag='9.9999999999999006e-15')

因此,这看起来像是numpy当前log1p()实现的(没有充分记录)限制.

因此,如果您必须为此使用numpy,则必须提供自己的替代方案.

Python相关问答推荐

acme错误-Veritas错误:模块收件箱没有属性linear_util'

使用新的类型语法正确注释ParamSecdecorator (3.12)

删除任何仅包含字符(或不包含其他数字值的邮政编码)的观察

如何从具有不同len的列表字典中创建摘要表?

从numpy数组和参数创建收件箱

如何使用数组的最小条目拆分数组

我们可以为Flask模型中的id字段主键设置默认uuid吗

如何在表中添加重复的列?

Django RawSQL注释字段

如何使用两个关键函数来排序一个多索引框架?

交替字符串位置的正则表达式

如何在Python Pandas中填充外部连接后的列中填充DDL值

如何在FastAPI中替换Pydantic的constr,以便在BaseModel之外使用?'

极柱内丢失类型信息""

为什么我的scipy.optimize.minimize(method=";newton-cg";)函数停留在局部最大值上?

Matplotlib中的曲线箭头样式

解析CSV文件以将详细信息添加到XML文件

Pandas:使列中的列表大小与另一列中的列表大小相同

将时间序列附加到数据帧

Django REST框架+Django Channel->;[Errno 111]连接调用失败(';127.0.0.1';,6379)