5

有没有人在 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。

谢谢!

4

3 回答 3

8

每当您在计算中获得时髦的数字时,请使用 bigdecimal

require 'bigdecimal'
a = BigDecimal(8.1999999.to_s)
(a.round(2) * 1000000).to_i
于 2012-07-12T05:06:10.193 回答
3

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

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

于 2012-07-12T04:56:00.677 回答
0

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

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

问题是我们用十进制写数字,但用二进制存储它们。这适用于整数;但它对分数效果不佳。

事实上,我们写的大多数小数部分都不能精确表示。

每个机器分数都是 x/2 n形式的有理数。现在,常数是十进制的,每个十进制常数都是 x/(2 n * 5 m )形式的有理数。5 m的数字是奇数,因此它们中的任何一个都没有 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。参数 to#round是您想要的小数位数,而不是有效位数。在这种情况下,结果是一样的,没关系。

于 2012-07-12T15:20:59.767 回答