Chisheng Huang wrote:
> It doesn't look like I can test if 2 single floats are equal (=)
> or not reliably.  I'm using cmucl-19b-test-x86-linux.  To reproduce
> this problem, enter the following forms into the REPL (do not compile them):
> 
> (declaim (inline sf=))
> 
> (defun sf= (x y)
>   (< (abs (- (the Single-Float x) 
>              (the Single-Float y)))
>      single-float-epsilon))
> 
> (defun test (wh w)
>   (declare (type fixnum w))
>   (print (list (car wh)
>              (/ w 3.8208954)
>              (= (the Single-Float (car wh))
>                 (/ w 3.8208954))
>              (sf= (the Single-Float (car wh))
>                   (/ w 3.8208954))
>              (< (abs (- (car wh) 
>                         (/ w 3.8208954)))
>                 single-float-epsilon))))
> 
> Evaluating (test '(217.48828 . 0.0) 831) will give you:
> (217.48828 217.48828 T T T), which is good.
> 
> After you do (compile 'sf=) and (compile 'test), evaluating
> (test '(217.48828 . 0.0) 831) will give you (217.48828 217.48828 NIL NIL T),
> which is weird.

I'm pretty sure this is due to the 80-bit FP registers on x86.  I didn't 
look at the generated code, but I suspect (/ w 3.82) is computed in the 
80-bit regs and not rounded to single-float so that it isn't equal to 
(car wh).

This is a known issue.  You have a workaround.  Another solution might 
be to set the FPU to single-precision (see set-floating-point-modes) 
when doing the computations.

But be sure to reset it afterwards to 80-bit precision or your 
double-float computations or special functions might now only give 
single-precision results or worse.

Ray


Reply via email to