Python 使用Numpy缓解浮点近似问题

Python 使用Numpy缓解浮点近似问题,python,numpy,floating-point,floating-accuracy,Python,Numpy,Floating Point,Floating Accuracy,我的代码非常简单,只有一行代码引起了问题: np.tan(np.radians(旋转)) 我的rotation=45的预期输出不是1,而是0.9999999999。我知道0和一吨9等于1。然而,在我的用例中,它似乎是在迭代过程中肯定会建立起来的类型 导致浮点错误的原因是什么:np.tan或np.radians,以及如何在不考虑浮点不准确的情况下正确得出问题函数 编辑: 我需要澄清的是,我熟悉浮点不准确。我担心的是,当这个数字被乘以、相加和比较时,1e-6错误突然变成了一个明显的问题。我通常能够安

我的代码非常简单,只有一行代码引起了问题:

np.tan(np.radians(旋转))

我的
rotation=45
的预期输出不是1,而是0.9999999999。我知道0和一吨9等于1。然而,在我的用例中,它似乎是在迭代过程中肯定会建立起来的类型

导致浮点错误的原因是什么:
np.tan
np.radians
,以及如何在不考虑浮点不准确的情况下正确得出问题函数

编辑: 我需要澄清的是,我熟悉浮点不准确。我担心的是,当这个数字被乘以、相加和比较时,1e-6错误突然变成了一个明显的问题。我通常能够安全地忽略浮点问题,但现在我更关心错误的累积。我想减少这种错误的可能性

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

看看这里:

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

请注意,即使
np.longdouble
提供了比python更高的精度 浮动,很容易失去额外的精度,因为python经常 强制值通过浮点。例如,
%
格式 运算符要求将其参数转换为标准python 类型,因此不可能保持扩展精度 即使需要许多小数位。进行测试可能很有用 您的代码的值为
1+np.finfo(np.longdouble).eps

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

在spyder(windows)中:

在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
导致浮点错误的原因是什么:
np.tan
np.radians
,以及如何在不考虑浮点不准确的情况下正确得出问题函数

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

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

这个问题与十进制表示无关,这将在您上面提到的确切情况之外产生更糟糕的结果,例如

>np.tan(np.radians(60))
1.7320508075688767
>>>圆形(np.tan(np.radians(60)),8)
1.73205081
>>>np.sqrt(3)#sqrt被正确舍入,因此这是最接近真实结果的浮点
1.7320508075688772

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

没有错误,我也不知道您必须缓解哪个问题,因为您永远不应该测试浮点值是否相等。另请参见这个关于主题的R问题(第一个答案有一个值得学习和理解的语言不可知部分):Pi是先验的。Pi/4是超越的。两者都不能用有限位数表示,因此pi/4不是ieee754浮点或双精度中可表示的数字。@EOF我知道pi是超越的。你说的是真的,但我想确定经过多次手术后,最终的数字是准确的。你真的得到了
0.999999
?如果是这样的话,这是一个相当大的错误(将近10亿ULP):。我得到了
0.999999999999999999
(实际存储值
0.999999999999888977697537484595763683319091796875
),这只是一个ulp错误,与我预期的错误级别有关。@MarkDickinson有点像noob问题,但我如何获得完整的浮点值呢?我目前得到的正是0.9999999999999。仍然得到了大量的9。不过,感谢您的回答,它确实提供了信息。请注意,
np.float
dtype是64位(默认)。
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