Ruby中的算术运算

6

为什么在ruby中,这段代码7.30 - 7.20返回的是0.0999999999999996而不是0.10

但如果我写7.30 - 7.16,一切都没问题,我会得到0.14

问题出在哪里,我该如何解决它?

6个回答

20

没错。无论是Java、Ruby还是C#,它们都“遭受”了这个问题。这是由于二进制逻辑的选择和我们表示浮点数的方式所导致的。 - duffymo

6
问题在于,我们可以轻松地用十进制写出一些数字,但是这些数字在当前硬件实现的特定浮点格式中并没有精确的表示。一个简单的说法是,所有整数都有精确表示,但不是所有分数,因为我们通常使用一个2 ** e指数存储分数。所以,你有3个选择:
  1. 适当四舍五入。未被四舍五入的结果总是非常接近,因此四舍五入后的结果总是“完美的”。这就是Javascript所做的,很多人甚至没有意识到JS在使用浮点数。
  2. 使用定点算术。Ruby实际上使这变得非常容易;它是唯一一种能够无缝地从Fixnum转换为Class Bignum的语言。
  3. 使用专门解决此问题的类,如BigDecimal

为了更详细地了解问题,我们可以尝试用二进制表示您的“7.3”。 7部分很容易,是111,但是我们如何表示0.3? 111.1是7.5,太大了,111.01是7.25,越来越接近。结果发现,111.010011是“下一个最接近的较小数”,即7.296875,当我们试图填补缺失的0.003125时,最终我们发现它只是111.010011001100110011...永远不会在有限的比特串中被表示。


3
问题在于浮点数不准确。您可以通过使用Rational、BigDecimal或纯整数来解决它(例如,如果您想存储货币,可以将分的数量作为int存储,而不是将美元的数量作为float存储)。
BigDecimal可以精确地存储任何在十进制中具有有限位数的数字,并四舍五入不能(例如三个三分之一不是一个整体)。
Rational可以精确地存储任何有理数,但根本无法存储无理数。

1

这是由于浮点数在内存中的表示方式而导致的常见错误。

如果您需要精确的结果,请使用BigDecimal。

result=BigDecimal.new("7.3")-BigDecimal("7.2")
puts "%2.2f" % result

2
请注意,BigDecimal仅在十进制下数字具有有限位数时才产生精确结果。 - sepp2k

1

有趣的是,一个在某个进制下小数位数很少的数字,在另一个进制下可能会有非常多的小数位数。例如,在十进制中,要用无限多的小数位数来表示1/3(=0.3333...),但在三进制中只需要一位小数。同样地,在二进制中,要用很多小数位数来表示数字1/10(=0.1)。


0

由于您正在进行浮点数运算,因此返回的数字是计算机用于精度的数字。

如果您想要更接近的答案,以一定的精度,请将浮点数乘以该精度(例如乘以100),将其转换为整数,进行计算,然后除以该精度。

还有其他解决方案,但我发现这是最简单的,因为四舍五入似乎总是有些棘手。

这个问题之前已经被问过了,您可能想要查找之前给出的一些答案,比如这个: 处理浮点数精度问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接