python - 为什么 fmod(1.0,0.1) == .1?

标签 python math floating-point

这个现象我是先在 Python 中遇到的,后来发现这是常见的答案,例如 MS Excel 就给出了这个。 Wolfram Alpha 给出了一个有趣的 split 式答案,它指出零的有理逼近是 1/5。 ( 1.0 mod 0.1 )

另一方面,如果我手动实现定义,它会给出“正确”答案 (0)。

def myFmod(a,n):
    return a - floor(a/n) * n

这是怎么回事。我错过了什么吗?

最佳答案

因为 0.1 不是 0.1;该值不能用 double 表示,因此它会四舍五入到最接近的 double 字,这恰好是:

0.1000000000000000055511151231257827021181583404541015625

当您调用 fmod 时,您会得到除以上面列出的值的余数,这恰好是:

0.0999999999999999500399638918679556809365749359130859375

打印时四舍五入为 0.1(或者 0.0999999999999995)。

换句话说,fmod 工作得很好,但您没有向它提供您认为的输入。


编辑:您自己的实现会给您正确的答案,因为它不够准确,信不信由您。首先,请注意 fmod 计算余数时没有任何舍入误差;不准确的唯一来源是使用值 0.1 引入的表示错误。现在,让我们来看看您的实现,看看它产生的舍入误差如何完全抵消表示误差。

评估 a - floor(a/n) * n 一次一个步骤,跟踪每个阶段计算的确切值:

首先,我们评估 1.0/n,其中 n 是最接近 0.1 的 double 近似值,如上所示。这样划分的结果大概是:

9.999999999999999444888487687421760603063276150363492645647081359...

请注意,此值不是可表示的 double 字——因此它被四舍五入。要了解这种舍入是如何发生的,让我们看一下二进制而不是十进制的数字:

1001.1111111111111111111111111111111111111111111111111 10110000000...

空格表示四舍五入到 double 的位置。由于圆点后的部分大于精确的中点,因此该值四舍五入到恰好 10

floor(10.0) 可以预见,10.0。所以剩下的就是计算 1.0 - 10.0*0.1

在二进制中,10.0 * 0.1 的精确值为:

1.0000000000000000000000000000000000000000000000000000 0100

同样,该值不能表示为 double 值,因此会在空格指示的位置四舍五入。这次四舍五入到恰好 1.0,所以最终的计算结果是 1.0 - 1.0,当然是 0.0

您的实现包含两个舍入误差,恰好抵消了本例中值 0.1 的表示误差。相比之下,fmod始终精确的(至少在具有良好数字库的平台上),并暴露出 0.1 的表示错误。

关于python - 为什么 fmod(1.0,0.1) == .1?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4218961/

相关文章:

python - GitHub 操作找不到 Django 的环境变量

image - 需要一点数学帮助才能调整图像大小

c - 有时单利计划中会出现错误的值

javascript - 使变量值为正

language-agnostic - 如何找到定义贝塞尔曲线的数学函数

c - 防止对 c 中的一个操作进行优化

c++ - 用浮点任意精度 C++ 库改造现有代码,有成功的机会吗?

python - 如何使用变量动态访问/覆盖类中的字段?

python - Django:在 models.py 中将 TimeField 更改为 DateTimeField

python - Django:启动时重定向到 Web 应用程序