Steven,

Thanks for your comments. You bring up some interesting points, however, you 
also raise some more questions.

First, you criticize my use of the variable name 'epsilon'. Of course, this 
usage is entirely consistent with its ubiquitous use in mathematics. I am 
designating a(n) (arbitrarily) small positive number used as a bound on the 
difference of x and y. I am well aware of the more restricted use that you are 
emphasizing:
* (apropos-list 'epsilon)

(DOUBLE-FLOAT-EPSILON DOUBLE-FLOAT-NEGATIVE-EPSILON LONG-FLOAT-EPSILON
 LONG-FLOAT-NEGATIVE-EPSILON SHORT-FLOAT-EPSILON SHORT-FLOAT-NEGATIVE-EPSILON
 SINGLE-FLOAT-EPSILON SINGLE-FLOAT-NEGATIVE-EPSILON EPSILON)

In fact, two articles referenced in this thread also use 'epsilon' in exactly 
the way I have:
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
http://adtmag.com/Articles/2000/03/16/Comparing-Floats-How-To-Determine-if-Floating-Quantities-Are-Close-Enough-Once-a-Tolerance-Has-Been.aspx?Page=1

But if you would prefer to use the word 'tolerance' or some such term and 
reserve 'epsilon' (more properly 'machine epsilon') for the concept you have in 
mind, then I'll go along with that (and I won't even complain about you using 
the word 'mantissa' :-) ).

More significantly, your discussion of scaling epsilon (your meaning, I 
presume) got me thinking. Is it strange that we are using a decimal fraction 
for our tolerance? Should we be thinking in terms of a binary fraction, i.e., 
rather than 1/100000 we use 1/131072. In other words (Math/pow 2 -17) rather 
than (Math/pow 10 -5):
(Math/pow 10 -5) => 9.999999999999999E-6
(Math/pow 2 -17) => 7.62939453125E-6

Or are you saying that we should specifically be scaling (machine) epsilon 
rather than some arbitrary tolerance? As you mentioned this is not as easy in 
Clojure/Java as in Common Lisp.

Could we define 'scaled-epsilon' something like this?
(defn log2 [x]
  (/ (Math/log x) (Math/log 2)))
(def epsilon
     (loop [eps 1.0]
       (if (> (+ eps 1.0) 1.0)
         (recur (* eps 0.5))
         eps)))
(defn scaled-epsilon [x]
  (* epsilon (Math/pow 2 (Math/floor (log2 x)))) )

And finally, what is your response to the OP? You define 'same?' but place 
several caveats on its use. Are you warning that there is no general-purpose 
solution?


Have all good days,
David Sletten

On Oct 16, 2010, at 7:05 PM, Steven E. Harris wrote:

> cej38 <junkerme...@gmail.com> writes:
> 
>> (defn float=
>>  ([x y] (float= x y 0.00001))
>>  ([x y epsilon]
>>     (let [scale (if (or (zero? x) (zero? y)) 1 (Math/abs x))]
>>       (<= (Math/abs (- x y)) (* scale epsilon)))) )
> 
> You're scaling epsilon incorrectly here. Epsilon defines the smallest
> value that yields a value greater than one when added to one. If you're
> not using it along with one, you're using it incorrectly.
> 
> What you need to do is scale epsilon by having its exponent match the
> value with which you want to use it, while maintaining its mantissa. The
> C library offers functions ldexp()¹ and frexp()² to split and scale the
> exponent of a floating point number, respectively; Common Lisp offers
> DECODE-FLOAT³ and SCALE-FLOAT for the same purpose.
> 
> I don't know of any standard functions in Java -- or Clojure -- that
> allow one to destructure a floating point number like this. It's
> possible to use Float#floatToRawIntBits(), an understanding of IEEE 754,
> and tweezers to get there.
> 
> If you assume you have a function called `scaled-epsilon' that accepts
> the exemplar value with which you intend to use epsilon,
> 
>  (defn scaled-epsilon [n] ...)
> 
> you can use the following function `same?' to compare your floating
> point values, assuming they're nonnegative:
> 
> ,----
> | (defn same?
> |   [m n]
> |   (if (< n m)
> |       (sufficiently-close? n m)
> |       (sufficiently-close? m n)))
> | 
> | (defn- sufficiently-close?
> |   [smaller larger]
> |   (or (zero? larger)
> |       (if (zero? smaller)
> |           (< larger (scaled-epsilon 0.0)))
> |           (zero? (- 1 (/ smaller larger)))))
> `----
> 
> Note too that scaling epsilon must take into account whether you intend
> to add it or subtract it from some companion number. It's common to use
> the word "epsilon" to mean some fudge factor without considering what
> the value really means for a floating point number. Indeed, using it
> properly in Java is still too difficult. 
> 
> 
> Footnotes: 
> ¹ http://www.dinkumware.com/manuals/?manual=compleat&page=math.html#frexp
> ² http://www.dinkumware.com/manuals/?manual=compleat&page=math.html#ldexp
> ³ 
> http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_fl.htm#decode-float
>  
> http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_fl.htm#scale-float
> 
> -- 
> Steven E. Harris
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en





-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to