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

rtoy rtoy at common-lisp.net
Wed Oct 10 15:24:07 UTC 2007


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

Modified Files:
	qd-io.lisp qd-methods.lisp qd-package.lisp 
Log Message:
qd-io.lisp:
o Add RATIONAL-TO-QD, a simple, fast and accurate method to convert
  rationals to quad-doubles.  (From Richard Fateman.)
o Use RATIONAL-TO-QD to create a quad-float

qd-methods.lisp:
o Use RATIONAL-TO-QD to create a quad-float from a bignum and ratio. 

qd-package.lisp:
o Export RATIONAL-TO-QD


--- /project/oct/cvsroot/oct/qd-io.lisp	2007/09/24 21:32:15	1.17
+++ /project/oct/cvsroot/oct/qd-io.lisp	2007/10/10 15:24:07	1.18
@@ -381,78 +381,29 @@
 		   (neg-qd (mul-qd xx yy))
 		   (mul-qd xx yy))))))))
 
+;; This is a slightly modified version of Richard Fateman's code to
+;; convert bignums to qd.  This supports converting rationals to qd
+;; too.
+(defun rational-to-qd (rat)
+  (declare (rational rat))
+  (let* ((p (coerce rat 'double-float))
+	 (ans (make-qd-d p))
+	 (remainder rat))
+    (declare (double-float p)
+	     (rational remainder)
+	     (type %quad-double ans))
+    (dotimes (k 3 ans)
+      (decf remainder (rational p))
+      (setf p (coerce remainder 'double-float))
+      (setf ans (add-qd-d ans p)))))
+
 (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)))))
+  (rational-to-qd (* sign
+		     (* (+ int-part (/ frac-part (expt 10 scale)))
+			(expt 10 exp)))))
 
 
 ;; This seems to work, but really needs to be rewritten!
--- /project/oct/cvsroot/oct/qd-methods.lisp	2007/09/24 21:30:07	1.61
+++ /project/oct/cvsroot/oct/qd-methods.lisp	2007/10/10 15:24:07	1.62
@@ -250,11 +250,7 @@
 
 (defun bignum-to-qd (bignum)
   (make-instance 'qd-real
-		 :value (qdi::make-float (if (minusp bignum) -1 1)
-					 (abs bignum)
-					 0
-					 0
-					 0)))
+		 :value (rational-to-qd bignum)))
 
 (defmethod qfloat ((x real) (num-type cl:float))
   (cl:float x num-type))
@@ -276,10 +272,7 @@
 	     (qfloat (denominator x) num-type)))
 
 (defmethod qfloat ((x ratio) (num-type qd-real))
-  ;; This probably has some issues with roundoff
-  (let ((top (qd-value (qfloat (numerator x) num-type)))
-	(bot (qd-value (qfloat (denominator x) num-type))))
-    (make-instance 'qd-real :value (div-qd top bot))))
+  (make-instance 'qd-real :value (rational-to-qd x)))
   
 #+cmu
 (defmethod qfloat ((x ext:double-double-float) (num-type qd-real))
@@ -1025,4 +1018,3 @@
 ;; and make a real qd-real float, instead of the hackish
 ;; %qd-real.
 (set-dispatch-macro-character #\# #\Q #'qd-class-reader)
-
--- /project/oct/cvsroot/oct/qd-package.lisp	2007/09/20 21:04:05	1.41
+++ /project/oct/cvsroot/oct/qd-package.lisp	2007/10/10 15:24:07	1.42
@@ -90,6 +90,7 @@
 	   #:ffloor-qd
 	   #:random-qd
 	   #:with-qd-parts
+	   #:rational-to-qd
 	   )
   #+cmu
   (:export #:add-qd-dd




More information about the oct-cvs mailing list