This is of course broken:
(0.1 + 0.1 + 0.1) => 0.30000000000000004
(0.1 + 0.1 + 0.1) == 0.3 # false
I don't need a perfect sum, just good enough to say two Floats are the same value. The best I can figure out is to multiply both sides of the equation and round. Is this the best way?
((0.1 + 0.1 + 0.1) * 1000).round == (0.3 * 1000).round
UPDATE: I'm stuck on Ruby v1.8.7.
There is a difference between summing accurately and comparing effectively. You say you want the former, but it looks like you want the later. The underlying Ruby float arithmetic is IEEE and has sensible semantics for minimizing accumulated error, but there always will be when using a representation that can't exactly represent all values. To accurately model error, FP addition shouldn't produce an exact value, it should produce an interval and further additions will operate on intervals.
In practice, many applications don't need to have detailed accounting for error, they just need to do their calculation and be aware that comparisons aren't exact and output decimal representations should be rounded.
Here's a simple extension to Float that will help you out with comparison. It or something like it should be in the stdlib, but ain't.
class Float
def near_enough?(other, epsilon = 1e-6)
(self - other.to_f).abs < epsilon.to_f
end
end
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3)
=> true
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3, 1e-17)
=> false
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5, 1e-5)
=> true
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5)
=> false
Picking an appropriate epsilon
can be tricky in the general case. You should read What Every Computer Scientist Should Know About Floating-Point Arithmetic. I've found Bruce Dawson's floating point tricks blogs excellent, here's his chapter on Comparing Floating Point Numbers
If you really are concerned about accuracy, you could do your arithmetic using an exact representation. Ruby supplies a Rational class (even back in 1.8) which let's you do exact arithmetic on fractions.
pry(main)> r=Rational(1,10)
=> (1/10)
pry(main)> (r + r + r) == Rational(3,10)
=> true
pry(main)> (r + r + r) == 0.3
=> true
pry(main)> r.to_f
=> 0.1
pry(main)> (r + r + r).to_f
=> 0.3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With