Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some `BigDecimal` values don't match with `Float`

Some BigDecimal values can be compared with a Float by eq in Rspec3, but some values can't be.

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

To avoid error, I'm using expressions like eq("83.79".to_d).

Why does the first test fail while the second succeeds?

like image 822
ironsand Avatar asked Mar 14 '23 00:03

ironsand


1 Answers

You should never try any sort of strict equality testing with floating point values. You always have to deal with inaccurate internal representation issues with Float, so == and != aren't terribly useful.

Consider this:

'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)> 

Note that the difference for 83.79 is not quite zero.

If you need to compare floating point values, you always need to use a delta in your comparison; you always want to say:

Are these values within some small amount from each other?

rather than

Are these values equal?

In Rspec terms:

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)

and choose the delta (1e-12 in this case) to match your requirements.

like image 80
mu is too short Avatar answered Mar 23 '23 05:03

mu is too short