使用 Numpy 缓解浮点逼近问题

Mitigating Floating Point Approximation Issues with Numpy

我的代码很简单,只有 1 行引起了问题:

np.tan(np.radians(rotation))

rotation = 45 的预期输出不是 1,而是 0.9999999999999999。我知道 0 和一吨 9 是 1。然而,在我的用例中,这似乎是一种肯定会在迭代中建立起来的东西。

是什么导致了浮点错误:np.tannp.radians,以及如何在不考虑浮点不准确的情况下使问题函数正确输出?

编辑:

我应该澄清一下,我熟悉浮点数的错误。我担心的是,随着该数字的乘法、相加和比较,1e-6 错误突然变成了一个有形的问题。我通常能够安全地忽略浮点问题,但现在我更关心错误的累积。我想减少这种错误的可能性。

编辑 2:

我目前的解决方案是四舍五入到小数点后 8 位,因为这很可能就足够了。这是一种临时解决方案,因为我更喜欢一种绕过 IEEE 十进制表示的方法。

看这里:https://docs.scipy.org/doc/numpy/user/basics.types.html .

numpy 中的标准数据类型不超过 64 位精度。来自文档:

Be warned that even if np.longdouble offers more precision than python float, it is easy to lose that extra precision, since python often forces values to pass through float. For example, the % formatting operator requires its arguments to be converted to standard python types, and it is therefore impossible to preserve extended precision even if many decimal places are requested. It can be useful to test your code with the value 1 + np.finfo(np.longdouble).eps.

您可以使用 np.longdouble 提高精度,但这取决于平台

在 spyder (windows) 中:

np.finfo(np.longdouble).eps  #same precision as float
>> 2.220446049250313e-16
np.finfo(np.longdouble).precision
>> 15

在 google colab 中:

np.finfo(np.longdouble).eps  #larger precision
>> 1.084202172485504434e-19
np.finfo(np.longdouble).precision
>> 18

print(np.tan(np.radians(45, dtype=np.float), dtype=np.float) - 1)
print(np.tan(np.radians(45, dtype=np.longfloat), dtype=np.longfloat) - 1)
>> -1.1102230246251565e-16
0.0

What is causing the floating point error: np.tan or np.radians, and how do I get the problem function to come out correctly regardless of floating point inaccuracies?

这两个函数都会产生舍入误差,因为在这两种情况下都不能用浮点数表示准确的结果。

My current solution is to just round to 8 decimal places because that's most likely enough. It's sort of a temporary solution because I'd much prefer a way to get around the IEEE decimal representations.

这个问题与十进制表示无关,除了你上面提到的确切情况,这会产生更糟糕的结果,例如

>>> np.tan(np.radians(60))
1.7320508075688767
>>> round(np.tan(np.radians(60)), 8)
1.73205081
>>> np.sqrt(3) # sqrt is correctly rounded, so this is the closest float to the true result
1.7320508075688772

如果您绝对需要比从上面的代码中获得的 15 位十进制数字更高的精度,那么您可以使用任意精度库,例如 gmpy2