daveg@csvax.caltech.edu (David Gillespie) (06/06/90)
Posting-number: Volume 13, Issue 28 Submitted-by: daveg@csvax.caltech.edu (David Gillespie) Archive-name: gmcalc/part02 ---- Cut Here and unpack ---- #!/bin/sh # this is part 2 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file calc.el continued # CurArch=2 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file calc.el" sed 's/^X//' << 'SHAR_EOF' >> calc.el X) X X(defun calc-record (val &optional prefix) X (or calc-executing-macro X (let* ((mainbuf (current-buffer)) X (buf (get-buffer-create "*Calc Trail*")) X (calc-display-raw (eq calc-display-raw t)) X (fval (if val X (if (stringp val) X val X (math-showing-full-precision X (math-format-flat-expr val 0))) X ""))) X (save-excursion X (set-buffer buf) X (if (not (eq major-mode 'calc-trail-mode)) X (calc-trail-mode mainbuf)) X (let ((aligned (calc-check-trail-aligned)) X (buffer-read-only nil)) X (goto-char (point-max)) X (cond ((null prefix) (insert " ")) X ((> (length prefix) 5) (insert (substring prefix 0 5) " ")) X (t (insert (format "%4s " prefix)))) X (insert fval "\n") X (let ((win (get-buffer-window buf))) X (if (and aligned win (not (memq 'hold-trail calc-command-flags))) X (progn X (calc-trail-here)))) X (goto-char (1- (point-max))))))) X val X) X X(defun calc-record-list (vals &optional prefix) X (while vals X (or (eq (car vals) 'top-of-stack) X (progn X (calc-record (car vals) prefix) X (setq prefix "..."))) X (setq vals (cdr vals))) X) X X(defun calc-trail-display (flag &optional no-refresh) X "Turn the Trail display on or off. XWith prefix argument 1, turn it on; with argument 0, turn it off." X (interactive "P") X (let* ((trail (get-buffer-create "*Calc Trail*")) X (win (get-buffer-window trail))) X (if (setq calc-display-trail X (not (if flag (memq flag '(nil 0)) win))) X (if (null win) X (progn X (if (and (boundp 'calc-trail-window-hook) calc-trail-window-hook) X (run-hooks 'calc-trail-window-hook) X (let ((w (split-window nil (/ (* (window-width) 2) 3) t))) X (set-window-buffer w trail))) X (calc-wrapper X (or no-refresh X (calc-refresh))))) X (if win X (progn X (delete-window win) X (calc-wrapper X (or no-refresh X (calc-refresh))))) X (if (and (boundp 'overlay-arrow-position) X (eq overlay-arrow-position calc-trail-pointer)) X (setq overlay-arrow-position nil))) X trail) X) X X(defun calc-trail-here () X "Move the trail pointer to the current cursor line." X (interactive) X (if (eq major-mode 'calc-trail-mode) X (progn X (beginning-of-line) X (if (bobp) X (forward-line 1) X (if (eobp) X (forward-line -1))) X (if (or (bobp) (eobp)) X (setq overlay-arrow-position nil) ; trail is empty X (set-marker calc-trail-pointer (point) (current-buffer)) X (setq overlay-arrow-string (concat (buffer-substring (point) X (+ (point) 4)) X ">") X overlay-arrow-position calc-trail-pointer) X (forward-char 4) X (let ((win (get-buffer-window (current-buffer)))) X (if win X (save-excursion X (forward-line (/ (window-height) 2)) X (forward-line (- 1 (window-height))) X (set-window-start win (point)) X (set-window-point win (+ calc-trail-pointer 4))))))) X (error "Not in Calc Trail buffer")) X) X X X X X;;;; The Undo list. X X(defun calc-record-undo (rec) X (or calc-executing-macro X (if (memq 'undo calc-command-flags) X (setq calc-undo-list (cons (cons rec (car calc-undo-list)) X (cdr calc-undo-list))) X (setq calc-undo-list (cons (list rec) calc-undo-list) X calc-redo-list nil) X (calc-set-command-flag 'undo))) X) X X X X;;; Arithmetic commands. X X(defun calc-binary-op (name func arg &optional ident unary) X (if (null arg) X (calc-enter-result 2 name (cons func (calc-top-list-n 2))) X (calc-extensions) X (calc-binary-op-fancy name func arg ident unary)) X) X X(defun calc-unary-op (name func arg) X (if (null arg) X (calc-enter-result 1 name (list func (calc-top-n 1))) X (calc-extensions) X (calc-unary-op-fancy name func arg)) X) X X X(defun calc-plus (arg) X "Add the top two elements of the Calculator stack." X (interactive "P") X (calc-slow-wrapper X (calc-binary-op "+" 'calcFunc-add arg 0)) X) X X(defun calc-minus (arg) X "Subtract the top two elements of the Calculator stack." X (interactive "P") X (calc-slow-wrapper X (calc-binary-op "-" 'calcFunc-sub arg 0 'calcFunc-neg)) X) X X(defun calc-times (arg) X "Multiply the top two elements of the Calculator stack." X (interactive "P") X (calc-slow-wrapper X (calc-binary-op "*" 'calcFunc-mul arg 1)) X) X X(defun calc-divide (arg) X "Divide the top two elements of the Calculator stack." X (interactive "P") X (calc-slow-wrapper X (calc-binary-op "/" 'calcFunc-div arg 0 'calcFunc-inv)) X) X X(defun calc-power (arg) X "Compute y^x for the top two elements of the Calculator stack." X (interactive "P") X (calc-slow-wrapper X (calc-binary-op "^" 'calcFunc-pow arg)) X) X X(defun calc-mod (arg) X "Compute the modulo of the top two elements of the Calculator stack." X (interactive "P") X (calc-slow-wrapper X (calc-binary-op "%" 'calcFunc-mod arg)) X) X X(defun calc-inv (arg) X "Invert the number or square matrix on the top of the stack." X (interactive "P") X (calc-slow-wrapper X (calc-unary-op "inv" 'calcFunc-inv arg)) X) X X(defun calc-change-sign (arg) X "Change the sign of the top element of the Calculator stack." X (interactive "P") X (calc-wrapper X (calc-unary-op "chs" 'calcFunc-neg arg)) X) X X X X;;; Stack management commands. X X(defun calc-enter (n) X "Duplicate the top N elements of the Calculator stack. XWith a negative argument -N, duplicate the Nth element of the stack." X (interactive "p") X (calc-wrapper X (cond ((< n 0) X (calc-push (calc-top (- n)))) X ((= n 0) X (calc-push-list (calc-top-list (calc-stack-size)))) X (t X (calc-push-list (calc-top-list n))))) X) X X(defun calc-over (n) X "Duplicate the Nth element of the Calculator stack. XWith a negative argument -N, duplicate the top N elements of the stack." X (interactive "P") X (if n X (calc-enter (- (prefix-numeric-value n))) X (calc-enter -2)) X) X X(defun calc-pop (n) X "Pop (and discard) the top N elements of the stack. XWith a negative argument -N, remove the Nth element from the stack." X (interactive "P") X (calc-wrapper X (let* ((nn (prefix-numeric-value n)) X (top (and (null n) (calc-top 1)))) X (cond ((and (null n) X (eq (car-safe top) 'incomplete) X (> (length top) (if (eq (nth 1 top) 'intv) 3 2))) X (calc-pop-push 1 (let ((tt (copy-sequence top))) X (setcdr (nthcdr (- (length tt) 2) tt) nil) X tt))) X ((< nn 0) X (calc-pop-stack 1 (- nn))) X ((= nn 0) X (calc-pop-stack (calc-stack-size))) X (t X (calc-pop-stack nn))))) X) X X(defun calc-roll-down (n) X "Exchange the top two elements of the Calculator stack. XWith a numeric prefix, roll down the top N elements." X (interactive "P") X (calc-wrapper X (let ((nn (prefix-numeric-value n))) X (cond ((null n) X (calc-roll-down-stack 2)) X ((> nn 0) X (calc-roll-down-stack nn)) X ((= nn 0) X (calc-pop-push-list (calc-stack-size) X (reverse X (calc-top-list (calc-stack-size))))) X (t X (calc-roll-down-stack (calc-stack-size) (- nn)))))) X) X X(defun calc-roll-up (n) X "Roll up the top three elements of the Calculator stack. XWith a numeric prefix, roll up the top N elements." X (interactive "P") X (calc-wrapper X (let ((nn (prefix-numeric-value n))) X (cond ((null n) X (calc-roll-up-stack 3)) X ((> nn 0) X (calc-roll-up-stack nn)) X ((= nn 0) X (calc-pop-push-list (calc-stack-size) X (reverse X (calc-top-list (calc-stack-size))))) X (t X (calc-roll-up-stack (calc-stack-size) (- nn)))))) X) X X X X X;;; Miscellaneous commands. X X(defun calc-precision (n) X "Display current float precision for Calculator, or set precision to N digits." X (interactive "NPrecision: ") X (calc-wrapper X (if (< (prefix-numeric-value n) 3) X (error "Precision must be at least 3 digits.") X (setq calc-internal-prec (prefix-numeric-value n)) X (calc-record calc-internal-prec "prec")) X (message "Floating-point precision is %d digits." calc-internal-prec)) X) X X X(defun calc-num-prefix-name (n) X (cond ((eq n '-) "- ") X ((equal n '(4)) "C-u ") X ((consp n) (format "%d " (car n))) X ((integerp n) (format "%d " n)) X (t "")) X) X X(defun calc-missing-key (n) X "This is a placeholder for a command which needs to be loaded from calc-ext. XWhen this key is used, calc-ext (the Calculator extensions module) will be Xloaded and the keystroke automatically re-typed." X (interactive "P") X (calc-extensions) X (if (keymapp (key-binding (char-to-string last-command-char))) X (message "%s%c-" (calc-num-prefix-name n) last-command-char)) X (setq unread-command-char last-command-char X prefix-arg n) X) X X(defun calc-why () X "Explain why the last result was unusual." X (interactive) X (if (not (eq this-command last-command)) X (setq calc-which-why calc-why)) X (if calc-which-why X (progn X (calc-explain-why (car calc-which-why)) X (setq calc-which-why (cdr calc-which-why))) X (if calc-why X (progn X (message "(No further explanations available)") X (setq calc-which-why calc-why)) X (message "No explanations available"))) X) X(setq calc-which-why nil) X X(defun calc-flush-caches () X "Clear all caches used internally by the Calculator, such as the values of Xpi and e. These values will be recomputed next time they are requested." X (interactive) X (calc-wrapper X (setq math-lud-cache nil X math-log2-cache nil X math-max-digits-cache nil X math-integral-cache nil X math-units-table nil) X (mapcar (function (lambda (x) (set x -100))) math-cache-list) X (message "All internal calculator caches have been reset.")) X) X(setq math-cache-list nil) X X X X;;;; Reading an expression in algebraic form. X X(defun calc-algebraic-entry () X "Read an algebraic expression (e.g., 1+2*3) and push the result on the stack." X (interactive) X (calc-wrapper X (calc-alg-entry)) X) X X(defun calc-auto-alg-entry () X "Begin entering an algebraic expression with a '$' or '\"' character." X (interactive) X (calc-wrapper X (calc-alg-entry (char-to-string last-command-char))) X) X X(defun calc-alg-entry (&optional initial prompt) X (let* ((calc-dollar-values (mapcar 'car-safe X (nthcdr calc-stack-top calc-stack))) X (calc-dollar-used 0) X (alg-exp (calc-do-alg-entry initial prompt t))) X (let ((nvals (mapcar 'calc-normalize alg-exp))) X (while alg-exp X (calc-record (car alg-exp) "alg'") X (calc-pop-push-record calc-dollar-used "" (car nvals)) X (setq alg-exp (cdr alg-exp) X nvals (cdr nvals) X calc-dollar-used 0))) X (calc-handle-whys)) X) X X(defun calc-do-alg-entry (&optional initial prompt no-normalize) X (let* ((alg-exp 'error) X (alg (read-from-minibuffer (or prompt "Algebraic: ") X (or initial "") X calc-alg-ent-map nil))) X (if (eq alg-exp 'error) X (if (eq (car (setq alg-exp (math-read-exprs alg))) X 'error) X (error "Error: %s" (or (nth 2 exp) "Bad format")))) X (or no-normalize X (setq alg-exp (mapcar 'calc-normalize alg-exp))) X alg-exp) X) X X(defvar calc-alg-ent-map nil "Keymap for use by the calc-algebraic-entry command.") X(if calc-alg-ent-map X () X (setq calc-alg-ent-map (copy-keymap minibuffer-local-map)) X (define-key calc-alg-ent-map "'" 'calcAlg-previous) X (define-key calc-alg-ent-map "\ep" 'calcAlg-plus-minus) X (define-key calc-alg-ent-map "\em" 'calcAlg-mod) X (define-key calc-alg-ent-map "\C-m" 'calcAlg-enter) X (define-key calc-alg-ent-map "\C-j" 'calcAlg-enter) X) X X(defun calcAlg-plus-minus () X (interactive) X (if (calc-minibuffer-contains ".* \\'") X (insert "+/- ") X (insert " +/- ")) X) X X(defun calcAlg-mod () X (interactive) X (if (not (calc-minibuffer-contains ".* \\'")) X (insert " ")) X (if (calc-minibuffer-contains ".* mod +\\'") X (if calc-previous-modulo X (insert (math-format-flat-expr calc-previous-modulo 0)) X (beep)) X (insert "mod ")) X) X X(defun calcAlg-previous () X (interactive) X (if (calc-minibuffer-contains "\\`\\'") X (if calc-previous-alg-entry X (insert calc-previous-alg-entry) X (beep)) X (insert "'")) X) X X(defun calcAlg-enter () X (interactive) X (let ((exp (and (> (buffer-size) 0) X (math-read-exprs (buffer-string))))) X (if (eq (car-safe exp) 'error) X (progn X (goto-char (point-min)) X (forward-char (nth 1 exp)) X (beep) X (calc-temp-minibuffer-message X (concat " [" (or (nth 2 exp) "Error") "]")) X (setq unread-command-char -1)) X (setq alg-exp (if (calc-minibuffer-contains "\\` *\\[ *\\'") X '((incomplete vec)) X exp) X calc-previous-alg-entry (buffer-string)) X (exit-minibuffer))) X) X X X X;;;; Reading a number using the minibuffer. X X(defun calcDigit-start () X "Begin digit entry in the Calculator." X (interactive) X (calc-wrapper X (if calc-algebraic-mode X (cond ((eq last-command-char ?e) (calc-alg-entry "1e")) X ((eq last-command-char ?#) (calc-alg-entry X (format "%d#" calc-number-radix))) X ((eq last-command-char ?_) (calc-alg-entry "-")) X ((eq last-command-char ?@) (calc-alg-entry "0@ ")) X (t (calc-alg-entry (char-to-string last-command-char)))) X (let ((calc-digit-value 'yow) X (calc-prev-char nil) X (calc-prev-prev-char nil)) X (setq unread-command-char last-command-char) X (let ((str (read-from-minibuffer "Calc: " "" X calc-digit-map))) X (if (eq calc-digit-value 'yow) X (setq calc-digit-value (math-read-number str)))) X (if (stringp calc-digit-value) X (calc-alg-entry calc-digit-value) X (if calc-digit-value X (calc-push (calc-record (calc-normalize calc-digit-value))))) X (if (eq calc-prev-char 'dots) X (progn X (calc-extensions) X (calc-dots)))))) X) X X(defun calcDigit-nondigit () X (interactive) X (setq calc-digit-value (math-read-number (buffer-string))) X (if (and (null calc-digit-value) (> (buffer-size) 0)) X (progn X (beep) X (calc-temp-minibuffer-message " [Bad format]")) X (or (memq last-command-char '(32 10 13)) X (setq prefix-arg current-prefix-arg X unread-command-char last-command-char)) X (exit-minibuffer)) X) X X(defun calcDigit-algebraic () X (interactive) X (if (calc-minibuffer-contains ".*[@oh] *[^'m ]+[^'m]*\\'") X (calcDigit-key) X (setq calc-digit-value (buffer-string)) X (exit-minibuffer)) X) X X(defun calc-minibuffer-contains (rex) X (save-excursion X (goto-char (point-min)) X (looking-at rex)) X) X X(defun calcDigit-key () X (interactive) X (goto-char (point-max)) X (if (or (and (memq last-command-char '(?+ ?-)) X (> (buffer-size) 0) X (/= (preceding-char) ?e)) X (and (memq last-command-char '(?m ?s)) X (not (calc-minibuffer-contains "[-+]?[0-9]+\\.?0*[@oh].*")) X (not (calc-minibuffer-contains "[-+]?\\(1[1-9]\\|[2-9][0-9]\\)#.*")))) X (calcDigit-nondigit) X (if (calc-minibuffer-contains "\\([-+]?\\|.* \\)\\'") X (cond ((memq last-command-char '(?. ?@)) (insert "0")) X ((and (memq last-command-char '(?o ?h ?m)) X (not (calc-minibuffer-contains ".*#.*"))) (insert "0")) X ((memq last-command-char '(?: ?e)) (insert "1")) X ((eq last-command-char ?#) X (insert (int-to-string calc-number-radix))))) X (if (and (calc-minibuffer-contains "\\([-+]?[0-9]+#\\|[^:]*:\\)\\'") X (eq last-command-char ?:)) X (insert "1")) X (if (or (and (memq last-command-char '(?e ?h ?o ?m ?s ?p)) X (calc-minibuffer-contains ".*#.*")) X (and (eq last-command-char ?n) X (calc-minibuffer-contains "[-+]?\\(2[4-9]\\|[3-9][0-9]\\)#.*"))) X (setq last-command-char (upcase last-command-char))) X (cond X ((memq last-command-char '(?_ ?n)) X (goto-char (point-min)) X (if (and (search-forward " +/- " nil t) X (not (search-forward "e" nil t))) X (beep) X (and (not (calc-minibuffer-contains ".*#.*")) X (search-forward "e" nil t)) X (if (looking-at "+") X (delete-char 1)) X (if (looking-at "-") X (delete-char 1) X (insert "-"))) X (goto-char (point-max))) X ((eq last-command-char ?p) X (if (or (calc-minibuffer-contains ".*\\+/-.*") X (calc-minibuffer-contains ".*mod.*") X (calc-minibuffer-contains ".*#.*") X (calc-minibuffer-contains ".*[-+e:]\\'")) X (beep) X (if (not (calc-minibuffer-contains ".* \\'")) X (insert " ")) X (insert "+/- "))) X ((and (eq last-command-char ?M) X (not (calc-minibuffer-contains X "[-+]?\\(2[3-9]\\|[3-9][0-9]\\)#.*"))) X (if (or (calc-minibuffer-contains ".*\\+/-.*") X (calc-minibuffer-contains ".*mod *[^ ]+") X (calc-minibuffer-contains ".*[-+e:]\\'")) X (beep) X (if (calc-minibuffer-contains ".*mod \\'") X (if calc-previous-modulo X (insert (math-format-flat-expr calc-previous-modulo 0)) X (beep)) X (if (not (calc-minibuffer-contains ".* \\'")) X (insert " ")) X (insert "mod ")))) X (t X (insert (char-to-string last-command-char)) X (if (or (and (calc-minibuffer-contains "[-+]?\\(.*\\+/- *\\|.*mod *\\)?\\([0-9][0-9]?\\)#[0-9a-zA-Z]*\\(:[0-9a-zA-Z]*\\)?\\(:[0-9a-zA-Z]*\\)?\\'") X (let ((radix (string-to-int X (buffer-substring X (match-beginning 2) (match-end 2))))) X (and (>= radix 2) X (<= radix 36) X (or (memq last-command-char '(?# ?:)) X (let ((dig (math-read-radix-digit X (upcase last-command-char)))) X (and dig X (< dig radix))))))) X (save-excursion X (goto-char (point-min)) X (looking-at X "[-+]?\\(.*\\+/- *\\|.*mod *\\)?\\([0-9]+\\.?0*[@oh] *\\)?\\([0-9]+\\.?0*['m] *\\)?[0-9]*\\(\\.?[0-9]*\\(e[-+]?[0-9]*\\)?\\|[0-9]:\\([0-9]+:\\)?[0-9]*\\)?[\"s]?\\'"))) X (if (and (memq last-command-char '(?@ ?o ?h ?\' ?m)) X (string-match " " calc-hms-format)) X (insert " ")) X (if (and (eq this-command last-command) X (eq last-command-char ?.)) X (if (eq calc-prev-char ?.) X (progn X (delete-backward-char 1) X (if (calc-minibuffer-contains ".*\\.\\'") X (delete-backward-char 1)) X (setq calc-prev-char 'dots X last-command-char 32) X (if calc-prev-prev-char X (calcDigit-nondigit) X (setq calc-digit-value nil) X (exit-minibuffer))) X ;; just ignore extra decimal point, anticipating ".." X (delete-backward-char 1)) X (delete-backward-char 1) X (beep) X (calc-temp-minibuffer-message " [Bad format]")))))) X (setq calc-prev-prev-char calc-prev-char X calc-prev-char last-command-char) X) X X(defun calcDigit-letter () X (interactive) X (if (calc-minibuffer-contains "[-+]?\\(1[1-9]\\|[2-9][0-9]\\)#.*") X (progn X (setq last-command-char (upcase last-command-char)) X (calcDigit-key)) X (calcDigit-nondigit)) X) X X(defun calcDigit-backspace () X (interactive) X (goto-char (point-max)) X (cond ((calc-minibuffer-contains ".* \\+/- \\'") X (backward-delete-char 5)) X ((calc-minibuffer-contains ".* mod \\'") X (backward-delete-char 5)) X ((calc-minibuffer-contains ".* \\'") X (backward-delete-char 2)) X (t (backward-delete-char 1))) X (if (= (buffer-size) 0) X (progn X (setq last-command-char 10) X (calcDigit-nondigit))) X) X X(defun calc-temp-minibuffer-message (m) X "A Lisp version of temp_minibuffer_message from minibuf.c." X (let ((savemax (point-max))) X (save-excursion X (goto-char (point-max)) X (insert m)) X (let ((inhibit-quit t)) X (sit-for 2) X (delete-region savemax (point-max)) X (if quit-flag X (setq quit-flag nil X unread-command-char 7)))) X) X X X X X X X X;;;; Arithmetic routines. X;;; X;;; An object as manipulated by one of these routines may take any of the X;;; following forms: X;;; X;;; integer An integer. For normalized numbers, this format X;;; is used only for -999999 ... 999999. X;;; X;;; (bigpos N0 N1 N2 ...) A big positive integer, N0 + N1*1000 + N2*10^6 ... X;;; (bigneg N0 N1 N2 ...) A big negative integer, - N0 - N1*1000 ... X;;; Each digit N is in the range 0 ... 999. X;;; Normalized, always at least three N present, X;;; and the most significant N is nonzero. X;;; X;;; (frac NUM DEN) A fraction. NUM and DEN are small or big integers. X;;; Normalized, DEN > 1. X;;; X;;; (float NUM EXP) A floating-point number, NUM * 10^EXP; X;;; NUM is a small or big integer, EXP is a small int. X;;; Normalized, NUM is not a multiple of 10, and X;;; abs(NUM) < 10^calc-internal-prec. X;;; Normalized zero is stored as (float 0 0). X;;; X;;; (cplx REAL IMAG) A complex number; REAL and IMAG are any of above. X;;; Normalized, IMAG is nonzero. X;;; X;;; (polar R THETA) Polar complex number. Normalized, R > 0 and THETA X;;; is neither zero nor 180 degrees (pi radians). X;;; X;;; (vec A B C ...) Vector of objects A, B, C, ... A matrix is a X;;; vector of vectors. X;;; X;;; (hms H M S) Angle in hours-minutes-seconds form. All three X;;; components have the same sign; H and M must be X;;; numerically integers; M and S are expected to X;;; lie in the range [0,60). X;;; X;;; (sdev X SIGMA) Error form, X +/- SIGMA. When normalized, X;;; SIGMA > 0. X and SIGMA are any real numbers, X;;; or symbolic expressions which are assumed real. X;;; X;;; (intv MASK LO HI) Interval form. MASK is 0=(), 1=(], 2=[), or 3=[]. X;;; LO and HI are any real numbers, or symbolic X;;; expressions which are assumed real, and LO < HI. X;;; For [LO..HI], if LO = HI normalization produces LO, X;;; and if LO > HI normalization produces [LO..LO). X;;; For other intervals, if LO > HI normalization X;;; sets HI equal to LO. X;;; X;;; (mod N M) Number modulo M. When normalized, 0 <= N < M. X;;; N and M are real numbers. X;;; X;;; (var V S) Symbolic variable. V is a Lisp symbol which X;;; represents the variable's visible name. S is X;;; the symbol which actually stores the variable's X;;; value: (var pi var-pi). X;;; X;;; In general, combining rational numbers in a calculation always produces X;;; a rational result, but if either argument is a float, result is a float. X X;;; In the following comments, [x y z] means result is x, args must be y, z, X;;; respectively, where the code letters are: X;;; X;;; O Normalized object (vector or number) X;;; V Normalized vector X;;; N Normalized number of any type X;;; N Normalized complex number X;;; R Normalized real number (float or rational) X;;; F Normalized floating-point number X;;; T Normalized rational number X;;; I Normalized integer X;;; B Normalized big integer X;;; S Normalized small integer X;;; D Digit (small integer, 0..999) X;;; L Normalized bignum digit list (without "bigpos" or "bigneg" symbol) X;;; or normalized vector element list (without "vec") X;;; P Predicate (truth value) X;;; X Any Lisp object X;;; Z "nil" X;;; X;;; Lower-case letters signify possibly un-normalized values. X;;; "L.D" means a cons of an L and a D. X;;; [N N; n n] means result will be normalized if argument is. X;;; Also, [Public] marks routines intended to be called from outside. X;;; [This notation has been neglected in many recent routines.] X X;;; Reduce an object to canonical (normalized) form. [O o; Z Z] [Public] X(defun math-normalize (a) X (cond X ((not (consp a)) X (if (integerp a) X (if (or (>= a 1000000) (<= a -1000000)) X (math-bignum a) X a) X a)) X ((eq (car a) 'bigpos) X (if (eq (nth (1- (length a)) a) 0) X (let* ((last (setq a (copy-sequence a))) (digs a)) X (while (setq digs (cdr digs)) X (or (eq (car digs) 0) (setq last digs))) X (setcdr last nil))) X (if (cdr (cdr (cdr a))) X a X (cond X ((cdr (cdr a)) (+ (nth 1 a) (* (nth 2 a) 1000))) X ((cdr a) (nth 1 a)) X (t 0)))) X ((eq (car a) 'bigneg) X (if (eq (nth (1- (length a)) a) 0) X (let* ((last (setq a (copy-sequence a))) (digs a)) X (while (setq digs (cdr digs)) X (or (eq (car digs) 0) (setq last digs))) X (setcdr last nil))) X (if (cdr (cdr (cdr a))) X a X (cond X ((cdr (cdr a)) (- (+ (nth 1 a) (* (nth 2 a) 1000)))) X ((cdr a) (- (nth 1 a))) X (t 0)))) X ((eq (car a) 'frac) X (math-make-frac (math-normalize (nth 1 a)) X (math-normalize (nth 2 a)))) X ((eq (car a) 'float) X (math-make-float (math-normalize (nth 1 a)) (nth 2 a))) X ((eq (car a) 'cplx) X (let ((real (math-normalize (nth 1 a))) X (imag (math-normalize (nth 2 a)))) X (if (math-zerop imag) real (list 'cplx real imag)))) X ((eq (car a) 'polar) X (calc-extensions) X (math-normalize-polar a)) X ((eq (car a) 'hms) X (calc-extensions) X (math-normalize-hms a)) X ((eq (car a) 'mod) X (calc-extensions) X (math-normalize-mod a)) X ((eq (car a) 'sdev) X (calc-extensions) X (math-make-sdev (math-normalize (nth 1 a)) X (math-normalize (nth 2 a)))) X ((eq (car a) 'intv) X (calc-extensions) X (math-make-intv (nth 1 a) X (math-normalize (nth 2 a)) X (math-normalize (nth 3 a)))) X ((eq (car a) 'vec) X (cons 'vec (mapcar 'math-normalize (cdr a)))) X ((memq (car a) '(quote special-const)) X (math-normalize (nth 1 a))) X ((eq (car a) 'var) X a) X ((or (integerp (car a)) (and (consp (car a)) X (not (eq (car (car a)) 'lambda)))) X (if (null (cdr a)) X (math-normalize (car a)) X (error "Can't use multi-valued function in an expression"))) X ((eq (car a) 'calcFunc-if) X (calc-extensions) X (math-normalize-logical-op a)) X (t X (let ((args (mapcar 'math-normalize (cdr a)))) X (or (and calc-simplify-mode X (symbolp (car a)) X (or (eq calc-simplify-mode 'none) X (and (eq calc-simplify-mode 'num) X (let ((aptr args)) X (while (and aptr (or (math-scalarp (car aptr)) X (eq (car-safe (car aptr)) X 'mod))) X (setq aptr (cdr aptr))) X aptr))) X (cons (car a) args)) X (condition-case err X (let ((func (assq (car a) '( ( + . math-add ) X ( - . math-sub ) X ( * . math-mul ) X ( / . math-div ) X ( % . math-mod ) X ( ^ . math-pow ) X ( neg . math-neg ) X ( | . math-concat ) )))) X (if func X (apply (cdr func) args) X (and (or (consp (car a)) X (fboundp (car a)) X (and (not calc-extensions-loaded) X (calc-extensions) X (fboundp (car a)))) X (apply (car a) args)))) X (wrong-number-of-arguments X (calc-record-why "Wrong number of arguments") nil) X (wrong-type-argument X (or calc-next-why (calc-record-why "Wrong type of argument")) X nil) X (args-out-of-range X (calc-record-why "Argument out of range") nil) X (inexact-result X (calc-record-why "No exact representation for result") nil)) X (if (consp (car a)) X (math-dimension-error) X (cons (car a) args)))))) X) X X(defmacro math-with-extra-prec (delta &rest body) X (` (math-normalize X (let ((calc-internal-prec (+ calc-internal-prec (, delta)))) X (,@ body)))) X) X(put 'math-with-extra-prec 'lisp-indent-hook 1) X X;;; Define "inexact-result" as an e-lisp error symbol. X(put 'inexact-result 'error-conditions '(error inexact-result calc-error)) X(put 'inexact-result 'error-message "Calc internal error (inexact-result)") X X;;; Normalize a bignum digit list by trimming high-end zeros. [L l] X(defun math-norm-bignum (a) X (let ((digs a) (last nil)) X (while digs X (or (eq (car digs) 0) (setq last digs)) X (setq digs (cdr digs))) X (and last X (progn X (setcdr last nil) X a))) X) X X X;;; Concatenate two vectors, or a vector and an object. [V O O] [Public] X(defun math-concat (v1 v2) X (if (stringp v1) X (concat v1 v2) X (calc-extensions) X (if (and (math-objvecp v1) (math-objvecp v2)) X (append (if (and (math-vectorp v1) X (or (math-matrixp v1) X (not (math-matrixp v2)))) X v1 X (list 'vec v1)) X (if (and (math-vectorp v2) X (or (math-matrixp v2) X (not (math-matrixp v1)))) X (cdr v2) X (list v2))) X (list '| v1 v2))) X) X(defun calcFunc-vconcat (a b) X (math-normalize (list '| a b)) X) X X X;;; True if A is zero. Works for un-normalized values. [P n] [Public] X(defun math-zerop (a) X (if (consp a) X (cond ((memq (car a) '(bigpos bigneg)) X (while (eq (car (setq a (cdr a))) 0)) X (null a)) X ((memq (car a) '(frac float polar mod)) X (math-zerop (nth 1 a))) X ((eq (car a) 'cplx) X (and (math-zerop (nth 1 a)) (math-zerop (nth 2 a)))) X ((eq (car a) 'hms) X (and (math-zerop (nth 1 a)) X (math-zerop (nth 2 a)) X (math-zerop (nth 3 a))))) X (eq a 0)) X) X;;; Faster in-line version zerop, normalized values only. X(defmacro Math-zerop (a) ; [P N] X (` (if (consp (, a)) X (and (not (memq (car (, a)) '(bigpos bigneg))) X (if (eq (car (, a)) 'float) X (eq (nth 1 (, a)) 0) X (math-zerop (, a)))) X (eq (, a) 0))) X) X X(defun math-zerop-bignum (a) X (and (eq (car a) 0) X (progn X (while (eq (car (setq a (cdr a))) 0)) X (null a))) X) X X(defmacro Math-natnum-lessp (a b) X (` (if (consp (, a)) X (and (consp (, b)) X (= (math-compare-bignum (cdr (, a)) (cdr (, b))) -1)) X (or (consp (, b)) X (< (, a) (, b))))) X) X X(defmacro Math-integer-negp (a) X (` (if (consp (, a)) X (eq (car (, a)) 'bigneg) X (< (, a) 0))) X) X X(defmacro Math-integer-posp (a) X (` (if (consp (, a)) X (eq (car (, a)) 'bigpos) X (> (, a) 0))) X) X X;;; True if A is real and negative. [P n] [Public] X(defun math-negp (a) X (if (consp a) X (cond ((eq (car a) 'bigpos) nil) X ((eq (car a) 'bigneg) (cdr a)) X ((eq (car a) 'frac) X (if (Math-integer-negp (nth 2 a)) X (Math-integer-posp (nth 1 a)) X (Math-integer-negp (nth 1 a)))) X ((eq (car a) 'float) X (Math-integer-negp (nth 1 a))) X ((eq (car a) 'hms) X (if (math-zerop (nth 1 a)) X (if (math-zerop (nth 2 a)) X (math-negp (nth 3 a)) X (math-negp (nth 2 a))) X (math-negp (nth 1 a)))) X ((eq (car a) 'intv) X (or (math-negp (nth 3 a)) X (and (math-zerop (nth 3 a)) X (memq (nth 1 a) '(0 2)))))) X (< a 0)) X) X(defmacro Math-negp (a) X (` (if (consp (, a)) X (or (eq (car (, a)) 'bigneg) X (and (not (eq (car (, a)) 'bigpos)) X (if (memq (car (, a)) '(frac float)) X (Math-integer-negp (nth 1 (, a))) X (math-negp (, a))))) X (< (, a) 0))) X) X X;;; True if A is a negative number or an expression the starts with '-'. X(defun math-looks-negp (a) ; [P x] [Public] X (or (Math-negp a) X (eq (car-safe a) 'neg) X (and (memq (car-safe a) '(* /)) X (or (math-looks-negp (nth 1 a)) X (math-looks-negp (nth 2 a))))) X) X(defmacro Math-looks-negp (a) ; [P x] [Public] X (` (or (Math-negp (, a)) X (and (consp (, a)) (or (eq (car (, a)) 'neg) X (and (memq (car (, a)) '(* /)) X (or (math-looks-negp (nth 1 (, a))) X (math-looks-negp (nth 2 (, a))))))))) X) X X;;; True if A is real and positive. [P n] [Public] X(defun math-posp (a) X (if (consp a) X (cond ((eq (car a) 'bigpos) (cdr a)) X ((eq (car a) 'bigneg) nil) X ((eq (car a) 'frac) X (if (Math-integer-negp (nth 2 a)) X (Math-integer-negp (nth 1 a)) X (Math-integer-posp (nth 1 a)))) X ((eq (car a) 'float) X (Math-integer-posp (nth 1 a))) X ((eq (car a) 'hms) X (if (math-zerop (nth 1 a)) X (if (math-zerop (nth 2 a)) X (math-posp (nth 3 a)) X (math-posp (nth 2 a))) X (math-posp (nth 1 a)))) X ((eq (car a) 'mod) X (not (math-zerop (nth 1 a)))) X ((eq (car a) 'intv) X (or (math-posp (nth 2 a)) X (and (math-zerop (nth 2 a)) X (memq (nth 1 a) '(0 1)))))) X (> a 0)) X) X(defmacro Math-posp (a) X (` (if (consp (, a)) X (or (eq (car (, a)) 'bigpos) X (and (not (eq (car (, a)) 'bigneg)) X (if (memq (car (, a)) '(frac float)) X (Math-integer-posp (nth 1 (, a))) X (math-posp (, a))))) X (> (, a) 0))) X) X X;;; True if A is a small or big integer. [P x] [Public] X(defun math-integerp (a) X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg))) X) X(defmacro Math-integerp (a) X (` (or (not (consp (, a))) X (memq (car (, a)) '(bigpos bigneg)))) X) X X(fset 'math-fixnump (symbol-function 'integerp)) X(fset 'math-fixnatnump (symbol-function 'natnump)) X X;;; True if A is (numerically) a non-negative integer. [P N] [Public] X(defun math-natnump (a) X (or (natnump a) X (eq (car-safe a) 'bigpos)) X) X(defmacro Math-natnump (a) X (` (if (consp (, a)) X (eq (car (, a)) 'bigpos) X (>= (, a) 0))) X) X X;;; True if A is a rational (or integer). [P x] [Public] X(defun math-ratp (a) X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac))) X) X(defmacro Math-ratp (a) X (` (or (not (consp (, a))) X (memq (car (, a)) '(bigpos bigneg frac)))) X) X X;;; True if A is a real (or rational). [P x] [Public] X(defun math-realp (a) X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac float))) X) X(defmacro Math-realp (a) X (` (or (not (consp (, a))) X (memq (car (, a)) '(bigpos bigneg frac float)))) X) X X;;; True if A is a real or HMS form. [P x] [Public] X(defun math-anglep (a) X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac float hms))) X) X(defmacro Math-anglep (a) X (` (or (not (consp (, a))) X (memq (car (, a)) '(bigpos bigneg frac float hms)))) X) X X;;; True if A is a floating-point real or complex number. [P x] [Public] X(defun math-floatp (a) X (or (eq (car-safe a) 'float) X (and (memq (car-safe a) '(cplx polar mod sdev intv)) X (or (math-floatp (nth 1 a)) X (math-floatp (nth 2 a)) X (and (eq (car a) 'intv) (math-floatp (nth 3 a)))))) X) X X;;; True if A is a number of any kind. [P x] [Public] X(defun math-numberp (a) X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac float cplx polar))) X) X(defmacro Math-numberp (a) X (` (or (not (consp (, a))) X (memq (car (, a)) '(bigpos bigneg frac float cplx polar)))) X) X X;;; True if A is a complex number or angle. [P x] [Public] X(defun math-scalarp (a) X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac float cplx polar hms))) X) X(defmacro Math-scalarp (a) X (` (or (not (consp (, a))) X (memq (car (, a)) '(bigpos bigneg frac float cplx polar hms)))) X) X X;;; True if A is a vector. [P x] [Public] X(defun math-vectorp (a) X (eq (car-safe a) 'vec) X) X(defmacro Math-vectorp (a) X (` (and (consp (, a)) (eq (car (, a)) 'vec))) X) X X;;; True if A is a number or a vector. [P x] [Public] X(defun math-numvecp (a) X (or (Math-numberp a) X (Math-vectorp a)) X) X X;;; True if A is numerically (but not literally) an integer. [P x] [Public] X(defun math-messy-integerp (a) X (cond X ((eq (car-safe a) 'float) (>= (nth 2 a) 0)) X ((eq (car-safe a) 'frac) (Math-integerp (math-normalize a)))) X) X(defmacro Math-messy-integerp (a) X (` (and (consp (, a)) X (eq (car (, a)) 'float) X (>= (nth 2 (, a)) 0))) X) X X;;; True if A is any scalar data object. [P x] X(defun math-objectp (a) ; [Public] X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac float cplx X polar hms sdev intv mod))) X) X(defmacro Math-objectp (a) ; [Public] X (` (or (not (consp (, a))) X (memq (car (, a)) X '(bigpos bigneg frac float cplx polar hms sdev intv mod)))) X) X X;;; True if A is any vector or scalar data object. [P x] X(defun math-objvecp (a) ; [Public] X (or (integerp a) X (memq (car-safe a) '(bigpos bigneg frac float cplx polar X hms sdev intv mod vec incomplete))) X) X(defmacro Math-objvecp (a) ; [Public] X (` (or (not (consp (, a))) X (memq (car (, a)) X '(bigpos bigneg frac float cplx polar hms sdev intv mod vec)))) X) X X X;;; True if A is an even integer. [P R R] [Public] X(defun math-evenp (a) X (if (consp a) X (and (memq (car a) '(bigpos bigneg)) X (= (% (nth 1 a) 2) 0)) X (= (% a 2) 0)) X) X X;;; Compute A / 2, for small or big integer A. [I i] X;;; If A is negative, type of truncation is undefined. X(defun math-div2 (a) X (if (consp a) X (if (cdr a) X (math-normalize (cons (car a) (math-div2-bignum (cdr a)))) X 0) X (/ a 2)) X) X X(defun math-div2-bignum (a) ; [l l] X (cond X ((null (cdr a)) (list (/ (car a) 2))) X (t (cons (+ (/ (car a) 2) (* (% (nth 1 a) 2) 500)) X (math-div2-bignum (cdr a))))) X) X X X;;; Verify that A is a complete object and return A. [x x] [Public] X(defun math-check-complete (a) X (cond ((integerp a) a) X ((eq (car-safe a) 'incomplete) X (cond ((memq (nth 1 a) '(cplx polar)) X (error "Complex number is incomplete")) X ((eq (nth 1 a) 'vec) X (error "Vector is incomplete")) X ((eq (nth 1 a) 'intv) X (error "Interval form is incomplete")) X (t (error "Object is incomplete")))) X ((consp a) a) X (t (error "Invalid data object encountered"))) X) X X;;; Reject an argument to a calculator function. [Public] X(defun math-reject-arg (&optional a p) X (calc-record-why p a) X (signal 'wrong-type-argument (and a (if p (list p a) (list a)))) X) X X X;;; Coerce A to be an integer (by truncation toward zero). [I N] [Public] X(defun math-trunc (a) X (cond ((Math-integerp a) a) X ((Math-looks-negp a) X (math-neg (math-trunc (math-neg a)))) X ((eq (car a) 'float) (math-scale-int (nth 1 a) (nth 2 a))) X ((eq (car a) 'frac) (math-quotient (nth 1 a) (nth 2 a))) X (t (calc-extensions) X (math-trunc-fancy a))) X) X(fset 'calcFunc-trunc (symbol-function 'math-trunc)) X X;;; Coerce A to be an integer (by truncation toward minus infinity). [I N] X(defun math-floor (a) ; [Public] X (cond ((Math-integerp a) a) X ((Math-messy-integerp a) (math-trunc a)) X ((Math-realp a) X (if (Math-negp a) X (math-add (math-trunc a) -1) X (math-trunc a))) X (t (calc-extensions) X (math-floor-fancy a))) X) X(fset 'calcFunc-floor (symbol-function 'math-floor)) X X X;;; Coerce integer A to be a bignum. [B S] X(defun math-bignum (a) X (if (>= a 0) X (cons 'bigpos (math-bignum-big a)) X (cons 'bigneg (math-bignum-big (- a)))) X) X X(defun math-bignum-big (a) ; [L s] X (if (= a 0) X nil X (cons (% a 1000) (math-bignum-big (/ a 1000)))) X) X X X;;; Build a normalized fraction. [R I I] X;;; (This could probably be implemented more efficiently than using the X;;; the plain gcd algorithm.) X(defun math-make-frac (num den) X (if (Math-integer-negp den) X (setq num (math-neg num) X den (math-neg den))) X (let ((gcd (math-gcd num den))) X (if (eq gcd 1) X (if (eq den 1) X num X (list 'frac num den)) X (if (equal gcd den) X (math-quotient num gcd) X (list 'frac (math-quotient num gcd) (math-quotient den gcd))))) X) X X;;; Build a normalized floating-point number. [F I S] X(defun math-make-float (mant exp) X (if (eq mant 0) X '(float 0 0) X (let* ((ldiff (- calc-internal-prec (math-numdigs mant)))) X (if (< ldiff 0) X (setq mant (math-scale-rounding mant ldiff) X exp (- exp ldiff)))) X (if (consp mant) X (let ((digs (cdr mant))) X (if (= (% (car digs) 10) 0) X (progn X (while (= (car digs) 0) X (setq digs (cdr digs) X exp (+ exp 3))) X (while (= (% (car digs) 10) 0) X (setq digs (math-div10-bignum digs) X exp (1+ exp))) X (setq mant (math-normalize (cons (car mant) digs)))))) X (while (= (% mant 10) 0) X (setq mant (/ mant 10) X exp (1+ exp)))) X (list 'float mant exp)) X) X X(defun math-div10-bignum (a) ; [l l] X (cond X ((null (cdr a)) (list (/ (car a) 10))) X (t (cons (+ (/ (car a) 10) (* (% (nth 1 a) 10) 100)) X (math-div10-bignum (cdr a))))) X) X X;;; Coerce A to be a float. [F N; V V] [Public] X(defun math-float (a) X (cond ((Math-integerp a) (math-make-float a 0)) X ((eq (car a) 'frac) (math-div (math-float (nth 1 a)) (nth 2 a))) X ((eq (car a) 'float) a) X ((memq (car a) '(cplx polar vec hms sdev intv mod)) X (cons (car a) (mapcar 'math-float (cdr a)))) X (t (math-reject-arg a 'objectp))) X) X(fset 'calcFunc-float (symbol-function 'math-float)) X X X;;; Compute the negative of A. [O O; o o] [Public] X(defmacro Math-integer-neg (a) X (` (if (consp (, a)) X (if (eq (car (, a)) 'bigpos) X (cons 'bigneg (cdr (, a))) X (cons 'bigpos (cdr (, a)))) X (- (, a)))) X) X(defun math-neg (a) X (cond ((not (consp a)) (- a)) X ((eq (car a) 'bigpos) (cons 'bigneg (cdr a))) X ((eq (car a) 'bigneg) (cons 'bigpos (cdr a))) X ((memq (car a) '(frac float)) X (list (car a) (Math-integer-neg (nth 1 a)) (nth 2 a))) X ((memq (car a) '(cplx vec hms)) X (cons (car a) (mapcar 'math-neg (cdr a)))) X (t (math-neg-fancy a))) X) X(defun calcFunc-neg (a) X (math-normalize (list 'neg a)) X) X X X;;; Compute the number of decimal digits in integer A. [S I] X(defun math-numdigs (a) X (if (consp a) X (if (cdr a) X (let* ((len (1- (length a))) X (top (nth len a))) X (+ (* len 3) (cond ((>= top 100) 0) ((>= top 10) -1) (t -2)))) X 0) X (cond ((>= a 100) (+ (math-numdigs (/ a 1000)) 3)) X ((>= a 10) 2) X ((>= a 1) 1) X ((= a 0) 0) X ((> a -10) 1) X ((> a -100) 2) X (t (math-numdigs (- a))))) X) X X;;; Multiply (with truncation toward 0) the integer A by 10^N. [I i S] X(defun math-scale-int (a n) X (cond ((= n 0) a) X ((> n 0) (math-scale-left a n)) X (t (math-normalize (math-scale-right a (- n))))) X) X X(defun math-scale-left (a n) ; [I I S] X (if (= n 0) X a X (if (consp a) X (cons (car a) (math-scale-left-bignum (cdr a) n)) X (if (>= n 3) X (if (or (>= a 1000) (<= a -1000)) X (math-scale-left (math-bignum a) n) X (math-scale-left (* a 1000) (- n 3))) X (if (= n 2) X (if (or (>= a 10000) (<= a -10000)) X (math-scale-left (math-bignum a) 2) X (* a 100)) X (if (or (>= a 100000) (<= a -100000)) X (math-scale-left (math-bignum a) 1) X (* a 10)))))) X) X X(defun math-scale-left-bignum (a n) X (if (>= n 3) X (while (>= (setq a (cons 0 a) X n (- n 3)) 3))) X (if (> n 0) X (math-mul-bignum-digit a (if (= n 2) 100 10) 0) X a) X) X X(defun math-scale-right (a n) ; [i i S] X (if (= n 0) X a X (if (consp a) X (cons (car a) (math-scale-right-bignum (cdr a) n)) X (if (<= a 0) X (if (= a 0) X 0 X (- (math-scale-right (- a) n))) X (if (>= n 3) X (while (and (> (setq a (/ a 1000)) 0) X (>= (setq n (- n 3)) 3)))) X (if (= n 2) X (/ a 100) X (if (= n 1) X (/ a 10) X a))))) X) X X(defun math-scale-right-bignum (a n) ; [L L S; l l S] X (if (>= n 3) X (setq a (nthcdr (/ n 3) a) X n (% n 3))) X (if (> n 0) X (cdr (math-mul-bignum-digit a (if (= n 2) 10 100) 0)) X a) X) X X;;; Multiply (with rounding) the integer A by 10^N. [I i S] X(defun math-scale-rounding (a n) X (cond ((>= n 0) X (math-scale-left a n)) X ((consp a) X (math-normalize X (cons (car a) X (let ((val (if (< n -3) X (math-scale-right-bignum (cdr a) (- -3 n)) X (if (= n -2) X (math-mul-bignum-digit (cdr a) 10 0) X (if (= n -1) X (math-mul-bignum-digit (cdr a) 100 0) X (cdr a)))))) ; n = -3 X (if (and val (>= (car val) 500)) X (if (cdr val) X (if (eq (car (cdr val)) 999) X (math-add-bignum (cdr val) '(1)) X (cons (1+ (car (cdr val))) (cdr (cdr val)))) X '(1)) X (cdr val)))))) X (t X (if (< a 0) X (- (math-scale-rounding (- a) n)) X (if (= n -1) X (/ (+ a 5) 10) X (/ (+ (math-scale-right a (- -1 n)) 5) 10))))) X) X X X;;; Compute the sum of A and B. [O O O] [Public] X(defun math-add (a b) X (or X (and (not (or (consp a) (consp b))) X (progn X (setq a (+ a b)) X (if (or (<= a -1000000) (>= a 1000000)) X (math-bignum a) X a))) X (and (Math-zerop a) (not (eq (car-safe a) 'mod)) X (if (and (math-floatp a) (Math-ratp b)) (math-float b) b)) X (and (Math-zerop b) (not (eq (car-safe b) 'mod)) X (if (and (math-floatp b) (Math-ratp a)) (math-float a) a)) X (and (Math-objvecp a) (Math-objvecp b) X (or X (and (Math-integerp a) (Math-integerp b) X (progn X (or (consp a) (setq a (math-bignum a))) X (or (consp b) (setq b (math-bignum b))) X (if (eq (car a) 'bigneg) X (if (eq (car b) 'bigneg) X (cons 'bigneg (math-add-bignum (cdr a) (cdr b))) X (math-normalize X (let ((diff (math-sub-bignum (cdr b) (cdr a)))) X (if (eq diff 'neg) X (cons 'bigneg (math-sub-bignum (cdr a) (cdr b))) X (cons 'bigpos diff))))) X (if (eq (car b) 'bigneg) X (math-normalize X (let ((diff (math-sub-bignum (cdr a) (cdr b)))) X (if (eq diff 'neg) X (cons 'bigneg (math-sub-bignum (cdr b) (cdr a))) X (cons 'bigpos diff)))) X (cons 'bigpos (math-add-bignum (cdr a) (cdr b))))))) X (and (Math-ratp a) (Math-ratp b) X (if (eq (car-safe a) 'frac) X (if (eq (car-safe b) 'frac) X (math-make-frac (math-add (math-mul (nth 1 a) (nth 2 b)) X (math-mul (nth 2 a) (nth 1 b))) X (math-mul (nth 2 a) (nth 2 b))) X (math-make-frac (math-add (nth 1 a) X (math-mul (nth 2 a) b)) X (nth 2 a))) X (math-make-frac (math-add (math-mul a (nth 2 b)) X (nth 1 b)) X (nth 2 b)))) X (and (Math-realp a) (Math-realp b) X (progn X (or (and (consp a) (eq (car a) 'float)) X (setq a (math-float a))) X (or (and (consp b) (eq (car b) 'float)) X (setq b (math-float b))) X (math-add-float a b))) X (and (calc-extensions) X (math-add-objects-fancy a b)))) X (and (calc-extensions) X (math-add-symb-fancy a b))) X) X(defun calcFunc-add (&rest rest) X (if rest X (let ((a (car rest))) X (while (setq rest (cdr rest)) X (setq a (list '+ a (car rest)))) X (math-normalize a)) X 0) X) X X(defun math-add-bignum (a b) ; [L L L; l l l] X (if a X (if b X (let* ((a (copy-sequence a)) (aa a) (carry nil) sum) X (while (and aa b) X (if carry X (if (< (setq sum (+ (car aa) (car b))) 999) X (progn X (setcar aa (1+ sum)) X (setq carry nil)) X (setcar aa (+ sum -999))) X (if (< (setq sum (+ (car aa) (car b))) 1000) X (setcar aa sum) X (setcar aa (+ sum -1000)) X (setq carry t))) X (setq aa (cdr aa) X b (cdr b))) X (if carry X (if b X (nconc a (math-add-bignum b '(1))) X (while (eq (car aa) 999) X (setcar aa 0) X (setq aa (cdr aa))) X (if aa X (progn X (setcar aa (1+ (car aa))) X a) X (nconc a '(1)))) X (if b X (nconc a b) X a))) X a) X b) X) X X(defun math-sub-bignum (a b) ; [l l l] X (if b X (if a X (let* ((a (copy-sequence a)) (aa a) (borrow nil) sum) X (while (and aa b) X (if borrow X (if (>= (setq diff (- (car aa) (car b))) 1) X (progn X (setcar aa (1- diff)) X (setq borrow nil)) X (setcar aa (+ diff 999))) X (if (>= (setq diff (- (car aa) (car b))) 0) X (setcar aa diff) X (setcar aa (+ diff 1000)) X (setq borrow t))) X (setq aa (cdr aa) X b (cdr b))) X (if borrow X (progn X (while (eq (car aa) 0) X (setcar aa 999) X (setq aa (cdr aa))) X (if aa X (progn X (setcar aa (1- (car aa))) X a) X 'neg)) X (while (eq (car b) 0) X (setq b (cdr b))) X (if b X 'neg X a))) X (while (eq (car b) 0) X (setq b (cdr b))) X (and b X 'neg)) X a) X) X X(defun math-add-float (a b) ; [F F F] X (let ((ediff (- (nth 2 a) (nth 2 b)))) X (if (>= ediff 0) X (if (>= ediff (+ calc-internal-prec calc-internal-prec)) X a X (math-make-float (math-add (nth 1 b) X (math-scale-int (nth 1 a) ediff)) X (nth 2 b))) X (if (>= (setq ediff (- ediff)) X (+ calc-internal-prec calc-internal-prec)) X b X (math-make-float (math-add (nth 1 a) X (math-scale-int (nth 1 b) ediff)) X (nth 2 a))))) X) X X;;; Compute the difference of A and B. [O O O] [Public] X(defun math-sub (a b) X (if (or (consp a) (consp b)) X (math-add a (math-neg b)) X (setq a (- a b)) X (if (or (<= a -1000000) (>= a 1000000)) X (math-bignum a) X a)) X) X(defun calcFunc-sub (&rest rest) X (if rest X (let ((a (car rest))) X (while (setq rest (cdr rest)) X (setq a (list '- a (car rest)))) X (math-normalize a)) X 0) X) X X(defun math-sub-float (a b) ; [F F F] X (let ((ediff (- (nth 2 a) (nth 2 b)))) X (if (>= ediff 0) X (if (>= ediff (+ calc-internal-prec calc-internal-prec)) X a X (math-make-float (math-add (Math-integer-neg (nth 1 b)) X (math-scale-int (nth 1 a) ediff)) X (nth 2 b))) X (if (>= (setq ediff (- ediff)) X (+ calc-internal-prec calc-internal-prec)) X b X (math-make-float (math-add (nth 1 a) X (Math-integer-neg X (math-scale-int (nth 1 b) ediff))) X (nth 2 a))))) X) X X X;;; Compute the product of A and B. [O O O] [Public] X(defun math-mul (a b) X (or X (and (not (consp a)) (not (consp b)) X (< a 1000) (> a -1000) (< b 1000) (> b -1000) X (* a b)) X (and (Math-zerop a) (not (eq (car-safe b) 'mod)) X (if (and (math-floatp b) (Math-ratp a)) (math-float a) a)) X (and (Math-zerop b) (not (eq (car-safe a) 'mod)) X (if (and (math-floatp a) (Math-ratp b)) (math-float b) b)) X (and (Math-objvecp a) (Math-objvecp b) X (or X (and (Math-integerp a) (Math-integerp b) X (progn X (or (consp a) (setq a (math-bignum a))) X (or (consp b) (setq b (math-bignum b))) X (math-normalize X (cons (if (eq (car a) (car b)) 'bigpos 'bigneg) X (if (cdr (cdr a)) X (if (cdr (cdr b)) X (math-mul-bignum (cdr a) (cdr b)) X (math-mul-bignum-digit (cdr a) (nth 1 b) 0)) X (math-mul-bignum-digit (cdr b) (nth 1 a) 0)))))) X (and (Math-ratp a) (Math-ratp b) X (if (eq (car-safe a) 'frac) X (if (eq (car-safe b) 'frac) X (math-make-frac (math-mul (nth 1 a) (nth 1 b)) X (math-mul (nth 2 a) (nth 2 b))) X (math-make-frac (math-mul (nth 1 a) b) X (nth 2 a))) X (math-make-frac (math-mul a (nth 1 b)) X (nth 2 b)))) X (and (Math-realp a) (Math-realp b) X (progn X (or (and (consp a) (eq (car a) 'float)) X (setq a (math-float a))) X (or (and (consp b) (eq (car b) 'float)) X (setq b (math-float b))) X (math-make-float (math-mul (nth 1 a) (nth 1 b)) X (+ (nth 2 a) (nth 2 b))))) X (and (calc-extensions) X (math-mul-objects-fancy a b)))) X (and (calc-extensions) X (math-mul-symb-fancy a b))) X) X X(defun calcFunc-mul (&rest rest) X (if rest X (let ((a (car rest))) X (while (setq rest (cdr rest)) X (setq a (list '* a (car rest)))) X (math-normalize a)) X 1) X) X X;;; Multiply digit lists A and B. [L L L; l l l] X(defun math-mul-bignum (a b) X (and a b X (let* ((sum (if (<= (car b) 1) X (if (= (car b) 0) X (list 0) X (copy-sequence a)) X (math-mul-bignum-digit a (car b) 0))) X (sump sum) c d aa prod) X (while (setq b (cdr b)) X (setq ss (setq sump (or (cdr sump) (setcdr sump (list 0)))) X d (car b) X c 0 X aa a) X (while (progn X (setcar ss (% (setq prod (+ (+ (car ss) (* (car aa) d)) X c)) 1000)) X (setq aa (cdr aa))) X (setq c (/ prod 1000) X ss (or (cdr ss) (setcdr ss (list 0))))) X (if (>= prod 1000) X (if (cdr ss) X (setcar (cdr ss) (+ (/ prod 1000) (car (cdr ss)))) X (setcdr ss (list (/ prod 1000)))))) X sum)) X) X X;;; Multiply digit list A by digit D. [L L D D; l l D D] X(defun math-mul-bignum-digit (a d c) X (and a X (if (<= d 1) X (and (= d 1) a) X (let* ((a (copy-sequence a)) (aa a) prod) X (while (progn X (setcar aa (% (setq prod (+ (* (car aa) d) c)) 1000)) X (cdr aa)) X (setq aa (cdr aa) X c (/ prod 1000))) X (if (>= prod 1000) X (setcdr aa (list (/ prod 1000)))) X a))) X) X X X;;; Compute the square of A. [O O] [Public] X(defun math-sqr (a) X (if (eq (car-safe a) 'calcFunc-sqrt) X (nth 1 a) X (math-mul a a)) X) X X X;;; Compute the integer (quotient . remainder) of A and B, which may be X;;; small or big integers. Type and consistency of truncation is undefined X;;; if A or B is negative. B must be nonzero. [I.I I I] [Public] X(defun math-idivmod (a b) X (if (eq b 0) X (math-reject-arg a "Division by zero")) X (if (or (consp a) (consp b)) X (if (and (natnump b) (< b 1000)) X (let ((res (math-div-bignum-digit (cdr a) b))) X (cons X (math-normalize (cons (car a) (car res))) X (cdr res))) X (or (consp a) (setq a (math-bignum a))) X (or (consp b) (setq b (math-bignum b))) X (let ((res (math-div-bignum (cdr a) (cdr b)))) X (cons X (math-normalize (cons (if (eq (car a) (car b)) 'bigpos 'bigneg) X (car res))) X (math-normalize (cons (car a) (cdr res)))))) X (cons (/ a b) (% a b))) X) X X(defun math-quotient (a b) ; [I I I] [Public] X (if (and (not (consp a)) (not (consp b))) X (if (= b 0) X (math-reject-arg a "Division by zero") X (/ a b)) X (if (and (natnump b) (< b 1000)) X (if (= b 0) X (math-reject-arg a "Division by zero") X (math-normalize (cons (car a) X (car (math-div-bignum-digit (cdr a) b))))) X (or (consp a) (setq a (math-bignum a))) X (or (consp b) (setq b (math-bignum b))) X (let* ((alen (1- (length a))) X (blen (1- (length b))) X (d (/ 1000 (1+ (nth (1- blen) (cdr b))))) X (res (math-div-bignum-big (math-mul-bignum-digit (cdr a) d 0) X (math-mul-bignum-digit (cdr b) d 0) X alen blen))) X (math-normalize (cons (if (eq (car a) (car b)) 'bigpos 'bigneg) X (car res)))))) X) X X(defun math-imod (a b) ; [I I I] [Public] X (if (and (not (consp a)) (not (consp b))) X (if (= b 0) X (math-reject-arg a "Division by zero") X (% a b)) X (cdr (math-idivmod a b))) X) X X;;; Divide a bignum digit list by another. [l.l l L] X;;; The following division algorithm is borrowed from Knuth vol. II, sec. 4.3.1 X(defun math-div-bignum (a b) X (if (null (cdr b)) X (let ((res (math-div-bignum-digit a (car b)))) X (cons (car res) (list (cdr res)))) X (let* ((alen (length a)) X (blen (length b)) X (d (/ 1000 (1+ (nth (1- blen) b)))) X (res (math-div-bignum-big (math-mul-bignum-digit a d 0) X (math-mul-bignum-digit b d 0) X alen blen))) X (if (= d 1) X res X (cons (car res) X (car (math-div-bignum-digit (cdr res) d)))))) X) X X;;; Divide a bignum digit list by a digit. [l.D l D] X(defun math-div-bignum-digit (a b) X (if (null a) X '(nil . 0) X (let* ((res (math-div-bignum-digit (cdr a) b)) X (num (+ (* (cdr res) 1000) (car a)))) X (cons X (cons (/ num b) (car res)) X (% num b)))) X) X X(defun math-div-bignum-big (a b alen blen) ; [l.l l L] X (if (< alen blen) X (cons nil a) X (let* ((res (math-div-bignum-big (cdr a) b (1- alen) blen)) X (num (cons (car a) (cdr res))) X (res2 (math-div-bignum-part num b blen))) X (cons X (cons (car res2) (car res)) X (cdr res2)))) X) X X(defun math-div-bignum-part (a b blen) ; a < b*1000 [D.l l L] X (let* ((num (+ (* (or (nth blen a) 0) 1000) (or (nth (1- blen) a) 0))) X (den (nth (1- blen) b)) X (guess (min (/ num den) 999))) X (math-div-bignum-try a b (math-mul-bignum-digit b guess 0) guess)) X) X X(defun math-div-bignum-try (a b c guess) ; [D.l l l D] X (let ((rem (math-sub-bignum a c))) X (if (eq rem 'neg) X (math-div-bignum-try a b (math-sub-bignum c b) (1- guess)) X (cons guess rem))) X) X X X;;; Compute the quotient of A and B. [O O N] [Public] X(defun math-div (a b) X (or X (and (Math-zerop b) X (math-reject-arg a "Division by zero")) X (and (Math-zerop a) (not (eq (car-safe b) 'mod)) X (if (and (math-floatp b) (Math-ratp a)) (math-float a) a)) X (and (Math-objvecp a) (Math-objvecp b) X (or X (and (Math-integerp a) (Math-integerp b) X (if calc-prefer-frac X (math-make-frac a b) X (let ((q (math-idivmod a b))) X (if (eq (cdr q) 0) X (car q) X (math-div-float (math-make-float a 0) X (math-make-float b 0)))))) X (and (Math-ratp a) (Math-ratp b) X (if (eq (car-safe a) 'frac) X (if (eq (car-safe b) 'frac) X (math-make-frac (math-mul (nth 1 a) (nth 2 b)) X (math-mul (nth 2 a) (nth 1 b))) X (math-make-frac (nth 1 a) X (math-mul (nth 2 a) b))) X (math-make-frac (math-mul a (nth 2 b)) X (nth 1 b)))) X (and (Math-realp a) (Math-realp b) X (progn X (or (and (consp a) (eq (car a) 'float)) X (setq a (math-float a))) X (or (and (consp b) (eq (car b) 'float)) X (setq b (math-float b))) X (math-div-float a b))) X (and (calc-extensions) X (math-div-objects-fancy a b)))) X (and (calc-extensions) X (math-div-symb-fancy a b))) X) X(defun calcFunc-div (a &rest rest) X (while rest X (setq a (list '/ a (car rest)) X rest (cdr rest))) X (math-normalize a) X) X X(defun math-div-float (a b) ; [F F F] X (let ((ldiff (max (- (1+ calc-internal-prec) X (- (math-numdigs (nth 1 a)) (math-numdigs (nth 1 b)))) SHAR_EOF echo "End of part 2" echo "File calc.el is continued in part 3" echo "3" > s2_seq_.tmp exit 0