为什么7.30 - 7.20
ruby 中的这段代码返回0.0999999999999996
,而不是0.10
?
但如果我会写7.30 - 7.16
,例如,一切都会好起来的,我会得到0.14
的。
什么问题,我该如何解决?
为什么7.30 - 7.20
ruby 中的这段代码返回0.0999999999999996
,而不是0.10
?
但如果我会写7.30 - 7.16
,例如,一切都会好起来的,我会得到0.14
的。
什么问题,我该如何解决?
问题是我们可以很容易地用十进制写的一些数字在当前硬件实现的特定浮点格式中没有精确的表示。一种随意的说法是,所有的整数都有,但不是所有的分数,因为我们通常用2**e
指数存储分数。因此,您有 3 个选择:
适当地四舍五入。未四舍五入的结果总是非常接近,因此四舍五入的结果总是“完美”的。这就是 Javascript 所做的事情,很多人甚至没有意识到 JS 以浮点数完成所有事情。
使用定点算法。Ruby 实际上使这变得非常容易。它是唯一一种随着数字变大而从 Fixnum 无缝转移到 Bignum 类的语言之一。
使用旨在解决此问题的类,例如BigDecimal
为了更详细地查看问题,我们可以尝试用二进制表示您的“7.3”。7 部分很简单,111,但我们如何做 0.3?111.1是7.5,太大了,111.01是7.25,越来越近了。事实证明,111.010011 是“下一个最接近的较小数字”,7.296875,当我们尝试填充缺失的 .003125 时,最终我们发现它只是 111.010011001100110011……永远,在我们选择的有限位字符串编码中无法表示.
问题是浮点数不准确。您可以使用 Rational、BigDecimal 或仅使用普通整数来解决它(例如,如果您想存储货币,则可以将美分数存储为 int 而不是将美元数存储为浮点数)。
BigDecimal 可以准确地存储以 10 为基数的有限位数的任何数字,并对没有的数字进行四舍五入(因此三分之三不是整数)。
有理数可以准确地存储任何有理数,根本不能存储无理数。
有趣的是,一个基数中小数位数很少的数字通常在另一个基数中可能有大量小数。例如,以 10 为底数表示 1/3 (=0.3333...) 需要无限位小数,但以 3 为底数只需要一位小数。类似地,表示数 1/10 ( =0.1) 以 2 为底。
这是浮点数在内存中表示方式的常见错误。
如果您需要准确的结果,请使用 BigDecimal。
result=BigDecimal.new("7.3")-BigDecimal("7.2")
puts "%2.2f" % result
由于您正在进行浮点数学运算,因此返回的数字就是您的计算机用于精度的数字。
如果您想要一个更接近的答案,达到设定的精度,只需将浮点数乘以该值(例如乘以 100),将其转换为 int,进行数学运算,然后除以。
还有其他解决方案,但我发现这是最简单的,因为舍入对我来说总是有点不确定。
这个之前已经问过这里,你可能想找一些之前给出的答案,比如这个: Dealing with accuracy problems in floating-point numbers