Ruby 小数的舍入和格式

Ruby rounding and formatting of decimal numbers

我看过了:Why can't decimal numbers be represented exactly in binary? and Why Are Floating Point Numbers Inaccurate?

我的问题是,当我使用 ruby 对浮点数进行舍入和格式化时,结果仍然与手动计算的结果不同。下面是一个例子:

编辑 2

[28] pry(main)> #####################################
[29] pry(main)> # test one
[30] pry(main)> #####################################
[31] pry(main)> foo = (6.0135 * (650000 / 1000)) 
             => 3908.7749999999996
[32] pry(main)> foo = '%.2f' % foo.round(2)
             => "3908.77"
[33] pry(main)> # should be 3908.78

[36] pry(main)> #####################################
[37] pry(main)> # test two
[38] pry(main)> #####################################
[39] pry(main)> foo = 650000 / 1000
             => 650
[40] pry(main)> foo = foo * 6.0135
             => 3908.7749999999996
[41] pry(main)> foo = '%.2f' % foo.round(2) # should be 3908.78
             => "3908.77"

[44] pry(main)> #####################################
[45] pry(main)> # test three 
[46] pry(main)> #####################################
[47] pry(main)> foo = 650000 / 1000
             => 650
[48] pry(main)> foo = foo * 6.0135
             => 3908.7749999999996
[49] pry(main)> foo = foo.round(2) # should be 3908.78
=> 3908.77

[52] pry(main)> #####################################
[53] pry(main)> # test four - The result of test four is expected
[54] pry(main)> #####################################
[55] pry(main)> foo = 650000 / 1000
             => 650
[56] pry(main)> foo = foo * 6.0135
             => 3908.7749999999996
[57] pry(main)> foo = '%.2f' % foo
             => "3908.77"

[58] pry(main)> #####################################
[59] pry(main)> # test five
[60] pry(main)> #####################################
[61] pry(main)> foo = 650000 / 1000
             => 650
[62] pry(main)> foo = foo * 6.0135
             => 3908.7749999999996
[63] pry(main)> foo = foo.round(5) 
             => 3908.775

测试 1:这是我在我的库中使用的正常公式,它给我带来了问题。

测试 2:我的想法是,也许在一个作业中执行这两个操作会导致一些问题

测试 3:既然已知 '%.2f' % 会在截断内容时引起一些舍入问题,也许这就是问题所在。

测试 4:由于 '%.2f' % 不是问题,可能是 .round(2) 导致了问题。

编辑 2: 测试 5:如果我扩展那轮正在查看的数字,我会得到一个我可以使用的数字(即再次轮(2)那个数字)。但这似乎是一个不可靠的解决方案,适用于有限的情况而不是一般情况

我真的不在乎浮点数不准确。我的问题是我怎样才能正确地舍入这个数字,以便得到正确的答案(如果你手动执行操作,你会得到的答案)。

一般来说,是否有舍入以纠正剂量点错误的最佳做法?我知道是用两个整数来表示浮点数,但是好像比较麻烦

谢谢。

编辑 1

如果您使用 .round(5) 而不是 .round(2),那么在将其与应有的答案进行比较时,您会得到一个更合理的答案。增加回合内的人数有什么缺点吗?

'%.2f' % - 截断数字并且无法正确舍入

.round(2) - 看起来没有足够的小数位以正确舍入。因此,如果您使数字大于 2,则四舍五入的问题就消失了。

编辑 1

根据 IEEE 有 5 种方法对数字进行舍入:

  1. 最接近,与偶数相关
  2. 到最近,从零开始
  3. 向 0
  4. 向+∞
  5. 向-∞

在这种情况下,与其说是我如何四舍五入,不如说是关于需要考虑的小数点后的位数。通常,一个人需要担心精度。由于此错误是由计算机造成的,因此我假设增加所考虑的小数点后数值的数量会更好、更准确。

我在我的 Rails 控制台上测试了所有内容,看不到任何奇怪的行为:

>> foo = 650000 / 1000
=> 650
>> foo = foo * 6.0135
=> 3908.7749999999996
>> foo.round(2)
=> 3908.77
>> foo.round(3)
=> 3908.775
>> foo.round(5)
=> 3908.775
>> afoo = '%.2f' % foo
=> "3908.77"
>> afoo = '%.5f' % foo
=> "3908.77500"

3908.7749999999996 小于 3908.775,如果使用 .round(2),将向下舍入为 3908.77。 .round(5) 结果与 3908.775 中的预期一致,也可以使用 google 计算器重现。为什么你认为这应该是不正确的?我真的很想明白这一点。

round 正在按预期工作。您得到了错误的结果,因为您的输入已经存在缺陷。浮点数6.0135其实是:

6.01349999999999962341235004714690148830413818359375

将此数字乘以 650 会使错误变得更糟。您得到的结果更接近 3908.77 而不是 3908.78:

foo = 6.0135 * 650
#=> 3908.7749999999996

(foo - 3908.77).abs
#=> 0.004999999999654392

(foo - 3908.78).abs
#=> 0.005000000000563887

要获得正确的结果,您可以使用如下方式:

foo = (6.0135 * 10000).round  * 0.065
#=> 3908.775

foo.round(2)
#=> 3908.78

或者您可以使用 BigDecimal 首先避免浮点错误:

require 'bigdecimal'
foo = BigDecimal('6.0135') * 650
foo.to_s('F')
#=> "3908.775"

foo.round(2).to_s('F')
#=> "3908.78"