From: William James Date: 2007-09-04T11:15:06+09:00 Subject: Re: wierd floating point output 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( " == " ) + " : #{ floats[0]==floats[1] } #{ eq( *floats ) }" } __END__ (0.05+0.01);0.06 (0.34+0.01);0.35 0.0;0.0 1.23456789e9;1.234567892e9 1.23456789e4;1.234567892e4 1.23456789e-1;1.234567892e-1 1.23456789e-6;1.234567892e-6 1.23456789e-11;1.234567892e-11 1.23456789012345e9;1.234567890123452e9 1.23456789012345e4;1.234567890123452e4 1.23456789012345e-1;1.234567890123452e-1 1.23456789012345e-6;1.234567890123452e-6 1.23456789012345e-11;1.234567890123452e-11 ==== output ==== (0.05+0.01) == 0.06 : false true (0.34+0.01) == 0.35 : false true 0.0 == 0.0 : true true 1.23456789e9 == 1.234567892e9 : false false 1.23456789e4 == 1.234567892e4 : false false 1.23456789e-1 == 1.234567892e-1 : false false 1.23456789e-6 == 1.234567892e-6 : false false 1.23456789e-11 == 1.234567892e-11 : false false 1.23456789012345e9 == 1.234567890123452e9 : false true 1.23456789012345e4 == 1.234567890123452e4 : false true 1.23456789012345e-1 == 1.234567890123452e-1 : false true 1.23456789012345e-6 == 1.234567890123452e-6 : false true 1.23456789012345e-11 == 1.234567890123452e-11 : false true > With both suggestions I have no idea about hazardeous situations, maybe > somebody with either more recent CS training or daily use of floats can > shed some light on that. Also it is too late at night to have clear > thoughts about that. > > Regards > Stefan