Ruby 1.8与1.9中的BigDecimal

Ruby 1.8与1.9中的BigDecimal,ruby,bigdecimal,Ruby,Bigdecimal,当升级到ruby 1.9时,我在比较BigDecimal的预期值和实际值时遇到了一个失败的测试,该值是除以浮点的结果 expected: '0.495E0',9(18) got: '0.4950000000 0000005E0',18(27) 18(18)和18(45)是什么意思?精度我想是吧,但符号/单位是什么 更新2 代码正在运行: ((10 - 0.1) * (5.0/100)).to_d 我的测试期望它等于(=): 这在1.8下通过,在1.9.2和1.9.3下失败相等性比较很

当升级到ruby 1.9时,我在比较
BigDecimal
的预期值和实际值时遇到了一个失败的测试,该值是除以浮点的结果

expected: '0.495E0',9(18) got: '0.4950000000 0000005E0',18(27) 18(18)和18(45)是什么意思?精度我想是吧,但符号/单位是什么

更新2

代码正在运行:

((10 - 0.1) * (5.0/100)).to_d
我的测试期望它等于(=):

这在1.8下通过,在1.9.2和1.9.3下失败

相等性比较很少在FP值上成功
简单的回答是,
Float#to_d
在1.9中更准确,并且正确地通过了1.8.7中不应该成功的相等性测试

长答案涉及浮点编程的一条基本规则:永远不要进行等式比较。相反,建议使用模糊比较,如
if(abs(x-y)
,或者编写代码以避免完全进行相等比较

虽然理论上有232个单精度数字和264个双精度数字可以精确比较,但有无限多的数字无法进行比较。(注意:对恰好是整数的FP值进行相等比较是安全的。因此,与许多建议相反,它们实际上对循环索引和下标是完全安全的。)

更糟糕的是,我们写分数的方式使得与任何特定常数的比较都不可能成功

那是因为分数是二进制的,也就是1/2+1/4+1/8。。。但我们的常数是十进制的。因此,例如,考虑范围内的货币量<代码> 1美元,1.01美元,1.02美元…1.99。
此范围内有100个值,但其中只有4个具有精确的FP表示:
1.00、1.25、1.50和1.75。

那么,回到你的问题上来。
0.495
的结果没有精确的表示,输入常数
0.1也没有精确的表示。
首先计算两个不同量级的FP数。较小的数字将被反规范化以完成减法,因此它将丢失两个或三个低阶位。因此,计算结果将导致一个略大于0.495的数字,因为整个0.1并没有从10中减去。您的常数实际上(内部)比0.495稍小。这就是为什么比较失败的原因

Ruby 1.8一定是意外或故意丢失了一些低阶位,并有效地引入了舍入步骤,最终帮助了您的测试

请记住:经验法则是,对于浮点比较,必须显式地在这种舍入中编程


注意。回答关于简单小数点常数没有精确表示的评论问题:它们没有精确的有限形式,因为它们以二进制形式重复。每个机器分数都是形式为x/2n的有理数。现在,常数是十进制的,每个十进制常数都是形式为x/(2n*5m)的有理数。这5百万个数字是奇数,因此它们中的任何一个都没有2n因子。只有当m==0时,分数的二进制和十进制展开式才有有限表示。1.25是精确的,因为它是5/(22*50),但0.1不是因为它是1/(20*51)根本无法将0.1表示为x/2n分量的有限和。

请参阅。它很好地解释了为什么像0.1和0.01这样的数字不能用浮点数精确表示

简单的解释是,当这些数字以二进制浮点格式表示时,它们是重复出现的,就像三分之一是0.3333。。。以十进制重复出现


正如您永远无法使用有限的十进制数字集精确表示三分之一,您也无法使用有限的二进制数字集精确表示这些数字。

除法的结果是什么?抱歉,一旦引入普通浮点数,所有赌注都将取消。如果您一直使用BigDecimal(
(10-BigDecimal.new('0.1'))*(BigDecimal.new('5.0')/100)
),那么您将得到预期的结果。您的测试有缺陷,只是偶然工作。请查看有效数字(
9(18)
vs
18(27)
),这可能就是差异的来源。如果你在9个有效数字处切掉“got”以匹配“expected”,那么你将得到“expected”结果。@muistooshort我知道所有这些(但很高兴看到它被拼写出来),我的问题主要是关于是否有人知道为什么行为会随着1.8和1.9而改变。史诗般的答案!在什么意义上,像1.01、0.495和0.1这样的数字没有精确的浮点表示法?我在回答的末尾加了一个注释。关于使用FP作为下标的注释是危险的,因为连续整数的范围,在FP中可以精确表示,通常比相应的整数类型短8到9位。关于R1.8上的BD和R1.9上的BD之间的增量,回答得很好。然而,有人应该指出,有时缩放整数数学比扩展精度浮点更好、更有效——特别是对于金融数据。
((10 - 0.1) * (5.0/100)).to_d
0.495.to_f