comparison lisp/calculator.el @ 27587:b529e919efd4

*** empty log message ***
author Gerd Moellmann <gerd@gnu.org>
date Wed, 02 Feb 2000 15:22:19 +0000
parents
children af501f05394a
comparison
equal deleted inserted replaced
27586:5d6eb73b10d0 27587:b529e919efd4
1 ;;; calculator.el --- A simple pocket calculator.
2
3 ;; Copyright (C) 1998 by Free Software Foundation, Inc.
4
5 ;; Author: Eli Barzilay <eli@lambda.cs.cornell.edu>
6 ;; Keywords: tools, convenience
7 ;; Time-stamp: <2000-02-01 20:12:16 eli>
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by the
13 ;; Free Software Foundation; either version 2, or (at your option) any
14 ;; later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 ;; MA 02111-1307, USA.
25
26 ;;; Commentary:
27 ;;
28 ;; A simple pocket calculator for Emacs.
29 ;; Why touch your mouse to get xcalc (or calc.exe), when you have Emacs?
30 ;;
31 ;; If this is not part of your Emacs distribution, then simply bind
32 ;; `calculator' to a key and make it an autoloaded function, e.g.:
33 ;; (autoload 'calculator "calculator"
34 ;; "Run the pocket calculator." t)
35 ;; (global-set-key [(control return)] 'calculator)
36 ;;
37 ;; Written by Eli Barzilay: Maze is Life! eli@cs.cornell.edu
38 ;; http://www.cs.cornell.edu/eli
39 ;;
40 ;; For latest version, check
41 ;; http://www.cs.cornell.edu/eli/misc/calculator.el
42
43
44 (eval-and-compile
45 (if (fboundp 'defgroup) nil
46 (defmacro defgroup (&rest forms) nil)
47 (defmacro defcustom (s v d &rest r) (list 'defvar s v d))))
48
49 ;;; Customization:
50
51 (defgroup calculator nil
52 "Simple pocket calculator."
53 :prefix "calculator"
54 :group 'tools
55 :group 'convenience)
56
57 (defcustom calculator-electric-mode nil
58 "*Run `calculator' electrically, in the echo area.
59 Note that if you use electric-mode, you wouldn't be able to use
60 conventional help keys."
61 :type 'boolean
62 :group 'calculator)
63
64 (defcustom calculator-bind-escape nil
65 "*If non-nil, set escape to exit the calculator."
66 :type 'boolean
67 :group 'calculator)
68
69 (defcustom calculator-unary-style 'postfix
70 "*Value is either 'prefix or 'postfix.
71 This determines the default behavior of unary operators."
72 :type '(choice (const prefix) (const postfix))
73 :group 'calculator)
74
75 (defcustom calculator-prompt "Calculator=%s> "
76 "*The prompt used by the pocket calculator.
77 It should contain a \"%s\" somewhere that will indicate the i/o radixes,
78 this string will be a two-character string as described in the
79 documentation for `calculator-mode'."
80 :type 'string
81 :group 'calculator)
82
83 (defcustom calculator-epsilon 1e-15
84 "*A threshold for results.
85 If any result computed in `calculator-funcall' is smaller than this in
86 its absolute value, then zero will be returned."
87 :type 'number
88 :group 'calculator)
89
90 (defcustom calculator-number-format "%1.3f"
91 "*The calculator's string used to display normal numbers."
92 :type 'string
93 :group 'calculator)
94
95 (defcustom calculator-number-exp-ulimit 1e16
96 "*The calculator's upper limit for normal numbers."
97 :type 'number
98 :group 'calculator)
99
100 (defcustom calculator-number-exp-llimit 0.001
101 "*The calculator's lower limit for normal numbers."
102 :type 'number
103 :group 'calculator)
104
105 (defcustom calculator-number-exp-format "%g"
106 "*The calculator's string used to display exponential numbers."
107 :type 'string
108 :group 'calculator)
109
110 (defcustom calculator-show-integers t
111 "*Non-nil value means delete all zero digits after the decimal point."
112 :type 'boolean
113 :group 'calculator)
114
115 (defcustom calculator-2s-complement nil
116 "*If non-nil, show negative numbers in 2s complement in radix modes.
117 Otherwise show as a negative number."
118 :type 'boolean
119 :group 'calculator)
120
121 (defcustom calculator-mode-hook nil
122 "*List of hook functions run by `calculator-mode'."
123 :type 'hook
124 :group 'calculator)
125
126 (defcustom calculator-user-registers nil
127 "*An association list of user-defined register bindings.
128
129 Each element in this list is a list of a character and a number that
130 will be stored in that character's register.
131
132 For example, use this to define the golden ratio number:
133 (setq calculator-user-registers '((?g . 1.61803398875)))"
134 :type '(repeat (cons character number))
135 :set '(lambda (_ val)
136 (and (boundp 'calculator-registers)
137 (setq calculator-registers
138 (append val calculator-registers)))
139 (setq calculator-user-registers val))
140 :group 'calculator)
141
142 (defcustom calculator-user-operators nil
143 "*A list of additional operators.
144
145 This is a list in the same format as specified in the documentation for
146 `calculator-operators', that you can use to bind additional calculator
147 operators. It is probably not a good idea to modify this value with
148 `customize' since it is too complex...
149
150 Examples:
151
152 * A very simple one, adding a postfix \"x-to-y\" convertion keys, using
153 `t' as a prefix key:
154
155 (setq calculator-user-operators
156 '((\"tf\" cl-to-fr (+ 32 (/ (* X 9) 5)) 1)
157 (\"tc\" fr-to-cl (/ (* (- X 32) 5) 9) 1)
158 (\"tp\" kg-to-lb (/ X 0.453592) 1)
159 (\"tk\" lb-to-kg (* X 0.453592) 1)
160 (\"tF\" mt-to-ft (/ X 0.3048) 1)
161 (\"tM\" ft-to-mt (* X 0.3048) 1)))
162
163 * Using a function-like form is very simple, X for an argument (Y the
164 second in case of a binary operator), TX is a truncated version of X
165 and F does a recursive call, Here is a [very inefficient] Fibonacci
166 number calculation:
167
168 (add-to-list 'calculator-user-operators
169 '(\"F\" fib (if (<= TX 1)
170 1
171 (+ (F (- TX 1)) (F (- TX 2)))) 0))
172
173 Note that this will be either postfix or prefix, according to
174 `calculator-unary-style'."
175 :type '(repeat (list string symbol sexp integer integer))
176 :group 'calculator)
177
178 ;;; Code:
179
180 (defvar calculator-initial-operators
181 '(;; these have keybindings of themselves, not calculator-ops
182 (nobind "=" = identity 1 -1)
183 (nobind "+" + + 2 4)
184 (nobind "-" - - 2 4)
185 (nobind "+" + + -1 9)
186 (nobind "-" - - -1 9)
187 (nobind "(" \( identity -1 -1)
188 (nobind ")" \) identity +1 10)
189 ;; normal keys
190 ("|" or (logior TX TY) 2 2)
191 ("#" xor (logxor TX TY) 2 2)
192 ("&" and (logand TX TY) 2 3)
193 ("*" * * 2 5)
194 ("/" / / 2 5)
195 ("\\" div (/ TX TY) 2 5)
196 ("%" rem (% TX TY) 2 5)
197 ("L" log log 2 6)
198 ("S" sin (sin DX) x 6)
199 ("C" cos (cos DX) x 6)
200 ("T" tan (tan DX) x 6)
201 ("IS" asin (D (asin X)) x 6)
202 ("IC" acos (D (acos X)) x 6)
203 ("IT" atan (D (atan X)) x 6)
204 ("Q" sqrt sqrt x 7)
205 ("^" ^ expt 2 7)
206 ("!" ! calculator-fact x 7)
207 (";" 1/ (/ 1 X) 1 7)
208 ("_" - - 1 8)
209 ("~" ~ (lognot TX) x 8)
210 (">" repR calculator-repR 1 8)
211 ("<" repL calculator-repL 1 8)
212 ("v" avg (/ (apply '+ L) (length L)) 0 8)
213 ("l" tot (apply '+ L) 0 8)
214 )
215 "A list of initial operators.
216
217 This is a list in the same format as `calculator-operators'. Whenever
218 `calculator' starts, it looks at the value of this variable, and if it
219 is not empty, its contents is prepended to `calculator-operators' and
220 the appropriate key bindings are made.
221
222 This variable is then reset to nil. Don't use this if you want to add
223 user-defined operators, use `calculator-user-operators' instead.")
224
225 (defvar calculator-operators nil
226 "The calculator operators, each a list with:
227
228 1. The key that is bound to for this operation (usually a string);
229
230 2. The displayed symbol for this function;
231
232 3. The function symbol, or a form that uses the variables `X' and `Y',
233 (if it is a binary operator), `TX' and `TY' (truncated integer
234 versions), `DX' (converted to radians if degrees mode is on), `D'
235 (function for converting radians to degrees if deg mode is on), `L'
236 (list of saved values), `F' (function for recursive iteration calls)
237 and evaluates to the function value - these variables are capital;
238
239 4. The function's arity, optional, one of: 2=binary, -1=prefix unary,
240 +1=postfix unary, 0=a 0-arg operator func, non-number=postfix/prefix
241 as determined by `calculator-unary-style' (the default);
242
243 5. The function's precedence - should be in the range of 1=lowest to
244 9=highest (optional, defaults to 1);
245
246 It it possible have a unary prefix version of a binary operator if it
247 comes later in this list. If the list begins with the symbol 'nobind,
248 then no key binding will take place - this is only useful for predefined
249 keys.
250
251 Use `calculator-user-operators' to add operators to this list, see its
252 documentation for an example.")
253
254 (defvar calculator-stack nil
255 "Stack contents - operations and operands.")
256
257 (defvar calculator-curnum nil
258 "Current number being entered (as a string).")
259
260 (defvar calculator-stack-display nil
261 "Cons of the stack and its string representation.")
262
263 (defvar calculator-char-radix
264 '((?D . nil) (?B . bin) (?O . oct) (?H . hex) (?X . hex))
265 "A table to convert input characters to corresponding radix symbols.")
266
267 (defvar calculator-output-radix nil
268 "The mode for display, one of: nil (decimal), 'bin, 'oct or 'hex.")
269
270 (defvar calculator-input-radix nil
271 "The mode for input, one of: nil (decimal), 'bin, 'oct or 'hex.")
272
273 (defvar calculator-deg nil
274 "Non-nil if trig functions operate on degrees instead of radians.")
275
276 (defvar calculator-saved-list nil
277 "A list of saved values collected.")
278
279 (defvar calculator-saved-ptr 0
280 "The pointer to the current saved number.")
281
282 (defvar calculator-add-saved nil
283 "Bound to t when a value should be added to the saved-list.")
284
285 (defvar calculator-display-fragile nil
286 "When non-nil, we see something that the next digit should replace.")
287
288 (defvar calculator-buffer nil
289 "The current calculator buffer.")
290
291 (defvar calculator-forced-input nil
292 "Used to make alias events, e.g., make Return equivalent to `='.")
293
294 (defvar calculator-last-opXY nil
295 "The last binary operation and its arguments.
296 Used for repeating operations in calculator-repR/L.")
297
298 (defvar calculator-registers ; use user-bindings first
299 (append calculator-user-registers (list (cons ?e e) (cons ?p pi)))
300 "The association list of calculator register values.")
301
302 (defvar calculator-saved-global-map nil
303 "Saved global key map.")
304
305 (defvar calculator-mode-map nil
306 "The calculator key map.")
307
308 (or calculator-mode-map
309 (let ((map (make-sparse-keymap "Calculator")))
310 (suppress-keymap map t)
311 (define-key map "i" nil)
312 (define-key map "o" nil)
313 (let ((p '(calculator-open-paren "(" "[" "{"
314 calculator-close-paren ")" "]" "}"
315 calculator-op-or-exp "+" "-" [kp-add] [kp-subtract]
316 calculator-digit "0" "1" "2" "3" "4" "5" "6" "7"
317 "8" "9" "a" "b" "c" "d" "f"
318 [kp-0] [kp-1] [kp-2] [kp-3] [kp-4]
319 [kp-5] [kp-6] [kp-7] [kp-8] [kp-9]
320 calculator-op [kp-divide] [kp-multiply]
321 calculator-decimal "." [kp-decimal]
322 calculator-exp "e"
323 calculator-dec/deg-mode "D"
324 calculator-set-register "s"
325 calculator-get-register "g"
326 calculator-radix-mode "H" "X" "O" "B"
327 calculator-radix-input-mode "id" "ih" "ix" "io" "ib"
328 "iD" "iH" "iX" "iO" "iB"
329 calculator-radix-output-mode "od" "oh" "ox" "oo" "ob"
330 "oD" "oH" "oX" "oO" "oB"
331 calculator-saved-up [?\C-p] [up]
332 calculator-saved-down [?\C-n] [down]
333 calculator-quit "q" [?\C-g]
334 calculator-enter [enter] [linefeed] [kp-enter]
335 [?\r] [?\n]
336 calculator-save-on-list " " [space]
337 calculator-clear-saved [?\C-c] [(control delete)]
338 calculator-save-and-quit [(control return)]
339 [(control kp-enter)]
340 calculator-paste [insert] [(shift insert)]
341 calculator-clear [delete] [?\C-?] [?\C-d]
342 calculator-help [?h] [??] [f1] [help]
343 calculator-copy [(control insert)]
344 calculator-backspace [backspace]
345 ))
346 (f nil))
347 (while p
348 (cond
349 ((symbolp (car p)) (setq f (car p)))
350 (p (define-key map (car p) f)))
351 (setq p (cdr p))))
352 (if calculator-bind-escape
353 (progn (define-key map [?\e] 'calculator-quit)
354 (define-key map [escape] 'calculator-quit))
355 (define-key map [?\e ?\e ?\e] 'calculator-quit))
356 ;; make C-h work in text-mode
357 (or window-system (define-key map [?\C-h] 'calculator-backspace))
358 (setq calculator-mode-map map)))
359
360 (defun calculator-mode ()
361 "A simple pocket calculator in Emacs.
362
363 This calculator is used in the same way as other popular calculators
364 like xcalc or calc.exe - but using an Emacs interface.
365
366 Expressions are entered using normal infix notation, parens are used as
367 normal. Unary functions are usually postfix, but some depends on the
368 value of `calculator-unary-style' (if the style for an operator below is
369 specified, then it is fixed, otherwise it depends on this variable).
370 `+' and `-' can be used as either binary operators or prefix unary
371 operators. Numbers can be entered with exponential notation using `e',
372 except when using a non-decimal radix mode for input (in this case `e'
373 will be the hexadecimal digit).
374
375 Here are the editing keys:
376 * `RET' `=' evaluate the current expression
377 * `C-insert' copy the whole current expression to the `kill-ring'
378 * `C-enter' evaluate, save result the `kill-ring' and exit
379 * `insert' paste a number if the one was copied (normally)
380 * `delete' `C-d' clear last argument or whole expression (hit twice)
381 * `backspace' delete a digit or a previous expression element
382 * `h' `?' pop-up a quick reference help
383 * `ESC' `q' exit (`ESC' can be used if `calculator-bind-escape' is
384 non-nil, otherwise use three consecutive `ESC's)
385
386 These operators are pre-defined:
387 * `+' `-' `*' `/' the common binary operators
388 * `\\' `%' integer division and reminder
389 * `_' `;' postfix unary negation and reciprocal
390 * `^' `L' binary operators for x^y and log(x) in base y
391 * `Q' `!' unary square root and factorial
392 * `S' `C' `T' unary trigonometric operators - sin, cos and tan
393 * `|' `#' `&' `~' bitwise operators - or, xor, and, not
394
395 The trigonometric functions can be inverted if prefixed with an `I', see
396 below for the way to use degrees instead of the default radians.
397
398 Two special postfix unary operators are `>' and `<': whenever a binary
399 operator is performed, it is remembered along with its arguments; then
400 `>' (`<') will apply the same operator with the same right (left)
401 argument.
402
403 hex/oct/bin modes can be set for input and for display separately.
404 Another toggle-able mode is for using degrees instead of radians for
405 trigonometric functions.
406 The keys to switch modes are (`X' is shortcut for `H'):
407 * `D' switch to all-decimal mode, or toggle degrees/radians
408 * `B' `O' `H' `X' binary/octal/hexadecimal modes for input & display
409 * `i' `o' followed by one of `D' `B' `O' `H' `X' (case
410 insensitive) sets only the input or display radix mode
411 The prompt indicates the current modes:
412 * \"D=\": degrees mode;
413 * \"?=\": (? is B/O/H) this is the radix for both input and output;
414 * \"=?\": (? is B/O/H) the display radix (when input is decimal);
415 * \"??\": (? is D/B/O/H) 1st char for input radix, 2nd for display.
416
417 Values can be saved for future reference in either a list of saved
418 values, or in registers.
419
420 The list of saved values is useful for statistics operations on some
421 collected data. It is possible to navigate in this list, and if the
422 value shown is the current one on the list, an indication is displayed
423 as \"[N]\" if this is the last number and there are N numbers, or
424 \"[M/N]\" if the M-th value is shown.
425 * `SPC' evaluate the current value as usual, but also adds
426 the result to the list of saved values
427 * `l' `v' computes total / average of saved values
428 * `up' `C-p' browse to the previous value in the list
429 * `down' `C-n' browse to the next value in the list
430 * `delete' `C-d' remove current value from the list (if it is on it)
431 * `C-delete' `C-c' delete the whole list
432
433 Registers are variable-like place-holders for values:
434 * `s' followed by a character attach the current value to that character
435 * `g' followed by a character fetches the attached value
436
437 There are many variables that can be used to customize the calculator.
438 Some interesting customization variables are:
439 * `calculator-electric-mode' use only the echo-area electrically.
440 * `calculator-unary-style' set most unary ops to pre/postfix style.
441 * `calculator-user-registers' to define user-preset registers.
442 * `calculator-user-operators' to add user-defined operators.
443 See the documentation for these variables, and \"calculator.el\" for
444 more information.
445
446 \\{calculator-mode-map}"
447 (interactive)
448 (kill-all-local-variables)
449 (setq major-mode 'calculator-mode)
450 (setq mode-name "Calculator")
451 (use-local-map calculator-mode-map)
452 (run-hooks 'calculator-mode-hook))
453
454 ;;;###autoload
455 (defun calculator ()
456 "Run the pocket calculator.
457 See the documentation for `calculator-mode' for more information."
458 (interactive)
459 (if calculator-electric-mode
460 (progn (require 'electric)
461 (message nil))) ; hide load message
462 (setq calculator-buffer
463 (or (and (bufferp calculator-buffer)
464 (buffer-live-p calculator-buffer)
465 calculator-buffer)
466 (if calculator-electric-mode
467 (get-buffer-create "*calculator*")
468 (let ((split-window-keep-point nil)
469 (window-min-height 2))
470 (select-window
471 (split-window-vertically (- (window-height) 2)))
472 (switch-to-buffer
473 (get-buffer-create "*calculator*"))))))
474 (set-buffer calculator-buffer)
475 (calculator-mode)
476 (setq buffer-read-only t)
477 (if calculator-initial-operators
478 (progn (calculator-add-operators calculator-initial-operators)
479 (setq calculator-initial-operators nil)
480 ;; don't change this since it is a customization variable,
481 ;; its set function will add any new operators.
482 (calculator-add-operators calculator-user-operators)))
483 (calculator-reset)
484 (calculator-update-display)
485 (if calculator-electric-mode
486 (save-window-excursion
487 (let (old-g-map old-l-map (echo-keystrokes 0)
488 (garbage-collection-messages nil)) ; no gc msg when electric
489 (kill-buffer calculator-buffer)
490 ;; strange behavior in FSF: doesn't always select correct
491 ;; minibuffer. I have no idea how to fix this
492 (setq calculator-buffer (window-buffer (minibuffer-window)))
493 (select-window (minibuffer-window))
494 (calculator-reset)
495 (calculator-update-display)
496 (setq old-l-map (current-local-map))
497 (setq old-g-map (current-global-map))
498 (setq calculator-saved-global-map (current-global-map))
499 (use-local-map calculator-mode-map)
500 (use-global-map calculator-mode-map)
501 (unwind-protect
502 (catch 'calculator-done
503 (Electric-command-loop
504 'calculator-done
505 ;; can't use 'noprompt, bug in electric.el
506 '(lambda () 'noprompt)
507 nil
508 (lambda (x y)
509 (calculator-update-display))))
510 (and calculator-buffer
511 (catch 'calculator-done (calculator-quit)))
512 (use-local-map old-l-map)
513 (use-global-map old-g-map))))
514 (message "Hit `?' For a quick help screen.")))
515
516 (defun calculator-op-arity (op)
517 "Return OP's arity, 2, +1 or -1."
518 (let ((arity (or (nth 3 op) 'x)))
519 (if (numberp arity)
520 arity
521 (if (eq calculator-unary-style 'postfix) +1 -1))))
522
523 (defun calculator-op-prec (op)
524 "Return OP's precedence for reducing when inserting into the stack.
525 Defaults to 1."
526 (or (nth 4 op) 1))
527
528 (defun calculator-add-operators (more-ops)
529 "This function handles operator addition.
530 Adds MORE-OPS to `calculator-operator', called initially to handle
531 `calculator-initial-operators' and `calculator-user-operators'."
532 (let ((added-ops nil))
533 (while more-ops
534 (or (eq (car (car more-ops)) 'nobind)
535 (let ((i -1) (key (car (car more-ops))))
536 ;; make sure the key is undefined, so it's easy to define
537 ;; prefix keys
538 (while (< (setq i (1+ i)) (length key))
539 (or (keymapp
540 (lookup-key calculator-mode-map
541 (substring key 0 (1+ i))))
542 (progn
543 (define-key
544 calculator-mode-map (substring key 0 (1+ i)) nil)
545 (setq i (length key)))))
546 (define-key calculator-mode-map key 'calculator-op)))
547 (setq added-ops (cons (if (eq (car (car more-ops)) 'nobind)
548 (cdr (car more-ops))
549 (car more-ops))
550 added-ops))
551 (setq more-ops (cdr more-ops)))
552 ;; added-ops come first, but in correct order
553 (setq calculator-operators
554 (append (nreverse added-ops) calculator-operators))))
555
556 (defun calculator-reset ()
557 "Reset calculator variables."
558 (setq calculator-stack nil
559 calculator-curnum nil
560 calculator-stack-display nil
561 calculator-display-fragile nil)
562 (calculator-update-display))
563
564 (defun calculator-get-prompt ()
565 "Return a string to display.
566 The string is set not to exceed the screen width."
567 (let* ((calculator-prompt
568 (format calculator-prompt
569 (cond
570 ((or calculator-output-radix calculator-input-radix)
571 (if (eq calculator-output-radix
572 calculator-input-radix)
573 (concat
574 (char-to-string
575 (car (rassq calculator-output-radix
576 calculator-char-radix)))
577 "=")
578 (concat
579 (if calculator-input-radix
580 (char-to-string
581 (car (rassq calculator-input-radix
582 calculator-char-radix)))
583 "=")
584 (char-to-string
585 (car (rassq calculator-output-radix
586 calculator-char-radix))))))
587 (calculator-deg "D=")
588 (t "=="))))
589 (prompt
590 (concat calculator-prompt
591 (cdr calculator-stack-display)
592 (cond (calculator-curnum
593 ;; number being typed
594 (concat calculator-curnum "_"))
595 ((and (= 1 (length calculator-stack))
596 calculator-display-fragile)
597 ;; only the result is shown, next number will
598 ;; restart
599 nil)
600 (t
601 ;; waiting for a number or an operator
602 "?"))))
603 (trim (- (length prompt) (1- (window-width)))))
604 (if (<= trim 0)
605 prompt
606 (concat calculator-prompt
607 (substring prompt (+ trim (length calculator-prompt)))))))
608
609 (defun calculator-curnum-value ()
610 "Get the numeric value of the displayed number string as a float."
611 (if calculator-input-radix
612 (let ((radix
613 (cdr (assq calculator-input-radix
614 '((bin . 2) (oct . 8) (hex . 16)))))
615 (i -1) (value 0))
616 ;; assume valid input (upcased & characters in range)
617 (while (< (setq i (1+ i)) (length calculator-curnum))
618 (setq value
619 (+ (let ((ch (aref calculator-curnum i)))
620 (- ch (if (<= ch ?9) ?0 (- ?A 10))))
621 (* radix value))))
622 value)
623 (car
624 (read-from-string
625 (cond
626 ((equal "." calculator-curnum)
627 "0.0")
628 ((string-match "[eE][+-]?$" calculator-curnum)
629 (concat calculator-curnum "0"))
630 ((string-match "\\.[0-9]\\|[eE]" calculator-curnum)
631 calculator-curnum)
632 ((string-match "\\." calculator-curnum)
633 ;; do this because Emacs reads "23." as an integer.
634 (concat calculator-curnum "0"))
635 ((stringp calculator-curnum)
636 (concat calculator-curnum ".0"))
637 (t "0.0"))))))
638
639 (defun calculator-num-to-string (num)
640 "Convert NUM to a displayable string."
641 (cond
642 ((and (numberp num) calculator-output-radix)
643 ;; print with radix - for binary I convert the octal number
644 (let ((str (format (if (eq calculator-output-radix 'hex) "%x" "%o")
645 (calculator-truncate
646 (if calculator-2s-complement num (abs num))))))
647 (if (eq calculator-output-radix 'bin)
648 (let ((i -1) (s ""))
649 (while (< (setq i (1+ i)) (length str))
650 (setq s
651 (concat s
652 (cdr (assq (aref str i)
653 '((?0 . "000") (?1 . "001")
654 (?2 . "010") (?3 . "011")
655 (?4 . "100") (?5 . "101")
656 (?6 . "110") (?7 . "111")))))))
657 (string-match "^0*\\(.+\\)" s)
658 (setq str (match-string 1 s))))
659 (upcase
660 (if (and (not calculator-2s-complement) (< num 0))
661 (concat "-" str)
662 str))))
663 ((and (numberp num)
664 ;; is this a normal-range number?
665 (>= (abs num) calculator-number-exp-llimit)
666 (< (abs num) calculator-number-exp-ulimit))
667 (let ((str (format calculator-number-format num)))
668 (cond
669 ((and calculator-show-integers (string-match "\\.?0+$" str))
670 ;; remove all redundant zeros
671 (substring str 0 (match-beginning 0)))
672 ((and (not calculator-show-integers)
673 (string-match "\\..\\(.*[^0]\\)?\\(0+\\)$" str))
674 ;; remove zeros, except for first after the "."
675 (substring str 0 (match-beginning 2)))
676 (t str))))
677 ((numberp num) (format calculator-number-exp-format num))
678 (t (prin1-to-string (nth 1 num) t))))
679
680 (defun calculator-update-display (&optional force)
681 "Update the display.
682 If optional argument FORCE is non-nil, don't use the cached string."
683 (set-buffer calculator-buffer)
684 ;; update calculator-stack-display
685 (if (or force
686 (not (eq (car calculator-stack-display) calculator-stack)))
687 (setq calculator-stack-display
688 (cons calculator-stack
689 (if calculator-stack
690 (concat
691 (mapconcat 'calculator-num-to-string
692 (reverse calculator-stack)
693 " ")
694 " "
695 (and calculator-display-fragile
696 calculator-saved-list
697 (= (car calculator-stack)
698 (nth calculator-saved-ptr
699 calculator-saved-list))
700 (if (= 0 calculator-saved-ptr)
701 (format "[%s]" (length calculator-saved-list))
702 (format "[%s/%s]"
703 (- (length calculator-saved-list)
704 calculator-saved-ptr)
705 (length calculator-saved-list)))))
706 ""))))
707 (let ((inhibit-read-only t))
708 (erase-buffer)
709 (insert (calculator-get-prompt)))
710 (set-buffer-modified-p nil)
711 (if calculator-display-fragile
712 (goto-char (1+ (length calculator-prompt)))
713 (goto-char (1- (point)))))
714
715 (defun calculator-reduce-stack (prec)
716 "Reduce the stack using top operator.
717 PREC is a precedence - reduce everything with higher precedence."
718 (while
719 (cond
720 ((and (cdr (cdr calculator-stack)) ; have three values
721 (consp (nth 0 calculator-stack)) ; two operators & num
722 (numberp (nth 1 calculator-stack))
723 (consp (nth 2 calculator-stack))
724 (eq '\) (nth 1 (nth 0 calculator-stack)))
725 (eq '\( (nth 1 (nth 2 calculator-stack))))
726 ;; reduce "... ( x )" --> "... x"
727 (setq calculator-stack
728 (cons (nth 1 calculator-stack)
729 (nthcdr 3 calculator-stack)))
730 ;; another iteration
731 t)
732 ((and (cdr (cdr calculator-stack)) ; have three values
733 (numberp (nth 0 calculator-stack)) ; two nums & operator
734 (consp (nth 1 calculator-stack))
735 (numberp (nth 2 calculator-stack))
736 (= 2 (calculator-op-arity ; binary operator
737 (nth 1 calculator-stack)))
738 (<= prec ; with higher prec.
739 (calculator-op-prec (nth 1 calculator-stack))))
740 ;; reduce "... x op y" --> "... r", r is the result
741 (setq calculator-stack
742 (cons (calculator-funcall
743 (nth 2 (nth 1 calculator-stack))
744 (nth 2 calculator-stack)
745 (nth 0 calculator-stack))
746 (nthcdr 3 calculator-stack)))
747 ;; another iteration
748 t)
749 ((and (>= (length calculator-stack) 2) ; have two values
750 (numberp (nth 0 calculator-stack)) ; number & operator
751 (consp (nth 1 calculator-stack))
752 (= -1 (calculator-op-arity ; prefix-unary op
753 (nth 1 calculator-stack)))
754 (<= prec ; with higher prec.
755 (calculator-op-prec (nth 1 calculator-stack))))
756 ;; reduce "... op x" --> "... r" for prefix op
757 (setq calculator-stack
758 (cons (calculator-funcall
759 (nth 2 (nth 1 calculator-stack))
760 (nth 0 calculator-stack))
761 (nthcdr 2 calculator-stack)))
762 ;; another iteration
763 t)
764 ((and (cdr calculator-stack) ; have two values
765 (consp (nth 0 calculator-stack)) ; operator & number
766 (numberp (nth 1 calculator-stack))
767 (= +1 (calculator-op-arity ; postfix-unary op
768 (nth 0 calculator-stack)))
769 (<= prec ; with higher prec.
770 (calculator-op-prec (nth 0 calculator-stack))))
771 ;; reduce "... x op" --> "... r" for postfix op
772 (setq calculator-stack
773 (cons (calculator-funcall
774 (nth 2 (nth 0 calculator-stack))
775 (nth 1 calculator-stack))
776 (nthcdr 2 calculator-stack)))
777 ;; another iteration
778 t)
779 ((and calculator-stack ; have one value
780 (consp (nth 0 calculator-stack)) ; an operator
781 (= 0 (calculator-op-arity ; 0-ary op
782 (nth 0 calculator-stack))))
783 ;; reduce "... op" --> "... r" for 0-ary op
784 (setq calculator-stack
785 (cons (calculator-funcall
786 (nth 2 (nth 0 calculator-stack)))
787 (nthcdr 1 calculator-stack)))
788 ;; another iteration
789 t)
790 ((and (cdr calculator-stack) ; have two values
791 (numberp (nth 0 calculator-stack)) ; both numbers
792 (numberp (nth 1 calculator-stack)))
793 ;; get rid of redundant numbers:
794 ;; reduce "... y x" --> "... x"
795 ;; needed for 0-ary ops that puts more values
796 (setcdr calculator-stack (cdr (cdr calculator-stack))))
797 (t ;; no more iterations
798 nil))))
799
800 (eval-when-compile ; silence the compiler
801 (or (fboundp 'event-key)
802 (defun event-key (&rest _) nil))
803 (or (fboundp 'key-press-event-p)
804 (defun key-press-event-p (&rest _) nil)))
805
806 (defun calculator-last-input ()
807 "Last char (or event or event sequence) that was read."
808 (let ((inp (or calculator-forced-input (this-command-keys))))
809 (if (or (stringp inp) (not (arrayp inp)))
810 inp
811 ;; this translates kp-x to x and [tries to] create a string to
812 ;; lookup operators
813 (let* ((i -1) (converted-str (make-string (length inp) ? )) k)
814 ;; converts an array to a string the ops lookup with keypad
815 ;; input
816 (while (< (setq i (1+ i)) (length inp))
817 (setq k (aref inp i))
818 ;; if Emacs will someday have a event-key, then this would
819 ;; probably be modified anyway
820 (and (fboundp 'event-key) (key-press-event-p k)
821 (setq k (event-key k)))
822 ;; assume all symbols are translatable with an ascii-character
823 (and (symbolp k)
824 (setq k (or (get k 'ascii-character) ? )))
825 (aset converted-str i k))
826 converted-str))))
827
828 (defun calculator-clear-fragile (&optional op)
829 "Clear the fragile flag if it was set, then maybe reset all.
830 OP is the operator (if any) that caused this call."
831 (if (and calculator-display-fragile
832 (or (not op)
833 (= -1 (calculator-op-arity op))
834 (= 0 (calculator-op-arity op))))
835 ;; reset if last calc finished, and now get a num or prefix or 0-ary
836 ;; op.
837 (calculator-reset))
838 (setq calculator-display-fragile nil))
839
840 (defun calculator-digit ()
841 "Enter a single digit."
842 (interactive)
843 (let ((inp (aref (calculator-last-input) 0)))
844 (if (and (or calculator-display-fragile
845 (not (numberp (car calculator-stack))))
846 (cond
847 ((not calculator-input-radix) (<= inp ?9))
848 ((eq calculator-input-radix 'bin) (<= inp ?1))
849 ((eq calculator-input-radix 'oct) (<= inp ?7))
850 (t t)))
851 ;; enter digit if starting a new computation or have an op on the
852 ;; stack.
853 (progn
854 (calculator-clear-fragile)
855 (let ((digit (upcase (char-to-string inp))))
856 (if (equal calculator-curnum "0")
857 (setq calculator-curnum nil))
858 (setq calculator-curnum
859 (concat (or calculator-curnum "") digit)))
860 (calculator-update-display)))))
861
862 (defun calculator-decimal ()
863 "Enter a decimal period."
864 (interactive)
865 (if (and (not calculator-input-radix)
866 (or calculator-display-fragile
867 (not (numberp (car calculator-stack))))
868 (not (and calculator-curnum
869 (string-match "[.eE]" calculator-curnum))))
870 ;; enter the period on the same condition as a digit, only if no
871 ;; period or exponent entered yet.
872 (progn
873 (calculator-clear-fragile)
874 (setq calculator-curnum (concat (or calculator-curnum "0") "."))
875 (calculator-update-display))))
876
877 (defun calculator-exp ()
878 "Enter an `E' exponent character, or a digit in hex input mode."
879 (interactive)
880 (if calculator-input-radix
881 (calculator-digit)
882 (if (and (or calculator-display-fragile
883 (not (numberp (car calculator-stack))))
884 (not (and calculator-curnum
885 (string-match "[eE]" calculator-curnum))))
886 ;; same condition as above, also no E so far.
887 (progn
888 (calculator-clear-fragile)
889 (setq calculator-curnum (concat (or calculator-curnum "1") "e"))
890 (calculator-update-display)))))
891
892 (defun calculator-op ()
893 "Enter an operator on the stack, doing all necessary reductions."
894 (interactive)
895 (let* ((last-inp (calculator-last-input))
896 (op (assoc last-inp calculator-operators)))
897 (calculator-clear-fragile op)
898 (if (and calculator-curnum (/= (calculator-op-arity op) 0))
899 (setq calculator-stack
900 (cons (calculator-curnum-value) calculator-stack)))
901 (setq calculator-curnum nil)
902 (if (and (= 2 (calculator-op-arity op))
903 (not (and calculator-stack
904 (numberp (nth 0 calculator-stack)))))
905 ;; we have a binary operator but no number - search for a prefix
906 ;; version
907 (let ((rest-ops calculator-operators))
908 (while (not (equal last-inp (car (car rest-ops))))
909 (setq rest-ops (cdr rest-ops)))
910 (setq op (assoc last-inp (cdr rest-ops)))
911 (if (not (and op (= -1 (calculator-op-arity op))))
912 (error "Binary operator without a first operand"))))
913 (calculator-reduce-stack
914 (cond ((eq (nth 1 op) '\() 10)
915 ((eq (nth 1 op) '\)) 0)
916 (t (calculator-op-prec op))))
917 (if (or (and (= -1 (calculator-op-arity op))
918 (numberp (car calculator-stack)))
919 (and (/= (calculator-op-arity op) -1)
920 (/= (calculator-op-arity op) 0)
921 (not (numberp (car calculator-stack)))))
922 (error "Unterminated expression"))
923 (setq calculator-stack (cons op calculator-stack))
924 (calculator-reduce-stack (calculator-op-prec op))
925 (and (= (length calculator-stack) 1)
926 (numberp (nth 0 calculator-stack))
927 ;; the display is fragile if it contains only one number
928 (setq calculator-display-fragile t)
929 ;; add number to the saved-list
930 calculator-add-saved
931 (if (= 0 calculator-saved-ptr)
932 (setq calculator-saved-list
933 (cons (car calculator-stack) calculator-saved-list))
934 (let ((p (nthcdr (1- calculator-saved-ptr)
935 calculator-saved-list)))
936 (setcdr p (cons (car calculator-stack) (cdr p))))))
937 (calculator-update-display)))
938
939 (defun calculator-op-or-exp ()
940 "Either enter an operator or a digit.
941 Used with +/- for entering them as digits in numbers like 1e-3."
942 (interactive)
943 (if (and (not calculator-display-fragile)
944 calculator-curnum
945 (string-match "[eE]$" calculator-curnum))
946 (calculator-digit)
947 (calculator-op)))
948
949 (defun calculator-dec/deg-mode ()
950 "Set decimal mode for display & input, if decimal, toggle deg mode."
951 (interactive)
952 (if calculator-curnum
953 (setq calculator-stack
954 (cons (calculator-curnum-value) calculator-stack)))
955 (setq calculator-curnum nil)
956 (if (or calculator-input-radix calculator-output-radix)
957 (progn (setq calculator-input-radix nil)
958 (setq calculator-output-radix nil))
959 ;; already decimal - toggle degrees mode
960 (setq calculator-deg (not calculator-deg)))
961 (calculator-update-display t))
962
963 (defun calculator-radix-mode ()
964 "Set input and display radix modes."
965 (interactive)
966 (calculator-radix-input-mode)
967 (calculator-radix-output-mode))
968
969 (defun calculator-radix-input-mode ()
970 "Set input radix modes."
971 (interactive)
972 (if calculator-curnum
973 (setq calculator-stack
974 (cons (calculator-curnum-value) calculator-stack)))
975 (setq calculator-curnum nil)
976 (setq calculator-input-radix
977 (let ((inp (calculator-last-input)))
978 (cdr (assq (upcase (aref inp (1- (length inp))))
979 calculator-char-radix))))
980 (calculator-update-display))
981
982 (defun calculator-radix-output-mode ()
983 "Set display radix modes."
984 (interactive)
985 (if calculator-curnum
986 (setq calculator-stack
987 (cons (calculator-curnum-value) calculator-stack)))
988 (setq calculator-curnum nil)
989 (setq calculator-output-radix
990 (let ((inp (calculator-last-input)))
991 (cdr (assq (upcase (aref inp (1- (length inp))))
992 calculator-char-radix))))
993 (calculator-update-display t))
994
995 (defun calculator-save-on-list ()
996 "Evaluate current expression, put result on the saved values list."
997 (interactive)
998 (let ((calculator-add-saved t)) ; marks the result to be added
999 (calculator-enter)))
1000
1001 (defun calculator-clear-saved ()
1002 "Clear the list of saved values in `calculator-saved-list'."
1003 (interactive)
1004 (setq calculator-saved-list nil)
1005 (calculator-update-display t))
1006
1007 (defun calculator-saved-move (n)
1008 "Go N elements up the list of saved values."
1009 (interactive)
1010 (and calculator-saved-list
1011 (or (null calculator-stack) calculator-display-fragile)
1012 (progn
1013 (setq calculator-saved-ptr
1014 (max (min (+ n calculator-saved-ptr)
1015 (length calculator-saved-list))
1016 0))
1017 (if (nth calculator-saved-ptr calculator-saved-list)
1018 (setq calculator-stack
1019 (list (nth calculator-saved-ptr calculator-saved-list))
1020 calculator-display-fragile t)
1021 (calculator-reset)))))
1022
1023 (defun calculator-saved-up ()
1024 "Go up the list of saved values."
1025 (interactive)
1026 (calculator-saved-move +1))
1027
1028 (defun calculator-saved-down ()
1029 "Go down the list of saved values."
1030 (interactive)
1031 (calculator-saved-move -1))
1032
1033 (defun calculator-open-paren ()
1034 "Equivalents of `(' use this."
1035 (interactive)
1036 (let ((calculator-forced-input "("))
1037 (calculator-op)))
1038
1039 (defun calculator-close-paren ()
1040 "Equivalents of `)' use this."
1041 (interactive)
1042 (let ((calculator-forced-input ")"))
1043 (calculator-op)))
1044
1045 (defun calculator-enter ()
1046 "Make Enter equivalent to `='."
1047 (interactive)
1048 (let ((calculator-forced-input "="))
1049 (calculator-op)))
1050
1051 (defun calculator-backspace ()
1052 "Backward delete a single digit or a stack element."
1053 (interactive)
1054 (if calculator-curnum
1055 (setq calculator-curnum
1056 (if (> (length calculator-curnum) 1)
1057 (substring calculator-curnum
1058 0 (1- (length calculator-curnum)))
1059 nil))
1060 (setq calculator-stack (cdr calculator-stack)))
1061 (calculator-update-display))
1062
1063 (defun calculator-clear ()
1064 "Clear current number."
1065 (interactive)
1066 (setq calculator-curnum nil)
1067 (cond
1068 ;; if the current number is from the saved-list - remove it
1069 ((and calculator-display-fragile
1070 calculator-saved-list
1071 (= (car calculator-stack)
1072 (nth calculator-saved-ptr calculator-saved-list)))
1073 (if (= 0 calculator-saved-ptr)
1074 (setq calculator-saved-list (cdr calculator-saved-list))
1075 (let ((p (nthcdr (1- calculator-saved-ptr)
1076 calculator-saved-list)))
1077 (setcdr p (cdr (cdr p)))
1078 (setq calculator-saved-ptr (1- calculator-saved-ptr))))
1079 (if calculator-saved-list
1080 (setq calculator-stack
1081 (list (nth calculator-saved-ptr calculator-saved-list)))
1082 (calculator-reset)))
1083 ;; reset if fragile or double clear
1084 ((or calculator-display-fragile (eq last-command this-command))
1085 (calculator-reset)))
1086 (calculator-update-display))
1087
1088 (defun calculator-copy ()
1089 "Copy current number to the `kill-ring'."
1090 (interactive)
1091 (calculator-enter)
1092 ;; remove trailing .0 and spaces .0
1093 (let ((s (cdr calculator-stack-display)))
1094 (if (string-match "^\\(.*[^ ]\\) *$" s)
1095 (setq s (match-string 1 s)))
1096 (kill-new s)))
1097
1098 (defun calculator-set-register (reg)
1099 "Set a register value for REG."
1100 (interactive "cRegister to store into: ")
1101 (let* ((as (assq reg calculator-registers))
1102 (val (progn (calculator-enter) (car calculator-stack))))
1103 (if as
1104 (setcdr as val)
1105 (setq calculator-registers
1106 (cons (cons reg val) calculator-registers)))
1107 (message (format "[%c] := %S" reg val))))
1108
1109 (defun calculator-put-value (val)
1110 "Paste VAL as if entered.
1111 Used by `calculator-paste' and `get-register'."
1112 (if (and (numberp val)
1113 ;; (not calculator-curnum)
1114 (or calculator-display-fragile
1115 (not (numberp (car calculator-stack)))))
1116 (progn
1117 (calculator-clear-fragile)
1118 (setq calculator-curnum (calculator-num-to-string val))
1119 (calculator-update-display))))
1120
1121 (defun calculator-paste ()
1122 "Paste a value from the `kill-ring'."
1123 (interactive)
1124 (calculator-put-value
1125 (condition-case nil (car (read-from-string (current-kill 0)))
1126 (error nil))))
1127
1128 (defun calculator-get-register (reg)
1129 "Get a value from a register REG."
1130 (interactive "cRegister to get value from: ")
1131 (calculator-put-value (cdr (assq reg calculator-registers))))
1132
1133 (defun calculator-help ()
1134 ;; this is used as the quick reference screen you get with `h'
1135 "Quick reference:
1136 * numbers/operators/parens/./e - enter expressions
1137 + - * / \\(div) %(rem) _(-X,postfix) ;(1/X,postfix) ^(exp) L(og)
1138 Q(sqrt) !(fact) S(in) C(os) T(an) |(or) #(xor) &(and) ~(not)
1139 * >/< repeats last binary operation with its 2nd (1st) arg as postfix op
1140 * I inverses next trig function
1141 * D - switch to all-decimal mode, or toggles deg/rad mode
1142 * B/O/H/X - binary/octal/hex mode for i/o (X is a shortcut for H)
1143 * i/o - prefix for d/b/o/x - set only input/output modes
1144 * enter/= - evaluate current expr. * s/g - set/get a register
1145 * space - evaluate & save on list * l/v - list total/average
1146 * up/down/C-p/C-n - browse saved * C-delete - clear all saved
1147 * C-insert - copy whole expr. * C-enter - evaluate, copy, exit
1148 * insert - paste a number * backspace- delete backwards
1149 * delete - clear argument or list value or whole expression (twice)
1150 * escape/q - exit."
1151 (interactive)
1152 (if (eq last-command 'calculator-help)
1153 (let ((mode-name "Calculator")
1154 (major-mode 'calculator-mode)
1155 (g-map (current-global-map))
1156 (win (selected-window)))
1157 (require 'ehelp)
1158 (if calculator-electric-mode
1159 (use-global-map calculator-saved-global-map))
1160 (electric-describe-mode)
1161 (if calculator-electric-mode
1162 (use-global-map g-map))
1163 (select-window win) ; these are for XEmacs (also below)
1164 (message nil))
1165 (let ((one (one-window-p t))
1166 (win (selected-window))
1167 (help-buf (get-buffer-create "*Help*")))
1168 (save-window-excursion
1169 (with-output-to-temp-buffer "*Help*"
1170 (princ (documentation 'calculator-help)))
1171 (if one
1172 (shrink-window-if-larger-than-buffer
1173 (get-buffer-window help-buf)))
1174 (message
1175 "`%s' again for more help, any other key continues normally."
1176 (calculator-last-input))
1177 (select-window win)
1178 (sit-for 360))
1179 (select-window win))))
1180
1181 (defun calculator-quit ()
1182 "Quit calculator."
1183 (interactive)
1184 (set-buffer calculator-buffer)
1185 (let ((inhibit-read-only t)) (erase-buffer))
1186 (if (not calculator-electric-mode)
1187 (progn
1188 (condition-case nil
1189 (while (get-buffer-window calculator-buffer)
1190 (delete-window (get-buffer-window calculator-buffer)))
1191 (error nil))
1192 (kill-buffer calculator-buffer)))
1193 (setq calculator-buffer nil)
1194 (message "Calculator done.")
1195 (if calculator-electric-mode (throw 'calculator-done nil)))
1196
1197 (defun calculator-save-and-quit ()
1198 "Quit the calculator, saving the result on the `kill-ring'."
1199 (interactive)
1200 (calculator-enter)
1201 (calculator-copy)
1202 (calculator-quit))
1203
1204 (defun calculator-funcall (f &optional X Y)
1205 "If F is a symbol, evaluate (F X Y).
1206 Otherwise, it should be a list, evaluate it with X, Y bound to the
1207 arguments."
1208 ;; remember binary ops for calculator-repR/L
1209 (if Y (setq calculator-last-opXY (list f X Y)))
1210 (condition-case nil
1211 (let ((result
1212 (if (symbolp f)
1213 (cond ((and X Y) (funcall f X Y))
1214 (X (funcall f X))
1215 (t (funcall f)))
1216 ;; f is an expression
1217 (let* ((__f__ f) ; so we can get this value below...
1218 (TX (calculator-truncate X))
1219 (TY (and Y (calculator-truncate Y)))
1220 (DX (if calculator-deg (/ (* X pi) 180) X))
1221 (L calculator-saved-list)
1222 (Fbound (fboundp 'F))
1223 (Fsave (and Fbound (symbol-function 'F)))
1224 (Dbound (fboundp 'D))
1225 (Dsave (and Dbound (symbol-function 'D))))
1226 ;; a shortened version of flet
1227 (fset 'F (function
1228 (lambda (&optional x y)
1229 (calculator-funcall __f__ x y))))
1230 (fset 'D (function
1231 (lambda (x)
1232 (if calculator-deg (/ (* x 180) pi) x))))
1233 (unwind-protect (eval f)
1234 (if Fbound (fset 'F Fsave) (fmakunbound 'F))
1235 (if Dbound (fset 'D Dsave) (fmakunbound 'D)))))))
1236 (if (< (abs result) calculator-epsilon)
1237 0
1238 result))
1239 (error 0)))
1240
1241 (defun calculator-repR (x)
1242 "Repeats the last binary operation with its second argument and X.
1243 To use this, apply a binary operator (evaluate it), then call this."
1244 (if calculator-last-opXY
1245 ;; avoid rebinding calculator-last-opXY
1246 (let ((calculator-last-opXY calculator-last-opXY))
1247 (calculator-funcall
1248 (car calculator-last-opXY) x (nth 2 calculator-last-opXY)))
1249 x))
1250
1251 (defun calculator-repL (x)
1252 "Repeats the last binary operation with its first argument and X.
1253 To use this, apply a binary operator (evaluate it), then call this."
1254 (if calculator-last-opXY
1255 ;; avoid rebinding calculator-last-opXY
1256 (let ((calculator-last-opXY calculator-last-opXY))
1257 (calculator-funcall
1258 (car calculator-last-opXY) (nth 1 calculator-last-opXY) x))
1259 x))
1260
1261 (defun calculator-fact (x)
1262 "Simple factorial of X."
1263 (let ((r (if (<= x 10) 1 1.0)))
1264 (while (> x 0)
1265 (setq r (* r (truncate x)))
1266 (setq x (1- x)))
1267 r))
1268
1269 (defun calculator-truncate (n)
1270 "Truncate N, return 0 in case of overflow."
1271 (condition-case nil (truncate n) (error 0)))
1272
1273
1274 (provide 'calculator)
1275
1276 ;;; calculator.el ends here