首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >一些“`BigDecimal`”值与“`Float`”不匹配

一些“`BigDecimal`”值与“`Float`”不匹配
EN

Stack Overflow用户
提问于 2016-03-08 22:49:55
回答 2查看 2.1K关注 0票数 5

一些BigDecimal值可以通过eq在Rspec3中与Float进行比较,但有些值不能。

代码语言:javascript
代码运行次数:0
运行
复制
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)这样的表达式。

为什么第一次测试失败而第二次测试成功?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-08 23:12:44

您不应该尝试使用浮点值进行任何严格的等式测试。您总是需要处理Float不准确的内部表示问题,因此==!=并不十分有用。

考虑到这一点:

代码语言:javascript
代码运行次数:0
运行
复制
'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方面:

代码语言:javascript
代码运行次数:0
运行
复制
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)以匹配您的需求。

票数 5
EN

Stack Overflow用户

发布于 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匹配。

但是,如果以另一种方式强制转换,我希望平等适用于:

代码语言:javascript
代码运行次数:0
运行
复制
expect("83.79".to_d.to_f).to eq(83.79)

这是因为我们可以合理地期望(最少的惊讶)转换to_f将回答最近的浮点到确切的分数,无论是从一个精确的大小数或字符串表示。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35879600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档