为什么fmod(1.0,0.1)== .1? [英] Why fmod(1.0,0.1) == .1?

查看:196
本文介绍了为什么fmod(1.0,0.1)== .1?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我首先在Python中经历了这种现象,但事实证明这是常见的答案,例如MS Excel给出了这个结论。 Wolfram Alpha给出了一个有趣的分裂的答案,它指出零的有理逼近是1/5。 ( 1.0 mod 0.1

另一方面,如果我手工实现定义,它给了我'正确的'答案(0)。

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

这里发生了什么事情。因为 0.1 不是0.1,所以我错过了什么? 该值不能以双精度表示,所以它会四舍五入到最接近的双精度数字,正是:

  0.1000000000000000055511151231257827021181583404541015625 

当您调用 fmod 剩下的除以上面列出的值,即:

  0.0999999999999999500399638918679556809365749359130859375 

包括 0.1 (或者 0.09999999999999995

换句话说, fmod 完美地工作,但是你没有给出它是您认为自己的输入。






编辑:正确的答案,因为它是不准确的,信不信由你。首先,注意 fmod 计算余数,没有舍入误差。唯一不准确的来源是通过使用值 0.1 引入的表示错误。现在,我们来看看你的实现,看看它发生的舍入错误是如何消除表示错误的。



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

首先我们评估 1.0 / n ,其中 n 是最接近 0.1 如上所示。这个部门的结果是:

  9.999999999999999444888487687421760603063276150363492645647081359 ... 

请注意,这个值不是一个可表示的双精度数 - 所以它被舍入。要看看这个舍入是怎么发生的,让我们来看看二进制数而不是十进制:

  1001.1111111111111111111111111111111111111111111111111 10110000000 ... 

空格表示舍入到双精度的位置。由于圆点之后的部分大于中间点,因此该值恰好为 10



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

c $ c> 10.0 * 0.1 是:

  1.0000000000000000000000000000000000000000000000000000 0100 

再一次,这个值不能表示为double,所以在空格指示的位置被舍入。这一次精确到 1.0 ,所以最终的计算是 1.0 - 1.0 ,这当然是 0.0



您的实现包含两个舍入错误,恰好抵消了值<在这种情况下c $ c> 0.1 。相反,总是确切的(至少在具有良好数字库的平台上),并暴露的表示错误c> 0.1


I experienced this phenomenon in Python first, but it turned out that it is the common answer, for example MS Excel gives this. Wolfram Alpha gives an interesting schizoid answer, where it states that the rational approximation of zero is 1/5. ( 1.0 mod 0.1 )

On the other hand, if I implement the definition by hand it gives me the 'right' answer (0).

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

What is going on here. Do I miss something?

解决方案

Because 0.1 isn't 0.1; that value isn't representable in double precision, so it gets rounded to the nearest double-precision number, which is exactly:

0.1000000000000000055511151231257827021181583404541015625

When you call fmod, you get the remainder of division by the value listed above, which is exactly:

0.0999999999999999500399638918679556809365749359130859375

which rounds to 0.1 (or maybe 0.09999999999999995) when you print it.

In other words, fmod works perfectly, but you're not giving it the input that you think you are.


Edit: Your own implementation gives you the correct answer because it is less accurate, believe it or not. First off, note that fmod computes the remainder without any rounding error; the only source of inaccuracy is the representation error introduced by using the value 0.1. Now, let's walk through your implementation, and see how the rounding error that it incurs exactly cancels out the representation error.

Evaluate a - floor(a/n) * n one step at a time, keeping track of the exact values computed at each stage:

First we evaluate 1.0/n, where n is the closest double-precision approximation to 0.1 as shown above. The result of this division is approximately:

9.999999999999999444888487687421760603063276150363492645647081359...

Note that this value is not a representable double precision number -- so it gets rounded. To see how this rounding happens, let's look at the number in binary instead of decimal:

1001.1111111111111111111111111111111111111111111111111 10110000000...

The space indicates where the rounding to double precision occurs. Since the part after the round point is larger than the exact half-way point, this value rounds up to exactly 10.

floor(10.0) is, predictably, 10.0. So all that's left is to compute 1.0 - 10.0*0.1.

In binary, the exact value of 10.0 * 0.1 is:

1.0000000000000000000000000000000000000000000000000000 0100

again, this value is not representable as a double, and so is rounded at the position indicated by a space. This time it rounds down to exactly 1.0, and so the final computation is 1.0 - 1.0, which is of course 0.0.

Your implementation contains two rounding errors, which happen to exactly cancel out the representation error of the value 0.1 in this case. fmod, by contrast, is always exact (at least on platforms with a good numerics library), and exposes the representation error of 0.1.

这篇关于为什么fmod(1.0,0.1)== .1?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆