changeset 81573:d5640ed7c397

(math-bignum-digit-length,math-bignum-digit-size,math-small-integer-size): New constants. (math-normalize,math-bignum-big,math-make-float,math-div10-bignum) (math-scale-left,math-scale-left-bignum,math-scale-right) (math-scale-right-bignum,math-scale-rounding,math-add,math-add-bignum) (math-sub-bignum,math-sub,math-mul,math-mul-bignum,math-mul-bignum-digit) (math-idivmod,math-quotient,math-div-bignum,math-div-bignum-digit) (math-div-bignum-part,math-format-bignum-decimal,math-read-bignum): Use math-bignum-digit-length, math-bignum-digit-size and math-small-integer-size.
author Jay Belanger <jay.p.belanger@gmail.com>
date Sat, 23 Jun 2007 04:05:29 +0000
parents 0991efe3cafa
children 5a3c4b356d6d
files lisp/calc/calc.el
diffstat 1 files changed, 111 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/calc/calc.el	Sat Jun 23 03:06:21 2007 +0000
+++ b/lisp/calc/calc.el	Sat Jun 23 04:05:29 2007 +0000
@@ -2283,7 +2283,18 @@
 
 
 
-
+(defconst math-bignum-digit-length 3
+  "The length of a \"digit\" in Calc bignums.
+If a big integer is of the form (bigpos N0 N1 ...), this is the
+length of the allowable Emacs integers N0, N1,...
+The value of 2*10^(2*MATH-BIGNUM-DIGIT-LENGTH) must be less than the
+largest Emacs integer.")
+
+(defconst math-bignum-digit-size (expt 10 math-bignum-digit-length)
+  "An upper bound for the size of the \"digit\"s in Calc bignums.")
+
+(defconst math-small-integer-size (expt 10 (* 2 math-bignum-digit-length))
+  "An upper bound for the size of \"small integer\"s in Calc.")
 
 
 ;;;; Arithmetic routines.
@@ -2292,11 +2303,17 @@
 ;;; following forms:
 ;;;
 ;;; integer                 An integer.  For normalized numbers, this format
-;;;			    is used only for -999999 ... 999999.
+;;;			    is used only for  
+;;;                         negative math-small-integer-size + 1 to
+;;;                         math-small-integer-size - 1
 ;;;
-;;; (bigpos N0 N1 N2 ...)   A big positive integer, N0 + N1*1000 + N2*10^6 ...
-;;; (bigneg N0 N1 N2 ...)   A big negative integer, - N0 - N1*1000 ...
-;;;			    Each digit N is in the range 0 ... 999.
+;;; (bigpos N0 N1 N2 ...)   A big positive integer, 
+;;;                           N0 + N1*math-bignum-digit-size 
+;;;                              + N2*(math-bignum-digit-size)^2 ...
+;;; (bigneg N0 N1 N2 ...)   A big negative integer, 
+;;;                           - N0 - N1*math-bignum-digit-size ...
+;;;			    Each digit N is in the range 
+;;;                             0 ... math-bignum-digit-size -1.
 ;;;			    Normalized, always at least three N present,
 ;;;			    and the most significant N is nonzero.
 ;;;
@@ -2386,7 +2403,8 @@
   (cond
    ((not (consp math-normalize-a))
     (if (integerp math-normalize-a)
-	(if (or (>= math-normalize-a 1000000) (<= math-normalize-a -1000000))
+	(if (or (>= math-normalize-a math-small-integer-size) 
+                (<= math-normalize-a (- math-small-integer-size)))
 	    (math-bignum math-normalize-a)
 	  math-normalize-a)
       math-normalize-a))
@@ -2401,7 +2419,8 @@
 	math-normalize-a
       (cond
        ((cdr (cdr math-normalize-a)) (+ (nth 1 math-normalize-a) 
-                                        (* (nth 2 math-normalize-a) 1000)))
+                                        (* (nth 2 math-normalize-a) 
+                                           math-bignum-digit-size)))
        ((cdr math-normalize-a) (nth 1 math-normalize-a))
        (t 0))))
    ((eq (car math-normalize-a) 'bigneg)
@@ -2415,7 +2434,8 @@
 	math-normalize-a
       (cond
        ((cdr (cdr math-normalize-a)) (- (+ (nth 1 math-normalize-a) 
-                                           (* (nth 2 math-normalize-a) 1000))))
+                                           (* (nth 2 math-normalize-a) 
+                                              math-bignum-digit-size))))
        ((cdr math-normalize-a) (- (nth 1 math-normalize-a)))
        (t 0))))
    ((eq (car math-normalize-a) 'float)
@@ -2535,7 +2555,8 @@
 (defun math-bignum-big (a)   ; [L s]
   (if (= a 0)
       nil
-    (cons (% a 1000) (math-bignum-big (/ a 1000)))))
+    (cons (% a math-bignum-digit-size) 
+          (math-bignum-big (/ a math-bignum-digit-size)))))
 
 
 ;;; Build a normalized floating-point number.  [F I S]
@@ -2552,7 +2573,7 @@
 	      (progn
 		(while (= (car digs) 0)
 		  (setq digs (cdr digs)
-			exp (+ exp 3)))
+			exp (+ exp math-bignum-digit-length)))
 		(while (= (% (car digs) 10) 0)
 		  (setq digs (math-div10-bignum digs)
 			exp (1+ exp)))
@@ -2570,7 +2591,8 @@
 
 (defun math-div10-bignum (a)   ; [l l]
   (if (cdr a)
-      (cons (+ (/ (car a) 10) (* (% (nth 1 a) 10) 100))
+      (cons (+ (/ (car a) 10) (* (% (nth 1 a) 10) 
+                                 (expt 10 (1- math-bignum-digit-length))))
 	    (math-div10-bignum (cdr a)))
     (list (/ (car a) 10))))
 
@@ -2601,7 +2623,7 @@
       (if (cdr a)
 	  (let* ((len (1- (length a)))
 		 (top (nth len a)))
-	    (+ (* len 3) (cond ((>= top 100) 0) ((>= top 10) -1) (t -2))))
+            (+ (* (1- len) math-bignum-digit-length) (math-numdigs top)))
 	0)
     (cond ((>= a 100) (+ (math-numdigs (/ a 1000)) 3))
 	  ((>= a 10) 2)
@@ -2622,24 +2644,24 @@
       a
     (if (consp a)
 	(cons (car a) (math-scale-left-bignum (cdr a) n))
-      (if (>= n 3)
-	  (if (or (>= a 1000) (<= a -1000))
+      (if (>= n math-bignum-digit-length)
+	  (if (or (>= a math-bignum-digit-size) 
+                  (<= a (- math-bignum-digit-size)))
 	      (math-scale-left (math-bignum a) n)
-	    (math-scale-left (* a 1000) (- n 3)))
-	(if (= n 2)
-	    (if (or (>= a 10000) (<= a -10000))
-		(math-scale-left (math-bignum a) 2)
-	      (* a 100))
-	  (if (or (>= a 100000) (<= a -100000))
-	      (math-scale-left (math-bignum a) 1)
-	    (* a 10)))))))
+	    (math-scale-left (* a math-bignum-digit-size) 
+                             (- n math-bignum-digit-length)))
+        (let ((sz (expt 10 (- (* 2 math-bignum-digit-length) n))))
+          (if (or (>= a sz) (<= a (- sz)))
+              (math-scale-left (math-bignum a) n)
+            (* a (expt 10 n))))))))
 
 (defun math-scale-left-bignum (a n)
-  (if (>= n 3)
+  (if (>= n math-bignum-digit-length)
       (while (>= (setq a (cons 0 a)
-		       n (- n 3)) 3)))
+		       n (- n math-bignum-digit-length)) 
+                 math-bignum-digit-length)))
   (if (> n 0)
-      (math-mul-bignum-digit a (if (= n 2) 100 10) 0)
+      (math-mul-bignum-digit a (expt 10 n) 0)
     a))
 
 (defun math-scale-right (a n)   ; [i i S]
@@ -2651,21 +2673,20 @@
 	  (if (= a 0)
 	      0
 	    (- (math-scale-right (- a) n)))
-	(if (>= n 3)
-	    (while (and (> (setq a (/ a 1000)) 0)
-			(>= (setq n (- n 3)) 3))))
-	(if (= n 2)
-	    (/ a 100)
-	  (if (= n 1)
-	      (/ a 10)
-	    a))))))
+	(if (>= n math-bignum-digit-length)
+	    (while (and (> (setq a (/ a math-bignum-digit-size)) 0)
+			(>= (setq n (- n math-bignum-digit-length)) 
+                            math-bignum-digit-length))))
+	(if (> n 0)
+            (/ a (expt 10 n))
+          a)))))
 
 (defun math-scale-right-bignum (a n)   ; [L L S; l l S]
-  (if (>= n 3)
-      (setq a (nthcdr (/ n 3) a)
-	    n (% n 3)))
+  (if (>= n math-bignum-digit-length)
+      (setq a (nthcdr (/ n math-bignum-digit-length) a)
+	    n (% n math-bignum-digit-length)))
   (if (> n 0)
-      (cdr (math-mul-bignum-digit a (if (= n 2) 10 100) 0))
+      (cdr (math-mul-bignum-digit a (expt 10 (- math-bignum-digit-length n)) 0))
     a))
 
 ;;; Multiply (with rounding) the integer A by 10^N.   [I i S]
@@ -2675,16 +2696,18 @@
 	((consp a)
 	 (math-normalize
 	  (cons (car a)
-		(let ((val (if (< n -3)
-			       (math-scale-right-bignum (cdr a) (- -3 n))
-			     (if (= n -2)
-				 (math-mul-bignum-digit (cdr a) 10 0)
-			       (if (= n -1)
-				   (math-mul-bignum-digit (cdr a) 100 0)
-				 (cdr a))))))  ; n = -3
-		  (if (and val (>= (car val) 500))
+		(let ((val (if (< n (- math-bignum-digit-length))
+			       (math-scale-right-bignum 
+                                (cdr a) 
+                                (- (- math-bignum-digit-length) n))
+			     (if (< n 0)
+				 (math-mul-bignum-digit 
+                                  (cdr a) 
+                                  (expt 10 (+ math-bignum-digit-length n)) 0)
+                               (cdr a)))))  ; n = -math-bignum-digit-length
+		  (if (and val (>= (car val) (/ math-bignum-digit-size 2)))
 		      (if (cdr val)
-			  (if (eq (car (cdr val)) 999)
+			  (if (eq (car (cdr val)) (1- math-bignum-digit-size))
 			      (math-add-bignum (cdr val) '(1))
 			    (cons (1+ (car (cdr val))) (cdr (cdr val))))
 			'(1))
@@ -2703,7 +2726,7 @@
    (and (not (or (consp a) (consp b)))
 	(progn
 	  (setq a (+ a b))
-	  (if (or (<= a -1000000) (>= a 1000000))
+	  (if (or (<= a (- math-small-integer-size)) (>= a math-small-integer-size))
 	      (math-bignum a)
 	    a)))
    (and (Math-zerop a) (not (eq (car-safe a) 'mod))
@@ -2752,14 +2775,15 @@
 	  (let* ((a (copy-sequence a)) (aa a) (carry nil) sum)
 	    (while (and aa b)
 	      (if carry
-		  (if (< (setq sum (+ (car aa) (car b))) 999)
+		  (if (< (setq sum (+ (car aa) (car b))) 
+                         (1- math-bignum-digit-size))
 		      (progn
 			(setcar aa (1+ sum))
 			(setq carry nil))
 		    (setcar aa (+ sum -999)))
-		(if (< (setq sum (+ (car aa) (car b))) 1000)
+		(if (< (setq sum (+ (car aa) (car b))) math-bignum-digit-size)
 		    (setcar aa sum)
-		  (setcar aa (+ sum -1000))
+		  (setcar aa (- sum math-bignum-digit-size))
 		  (setq carry t)))
 	      (setq aa (cdr aa)
 		    b (cdr b)))
@@ -2790,17 +2814,17 @@
 		      (progn
 			(setcar aa (1- diff))
 			(setq borrow nil))
-		    (setcar aa (+ diff 999)))
+		    (setcar aa (+ diff (1- math-bignum-digit-size))))
 		(if (>= (setq diff (- (car aa) (car b))) 0)
 		    (setcar aa diff)
-		  (setcar aa (+ diff 1000))
+		  (setcar aa (+ diff math-bignum-digit-size))
 		  (setq borrow t)))
 	      (setq aa (cdr aa)
 		    b (cdr b)))
 	    (if borrow
 		(progn
 		  (while (eq (car aa) 0)
-		    (setcar aa 999)
+		    (setcar aa (1- math-bignum-digit-size))
 		    (setq aa (cdr aa)))
 		  (if aa
 		      (progn
@@ -2840,7 +2864,7 @@
   (if (or (consp a) (consp b))
       (math-add a (math-neg b))
     (setq a (- a b))
-    (if (or (<= a -1000000) (>= a 1000000))
+    (if (or (<= a (- math-small-integer-size)) (>= a math-small-integer-size))
 	(math-bignum a)
       a)))
 
@@ -2867,7 +2891,8 @@
 (defun math-mul (a b)
   (or
    (and (not (consp a)) (not (consp b))
-	(< a 1000) (> a -1000) (< b 1000) (> b -1000)
+	(< a math-bignum-digit-size) (> a (- math-bignum-digit-size)) 
+        (< b math-bignum-digit-size) (> b (- math-bignum-digit-size))
 	(* a b))
    (and (Math-zerop a) (not (eq (car-safe b) 'mod))
 	(if (Math-scalarp b)
@@ -2936,14 +2961,14 @@
 		 aa a)
 	   (while (progn
 		    (setcar ss (% (setq prod (+ (+ (car ss) (* (car aa) d))
-						c)) 1000))
+						c)) math-bignum-digit-size))
 		    (setq aa (cdr aa)))
-	     (setq c (/ prod 1000)
+	     (setq c (/ prod math-bignum-digit-size)
 		   ss (or (cdr ss) (setcdr ss (list 0)))))
-	   (if (>= prod 1000)
+	   (if (>= prod math-bignum-digit-size)
 	       (if (cdr ss)
-		   (setcar (cdr ss) (+ (/ prod 1000) (car (cdr ss))))
-		 (setcdr ss (list (/ prod 1000))))))
+		   (setcar (cdr ss) (+ (/ prod math-bignum-digit-size) (car (cdr ss))))
+		 (setcdr ss (list (/ prod math-bignum-digit-size))))))
 	 sum)))
 
 ;;; Multiply digit list A by digit D.  [L L D D; l l D D]
@@ -2953,12 +2978,14 @@
 	  (and (= d 1) a)
 	(let* ((a (copy-sequence a)) (aa a) prod)
 	  (while (progn
-		   (setcar aa (% (setq prod (+ (* (car aa) d) c)) 1000))
+		   (setcar aa 
+                           (% (setq prod (+ (* (car aa) d) c)) 
+                              math-bignum-digit-size))
 		   (cdr aa))
 	    (setq aa (cdr aa)
-		  c (/ prod 1000)))
-	  (if (>= prod 1000)
-	      (setcdr aa (list (/ prod 1000))))
+		  c (/ prod math-bignum-digit-size)))
+	  (if (>= prod math-bignum-digit-size)
+	      (setcdr aa (list (/ prod math-bignum-digit-size))))
 	  a))
     (and (> c 0)
 	 (list c))))
@@ -2971,7 +2998,7 @@
   (if (eq b 0)
       (math-reject-arg a "*Division by zero"))
   (if (or (consp a) (consp b))
-      (if (and (natnump b) (< b 1000))
+      (if (and (natnump b) (< b math-bignum-digit-size))
 	  (let ((res (math-div-bignum-digit (cdr a) b)))
 	    (cons
 	     (math-normalize (cons (car a) (car res)))
@@ -2990,7 +3017,7 @@
       (if (= b 0)
 	  (math-reject-arg a "*Division by zero")
 	(/ a b))
-    (if (and (natnump b) (< b 1000))
+    (if (and (natnump b) (< b math-bignum-digit-size))
 	(if (= b 0)
 	    (math-reject-arg a "*Division by zero")
 	  (math-normalize (cons (car a)
@@ -2999,7 +3026,7 @@
       (or (consp b) (setq b (math-bignum b)))
       (let* ((alen (1- (length a)))
 	     (blen (1- (length b)))
-	     (d (/ 1000 (1+ (nth (1- blen) (cdr b)))))
+	     (d (/ math-bignum-digit-size (1+ (nth (1- blen) (cdr b)))))
 	     (res (math-div-bignum-big (math-mul-bignum-digit (cdr a) d 0)
 				       (math-mul-bignum-digit (cdr b) d 0)
 				       alen blen)))
@@ -3013,7 +3040,7 @@
   (if (cdr b)
       (let* ((alen (length a))
 	     (blen (length b))
-	     (d (/ 1000 (1+ (nth (1- blen) b))))
+	     (d (/ math-bignum-digit-size (1+ (nth (1- blen) b))))
 	     (res (math-div-bignum-big (math-mul-bignum-digit a d 0)
 				       (math-mul-bignum-digit b d 0)
 				       alen blen)))
@@ -3028,7 +3055,7 @@
 (defun math-div-bignum-digit (a b)
   (if a
       (let* ((res (math-div-bignum-digit (cdr a) b))
-	     (num (+ (* (cdr res) 1000) (car a))))
+	     (num (+ (* (cdr res) math-bignum-digit-size) (car a))))
 	(cons
 	 (cons (/ num b) (car res))
 	 (% num b)))
@@ -3044,10 +3071,11 @@
        (cons (car res2) (car res))
        (cdr res2)))))
 
-(defun math-div-bignum-part (a b blen)   ; a < b*1000  [D.l l L]
-  (let* ((num (+ (* (or (nth blen a) 0) 1000) (or (nth (1- blen) a) 0)))
+(defun math-div-bignum-part (a b blen)   ; a < b*math-bignum-digit-size  [D.l l L]
+  (let* ((num (+ (* (or (nth blen a) 0) math-bignum-digit-size) 
+                 (or (nth (1- blen) a) 0)))
 	 (den (nth (1- blen) b))
-	 (guess (min (/ num den) 999)))
+	 (guess (min (/ num den) (1- math-bignum-digit-size))))
     (math-div-bignum-try a b (math-mul-bignum-digit b guess 0) guess)))
 
 (defun math-div-bignum-try (a b c guess)   ; [D.l l l D]
@@ -3358,9 +3386,15 @@
   (if a
       (let ((s ""))
 	(while (cdr (cdr a))
-	  (setq s (concat (format "%06d" (+ (* (nth 1 a) 1000) (car a))) s)
+	  (setq s (concat 
+                   (format 
+                    (concat "%0" 
+                            (number-to-string (* 2 math-bignum-digit-length))  
+                            "d")
+                    (+ (* (nth 1 a) math-bignum-digit-size) (car a))) s)
 		a (cdr (cdr a))))
-	(concat (int-to-string (+ (* (or (nth 1 a) 0) 1000) (car a))) s))
+	(concat (int-to-string 
+                 (+ (* (or (nth 1 a) 0) math-bignum-digit-size) (car a))) s))
     "0"))
 
 
@@ -3447,9 +3481,9 @@
     ""))
 
 (defun math-read-bignum (s)   ; [l X]
-  (if (> (length s) 3)
-      (cons (string-to-number (substring s -3))
-	    (math-read-bignum (substring s 0 -3)))
+  (if (> (length s) math-bignum-digit-length)
+      (cons (string-to-number (substring s (- math-bignum-digit-length)))
+	    (math-read-bignum (substring s 0 (- math-bignum-digit-length))))
     (list (string-to-number s))))