Subject: SF bug [ 2013654 ] bfloat(NaN) => finite number
From: Robert Dodier
Date: Sun, 13 Jul 2008 13:49:55 -0600
Hello,
I have some code (still experimental) to detect floating point infinity
and not-a-number. The immediate use is to disallow bigfloat conversion
for those values, but I am guessing there could be other uses.
I tried to implement tests in terms of operations that are valid for
all non-special floating point values. Also I tried to use properties
of floating point arithmetic rather than inspecting bits since I don't
know a bit-inspection method which works on special values.
Context: http://sourceforge.net/tracker/index.php?func=detail&aid=2013654&group_id=4933&atid=104933
HTH
Robert Dodier
PS.
$ cat /tmp/disallow-bfloat-nan-inf-patch
Index: src/float.lisp
===================================================================
RCS file: /cvsroot/maxima/maxima/src/float.lisp,v
retrieving revision 1.39
diff -u -r1.39 float.lisp
--- src/float.lisp 14 Feb 2008 01:31:37 -0000 1.39
+++ src/float.lisp 13 Jul 2008 19:31:41 -0000
@@ -258,10 +258,41 @@
(list '(rat simp) 1 (exptrl 2 (1- fpprec)))
$ratepsilon)))))
+(defun float-nan-p (x)
+ (and (floatp x) (not (= x x))))
+
+(defun float-inf-p (x)
+ (and (floatp x) (not (float-nan-p x)) (beyond-extreme-values x)))
+
+(defun beyond-extreme-values (x)
+ (multiple-value-bind (most-negative most-positive) (extreme-float-values x)
+ (cond
+ ((< x 0) (< x most-negative))
+ ((> x 0) (> x most-positive))
+ (t nil))))
+
+(defun extreme-float-values (x)
+ ;; BLECHH, I HATE ENUMERATING CASES. IS THERE A BETTER WAY ??
+ (case (type-of x)
+ (short-float (values most-negative-short-float most-positive-short-float))
+ (single-float (values most-negative-single-float
most-positive-single-float))
+ (double-float (values most-negative-double-float
most-positive-double-float))
+ (long-float (values most-negative-long-float most-positive-long-float))
+ ;; NOT SURE THE FOLLOWING REALLY WORKS
+ ;; #+(and cmu double-double)
+ ;; (kernel:double-double-float
+ ;; (values most-negative-double-double-float
most-positive-double-double-float))
+ ))
+
;; Convert a floating point number into a bigfloat.
(defun floattofp (x)
+ (if (float-nan-p x)
+ (merror "Attempted float-to-bigfloat conversion of floating point
NaN (not-a-number).~%"))
+ (if (float-inf-p x)
+ (merror "Attempted float-to-bigfloat conversion of floating-point
infinity.~%"))
(unless $float2bf
(mtell "Warning: Float to bigfloat conversion of ~S~%" x))
+
(multiple-value-bind (frac exp sign)
(integer-decode-float x)
;; Scale frac to the desired number of bits, and adjust the
Index: tests/rtest15.mac
===================================================================
RCS file: /cvsroot/maxima/maxima/tests/rtest15.mac,v
retrieving revision 1.68
diff -u -r1.68 rtest15.mac
--- tests/rtest15.mac 5 Apr 2008 19:38:27 -0000 1.68
+++ tests/rtest15.mac 13 Jul 2008 19:31:44 -0000
@@ -983,3 +983,23 @@
(reset (float_approx_equal_tolerance), 0);
0;
+
+/* disallow bigfloat conversion for floating point infinity and not-a-number.
+ * SF bug [ 2013654 ] bfloat(NaN) => finite number
+ */
+
+(foo : ?most\-positive\-double\-float,
+ bar : ?most\-negative\-double\-float,
+ block ([ratepsilon : 0], [bfloat (foo), bfloat (bar)]));
+/* might need to replace the expected result w/ a rat-ified value to
ensure equality ... */
+[1.797693134862316b308, - 1.797693134862316b308];
+
+errcatch (bfloat (2*foo));
+[];
+
+errcatch (bfloat (2*bar));
+[];
+
+errcatch (bfloat (2*foo + 3*bar));
+[];
+