一些BigDecimal
值可以通过eq
在Rspec3中与Float
进行比较,但有些值不能。
describe "compare BigDecimal with Float" do
it { expect("83.79".to_d).to eq(83.79) } # => fail
it { expect("83.75".to_d).to eq(83.75) } # => succeed
end
为了避免错误,我使用了像eq("83.79".to_d)
这样的表达式。
为什么第一次测试失败而第二次测试成功?
发布于 2016-03-08 23:12:44
您不应该尝试使用浮点值进行任何严格的等式测试。您总是需要处理Float
不准确的内部表示问题,因此==
和!=
并不十分有用。
考虑到这一点:
'83.79'.to_d - 83.79
# => #<BigDecimal:7ff33fcea560,'-0.1E-13',9(36)>
'83.75'.to_d - 83.75
# => #<BigDecimal:7ff33fcee688,'0.0',9(27)>
请注意,83.79
的差异并非完全为零。
如果您需要比较浮点值,则始终需要在比较中使用增量;您总是想说:
这些值是否在彼此之间的一些小数目内?
而不是
这些价值相等吗?
在Rspec方面:
expect('83.75'.to_d).to be_within(1e-12).of(83.75)
expect('83.79'.to_d).to be_within(1e-12).of(83.79)
并选择增量(在本例中为1e-12
)以匹配您的需求。
发布于 2016-03-09 07:19:20
"83.79".to_d精确地在内部表示中表示分数8379/100,因为它使用基数10 (或它的幂),而"83.79".to_f并不是因为内部表示使用基2,因此它们是不相等的。
对于83.75来说,这是不一样的,因为is被精确地表示在基数2和10中(这是83 + 1/2 + 1/4)。
如果将大小数和浮点数混合在同一个表达式中,则浮点数将转换为最近的大小数点.因此,实际上您正在执行以下操作:83.79.to_d
或put不同的"83.79".to_f.to_d
因为"83.79".to_f
不是精确的,而且由于大小数点比浮点数更精确,所以它没有理由与"83.79".to_d
匹配。
但是,如果以另一种方式强制转换,我希望平等适用于:
expect("83.79".to_d.to_f).to eq(83.79)
这是因为我们可以合理地期望(最少的惊讶)转换to_f将回答最近的浮点到确切的分数,无论是从一个精确的大小数或字符串表示。
https://stackoverflow.com/questions/35879600
复制相似问题