[oct-cvs] Oct commit: oct qd-io.lisp

rtoy rtoy at common-lisp.net
Mon Sep 24 21:32:15 UTC 2007


Update of /project/oct/cvsroot/oct
In directory clnet:/tmp/cvs-serv16369

Modified Files:
	qd-io.lisp 
Log Message:
A new version of MAKE-FLOAT that converts the number to rational
before converting to a quad-double.  This reduces round-off errors.
This still needs work, I think.


--- /project/oct/cvsroot/oct/qd-io.lisp	2007/09/24 02:37:31	1.16
+++ /project/oct/cvsroot/oct/qd-io.lisp	2007/09/24 21:32:15	1.17
@@ -305,11 +305,13 @@
 	(t
 	 (qd-output-aux arg stream))))
 
+;; This version has problems with roundoff.
+#+nil
 (defun make-float (sign int-part frac-part scale exp)
   (declare (type (member -1 1) sign)
 	   (type unsigned-byte int-part frac-part)
 	   (fixnum scale exp))
-  #+(or)
+  ;;#+(or)
   (progn
     (format t "sign      = ~A~%" sign)
     (format t "int-part  = ~A~%" int-part)
@@ -319,7 +321,7 @@
   (let ((int (cl:+ (cl:* int-part (expt 10 scale))
 		   frac-part))
 	(power (cl:- exp scale)))
-    #+(or)
+    ;;#+(or)
     (format t "~A * ~A * 10^(~A)~%" sign int power)
     (let* ((len (integer-length int)))
       #+(or)
@@ -379,6 +381,80 @@
 		   (neg-qd (mul-qd xx yy))
 		   (mul-qd xx yy))))))))
 
+(defun make-float (sign int-part frac-part scale exp)
+  (declare (type (member -1 1) sign)
+	   (type unsigned-byte int-part frac-part)
+	   (fixnum scale exp))
+  (flet ((convert-int (int)
+	   ;; Convert integer INT to a quad-double.
+	   (let ((len (integer-length int)))
+	     (cond ((<= len 53)
+		    ;; The simple case that fits in a double-float
+		    (let ((xx (make-qd-d (float int 1d0))))
+		      xx))
+		   (t
+		    ;; The complicated case.  We look at the top 5*53
+		    ;; bits and create doubles from them (properly
+		    ;; scaled) and then combine into a quad-double.
+		    ;; Looking at only 4*53 (212 bits) isn't accurate
+		    ;; enough.  In particulare 10^100 isn't converted
+		    ;; as accurately as desired if only 212 bits are
+		    ;; used.
+		    ;;
+		    ;; If the integer doesn't have 5*53 bits, left
+		    ;; shift it until it does, and set the length to
+		    ;; 5*53, so that the scaling is done properly.
+		    (let* 
+			((new-int (if (< len (* 5 53))
+				      (progn
+					(setf len (* 5 53))
+					(ash int (- (* 5 53) len)))
+				      int))
+			 (q0 (ldb (byte 53 (cl:- len 53)) new-int))
+			 (q1 (ldb (byte 53 (cl:- len (* 2 53))) new-int))
+			 (q2 (ldb (byte 53 (cl:- len (* 3 53))) new-int))
+			 (q3 (ldb (byte 53 (cl:- len (* 4 53))) new-int))
+			 (q4 (ldb (byte 53 (cl:- len (* 5 53))) new-int))
+			 (xx (multiple-value-call #'%make-qd-d
+			       (renorm-5 (scale-float (float q0 1d0)
+						      (cl:- len 53))
+					 (scale-float (float q1 1d0)
+						      (cl:- len (* 2 53)))
+					 (scale-float (float q2 1d0)
+						      (cl:- len (* 3 53)))
+					 (scale-float (float q3 1d0)
+						      (cl:- len (* 4 53)))
+					 (scale-float (float q4 1d0)
+						      (cl:- len (* 5 53)))))))
+		      #+(or)
+		      (progn
+			(format t "xx = ~A~%" xx)
+			#+(or)
+			(format t "   = ~/qd::qd-format/~%" xx)
+			(format t "yy = ~A~%" yy)
+			#+(or)
+			(format t "   = ~/qd::qd-format/~%" yy)
+			(format t "q0 = ~X (~A)~%" q0
+				(scale-float (float q0 1d0)
+					     (cl:- len 53)))
+			(format t "q1 = ~X (~A)~%" q1
+				(scale-float (float q1 1d0)
+					     (cl:- len (* 2 53))))
+			#+(or)
+			(format t "~/qdi::qd-format/~%" (mul-qd xx yy)))
+		      xx))))))
+    (let* ((rat (* (cl:+ (cl:* int-part (expt 10 scale))
+			 frac-part)
+		   (expt 10 (cl:- exp scale))))
+	   (top (numerator rat))
+	   (bot (denominator rat)))
+      (div-qd (let ((top-qd (convert-int top)))
+		(if (minusp sign)
+		    (neg-qd top-qd)
+		    top-qd))
+	      (convert-int bot)))))
+
+
 ;; This seems to work, but really needs to be rewritten!
 (defun read-qd (stream)
   (labels ((read-digits (s)




More information about the oct-cvs mailing list