[LISPWORKS][Common Lisp HyperSpec (TM)] [Previous][Up][Next]



References: CLtL p.194

Category: CHANGE

Edit history: Version 1, 14-Sep-88, Moon

Problem description:

The numerical contagion rules specified on CLtL p.194 make it impossible

for the numerical comparison functions to be transitive when given

arguments of mixed floating and rational types (see example below).


Instead of using the same contagion rule both for combining functions

and for comparing functions, make the present rule apply only to

combining functions and add the following rule: When rational and

floating-point numbers are compared by a numerical function, the

function RATIONAL is called to convert the floating-point number to a

rational and then an exact comparison is performed. In the case of

complex numbers (RATIONAL is for some unknown reason only allowed on

reals), the real and imaginary parts are handled individually.

It is of course valid to use a more efficient implementation than

actually calling RATIONAL, as long as the result of the comparison is

the same.

Test Cases/Examples:

(defvar a (/ 10.0 single-float-epsilon))

(= a (1+ (floor a)))

should be NIL, since

(= a (floor a))

is certainly T and

(= (floor a) (1+ (floor a)))

is certainly NIL. However, by the rule of floating-point contagion,

(= a (1+ (floor a)))

is the same as

(= a (float (1+ (floor a)) a))

and the latter form is certainly T.

To understand this example better, it helps to realize that

(= a (+ a 1.0))

is always true, by the definition of single-float-epsilon.

Here is a second example:

(defvar i (floor a))

(<= a (+ i 1)) is T.

(< (+ i 1) (+ i 2)) is T.

(<= (+ i 2) a) is T by CLtL, NIL by this proposal.

Thus CLtL requires

a <= i+1 < i+2 <= a

which ought to imply

a < a

which is absurd.


Transitivity of = and of < are important to many algorithms. What CLtL

says now was probably not intentional, but just the result of thinking

that comparing and combining could be lumped together without really

thinking about it.

Without this change, it is impossible to extend the :TEST argument to

MAKE-HASH-TABLE to allow = or EQUALP, since there could be two table

entries with rational keys that are not =, then GETHASH could be

presented with a floating-point argument that is = to both keys.

Current practice:

Lucid is said to implement the proposal. As far as I know all other

implementations do what CLtL currently says.

Cost to Implementors:

This requires a change in what is likely to be intricate and

implementation-dependent code. However, the total effort should

be small compared to the cost of writing that code originally.

Cost to Users:

This is an incompatible change. It's difficult to know if any users

are depending on the current behavior. It seems likely that most users

would expect the proposed behavior, and may be wondering why their

programs don't quite work when the numbers get large.

Cost of non-adoption:

Comparison functions in Common Lisp will be non-transitive.


Comparison functions in Common Lisp will be transitive.


Having two rules of floating-point contagion may seem less esthetic,

but I'm certain that having the comparison functions behave in a more

mathematically correct fashion outweighs that esthetically.


Everyone who has expressed an opinion has thought this was the right

thing for years, but we never got around to writing it up as a cleanup


[Starting Points][Contents][Index][Symbols][Glossary][Issues]
Copyright 1996-2005, LispWorks Ltd. All rights reserved.