3 回答

TA贡献1887条经验 获得超5个赞
您的测试用例中的商不相等的原因是,在这种math.floor(a/b)
情况下,结果是使用浮点算法(IEEE-754 64 位)计算的,这意味着存在最大精度。您拥有的商大于 2 53限制,高于该限制的浮点不再精确到单位。
然而,对于整数除法,Python 使用其无限的整数范围,因此结果是正确的。
请注意,对于 int 和 long 参数,真正的除法可能会丢失信息;这是真正除法的本质(只要语言中没有有理数)。有意识地使用 long 的算法应该考虑使用
//
,因为真正的 long 划分保留不超过 53 位的精度(在大多数平台上)。

TA贡献1847条经验 获得超11个赞
您可能正在处理太大而无法准确表达为浮点数的整数值。您的数字明显大于 2^53,这是相邻浮点双精度之间的差距开始大于 1 的地方。因此,在进行浮点除法时会损失一些精度。
另一方面,整数除法是精确计算的。

TA贡献2065条经验 获得超14个赞
你的问题是,尽管“/”有时被称为“真正的除法运算符”并且它的方法名称是__truediv__,但它对整数的行为不是“真正的数学除法”。相反,它产生的浮点结果不可避免地具有有限的精度。
对于足够大的数字,即使是数字的整数部分也会出现浮点舍入误差。当 648705536316023400 转换为 Python 浮点数(IEEE double)时,它会四舍五入为 648705536316023424 1。
我似乎无法找到有关当前 Python 中内置类型运算符的确切行为的权威文档。引入该功能的原始 PEP 指出“/”相当于将整数转换为浮点数,然后执行浮点数除法。然而,在 Python 3.5 中的快速测试表明情况并非如此。如果是,那么下面的代码将不会产生任何输出。
for i in range(648705536316023400,648705536316123400):
if math.floor(i/7) != math.floor(float(i)/7):
print(i)
但至少对我来说它确实产生了输出。
相反,在我看来,Python 正在对所显示的数字进行除法,并将结果四舍五入以适合浮点数。以该程序输出为例。
648705536316123383 // 7 == 92672219473731911
math.floor(648705536316123383 / 7) == 92672219473731904
math.floor(float(648705536316123383) / 7) == 92672219473731920
int(float(92672219473731911)) == 92672219473731904
Python 标准库确实提供了 Fraction 类型,并且除以 int 的 Fraction 的除法运算符确实执行“真正的数学除法”。
math.floor(Fraction(648705536316023400) / 7) == 92672219473717628
math.floor(Fraction(648705536316123383) / 7) == 92672219473731911
但是,您应该意识到使用 Fraction 类型可能带来的严重性能和内存影响。请记住,分数可以增加存储需求而不增加数量。
为了进一步测试我的“一个舍入对两个”的理论,我使用以下代码进行了测试。
#!/usr/bin/python3
from fractions import Fraction
edt = 0
eft = 0
base = 1000000000010000000000
top = base + 1000000
for i in range(base,top):
ex = (Fraction(i)/7)
di = (i/7)
fl = (float(i)/7)
ed = abs(ex-Fraction(di))
ef = abs(ex-Fraction(fl))
edt += ed
eft += ef
print(edt/10000000000)
print(eft/10000000000)
并且直接执行除法的平均误差幅度比首先转换为浮点数小得多,支持一个舍入对两个舍入的理论。
1请注意,直接打印浮点数不会显示其确切值,而是显示将舍入到该值的最短十进制数(允许从浮点数到字符串再到浮点数的无损往返转换)。
添加回答
举报