Initial Commit
[packages] / xemacs-packages / calc / calc-misc.el
1 ;; Calculator for GNU Emacs, part I [calc-misc.el]
2 ;; Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3 ;; Written by Dave Gillespie, daveg@synaptics.com.
4
5 ;; This file is part of GNU Emacs.
6
7 ;; GNU Emacs is distributed in the hope that it will be useful,
8 ;; but WITHOUT ANY WARRANTY.  No author or distributor
9 ;; accepts responsibility to anyone for the consequences of using it
10 ;; or for whether it serves any particular purpose or works at all,
11 ;; unless he says so in writing.  Refer to the GNU Emacs General Public
12 ;; License for full details.
13
14 ;; Everyone is granted permission to copy, modify and redistribute
15 ;; GNU Emacs, but only under the conditions described in the
16 ;; GNU Emacs General Public License.   A copy of this license is
17 ;; supposed to have been given to you along with GNU Emacs so you
18 ;; can know your rights and responsibilities.  It should be in a
19 ;; file named COPYING.  Among other things, the copyright notice
20 ;; and this notice must be preserved on all copies.
21
22
23
24 ;; This file is autoloaded from calc.el.
25 (require 'calc)
26
27 (require 'calc-macs)
28
29 (defun calc-Need-calc-misc () nil)
30
31
32 (defun calc-dispatch-help (arg)
33   "M-# is a prefix key; follow it with one of these letters:
34
35 For turning Calc on and off:
36   C  calc.  Start the Calculator in a window at the bottom of the screen.
37   O  calc-other-window.  Start the Calculator but don't select its window.
38   B  calc-big-or-small.  Control whether to use the full Emacs screen for Calc.
39   Q  quick-calc.  Use the Calculator in the minibuffer.
40   K  calc-keypad.  Start the Calculator in keypad mode (X window system only).
41   E  calc-embedded.  Use the Calculator on a formula in this editing buffer.
42   J  calc-embedded-select.  Like E, but select appropriate half of => or :=.
43   W  calc-embedded-word.  Like E, but activate a single word, i.e., a number.
44   Z  calc-user-invocation.  Invoke Calc in the way you defined with `Z I' cmd.
45   X  calc-quit.  Turn Calc off.
46
47 For moving data into and out of Calc:
48   G  calc-grab-region.  Grab the region defined by mark and point into Calc.
49   R  calc-grab-rectangle.  Grab the rectangle defined by mark, point into Calc.
50   :  calc-grab-sum-down.  Grab a rectangle and sum the columns.
51   _  calc-grab-sum-across.  Grab a rectangle and sum the rows.
52   Y  calc-copy-to-buffer.  Copy a value from the stack into the editing buffer.
53
54 For use with Embedded mode:
55   A  calc-embedded-activate.  Find and activate all :='s and =>'s in buffer.
56   D  calc-embedded-duplicate.  Make a copy of this formula and select it.
57   F  calc-embedded-new-formula.  Insert a new formula at current point.
58   N  calc-embedded-next.  Advance cursor to next known formula in buffer.
59   P  calc-embedded-previous.  Advance cursor to previous known formula.
60   U  calc-embedded-update-formula.  Re-evaluate formula at point.
61   `  calc-embedded-edit.  Use calc-edit to edit formula at point.
62
63 Documentation:
64   I  calc-info.  Read the Calculator manual in the Emacs Info system.
65   T  calc-tutorial.  Run the Calculator Tutorial using the Emacs Info system.
66   S  calc-summary.  Read the Summary from the Calculator manual in Info.
67
68 Miscellaneous:
69   L  calc-load-everything.  Load all parts of the Calculator into memory.
70   M  read-kbd-macro.  Read a region of keystroke names as a keyboard macro.
71   0  (zero) calc-reset.  Reset Calc stack and modes to default state.
72
73 Press twice (`M-# M-#' or `M-# #') to turn Calc on or off using the same
74 Calc user interface as before (either M-# C or M-# K; initially M-# C)."
75   (interactive "P")
76   (calc-check-defines)
77   (if calc-dispatch-help
78       (progn
79         (save-window-excursion
80           (describe-function 'calc-dispatch-help)
81           (let ((win (get-buffer-window "*Help*")))
82             (if win
83                 (let (key)
84                   (select-window win)
85                   (while (progn
86                            (message "Calc options: Calc, Keypad, ...  %s"
87                                     "press SPC, DEL to scroll, C-g to cancel")
88                            (memq (car (setq key (calc-read-key t)))
89                                  '(?  ?\C-h ?\C-? ?\C-v ?\M-v)))
90                     (condition-case err
91                         (if (memq (car key) '(?  ?\C-v))
92                             (scroll-up)
93                           (scroll-down))
94                       (error (beep))))
95                       (calc-unread-command (cdr key))))))
96         (calc-do-dispatch nil))
97     (let ((calc-dispatch-help t))
98       (calc-do-dispatch arg)))
99 )
100
101
102 (defun calc-big-or-small (arg)
103   "Toggle Calc between full-screen and regular mode."
104   (interactive "P")
105   (let ((cwin (get-buffer-window "*Calculator*"))
106         (twin (get-buffer-window "*Calc Trail*"))
107         (kwin (get-buffer-window "*Calc Keypad*")))
108     (if cwin
109         (setq calc-full-mode
110               (if kwin
111                   (and twin (eq (window-width twin) (frame-width)))
112                 (eq (window-height cwin) (1- (frame-height))))))
113     (setq calc-full-mode (if arg
114                              (> (prefix-numeric-value arg) 0)
115                            (not calc-full-mode)))
116     (if kwin
117         (progn
118           (calc-quit)
119           (calc-do-keypad calc-full-mode nil))
120       (if cwin
121           (progn
122             (calc-quit)
123             (calc nil calc-full-mode nil))))
124     (message (if calc-full-mode
125                  "Now using full screen for Calc."
126                "Now using partial screen for Calc.")))
127 )
128
129 (defun calc-other-window ()
130   "Invoke the Calculator in another window."
131   (interactive)
132   (if (memq major-mode '(calc-mode calc-trail-mode))
133       (progn
134         (other-window 1)
135         (if (memq major-mode '(calc-mode calc-trail-mode))
136             (other-window 1)))
137     (if (get-buffer-window "*Calculator*")
138         (calc-quit)
139       (let ((win (selected-window)))
140         (calc nil win (interactive-p)))))
141 )
142
143 (defun another-calc ()
144   "Create another, independent Calculator buffer."
145   (interactive)
146   (if (eq major-mode 'calc-mode)
147       (mapcar (function
148                (lambda (v)
149                  (set-default v (symbol-value v)))) calc-local-var-list))
150   (set-buffer (generate-new-buffer "*Calculator*"))
151   (pop-to-buffer (current-buffer))
152   (calc-mode)
153 )
154
155
156 ;;; Make an attempt to preserve the window configuration, while deleting
157 ;;; windows on "bufs".  Emacs 19's delete-window function will probably
158 ;;; make this kludgery unnecessary, but Emacs 18's tendency to grow all
159 ;;; windows on the screen to take up the slack from the deleted windows
160 ;;; can be annoying when Calc was called during another multi-window
161 ;;; application, such as GNUS.
162
163 (defun calc-delete-windows-keep (&rest bufs)
164   (if (one-window-p)
165       (mapcar 'delete-windows-on bufs)
166     (let* ((w (car calc-was-split))
167            (e (window-edges w))
168            (wins nil)
169            w2 e2)
170       (while (progn
171                (setq w2 (previous-window w)
172                      e2 (window-edges w2))
173                (and (= (car e2) (car e))
174                     (= (nth 2 e2) (nth 2 e))
175                     (< (nth 1 e2) (nth 1 e))))
176         (setq w w2 e e2))
177       (setq w2 w e2 e)
178       (while (progn
179                (setq wins (cons (list w (nth 1 e) (window-buffer w)
180                                       (window-point w) (window-start w))
181                                 wins)
182                      w (next-window w)
183                      e (window-edges w))
184                (and (not (eq w w2))
185                     (= (car e2) (car e))
186                     (= (nth 2 e2) (nth 2 e)))))
187       (setq wins (nreverse wins))
188       (mapcar 'delete-windows-on bufs)
189       (or (one-window-p)
190           (let ((w wins)
191                 (main nil)
192                 (mainpos 0)
193                 (sel (if (window-point (nth 2 calc-was-split))
194                          (nth 2 calc-was-split)
195                        (selected-window))))
196             (while w
197               (if (window-point (car (car w)))
198                   (if main
199                       (delete-window (car (car w)))
200                     (setq main (car (car w))
201                           mainpos (nth 1 (car w))
202                           wins (cdr wins)))
203                 (setq wins (delq (car w) wins)))
204               (setq w (cdr w)))
205             (while wins
206               (setq w (split-window main
207                                     (if (eq main (car calc-was-split))
208                                         (nth 1 calc-was-split)
209                                       (- (nth 1 (car wins)) mainpos))))
210               (set-window-buffer w (nth 2 (car wins)))
211               (set-window-point w (nth 3 (car wins)))
212               (set-window-start w (nth 4 (car wins)))
213               (if (eq sel (car (car wins)))
214                   (select-window w))
215               (setq main w
216                     mainpos (nth 1 (car wins))
217                     wins (cdr wins)))
218             (if (window-point sel)
219                 (select-window sel))))))
220 )
221
222
223 (defun calc-info ()
224   "Run the Emacs Info system on the Calculator documentation."
225   (interactive)
226   (require 'info)
227   (select-window (get-largest-window))
228   (or calc-emacs-type-lucid
229       (file-name-absolute-p calc-info-filename)
230        (let ((p load-path)
231              name)
232          (if (boundp 'Info-directory)
233              (setq p (cons Info-directory p)))
234          (while (and p (not (file-exists-p
235                              (setq name (expand-file-name calc-info-filename
236                                                           (car p))))))
237            (setq p (cdr p)))
238          (if p (setq calc-info-filename name))))
239   (condition-case err
240       (info)
241     (error nil))
242   (or (and (boundp 'Info-current-file)
243            (stringp Info-current-file)
244            (string-match "calc" Info-current-file))
245       (Info-find-node calc-info-filename "Top"))
246 )
247
248 ;;;###autoload
249 (defun calc-tutorial ()
250   "Run the Emacs Info system on the Calculator Tutorial."
251   (interactive)
252   (if (get-buffer-window "*Calculator*")
253       (calc-quit))
254   (calc-info)
255   (Info-goto-node "Interactive Tutorial")
256   (calc-other-window)
257   (message "Welcome to the Calc Tutorial!")
258 )
259
260 (defun calc-info-summary ()
261   "Run the Emacs Info system on the Calculator Summary."
262   (interactive)
263   (calc-info)
264   (Info-goto-node "Summary")
265 )
266
267 (defun calc-help ()
268   (interactive)
269   (let ((msgs (append
270          '("Press `h' for complete help; press `?' repeatedly for a summary"
271            "Letter keys: Negate; Precision; Yank; Why; Xtended cmd; Quit"
272            "Letter keys: SHIFT + Undo, reDo; Keep-args; Inverse, Hyperbolic"
273            "Letter keys: SHIFT + sQrt; Sin, Cos, Tan; Exp, Ln, logB"
274            "Letter keys: SHIFT + Floor, Round; Abs, conJ, arG; Pi"
275            "Letter keys: SHIFT + Num-eval; More-recn; eXec-kbd-macro"
276            "Other keys: +, -, *, /, ^, \\ (int div), : (frac div)"
277            "Other keys: & (1/x), | (concat), % (modulo), ! (factorial)"
278            "Other keys: ' (alg-entry), = (eval), ` (edit); M-RET (last-args)"
279            "Other keys: SPC/RET (enter/dup), LFD (over); < > (scroll horiz)"
280            "Other keys: DEL (drop), M-DEL (drop-above); { } (scroll vert)"
281            "Other keys: TAB (swap/roll-dn), M-TAB (roll-up)"
282            "Other keys: [ , ; ] (vector), ( , ) (complex), ( ; ) (polar)"
283            "Prefix keys: Algebra, Binary/business, Convert, Display"
284            "Prefix keys: Functions, Graphics, Help, J (select)"
285            "Prefix keys: Kombinatorics/statistics, Modes, Store/recall"
286            "Prefix keys: Trail/time, Units/statistics, Vector/matrix"
287            "Prefix keys: Z (user), SHIFT + Z (define)"
288            "Prefix keys: prefix + ? gives further help for that prefix")
289          (list (format
290                 "  Calc %s by Dave Gillespie, daveg@synaptics.com"
291                 calc-version)))))
292     (if calc-full-help-flag
293         msgs
294       (if (or calc-inverse-flag calc-hyperbolic-flag)
295           (if calc-inverse-flag
296               (if calc-hyperbolic-flag
297                   (calc-inv-hyp-prefix-help)
298                 (calc-inverse-prefix-help))
299             (calc-hyperbolic-prefix-help))
300         (setq calc-help-phase
301               (if (eq this-command last-command)
302                   (% (1+ calc-help-phase) (1+ (length msgs)))
303                 0))
304         (let ((msg (nth calc-help-phase msgs)))
305           (message "%s" (if msg
306                             (concat msg ":"
307                                     (make-string (- (apply 'max
308                                                            (mapcar 'length
309                                                                    msgs))
310                                                     (length msg)) 32)
311                                     "  [?=MORE]")
312                           ""))))))
313 )
314
315
316
317
318 ;;;; Stack and buffer management.
319
320
321 (defun calc-do-handle-whys ()
322   (setq calc-why (sort calc-next-why
323                        (function
324                         (lambda (x y)
325                           (and (eq (car x) '*) (not (eq (car y) '*))))))
326         calc-next-why nil)
327   (if (and calc-why (or (eq calc-auto-why t)
328                         (and (eq (car (car calc-why)) '*)
329                              calc-auto-why)))
330       (progn
331         (calc-extensions)
332         (calc-explain-why (car calc-why)
333                           (if (eq calc-auto-why t)
334                               (cdr calc-why)
335                             (if calc-auto-why
336                                 (eq (car (nth 1 calc-why)) '*))))
337         (setq calc-last-why-command this-command)
338         (calc-clear-command-flag 'clear-message)))
339 )
340
341 (defun calc-record-why (&rest stuff)
342   (if (eq (car stuff) 'quiet)
343       (setq stuff (cdr stuff))
344     (if (and (symbolp (car stuff))
345              (cdr stuff)
346              (or (Math-objectp (nth 1 stuff))
347                  (and (Math-vectorp (nth 1 stuff))
348                       (math-constp (nth 1 stuff)))
349                  (math-infinitep (nth 1 stuff))))
350         (setq stuff (cons '* stuff))
351       (if (and (stringp (car stuff))
352                (string-match "\\`\\*" (car stuff)))
353           (setq stuff (cons '* (cons (substring (car stuff) 1)
354                                      (cdr stuff)))))))
355   (setq calc-next-why (cons stuff calc-next-why))
356   nil
357 )
358
359 ;;; True if A is a constant or vector of constants.  [P x] [Public]
360 (defun math-constp (a)
361   (or (Math-scalarp a)
362       (and (memq (car a) '(sdev intv mod vec))
363            (progn
364              (while (and (setq a (cdr a))
365                          (or (Math-scalarp (car a))  ; optimization
366                              (math-constp (car a)))))
367              (null a))))
368 )
369
370
371 (defun calc-roll-down-stack (n &optional m)
372   (if (< n 0)
373       (calc-roll-up-stack (- n) m)
374     (if (or (= n 0) (> n (calc-stack-size))) (setq n (calc-stack-size)))
375     (or m (setq m 1))
376     (and (> n 1)
377          (< m n)
378          (if (and calc-any-selections
379                   (not calc-use-selections))
380              (calc-roll-down-with-selections n m)
381            (calc-pop-push-list n
382                                (append (calc-top-list m 1)
383                                        (calc-top-list (- n m) (1+ m)))))))
384 )
385
386 (defun calc-roll-up-stack (n &optional m)
387   (if (< n 0)
388       (calc-roll-down-stack (- n) m)
389     (if (or (= n 0) (> n (calc-stack-size))) (setq n (calc-stack-size)))
390     (or m (setq m 1))
391     (and (> n 1)
392          (< m n)
393          (if (and calc-any-selections
394                   (not calc-use-selections))
395              (calc-roll-up-with-selections n m)
396            (calc-pop-push-list n
397                                (append (calc-top-list (- n m) 1)
398                                        (calc-top-list m (- n m -1)))))))
399 )
400
401
402 (defun calc-do-refresh ()
403   (if calc-hyperbolic-flag
404       (progn
405         (setq calc-display-dirty t)
406         nil)
407     (calc-refresh)
408     t)
409 )
410
411
412 (defun calc-record-list (vals &optional prefix)
413   (while vals
414     (or (eq (car vals) 'top-of-stack)
415         (progn
416           (calc-record (car vals) prefix)
417           (setq prefix "...")))
418     (setq vals (cdr vals)))
419 )
420
421
422 (defun calc-last-args-stub (arg)
423   (interactive "p")
424   (calc-extensions)
425   (calc-last-args arg)
426 )
427
428
429 (defun calc-power (arg)
430   (interactive "P")
431   (calc-slow-wrapper
432    (if (and calc-extensions-loaded
433             (calc-is-inverse))
434        (calc-binary-op "root" 'calcFunc-nroot arg nil nil)
435      (calc-binary-op "^" 'calcFunc-pow arg nil nil '^)))
436 )
437
438 (defun calc-mod (arg)
439   (interactive "P")
440   (calc-slow-wrapper
441    (calc-binary-op "%" 'calcFunc-mod arg nil nil '%))
442 )
443
444 (defun calc-inv (arg)
445   (interactive "P")
446   (calc-slow-wrapper
447    (calc-unary-op "inv" 'calcFunc-inv arg))
448 )
449
450 (defun calc-percent ()
451   (interactive)
452   (calc-slow-wrapper
453    (calc-pop-push-record-list
454     1 "%" (list (list 'calcFunc-percent (calc-top-n 1)))))
455 )
456
457
458 (defun calc-over (n)
459   (interactive "P")
460   (if n
461       (calc-enter (- (prefix-numeric-value n)))
462     (calc-enter -2))
463 )
464
465
466 (defun calc-pop-above (n)
467   (interactive "P")
468   (if n
469       (calc-pop (- (prefix-numeric-value n)))
470     (calc-pop -2))
471 )
472
473 (defun calc-roll-down (n)
474   (interactive "P")
475   (calc-wrapper
476    (let ((nn (prefix-numeric-value n)))
477      (cond ((null n)
478             (calc-roll-down-stack 2))
479            ((> nn 0)
480             (calc-roll-down-stack nn))
481            ((= nn 0)
482             (calc-pop-push-list (calc-stack-size)
483                                 (reverse
484                                  (calc-top-list (calc-stack-size)))))
485            (t
486             (calc-roll-down-stack (calc-stack-size) (- nn))))))
487 )
488
489 (defun calc-roll-up (n)
490   (interactive "P")
491   (calc-wrapper
492    (let ((nn (prefix-numeric-value n)))
493      (cond ((null n)
494             (calc-roll-up-stack 3))
495            ((> nn 0)
496             (calc-roll-up-stack nn))
497            ((= nn 0)
498             (calc-pop-push-list (calc-stack-size)
499                                 (reverse
500                                  (calc-top-list (calc-stack-size)))))
501            (t
502             (calc-roll-up-stack (calc-stack-size) (- nn))))))
503 )
504
505
506
507
508 ;;; Other commands.
509
510 (defun calc-num-prefix-name (n)
511   (cond ((eq n '-) "- ")
512         ((equal n '(4)) "C-u ")
513         ((consp n) (format "%d " (car n)))
514         ((integerp n) (format "%d " n))
515         (t ""))
516 )
517
518 (defun calc-missing-key (n)
519   "This is a placeholder for a command which needs to be loaded from calc-ext.
520 When this key is used, calc-ext (the Calculator extensions module) will be
521 loaded and the keystroke automatically re-typed."
522   (interactive "P")
523   (calc-extensions)
524   (if (keymapp (key-binding (char-to-string last-command-char)))
525       (message "%s%c-" (calc-num-prefix-name n) last-command-char))
526   (calc-unread-command)
527   (setq prefix-arg n)
528 )
529
530 (defun calc-shift-Y-prefix-help ()
531   (interactive)
532   (calc-extensions)
533   (calc-do-prefix-help calc-Y-help-msgs "other" ?Y)
534 )
535
536
537
538
539 (defun calcDigit-letter ()
540   (interactive)
541   (if (calc-minibuffer-contains "[-+]?\\(1[1-9]\\|[2-9][0-9]\\)#.*")
542       (progn
543         (setq last-command-char (upcase last-command-char))
544         (calcDigit-key))
545     (calcDigit-nondigit))
546 )
547
548
549 ;; A Lisp version of temp_minibuffer_message from minibuf.c.
550 (defun calc-temp-minibuffer-message (m)
551   (let ((savemax (point-max)))
552     (save-excursion
553       (goto-char (point-max))
554       (insert m))
555     (let ((okay nil))
556       (unwind-protect
557           (progn
558             (sit-for 2)
559             (identity 1)   ; this forces a call to QUIT; in bytecode.c.
560             (setq okay t))
561         (progn
562           (delete-region savemax (point-max))
563           (or okay (abort-recursive-edit))))))
564 )
565
566
567 (put 'math-with-extra-prec 'lisp-indent-hook 1)
568
569
570 ;;; Concatenate two vectors, or a vector and an object.  [V O O] [Public]
571 (defun math-concat (v1 v2)
572   (if (stringp v1)
573       (concat v1 v2)
574     (calc-extensions)
575     (if (and (or (math-objvecp v1) (math-known-scalarp v1))
576              (or (math-objvecp v2) (math-known-scalarp v2)))
577         (append (if (and (math-vectorp v1)
578                          (or (math-matrixp v1)
579                              (not (math-matrixp v2))))
580                     v1
581                   (list 'vec v1))
582                 (if (and (math-vectorp v2)
583                          (or (math-matrixp v2)
584                              (not (math-matrixp v1))))
585                     (cdr v2)
586                   (list v2)))
587       (list '| v1 v2)))
588 )
589
590
591 ;;; True if A is zero.  Works for un-normalized values.  [P n] [Public]
592 (defun math-zerop (a)
593   (if (consp a)
594       (cond ((memq (car a) '(bigpos bigneg))
595              (while (eq (car (setq a (cdr a))) 0))
596              (null a))
597             ((memq (car a) '(frac float polar mod))
598              (math-zerop (nth 1 a)))
599             ((eq (car a) 'cplx)
600              (and (math-zerop (nth 1 a)) (math-zerop (nth 2 a))))
601             ((eq (car a) 'hms)
602              (and (math-zerop (nth 1 a))
603                   (math-zerop (nth 2 a))
604                   (math-zerop (nth 3 a)))))
605     (eq a 0))
606 )
607
608
609 ;;; True if A is real and negative.  [P n] [Public]
610
611 (defun math-negp (a)
612   (if (consp a)
613       (cond ((eq (car a) 'bigpos) nil)
614             ((eq (car a) 'bigneg) (cdr a))
615             ((memq (car a) '(float frac))
616              (Math-integer-negp (nth 1 a)))
617             ((eq (car a) 'hms)
618              (if (math-zerop (nth 1 a))
619                  (if (math-zerop (nth 2 a))
620                      (math-negp (nth 3 a))
621                    (math-negp (nth 2 a)))
622                (math-negp (nth 1 a))))
623             ((eq (car a) 'date)
624              (math-negp (nth 1 a)))
625             ((eq (car a) 'intv)
626              (or (math-negp (nth 3 a))
627                  (and (math-zerop (nth 3 a))
628                       (memq (nth 1 a) '(0 2)))))
629             ((equal a '(neg (var inf var-inf))) t))
630     (< a 0))
631 )
632
633 ;;; True if A is a negative number or an expression the starts with '-'.
634 (defun math-looks-negp (a)   ; [P x] [Public]
635   (or (Math-negp a)
636       (eq (car-safe a) 'neg)
637       (and (memq (car-safe a) '(* /))
638            (or (math-looks-negp (nth 1 a))
639                (math-looks-negp (nth 2 a))))
640       (and (eq (car-safe a) '-)
641            (math-looks-negp (nth 1 a))))
642 )
643
644
645 ;;; True if A is real and positive.  [P n] [Public]
646 (defun math-posp (a)
647   (if (consp a)
648       (cond ((eq (car a) 'bigpos) (cdr a))
649             ((eq (car a) 'bigneg) nil)
650             ((memq (car a) '(float frac))
651              (Math-integer-posp (nth 1 a)))
652             ((eq (car a) 'hms)
653              (if (math-zerop (nth 1 a))
654                  (if (math-zerop (nth 2 a))
655                      (math-posp (nth 3 a))
656                    (math-posp (nth 2 a)))
657                (math-posp (nth 1 a))))
658             ((eq (car a) 'date)
659              (math-posp (nth 1 a)))
660             ((eq (car a) 'mod)
661              (not (math-zerop (nth 1 a))))
662             ((eq (car a) 'intv)
663              (or (math-posp (nth 2 a))
664                  (and (math-zerop (nth 2 a))
665                       (memq (nth 1 a) '(0 1)))))
666             ((equal a '(var inf var-inf)) t))
667     (> a 0))
668 )
669
670 (fset 'math-fixnump (symbol-function 'integerp))
671 (fset 'math-fixnatnump (symbol-function 'natnump))
672
673
674 ;;; True if A is an even integer.  [P R R] [Public]
675 (defun math-evenp (a)
676   (if (consp a)
677       (and (memq (car a) '(bigpos bigneg))
678            (= (% (nth 1 a) 2) 0))
679     (= (% a 2) 0))
680 )
681
682 ;;; Compute A / 2, for small or big integer A.  [I i]
683 ;;; If A is negative, type of truncation is undefined.
684 (defun math-div2 (a)
685   (if (consp a)
686       (if (cdr a)
687           (math-normalize (cons (car a) (math-div2-bignum (cdr a))))
688         0)
689     (/ a 2))
690 )
691
692 (defun math-div2-bignum (a)   ; [l l]
693   (if (cdr a)
694       (cons (+ (/ (car a) 2) (* (% (nth 1 a) 2) 500))
695             (math-div2-bignum (cdr a)))
696     (list (/ (car a) 2)))
697 )
698
699
700 ;;; Reject an argument to a calculator function.  [Public]
701 (defun math-reject-arg (&optional a p option)
702   (if option
703       (calc-record-why option p a)
704     (if p
705         (calc-record-why p a)))
706   (signal 'wrong-type-argument (and a (if p (list p a) (list a))))
707 )
708
709
710 ;;; Coerce A to be an integer (by truncation toward zero).  [I N] [Public]
711 (defun math-trunc (a &optional prec)
712   (cond (prec
713          (calc-extensions)
714          (math-trunc-special a prec))
715         ((Math-integerp a) a)
716         ((Math-looks-negp a)
717          (math-neg (math-trunc (math-neg a))))
718         ((eq (car a) 'float)
719          (math-scale-int (nth 1 a) (nth 2 a)))
720         (t (calc-extensions)
721            (math-trunc-fancy a)))
722 )
723 (fset 'calcFunc-trunc (symbol-function 'math-trunc))
724
725 ;;; Coerce A to be an integer (by truncation toward minus infinity).  [I N]
726 (defun math-floor (a &optional prec)    ;  [Public]
727   (cond (prec
728          (calc-extensions)
729          (math-floor-special a prec))
730         ((Math-integerp a) a)
731         ((Math-messy-integerp a) (math-trunc a))
732         ((Math-realp a)
733          (if (Math-negp a)
734              (math-add (math-trunc a) -1)
735            (math-trunc a)))
736         (t (calc-extensions)
737            (math-floor-fancy a)))
738 )
739 (fset 'calcFunc-floor (symbol-function 'math-floor))
740
741
742 (defun math-imod (a b)   ; [I I I] [Public]
743   (if (and (not (consp a)) (not (consp b)))
744       (if (= b 0)
745           (math-reject-arg a "*Division by zero")
746         (% a b))
747     (cdr (math-idivmod a b)))
748 )
749
750
751 (defun calcFunc-inv (m)
752   (if (Math-vectorp m)
753       (progn
754         (calc-extensions)
755         (if (math-square-matrixp m)
756             (or (math-with-extra-prec 2 (math-matrix-inv-raw m))
757                 (math-reject-arg m "*Singular matrix"))
758           (math-reject-arg m 'square-matrixp)))
759     (math-div 1 m))
760 )
761
762
763 (defun math-do-working (msg arg)
764   (or executing-kbd-macro
765       (progn
766         (calc-set-command-flag 'clear-message)
767         (if math-working-step
768             (if math-working-step-2
769                 (setq msg (format "[%d/%d] %s"
770                                   math-working-step math-working-step-2 msg))
771               (setq msg (format "[%d] %s" math-working-step msg))))
772         (message "Working... %s = %s" msg
773                  (math-showing-full-precision (math-format-number arg)))))
774 )
775
776
777 ;;; Compute A modulo B, defined in terms of truncation toward minus infinity.
778 (defun math-mod (a b)   ; [R R R] [Public]
779   (cond ((and (Math-zerop a) (not (eq (car-safe a) 'mod))) a)
780         ((Math-zerop b)
781          (math-reject-arg a "*Division by zero"))
782         ((and (Math-natnump a) (Math-natnump b))
783          (math-imod a b))
784         ((and (Math-anglep a) (Math-anglep b))
785          (math-sub a (math-mul (math-floor (math-div a b)) b)))
786         (t (calc-extensions)
787            (math-mod-fancy a b)))
788 )
789
790
791
792 ;;; General exponentiation.
793
794 (defun math-pow (a b)   ; [O O N] [Public]
795   (cond ((equal b '(var nan var-nan))
796          b)
797         ((Math-zerop a)
798          (if (and (Math-scalarp b) (Math-posp b))
799              (if (math-floatp b) (math-float a) a)
800            (calc-extensions)
801            (math-pow-of-zero a b)))
802         ((or (eq a 1) (eq b 1)) a)
803         ((or (equal a '(float 1 0)) (equal b '(float 1 0))) a)
804         ((Math-zerop b)
805          (if (Math-scalarp a)
806              (if (or (math-floatp a) (math-floatp b))
807                  '(float 1 0) 1)
808            (calc-extensions)
809            (math-pow-zero a b)))
810         ((and (Math-integerp b) (or (Math-numberp a) (Math-vectorp a)))
811          (if (and (equal a '(float 1 1)) (integerp b))
812              (math-make-float 1 b)
813            (math-with-extra-prec 2
814              (math-ipow a b))))
815         (t
816          (calc-extensions)
817          (math-pow-fancy a b)))
818 )
819
820 (defun math-ipow (a n)   ; [O O I] [Public]
821   (cond ((Math-integer-negp n)
822          (math-ipow (math-div 1 a) (Math-integer-neg n)))
823         ((not (consp n))
824          (if (and (Math-ratp a) (> n 20))
825              (math-iipow-show a n)
826            (math-iipow a n)))
827         ((math-evenp n)
828          (math-ipow (math-mul a a) (math-div2 n)))
829         (t
830          (math-mul a (math-ipow (math-mul a a)
831                                 (math-div2 (math-add n -1))))))
832 )
833
834 (defun math-iipow (a n)   ; [O O S]
835   (cond ((= n 0) 1)
836         ((= n 1) a)
837         ((= (% n 2) 0) (math-iipow (math-mul a a) (/ n 2)))
838         (t (math-mul a (math-iipow (math-mul a a) (/ n 2)))))
839 )
840
841 (defun math-iipow-show (a n)   ; [O O S]
842   (math-working "pow" a)
843   (let ((val (cond
844               ((= n 0) 1)
845               ((= n 1) a)
846               ((= (% n 2) 0) (math-iipow-show (math-mul a a) (/ n 2)))
847               (t (math-mul a (math-iipow-show (math-mul a a) (/ n 2)))))))
848     (math-working "pow" val)
849     val)
850 )
851
852
853 (defun math-read-radix-digit (dig)   ; [D S; Z S]
854   (if (> dig ?9)
855       (if (< dig ?A)
856           nil
857         (- dig 55))
858     (if (>= dig ?0)
859         (- dig ?0)
860       nil))
861 )
862
863
864
865
866
867 ;;; Bug reporting
868
869 (defun report-calc-bug (topic)
870   "Report a bug in Calc, the GNU Emacs calculator.
871 Prompts for bug subject.  Leaves you in a mail buffer."
872   (interactive "sBug Subject: ")
873   (mail nil calc-bug-address topic)
874   (goto-char (point-max))
875   (insert "\nIn Calc " calc-version ", Emacs " (emacs-version) "\n\n")
876   (message (substitute-command-keys "Type \\[mail-send] to send bug report."))
877 )
878 (fset 'calc-report-bug (symbol-function 'report-calc-bug))
879