浮点乘法的Ruby奇怪问题

有没有人在ruby中解决这个问题:

让我们说:a = 8.1999999

我们想把它舍入2位小数,即8.20,然后乘以1,000,000,变成8,200,000

我们这样做;

(a.round(2) * 1000000).to_i 

但我们得到的是8199999,为什么?

事情是,如果我们乘以1000,100000或10000000而不是1000000,我们得到了正确的结果。任何人都知道为什么?

我们使用ruby 1.9.2并尝试使用1.9.3。

谢谢!

每当你在计算中得到时髦的数字时使用bigdecimal

 require 'bigdecimal' a = BigDecimal(8.1999999.to_s) (a.round(2) * 1000000).to_i 

它变得像是因为a.round(2)返回一个浮点数,因此计算并不完美。

要获得正确的结果,请尝试以下操作:(10 * a).round.to_i * 100000

从某种意义上说,你的初始舍入工作正常。 问题是8.2没有精确的内部表示。 如果你只是输入8.2到irb或显示#round(2)方法调用的结果, 看起来你有8.2但你没有。 实际存储的数字略小于8.2。

您最终会被输出舍入逻辑的默认值所击败。 一旦内部略小于8.2位被加倍,错误就会转移到数字的整数部分,除非你要求,否则这部分不会被舍入。 你可以这样做: (a * 1000000).round

问题是我们用十进制编写数字但是将它们存储在二进制中。 这适用于整数; 但是分数很差。

实际上,我们编写的大多数小数部分都无法准确表示。

每个机器分数是x / 2 nforms的有理数。 现在,常量是十进制的,每个十进制常数是x /(2 n * 5 m )forms的有理数。 5 米的数字是奇数,因此其中任何一个都没有2 n因子。 只有当m == 0时,才能在分数的二进制和十进制扩展中得到有限的表示。 因此,1.25是准确的,因为它是5 /(2 2 * 5 0 ),但0.1不是因为它是1 /(2 0 * 5 1 )。 实际上,在1.01 .. 1.99系列中,只有3个数字可以准确表示:1.25,1.50和1.75。

因为8.2没有精确的表示,所以它永远以二进制重复,从未完全加起来精确到8.2。 它继续无限为1100110011 …


1.但请注意,您可能需要a.round(1)而不是2. #round的参数是您想要的小数位数,而不是有效位数。 在这种情况下,结果是相同的,并不重要。