From: Mauricio Fernandez Date: 2007-06-25T06:30:36+09:00 Subject: Re: Ruby doesn't know how to multiply On Mon, Jun 25, 2007 at 01:52:07AM +0900, Stefan Rusterholz wrote: > Shot (Piotr Szotkowski) wrote: > > MenTaLguY: > > > >> The best you can do is test whether the result is > >> within some interval (epsilon) of the expected result: > > > >> ( ( 14.95 * 0.6 ) - 8.97 ).abs < 1e-6 > > > >> (Here, we've chosen 1e-6 as our epsilon, which is arbitrary but > >> probably "small enough" in this case. For mathematically intensive > >> code, you may need to be more careful.) > > > > Any particular reason against using Float::EPSILON here? :) Comparing floating-point values different from 1.0? (also, greater errors) > > Maybe Float#== could simply be extended to consider the above? That > > would most probably open another can of worms, though, and extending > > Float#<=> would open yet another, I guess. > > > > -- Shot > > I think Float#== as it is is fine. Arguably it could use delta > comparison with Float::EPSILON and leave the exact comparison to eql? > But I'd like it if Float#in_delta(other, delta=Float::EPSILON) was in > core (personally I add it in my libs as Numeric#in_delta). That default value for delta makes no sense in general if you're using it as in the above example. Comparing the absolute difference against a fixed epsilon (especially Float::EPSILON) isn't normally as interesting as giving a bound for the relative error, so you'd at least need something like class Float def in_rdelta(other, rdelta = 1e-6) # or maybe no default at all? return true if self == other d = self.abs > other.abs ? (self - other) / self : (self - other) / other d.abs <= rdelta end end e = Float::EPSILON # => 2.22044604925031e-16 1.0.in_rdelta(1.000000000000000222, e) # => true 100.0.in_rdelta(100.000000000000021, e) # => true 100.0.in_rdelta(100.000000000000044, e) # => false 1.0.in_rdelta(1.000000000000000322, e) # => true 1.000000000000000322 == 1.000000000000000222 # => true "%20.18f" % 1.000000000000000322 # => "1.000000000000000222" # And you'd have to add an extra check if you want a different semantics # around 0.0: 0.0.in_rdelta(2.22e-16, 0.1) # => false 0.0.in_rdelta(2e-17, 0.99) # => false 0.0.in_rdelta(2e-20, 0.9999) # => false -- Mauricio Fernandez - http://eigenclass.org - singular Ruby