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
