From: Michael Ulm Date: 2007-09-12T19:13:50+09:00 Subject: Re: wierd floating point output William James wrote: > On Sep 3, 9:02 pm, Stefan Rusterholz wrote: >> William James wrote: >>> On Sep 3, 5:32 pm, Stefan Rusterholz wrote: >>>>>> using delta comparison anyway too. >>>> end >>>> (0.01 + 0.05).in_delta?(0.06) # => true >>>> 0.01 + 0.05 =~ 0.06 # => true # can't set the delta, is similarly evil >>>> as == >>> class Numeric >>> def in_delta?(other, delta=Float::EPSILON*16) # chose the delta >>> wisely >>> (self-other).abs < delta >>> end >>> alias =~ in_delta? >>> end >>> p 1.23456789e4.in_delta?( 1.234567892e4 ) >>> p 1.23456789e-1.in_delta?( 1.234567892e-1 ) >>> p 1.23456789e-6.in_delta?( 1.234567892e-6 ) >>> p 1.23456789e-11.in_delta?( 1.234567892e-11 ) >>> ==== output ==== >>> false >>> false >>> true >>> true >> That's why, chose your delta wisely. It is also why the =~ is only >> marginally less surprising than == and still evil. >> Maybe one could improve it a bit using a delta created using the >> magnitude (hello, dear log). Another approach might be to use the >> quotient of the two numbers (its proximity to 1). > > Yes, having manually to choose the delta for each > comparison is not good. > > Here is a modificaion of a method mentioned > by Michael Ulm earlier. > > def eq( x, y ) > x == y or > (x-y).abs < (x.abs + y.abs) * Float::EPSILON * 4 > end > > DATA.each{|s| > strings = s.chomp.split(";") > floats = strings.map{|s| eval(s) } > puts strings.join( " (x-y).abs < (x.abs + y.abs) *== " ) + > " : #{ floats[0]==floats[1] } #{ eq( *floats ) }" > } --snip-- Please note, that the formula I gave has a bug in it: The condition (x-y).abs < (x.abs + y.abs) * Delta is always false if y == 0 (and Delta < 1 :-) Better use something along the lines of (x-y).abs < (x.abs + y.abs + 1.0) * Delta Still, there is no Delta that would fit all applications. The one you gave may be good for the examples you had, but I doubt it would be fitting for more complex computations (where the rounding error gets larger than 4*Float::EPSILON). Regards, Michael