为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

料青山看我应如是 2021-09-23 09:43:57
对于大商,整数除法 ( //) 似乎不一定等于常规除法 ( math.floor(a/b))的下限。根据 Python 文档(https://docs.python.org/3/reference/expressions.html - 6.7),整数的地板除法产生一个整数;结果是将“floor”函数应用于结果的数学除法。然而,math.floor(648705536316023400 / 7) = 92672219473717632648705536316023400 // 7 = 92672219473717628'{0:.10f}'.format(648705536316023400 / 7) 产生 '92672219473717632.0000000000',但小数部分的最后两位数字应该是 28 而不是 32。
查看完整描述

3 回答

?
慕工程0101907

TA贡献1887条经验 获得超5个赞

您的测试用例中的商不相等的原因是,在这种math.floor(a/b)情况下,结果是使用浮点算法(IEEE-754 64 位)计算的,这意味着存在最大精度。您拥有的商大于 2 53限制,高于该限制的浮点不再精确到单位。

然而,对于整数除法,Python 使用其无限的整数范围,因此结果是正确的。

另见PEP 238 中的“真除法语义”

请注意,对于 int 和 long 参数,真正的除法可能会丢失信息;这是真正除法的本质(只要语言中没有有理数)。有意识地使用 long 的算法应该考虑使用//,因为真正的 long 划分保留不超过 53 位的精度(在大多数平台上)。


查看完整回答
反对 回复 2021-09-23
?
回首忆惘然

TA贡献1847条经验 获得超11个赞

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

另一方面,整数除法是精确计算的。



查看完整回答
反对 回复 2021-09-23
?
翻翻过去那场雪

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请注意,直接打印浮点数不会显示其确切值,而是显示将舍入到该值的最短十进制数(允许从浮点数到字符串再到浮点数的无损往返转换)。


查看完整回答
反对 回复 2021-09-23
  • 3 回答
  • 0 关注
  • 201 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号