python - Numpy 返回分析函数的意外结果

标签 python numpy floating-point

当我尝试计算 d_j(x) ,定义如下,基于 Numpy 的算法会导致意外的值。我相信它与数值精度有关,但我不确定如何解决这个问题。
功能是:
latex equation
在哪里
latex equation

latex equation
j>10 时代码失败.例如,当 j=16 ,函数d_j(x)x=1 附近返回错误的值,而预期的结果是一条平滑的、几乎是周期性的曲线。0<x<1.5的图:

代码是:

#%%
import numpy as np
import matplotlib.pyplot as plt

#%%
L = 1.5  # Length [m]

def eta(j):
    if j == 1:
        return 1.875 / L
    if j > 1:
        return (j - 0.5) * np.pi / L


def D(etaj):
    etajL = etaj * L
    return (np.cos(etajL) + np.cosh(etajL)) / (np.sin(etajL) - np.sinh(etajL))


def d(x, etaj):
    etajx = etaj * x
    return np.sin(etajx) - np.sinh(etajx) + D(etaj) * (np.cos(etajx) - np.cosh(etajx))


#%%
aux = np.linspace(0, L, 2000)
plt.plot(aux, d(aux, eta(16)))
plt.show()

最佳答案

TL;博士:问题来自数值不稳定性 .
首先,这是一个简化的代码,出现完全相同的问题(具有不同的值):

x = np.arange(0, 50, 0.1)
plt.plot(np.sin(x) - np.sinh(x) - np.cos(x) + np.cosh(x))
plt.show()
这是另一个没有出现问题的示例:
x = np.arange(0, 50, 0.1)
plt.plot((np.sin(x) - np.cos(x)) + (np.cosh(x) - np.sinh(x)))
plt.show()
虽然这两个代码在数学上与实数等效,但由于固定大小的浮点精度,它们并不等效。确实,np.sinh(x)np.cosh(x)结果都在 x 时的巨大值(value)大np.sin(x) 相比和 np.cos(x) .不幸的是,当两个固定大小的浮点数相加时,精度会下降。当相加数字的数量级非常不同时,精度损失可能会很大(如果不是很严重的话)。例如,在 Python 和主流平台上(IEEE-754 64 位浮点数也是如此),0.1 + 1e20 == 1e20由于数字表示的精度有限,因此为真。因此(0.1 + 1e20) - 1e20 == 0.0也是如此,而 0.1 + (1e20 - 1e20) == 0.0不是真的(结果值为 0.1)。 浮点加法既不是结合也不是交换 .在这种特定情况下,准确度可以达到阈值,此时结果中不再有重要数字。有关浮点精度的更多信息,请阅读 this post .
关键是你应该减去浮点数时要非常小心 .一个好的解决方案是放置括号,以便添加/减去的值具有相同的数量级。可变大小和更高的精度也有帮助。但是,最好的解决方案是analyses the numerical stability你的算法。比如学习condition number算法中使用的数值运算是一个良好的开端。
在这里,一个比较好的解决方案就是使用第二个代码而不是第一个。

关于python - Numpy 返回分析函数的意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68536339/

相关文章:

iphone - 如何在 Swift 4 中打印 float 后的 5 位数字,有没有最短的方法?

python - Python (Django) 的专业体验可与 Ruby on Rails 媲美吗?

python - 我将如何在 python 中创建一个(异步/线程/任务)后台队列?

python - Google App Engine 上的 numpy 有哪些替代方案?

python - NP阵列的形状为(2186, 128)。我有兴趣将获得的数组应用到SVM

Javascript浮点加法解决方法

python - 比较两个数据帧并保留重叠的行

Python 快速单色位图

python - python中 "for loop"的步骤

c++ - 是否可以构造一个通用程序来判断二元运算是否会导致溢出?