A friend recently gave me a crash-course in the issues of computing the
equality of floating-point numbers. I've written functions such as f=,
f<, f>, etc., which use an epsilon value to test for fp equality. I
want to make these into CLOS methods on =, <, >, etc., for arguments of
the class, Float (that way, I don't have to worry about whether I'm
calling the fp or non-fp function). I'm led to believe this is common
practice in CL.
However, when I load the system (I'm using Allegro for Windows web
version), I'm given the warning message about redefining a regular
function as a generic function. e.g.
Error: Attempt to redefine the non-generic function = as generic.
I can choose to "Redefine it as generic" from the pop-up window, but
that's a bit unreasonable to do for each fp function every time I load
my system. I'm told that this protection is done for efficiency
reasons. But I still don't know what to DO about it.
So my question is how do CL programmers generally hide these fp
functions so that they may be used via the regular =, <, >, etc.
functions?
Cheers................
Kev
--------------------------------Bermuda Massive
Kevin Mayall ·······@uwaterloo.ca
http://www.fes.uwaterloo.ca/u/kmayall/
School of Planning, University of Waterloo
From: Erik Naggum
Subject: Re: equality of floating point numbers
Date:
Message-ID: <3066494244824844@naggum.no>
* Kevin Mayall
| A friend recently gave me a crash-course in the issues of computing the
| equality of floating-point numbers. I've written functions such as f=,
| f<, f>, etc., which use an epsilon value to test for fp equality. I want
| to make these into CLOS methods on =, <, >, etc., for arguments of the
| class, Float (that way, I don't have to worry about whether I'm calling
| the fp or non-fp function). I'm led to believe this is common practice
| in CL.
|
| So my question is how do CL programmers generally hide these fp functions
| so that they may be used via the regular =, <, >, etc. functions?
if they do this, they do it by creating a new package that inherits from
the "COMMON-LISP" package and then shadows the relevant functions. they
also define a methods that do not take objects of type float.
(defpackage :fuzzy
(:use :common-lisp)
(:shadow "=" "<" "<=" ">" ">=" "zerop")
(:export "=" "<" "<=" ">" ">=" "zerop"))
(in-package :fuzzy)
(defconstant epsilon 1e-4)
(cl:< (- epsilon) x epsilon))
(defun = (x y)
(cl:< (- epsilon) (- x y) epsilon))
(defun < (x y)
(cl:< (- x y) epsilon))
(defun <= (x y)
(cl:<= (- x y) epsilon))
(defun > (x y)
(cl:> (- x y) (- epsilon)))
(defun >= (x y)
(cl:>= (- x y) (- epsilon)))
(of course, you know how to do the fuzzy comparisons better than I do, and
the above might not even be correct implementations, but this should only
illustrate how the package system may be used.)
note that the comparison functions in the COMMON-LISP package all take any
number of arguments. you may wish to implement this functionality if you
run "normal" code, since it is quite common to test for ranges with, e.g.,
(< low x high). if you do, note that (OP x y z...) is the same as
(and (OP x y) (OP y z...)) for all OPs _except_ /=.
#\Erik
--
if you think big enough, you never have to do it
In article <...> Kevin Mayall <·······@uwaterloo.ca> writes:
> ... I've written functions such as f=,
> f<, f>, etc., which use an epsilon value to test for fp equality. I
> want to make these into CLOS methods on =, <, >, etc., for arguments of
> the class, Float (that way, I don't have to worry about whether I'm
> calling the fp or non-fp function). I'm led to believe this is common
> practice in CL.
>
> However, when I load the system (I'm using Allegro for Windows web
> version), I'm given the warning message about redefining a regular
> function as a generic function. e.g.
>
> Error: Attempt to redefine the non-generic function = as generic.
>
> I can choose to "Redefine it as generic" from the pop-up window, but
> that's a bit unreasonable to do for each fp function every time I load
> my system. I'm told that this protection is done for efficiency
> reasons. But I still don't know what to DO about it.
Well, it's also done for safety reasons, like making it harder for you to
completely destroy your lisp environment.
> So my question is how do CL programmers generally hide these fp
> functions so that they may be used via the regular =, <, >, etc.
> functions?
The officially sanctioned way to do this is with packages. You will
want to create your own package and shadow the arithmetic operators that
you want to be generic functions:
(defpackage MY-WORK (:use "COMMON-LISP")
(:shadow "=" ">" "<" ...))
(in-package "MY-WORK")
(defgeneric = (x y))
(defmethod = (x y) (cl:= x y))
(defmethod = ((x float) (y float)) ...)
;; etc.
--
Thomas A. Russ, USC/Information Sciences Institute ···@isi.edu