numpy 为什么a//B和np.floor(a/b)产生不同的结果?

qybjjes1  于 2023-08-05  发布在  其他
关注(0)|答案(3)|浏览(109)

我偶然发现了python 3的“floor division”使用//的一个奇怪的边缘行为。经过一些计算,我得出了公式(a1 - a2) // b。正在使用

a1 = 226.72560000000001
a2 = 0.2856000000000165
b = 1.02
# all types are np.float64

字符串
我得到了与使用np.floor()不同的结果:

>>> (a1 - a2) // b
221.0
>>> np.floor((a1 - a2) / b)
222.0


这种差异显然源于浮点计算,但为什么它们的行为不同呢?使用更高精度的计算器,如ke!san,我可以验证//的行为在数学上是正确的,而对于我的计算,np.floor()将提供正确的结果。

pprl5pva

pprl5pva1#

实际上,//的结果在数学上是正确的。
但是如果你只执行(a1 - a2) / b,你可以看到结果已经四舍五入到222.0(由于浮点存储限制,它应该是221.9999999999999936275),所以现在使用floor将返回222.0
编辑:实际上对于//,首先a1-a2被舍入为226.44(而不是226.4399999999999935),然后226.44 // 1.02错误地返回221而不是222,因为@Talha Tayyab解释(x//y返回(x-x%y)//y)。
因此,有两个连续的舍入误差,它们相互补偿并落在正确的结果上。

yb3bgrhw

yb3bgrhw2#

如果x非常接近y的整数倍,则由于舍入,x//y可能比(x-x%y)//y大1。在这种情况下,Python返回后一个结果,以保持divmod(x,y)[0] * y + x % y非常接近x
链接到doc:
https://docs.python.org/3/reference/expressions.html#id10
的输出应该是:

3.3//1.1

3.0 right?

wrong it is 2.0

字符串
所以,当分子和分母的倍数非常接近时
x//y将返回(x-x%y)//y

a1 = 226.72560000000001
a2 = 0.2856000000000165
b = 1.02

x = a1-a2
y = 1.02

(x-x%y)//y

#output
221.0

6pp0gazn

6pp0gazn3#

请记住,浮点运算可能很棘手,了解它的陷阱总是一个好主意。这不是Python或NumPy中的错误,而是浮点数的本质以及对它们进行的算术运算。
您正在观察的行为是由于不同浮点排序之间的准确性对比。
“漂移点”一词暗指这些数字在里面的说话方式。细微的元素是非常专业化的,但关键是这些数字是用固定的位数来表达的,你拥有的位数越多,你得到的精确度就越高。
Python(或NumPy等库)中的各种浮点数,如float16,float32和float64,分别使用16,32和64位的浮点数。
float64(也称为“双重精度漂移”)具有比float32(“单精度漂移”)更高的精度和更大的行程,而float32又具有比float16(“半精度浮点数”)更高的精度和更大的范围。
因此,在使用不同的浮点排序执行相同的计算之后,由于这些精确性的对比,您将得到一些不同的结果。这是数值计算中常见的问题,需要注意.
必须为您的特定使用情况选择正确的浮动类型。一般来说,float64可能是一个很好的默认选择,因为它在精度和内存利用率之间提供了很好的调整。但是,如果您正在处理异常庞大的数据集和内存利用率可能会引起关注,或者您正在支持float32或float16计算的GPU上执行计算,那么在这一点上,使用较低精度的漂移排序可能是有意义的。
这里有一小段代码来说明原因
这里有一段代码来说明原因:

import numpy as np

a1 = np.float16(226.72560000000001)
a2 = np.float16(0.2856000000000165)
b = np.float16(1.02)

a3= float(226.72560000000001)
a4 = float(0.2856000000000165)
b1 = float(1.02)

print((a3 - a4) // b1)
print((a1 - a2) // b)

print(np.floor((a3 - a4) / b1))
print(np.floor((a1 - a2) / b))

字符串
产出:

221.0
222.0
222.0
222.0


您可以更改浮动的类型以查看它如何影响结果。

相关问题