整数除法总是等于常规除法的下限吗?

对于大商,整数除法 ( //) 似乎不一定等于常规除法 ( math.floor(a/b))的下限。


根据 Python 文档(https://docs.python.org/3/reference/expressions.html - 6.7),


整数的地板除法产生一个整数;结果是将“floor”函数应用于结果的数学除法。


然而,


math.floor(648705536316023400 / 7) = 92672219473717632


648705536316023400 // 7 = 92672219473717628

'{0:.10f}'.format(648705536316023400 / 7) 产生 '92672219473717632.0000000000',但小数部分的最后两位数字应该是 28 而不是 32。


料青山看我应如是
浏览 202回答 3
3回答

慕工程0101907

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

回首忆惘然

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

翻翻过去那场雪

你的问题是,尽管“/”有时被称为“真正的除法运算符”并且它的方法名称是__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                   == 92672219473731911math.floor(648705536316123383 / 7)        == 92672219473731904math.floor(float(648705536316123383) / 7) == 92672219473731920int(float(92672219473731911))             == 92672219473731904Python 标准库确实提供了 Fraction 类型,并且除以 int 的 Fraction 的除法运算符确实执行“真正的数学除法”。math.floor(Fraction(648705536316023400) / 7) == 92672219473717628math.floor(Fraction(648705536316123383) / 7) == 92672219473731911但是,您应该意识到使用 Fraction 类型可能带来的严重性能和内存影响。请记住,分数可以增加存储需求而不增加数量。为了进一步测试我的“一个舍入对两个”的理论,我使用以下代码进行了测试。#!/usr/bin/python3from fractions import Fractionedt = 0eft = 0base = 1000000000010000000000top = base + 1000000for 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 += efprint(edt/10000000000)print(eft/10000000000)并且直接执行除法的平均误差幅度比首先转换为浮点数小得多,支持一个舍入对两个舍入的理论。1请注意,直接打印浮点数不会显示其确切值,而是显示将舍入到该值的最短十进制数(允许从浮点数到字符串再到浮点数的无损往返转换)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python