gpt4 book ai didi

ruby - 1.8 与 1.9 中的 BigDecimal

转载 作者:数据小太阳 更新时间:2023-10-29 07:09:26 26 4
gpt4 key购买 nike

当升级到 ruby​​ 1.9 时,我在比较 BigDecimal 的预期值与实际值时测试失败,这是除 float 的结果。

expected: '0.495E0',9(18)got:      '0.4950000000 0000005E0',18(27)

googling for things like "bigdecimal ruby precision" and "bigdecimal changes ruby 1.9" isn't getting me anywhere.

How did BigDecimal's behavior change in ruby 1.9?

update 1

> RUBY_VERSION
=> "1.8.7"
> 1.23.to_d
=> #<BigDecimal:1034630a8,'0.123E1',18(18)>

> RUBY_VERSION
=> "1.9.3"
> 1.23.to_d
=> #<BigDecimal:1029f3988,'0.123E1',18(45)>

18(18) 和 18(45) 是什么意思?我想象的精度,但符号/单位是什么?

更新 2

代码正在运行:

((10 - 0.1) * (5.0/100)).to_d

我的测试期望这等于 (==):

0.495.to_f

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

最佳答案

相等比较很少在 FP 值上成功


简短的回答是 Float#to_d在 1.9 中更准确,并且正确地未通过在 1.8.7 中不应成功的相等性测试。

长答案涉及浮点编程的基本规则:永远不要进行相等比较。相反,像if (abs(x-y) < epsilon) 这样的模糊比较。推荐,或者编写代码来完全避免相等比较的需要。

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

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

那是因为分数是二进制的,即 1/2 + 1/4 + 1/8 ... 但我们的常量是十进制的。因此,例如,考虑 $1.00, $1.01, $1.02 .. $1.99. 范围内的货币金额此范围内有 100 个值,但其中只有 4 个具有精确的 FP 表示:1.00, 1.25, 1.50, and 1.75.

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

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

请记住:根据经验,您必须在此类舍入中显式编程以进行浮点比较。


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

关于ruby - 1.8 与 1.9 中的 BigDecimal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9642552/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com