diff options
| author | Eli Barzilay | 2014-06-15 00:52:34 -0400 |
|---|---|---|
| committer | Eli Barzilay | 2014-06-15 00:52:34 -0400 |
| commit | 5335a8ced5a44befa20b759b73c900856defa0d7 (patch) | |
| tree | 4e306f61e435b5ca97b80da6971076598d1d33b9 | |
| parent | df5703a00d610a89fa6bc1da906228907b36b5d8 (diff) | |
| download | emacs-5335a8ced5a44befa20b759b73c900856defa0d7.tar.gz emacs-5335a8ced5a44befa20b759b73c900856defa0d7.zip | |
* lisp/calculator.el: Lots of revisions
- Kill the calculator buffer after electric mode too.
- Make decimal mode have "," groups, so it's more fitting for use in
money calculations.
- Factorial works with non-integer inputs.
- Swallow less errors.
- Lots of other improvements, but no changes to custom variables, or
other user visible changes (except the above).
| -rw-r--r-- | lisp/calculator.el | 996 |
1 files changed, 423 insertions, 573 deletions
diff --git a/lisp/calculator.el b/lisp/calculator.el index d6eb892f7fb..52dc8c53661 100644 --- a/lisp/calculator.el +++ b/lisp/calculator.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; calculator.el --- a [not so] simple calculator for Emacs -*- lexical-binding: t -*- | 1 | ;;; calculator.el --- a calculator for Emacs -*- lexical-binding: t -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1998, 2000-2014 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1998, 2000-2014 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -33,15 +33,8 @@ | |||
| 33 | ;; "Run the Emacs calculator." t) | 33 | ;; "Run the Emacs calculator." t) |
| 34 | ;; (global-set-key [(control return)] 'calculator) | 34 | ;; (global-set-key [(control return)] 'calculator) |
| 35 | ;; | 35 | ;; |
| 36 | ;; Written by Eli Barzilay: Maze is Life! eli@barzilay.org | 36 | ;; Written by Eli Barzilay, eli@barzilay.org |
| 37 | ;; http://www.barzilay.org/ | ||
| 38 | ;; | 37 | ;; |
| 39 | ;; For latest version, check | ||
| 40 | ;; http://www.barzilay.org/misc/calculator.el | ||
| 41 | ;; | ||
| 42 | |||
| 43 | ;;; History: | ||
| 44 | ;; I hate history. | ||
| 45 | 38 | ||
| 46 | ;;;===================================================================== | 39 | ;;;===================================================================== |
| 47 | ;;; Customization: | 40 | ;;; Customization: |
| @@ -79,7 +72,7 @@ This determines the default behavior of unary operators." | |||
| 79 | 72 | ||
| 80 | (defcustom calculator-prompt "Calc=%s> " | 73 | (defcustom calculator-prompt "Calc=%s> " |
| 81 | "The prompt used by the Emacs calculator. | 74 | "The prompt used by the Emacs calculator. |
| 82 | It should contain a \"%s\" somewhere that will indicate the i/o radices; | 75 | It should contain a \"%s\" somewhere that will indicate the i/o radixes; |
| 83 | this will be a two-character string as described in the documentation | 76 | this will be a two-character string as described in the documentation |
| 84 | for `calculator-mode'." | 77 | for `calculator-mode'." |
| 85 | :type 'string | 78 | :type 'string |
| @@ -115,8 +108,8 @@ See `calculator-radix-grouping-mode'." | |||
| 115 | 108 | ||
| 116 | (defcustom calculator-remove-zeros t | 109 | (defcustom calculator-remove-zeros t |
| 117 | "Non-nil value means delete all redundant zero decimal digits. | 110 | "Non-nil value means delete all redundant zero decimal digits. |
| 118 | If this value is not t, and not nil, redundant zeros are removed except | 111 | If this value is not t and not nil, redundant zeros are removed except |
| 119 | for one and if it is nil, nothing is removed. | 112 | for one. |
| 120 | Used by the `calculator-remove-zeros' function." | 113 | Used by the `calculator-remove-zeros' function." |
| 121 | :type '(choice (const t) (const leave-decimal) (const nil)) | 114 | :type '(choice (const t) (const leave-decimal) (const nil)) |
| 122 | :group 'calculator) | 115 | :group 'calculator) |
| @@ -136,23 +129,27 @@ should be able to handle special symbol arguments, currently `left' and | |||
| 136 | associated with the displayer function (for example to change the number | 129 | associated with the displayer function (for example to change the number |
| 137 | of digits displayed). | 130 | of digits displayed). |
| 138 | 131 | ||
| 139 | An exception to the above is the case of the list (std C) where C is a | 132 | An exception to the above is the case of the list (std C [G]) where C is |
| 140 | character, in this case the `calculator-standard-displayer' function | 133 | a character and G is an optional boolean, in this case the |
| 141 | will be used with this character for a format string." | 134 | `calculator-standard-displayer' function will be used with these as |
| 142 | :type '(choice (function) (string) (list (const std) character) (sexp)) | 135 | arguments." |
| 136 | :type '(choice (function) (string) (sexp) | ||
| 137 | (list (const std) character) | ||
| 138 | (list (const std) character boolean)) | ||
| 143 | :group 'calculator) | 139 | :group 'calculator) |
| 144 | 140 | ||
| 145 | (defcustom calculator-displayers | 141 | (defcustom calculator-displayers |
| 146 | '(((std ?n) "Standard display, decimal point or scientific") | 142 | '(((std ?n) "Standard display, decimal point or scientific") |
| 147 | (calculator-eng-display "Eng display") | 143 | (calculator-eng-display "Eng display") |
| 148 | ((std ?f) "Standard display, decimal point") | 144 | ((std ?f t) "Standard display, decimal point with grouping") |
| 149 | ((std ?e) "Standard display, scientific") | 145 | ((std ?e) "Standard display, scientific") |
| 150 | ("%S" "Emacs printer")) | 146 | ("%S" "Emacs printer")) |
| 151 | "A list of displayers. | 147 | "A list of displayers. |
| 152 | Each element is a list of a displayer and a description string. The | 148 | Each element is a list of a displayer and a description string. The |
| 153 | first element is the one which is currently used, this is for the display | 149 | first element is the one which is currently used, this is for the |
| 154 | of result values not values in expressions. A displayer specification | 150 | display of result values not values in expressions. A displayer |
| 155 | is the same as the values that can be stored in `calculator-displayer'. | 151 | specification is the same as the values that can be stored in |
| 152 | `calculator-displayer'. | ||
| 156 | 153 | ||
| 157 | `calculator-rotate-displayer' rotates this list." | 154 | `calculator-rotate-displayer' rotates this list." |
| 158 | :type 'sexp | 155 | :type 'sexp |
| @@ -182,7 +179,7 @@ Otherwise show as a negative number." | |||
| 182 | (defcustom calculator-mode-hook nil | 179 | (defcustom calculator-mode-hook nil |
| 183 | "List of hook functions for `calculator-mode' to run. | 180 | "List of hook functions for `calculator-mode' to run. |
| 184 | Note: if `calculator-electric-mode' is on, then this hook will get | 181 | Note: if `calculator-electric-mode' is on, then this hook will get |
| 185 | activated in the minibuffer - in that case it should not do much more | 182 | activated in the minibuffer -- in that case it should not do much more |
| 186 | than local key settings and other effects that will change things | 183 | than local key settings and other effects that will change things |
| 187 | outside the scope of calculator related code." | 184 | outside the scope of calculator related code." |
| 188 | :type 'hook | 185 | :type 'hook |
| @@ -224,15 +221,14 @@ Examples: | |||
| 224 | (\"tF\" mt-to-ft (/ X 0.3048) 1) | 221 | (\"tF\" mt-to-ft (/ X 0.3048) 1) |
| 225 | (\"tM\" ft-to-mt (* X 0.3048) 1))) | 222 | (\"tM\" ft-to-mt (* X 0.3048) 1))) |
| 226 | 223 | ||
| 227 | * Using a function-like form is very simple, X for an argument (Y the | 224 | * Using a function-like form is very simple: use `X' for the argument |
| 228 | second in case of a binary operator), TX is a truncated version of X | 225 | (`Y' for the second in case of a binary operator), `TX' is a truncated |
| 229 | and F does a recursive call, Here is a [very inefficient] Fibonacci | 226 | version of `X' and `F' for a recursive call. Here is a [very |
| 230 | number calculation: | 227 | inefficient] Fibonacci number calculation: |
| 231 | 228 | ||
| 232 | (add-to-list 'calculator-user-operators | 229 | (add-to-list 'calculator-user-operators |
| 233 | '(\"F\" fib (if (<= TX 1) | 230 | '(\"F\" fib |
| 234 | 1 | 231 | (if (<= TX 1) 1 (+ (F (- TX 1)) (F (- TX 2)))))) |
| 235 | (+ (F (- TX 1)) (F (- TX 2)))) 0)) | ||
| 236 | 232 | ||
| 237 | Note that this will be either postfix or prefix, according to | 233 | Note that this will be either postfix or prefix, according to |
| 238 | `calculator-unary-style'." | 234 | `calculator-unary-style'." |
| @@ -248,7 +244,7 @@ Examples: | |||
| 248 | ;;; Variables | 244 | ;;; Variables |
| 249 | 245 | ||
| 250 | (defvar calculator-initial-operators | 246 | (defvar calculator-initial-operators |
| 251 | '(;; "+"/"-" have keybindings of themselves, not calculator-ops | 247 | '(;; "+"/"-" have keybindings of their own, not calculator-ops |
| 252 | ("=" = identity 1 -1) | 248 | ("=" = identity 1 -1) |
| 253 | (nobind "+" + + 2 4) | 249 | (nobind "+" + + 2 4) |
| 254 | (nobind "-" - - 2 4) | 250 | (nobind "-" - - 2 4) |
| @@ -303,26 +299,27 @@ user-defined operators, use `calculator-user-operators' instead.") | |||
| 303 | versions), `DX' (converted to radians if degrees mode is on), `D' | 299 | versions), `DX' (converted to radians if degrees mode is on), `D' |
| 304 | (function for converting radians to degrees if deg mode is on), `L' | 300 | (function for converting radians to degrees if deg mode is on), `L' |
| 305 | (list of saved values), `F' (function for recursive iteration calls) | 301 | (list of saved values), `F' (function for recursive iteration calls) |
| 306 | and evaluates to the function value - these variables are capital; | 302 | and evaluates to the function value -- these variables are capital; |
| 307 | 303 | ||
| 308 | 4. The function's arity, optional, one of: 2 => binary, -1 => prefix | 304 | 4. The function's arity, optional, one of: 2 => binary, -1 => prefix |
| 309 | unary, +1 => postfix unary, 0 => a 0-arg operator func, non-number => | 305 | unary, +1 => postfix unary, 0 => a 0-arg operator func (note that |
| 310 | postfix/prefix as determined by `calculator-unary-style' (the | 306 | using such a function replaces the currently entered number, if any), |
| 311 | default); | 307 | non-number (the default) => postfix or prefix as determined by |
| 308 | `calculator-unary-style'; | ||
| 312 | 309 | ||
| 313 | 5. The function's precedence - should be in the range of 1 (lowest) to | 310 | 5. The function's precedence -- should be in the range of 1 (lowest) to |
| 314 | 9 (highest) (optional, defaults to 1); | 311 | 9 (highest) (optional, defaults to 1); |
| 315 | 312 | ||
| 316 | It it possible have a unary prefix version of a binary operator if it | 313 | It it possible have a unary prefix version of a binary operator if it |
| 317 | comes later in this list. If the list begins with the symbol 'nobind, | 314 | comes later in this list. If the list begins with the symbol 'nobind, |
| 318 | then no key binding will take place - this is only useful for predefined | 315 | then no key binding will take place -- this is only useful for predefined |
| 319 | keys. | 316 | keys. |
| 320 | 317 | ||
| 321 | Use `calculator-user-operators' to add operators to this list, see its | 318 | Use `calculator-user-operators' to add operators to this list, see its |
| 322 | documentation for an example.") | 319 | documentation for an example.") |
| 323 | 320 | ||
| 324 | (defvar calculator-stack nil | 321 | (defvar calculator-stack nil |
| 325 | "Stack contents - operations and operands.") | 322 | "Stack contents -- operations and operands.") |
| 326 | 323 | ||
| 327 | (defvar calculator-curnum nil | 324 | (defvar calculator-curnum nil |
| 328 | "Current number being entered (as a string).") | 325 | "Current number being entered (as a string).") |
| @@ -427,9 +424,9 @@ Used for repeating operations in calculator-repR/L.") | |||
| 427 | (calculator-backspace [backspace]) | 424 | (calculator-backspace [backspace]) |
| 428 | ))) | 425 | ))) |
| 429 | (while p | 426 | (while p |
| 430 | ;; reverse the keys so first defs come last - makes the more | 427 | ;; reverse the keys so earlier definitions come last -- makes |
| 431 | ;; sensible bindings visible in the menu | 428 | ;; the more sensible bindings visible in the menu |
| 432 | (let ((func (car (car p))) (keys (reverse (cdr (car p))))) | 429 | (let ((func (caar p)) (keys (reverse (cdar p)))) |
| 433 | (while keys | 430 | (while keys |
| 434 | (define-key map (car keys) func) | 431 | (define-key map (car keys) func) |
| 435 | (setq keys (cdr keys)))) | 432 | (setq keys (cdr keys)))) |
| @@ -441,7 +438,7 @@ Used for repeating operations in calculator-repR/L.") | |||
| 441 | ;; make C-h work in text-mode | 438 | ;; make C-h work in text-mode |
| 442 | (or window-system (define-key map [?\C-h] 'calculator-backspace)) | 439 | (or window-system (define-key map [?\C-h] 'calculator-backspace)) |
| 443 | ;; set up a menu | 440 | ;; set up a menu |
| 444 | (if (and calculator-use-menu (not (boundp 'calculator-menu))) | 441 | (when (and calculator-use-menu (not (boundp 'calculator-menu))) |
| 445 | (let ((radix-selectors | 442 | (let ((radix-selectors |
| 446 | (mapcar (lambda (x) | 443 | (mapcar (lambda (x) |
| 447 | `([,(nth 0 x) | 444 | `([,(nth 0 x) |
| @@ -580,7 +577,7 @@ Used for repeating operations in calculator-repR/L.") | |||
| 580 | "A [not so] simple calculator for Emacs. | 577 | "A [not so] simple calculator for Emacs. |
| 581 | 578 | ||
| 582 | This calculator is used in the same way as other popular calculators | 579 | This calculator is used in the same way as other popular calculators |
| 583 | like xcalc or calc.exe - but using an Emacs interface. | 580 | like xcalc or calc.exe -- but using an Emacs interface. |
| 584 | 581 | ||
| 585 | Expressions are entered using normal infix notation, parens are used as | 582 | Expressions are entered using normal infix notation, parens are used as |
| 586 | normal. Unary functions are usually postfix, but some depends on the | 583 | normal. Unary functions are usually postfix, but some depends on the |
| @@ -589,8 +586,7 @@ specified, then it is fixed, otherwise it depends on this variable). | |||
| 589 | `+' and `-' can be used as either binary operators or prefix unary | 586 | `+' and `-' can be used as either binary operators or prefix unary |
| 590 | operators. Numbers can be entered with exponential notation using `e', | 587 | operators. Numbers can be entered with exponential notation using `e', |
| 591 | except when using a non-decimal radix mode for input (in this case `e' | 588 | except when using a non-decimal radix mode for input (in this case `e' |
| 592 | will be the hexadecimal digit). If the result of a calculation is too | 589 | will be the hexadecimal digit). |
| 593 | large (out of range for Emacs), the value of \"inf\" is returned. | ||
| 594 | 590 | ||
| 595 | Here are the editing keys: | 591 | Here are the editing keys: |
| 596 | * `RET' `=' evaluate the current expression | 592 | * `RET' `=' evaluate the current expression |
| @@ -609,8 +605,8 @@ These operators are pre-defined: | |||
| 609 | * `_' `;' postfix unary negation and reciprocal | 605 | * `_' `;' postfix unary negation and reciprocal |
| 610 | * `^' `L' binary operators for x^y and log(x) in base y | 606 | * `^' `L' binary operators for x^y and log(x) in base y |
| 611 | * `Q' `!' unary square root and factorial | 607 | * `Q' `!' unary square root and factorial |
| 612 | * `S' `C' `T' unary trigonometric operators - sin, cos and tan | 608 | * `S' `C' `T' unary trigonometric operators: sin, cos and tan |
| 613 | * `|' `#' `&' `~' bitwise operators - or, xor, and, not | 609 | * `|' `#' `&' `~' bitwise operators: or, xor, and, not |
| 614 | 610 | ||
| 615 | The trigonometric functions can be inverted if prefixed with an `I', see | 611 | The trigonometric functions can be inverted if prefixed with an `I', see |
| 616 | below for the way to use degrees instead of the default radians. | 612 | below for the way to use degrees instead of the default radians. |
| @@ -636,9 +632,9 @@ The prompt indicates the current modes: | |||
| 636 | 632 | ||
| 637 | Also, the quote key can be used to switch display modes for decimal | 633 | Also, the quote key can be used to switch display modes for decimal |
| 638 | numbers (double-quote rotates back), and the two brace characters | 634 | numbers (double-quote rotates back), and the two brace characters |
| 639 | \(\"{\" and \"}\" change display parameters that these displayers use (if | 635 | \(\"{\" and \"}\" change display parameters that these displayers use, |
| 640 | they handle such). If output is using any radix mode, then these keys | 636 | if they handle such). If output is using any radix mode, then these |
| 641 | toggle digit grouping mode and the chunk size. | 637 | keys toggle digit grouping mode and the chunk size. |
| 642 | 638 | ||
| 643 | Values can be saved for future reference in either a list of saved | 639 | Values can be saved for future reference in either a list of saved |
| 644 | values, or in registers. | 640 | values, or in registers. |
| @@ -680,19 +676,21 @@ more information. | |||
| 680 | "Run the Emacs calculator. | 676 | "Run the Emacs calculator. |
| 681 | See the documentation for `calculator-mode' for more information." | 677 | See the documentation for `calculator-mode' for more information." |
| 682 | (interactive) | 678 | (interactive) |
| 683 | (if calculator-restart-other-mode | 679 | (when calculator-restart-other-mode |
| 684 | (setq calculator-electric-mode (not calculator-electric-mode))) | 680 | (setq calculator-electric-mode (not calculator-electric-mode))) |
| 685 | (if calculator-initial-operators | 681 | (when calculator-initial-operators |
| 686 | (progn (calculator-add-operators calculator-initial-operators) | 682 | (calculator-add-operators calculator-initial-operators) |
| 687 | (setq calculator-initial-operators nil) | 683 | (setq calculator-initial-operators nil) |
| 688 | ;; don't change this since it is a customization variable, | 684 | ;; don't change this since it is a customization variable, |
| 689 | ;; its set function will add any new operators | 685 | ;; its set function will add any new operators |
| 690 | (calculator-add-operators calculator-user-operators))) | 686 | (calculator-add-operators calculator-user-operators)) |
| 691 | (setq calculator-buffer (get-buffer-create "*calculator*")) | 687 | (setq calculator-buffer (get-buffer-create "*calculator*")) |
| 692 | (if calculator-electric-mode | 688 | (if calculator-electric-mode |
| 693 | (save-window-excursion | 689 | (save-window-excursion |
| 694 | (progn (require 'electric) (message nil)) ; hide load message | 690 | (require 'electric) (message nil) ; hide load message |
| 695 | (let (old-g-map old-l-map (echo-keystrokes 0) | 691 | (let (old-g-map old-l-map |
| 692 | (old-buf (window-buffer (minibuffer-window))) | ||
| 693 | (echo-keystrokes 0) | ||
| 696 | (garbage-collection-messages nil)) ; no gc msg when electric | 694 | (garbage-collection-messages nil)) ; no gc msg when electric |
| 697 | (set-window-buffer (minibuffer-window) calculator-buffer) | 695 | (set-window-buffer (minibuffer-window) calculator-buffer) |
| 698 | (select-window (minibuffer-window)) | 696 | (select-window (minibuffer-window)) |
| @@ -712,8 +710,8 @@ See the documentation for `calculator-mode' for more information." | |||
| 712 | (lambda () 'noprompt) | 710 | (lambda () 'noprompt) |
| 713 | nil | 711 | nil |
| 714 | (lambda (_x _y) (calculator-update-display)))) | 712 | (lambda (_x _y) (calculator-update-display)))) |
| 715 | (and calculator-buffer | 713 | (set-window-buffer (minibuffer-window) old-buf) |
| 716 | (catch 'calculator-done (calculator-quit))) | 714 | (kill-buffer calculator-buffer) |
| 717 | (use-local-map old-l-map) | 715 | (use-local-map old-l-map) |
| 718 | (use-global-map old-g-map)))) | 716 | (use-global-map old-g-map)))) |
| 719 | (progn | 717 | (progn |
| @@ -722,45 +720,8 @@ See the documentation for `calculator-mode' for more information." | |||
| 722 | (let ((window-min-height 2)) | 720 | (let ((window-min-height 2)) |
| 723 | ;; maybe leave two lines for our window because of the | 721 | ;; maybe leave two lines for our window because of the |
| 724 | ;; normal `raised' mode line | 722 | ;; normal `raised' mode line |
| 725 | (select-window | 723 | (select-window (split-window-below |
| 726 | (split-window-below | 724 | (if (calculator-need-3-lines) -3 -2))) |
| 727 | ;; If the mode line might interfere with the calculator | ||
| 728 | ;; buffer, use 3 lines instead. | ||
| 729 | (if (and (fboundp 'face-attr-construct) | ||
| 730 | (let* ((dh (plist-get (face-attr-construct 'default) :height)) | ||
| 731 | (mf (face-attr-construct 'mode-line)) | ||
| 732 | (mh (plist-get mf :height))) | ||
| 733 | ;; If the mode line is shorter than the default, | ||
| 734 | ;; stick with 2 lines. (It may be necessary to | ||
| 735 | ;; check how much shorter.) | ||
| 736 | (and | ||
| 737 | (not | ||
| 738 | (or (and (integerp dh) | ||
| 739 | (integerp mh) | ||
| 740 | (< mh dh)) | ||
| 741 | (and (numberp mh) | ||
| 742 | (not (integerp mh)) | ||
| 743 | (< mh 1)))) | ||
| 744 | (or | ||
| 745 | ;; If the mode line is taller than the default, | ||
| 746 | ;; use 3 lines. | ||
| 747 | (and (integerp dh) | ||
| 748 | (integerp mh) | ||
| 749 | (> mh dh)) | ||
| 750 | (and (numberp mh) | ||
| 751 | (not (integerp mh)) | ||
| 752 | (> mh 1)) | ||
| 753 | ;; If the mode line has a box with non-negative line-width, | ||
| 754 | ;; use 3 lines. | ||
| 755 | (let* ((bx (plist-get mf :box)) | ||
| 756 | (lh (plist-get bx :line-width))) | ||
| 757 | (and bx | ||
| 758 | (or | ||
| 759 | (not lh) | ||
| 760 | (> lh 0)))) | ||
| 761 | ;; If the mode line has an overline, use 3 lines. | ||
| 762 | (plist-get (face-attr-construct 'mode-line) :overline))))) | ||
| 763 | -3 -2))) | ||
| 764 | (switch-to-buffer calculator-buffer))) | 725 | (switch-to-buffer calculator-buffer))) |
| 765 | ((not (eq (current-buffer) calculator-buffer)) | 726 | ((not (eq (current-buffer) calculator-buffer)) |
| 766 | (select-window (get-buffer-window calculator-buffer)))) | 727 | (select-window (get-buffer-window calculator-buffer)))) |
| @@ -768,24 +729,46 @@ See the documentation for `calculator-mode' for more information." | |||
| 768 | (setq buffer-read-only t) | 729 | (setq buffer-read-only t) |
| 769 | (calculator-reset) | 730 | (calculator-reset) |
| 770 | (message "Hit `?' For a quick help screen."))) | 731 | (message "Hit `?' For a quick help screen."))) |
| 771 | (if (and calculator-restart-other-mode calculator-electric-mode) | 732 | (when (and calculator-restart-other-mode calculator-electric-mode) |
| 772 | (calculator))) | 733 | (calculator))) |
| 773 | 734 | ||
| 735 | (defun calculator-need-3-lines () | ||
| 736 | ;; If the mode line might interfere with the calculator buffer, use 3 | ||
| 737 | ;; lines instead. | ||
| 738 | (let* ((dh (face-attribute 'default :height)) | ||
| 739 | (mh (face-attribute 'mode-line :height))) | ||
| 740 | ;; if the mode line is shorter than the default, stick with 2 lines | ||
| 741 | ;; (it may be necessary to check how much shorter) | ||
| 742 | (and (not (or (and (integerp dh) (integerp mh) (< mh dh)) | ||
| 743 | (and (numberp mh) (not (integerp mh)) (< mh 1)))) | ||
| 744 | (or ;; if the mode line is taller than the default, use 3 lines | ||
| 745 | (and (integerp dh) (integerp mh) (> mh dh)) | ||
| 746 | (and (numberp mh) (not (integerp mh)) (> mh 1)) | ||
| 747 | ;; if the mode line has a box with non-negative line-width, | ||
| 748 | ;; use 3 lines | ||
| 749 | (let* ((bx (face-attribute 'mode-line :box)) | ||
| 750 | (lh (plist-get bx :line-width))) | ||
| 751 | (and bx (or (not lh) (> lh 0)))) | ||
| 752 | ;; if the mode line has an overline, use 3 lines | ||
| 753 | (not (memq (face-attribute 'mode-line :overline) | ||
| 754 | '(nil unspecified))))))) | ||
| 755 | |||
| 774 | (defun calculator-message (string &rest arguments) | 756 | (defun calculator-message (string &rest arguments) |
| 775 | "Same as `message', but special handle of electric mode." | 757 | "Same as `message', but also handle electric mode." |
| 776 | (apply 'message string arguments) | 758 | (apply 'message string arguments) |
| 777 | (if calculator-electric-mode | 759 | (when calculator-electric-mode (sit-for 1) (message nil))) |
| 778 | (progn (sit-for 1) (message nil)))) | ||
| 779 | 760 | ||
| 780 | ;;;--------------------------------------------------------------------- | 761 | ;;;--------------------------------------------------------------------- |
| 781 | ;;; Operators | 762 | ;;; Operators |
| 782 | 763 | ||
| 783 | (defun calculator-op-arity (op) | 764 | (defun calculator-op-arity (op) |
| 784 | "Return OP's arity, 2, +1 or -1." | 765 | "Return OP's arity. |
| 785 | (let ((arity (or (nth 3 op) 'x))) | 766 | Current results are one of 2 (binary), +1 (postfix), -1 (prefix), or |
| 786 | (if (numberp arity) | 767 | 0 (nullary)." |
| 787 | arity | 768 | (let ((arity (nth 3 op))) |
| 788 | (if (eq calculator-unary-style 'postfix) +1 -1)))) | 769 | (cond ((numberp arity) arity) |
| 770 | ((eq calculator-unary-style 'postfix) +1) | ||
| 771 | (t -1)))) | ||
| 789 | 772 | ||
| 790 | (defun calculator-op-prec (op) | 773 | (defun calculator-op-prec (op) |
| 791 | "Return OP's precedence for reducing when inserting into the stack. | 774 | "Return OP's precedence for reducing when inserting into the stack. |
| @@ -798,8 +781,8 @@ Adds MORE-OPS to `calculator-operator', called initially to handle | |||
| 798 | `calculator-initial-operators' and `calculator-user-operators'." | 781 | `calculator-initial-operators' and `calculator-user-operators'." |
| 799 | (let ((added-ops nil)) | 782 | (let ((added-ops nil)) |
| 800 | (while more-ops | 783 | (while more-ops |
| 801 | (or (eq (car (car more-ops)) 'nobind) | 784 | (or (eq (caar more-ops) 'nobind) |
| 802 | (let ((i -1) (key (car (car more-ops)))) | 785 | (let ((i -1) (key (caar more-ops))) |
| 803 | ;; make sure the key is undefined, so it's easy to define | 786 | ;; make sure the key is undefined, so it's easy to define |
| 804 | ;; prefix keys | 787 | ;; prefix keys |
| 805 | (while (< (setq i (1+ i)) (length key)) | 788 | (while (< (setq i (1+ i)) (length key)) |
| @@ -811,8 +794,8 @@ Adds MORE-OPS to `calculator-operator', called initially to handle | |||
| 811 | calculator-mode-map (substring key 0 (1+ i)) nil) | 794 | calculator-mode-map (substring key 0 (1+ i)) nil) |
| 812 | (setq i (length key))))) | 795 | (setq i (length key))))) |
| 813 | (define-key calculator-mode-map key 'calculator-op))) | 796 | (define-key calculator-mode-map key 'calculator-op))) |
| 814 | (setq added-ops (cons (if (eq (car (car more-ops)) 'nobind) | 797 | (setq added-ops (cons (if (eq (caar more-ops) 'nobind) |
| 815 | (cdr (car more-ops)) | 798 | (cdar more-ops) |
| 816 | (car more-ops)) | 799 | (car more-ops)) |
| 817 | added-ops)) | 800 | added-ops)) |
| 818 | (setq more-ops (cdr more-ops))) | 801 | (setq more-ops (cdr more-ops))) |
| @@ -833,50 +816,37 @@ Adds MORE-OPS to `calculator-operator', called initially to handle | |||
| 833 | (setq calculator-restart-other-mode nil) | 816 | (setq calculator-restart-other-mode nil) |
| 834 | (calculator-update-display)) | 817 | (calculator-update-display)) |
| 835 | 818 | ||
| 836 | (defun calculator-get-prompt () | 819 | (defun calculator-get-display () |
| 837 | "Return a string to display. | 820 | "Return a string to display. |
| 838 | The string is set not to exceed the screen width." | 821 | The result should not exceed the screen width." |
| 839 | (let* ((calculator-prompt | 822 | (let* ((in-r (and calculator-input-radix |
| 840 | (format calculator-prompt | 823 | (char-to-string |
| 824 | (car (rassq calculator-input-radix | ||
| 825 | calculator-char-radix))))) | ||
| 826 | (out-r (and calculator-output-radix | ||
| 827 | (char-to-string | ||
| 828 | (car (rassq calculator-output-radix | ||
| 829 | calculator-char-radix))))) | ||
| 830 | (prompt (format calculator-prompt | ||
| 831 | (cond ((or in-r out-r) | ||
| 832 | (concat (or in-r "=") | ||
| 833 | (if (equal in-r out-r) "=" | ||
| 834 | (or out-r "=")))) | ||
| 835 | (calculator-deg "D=") | ||
| 836 | (t "==")))) | ||
| 837 | (expr | ||
| 838 | (concat (cdr calculator-stack-display) | ||
| 841 | (cond | 839 | (cond |
| 842 | ((or calculator-output-radix calculator-input-radix) | 840 | ;; entering a number |
| 843 | (if (eq calculator-output-radix | 841 | (calculator-curnum (concat calculator-curnum "_")) |
| 844 | calculator-input-radix) | 842 | ;; showing a result |
| 845 | (concat | 843 | ((and (= 1 (length calculator-stack)) |
| 846 | (char-to-string | 844 | calculator-display-fragile) |
| 847 | (car (rassq calculator-output-radix | 845 | nil) |
| 848 | calculator-char-radix))) | 846 | ;; waiting for a number or an operator |
| 849 | "=") | 847 | (t "?")))) |
| 850 | (concat | 848 | (trim (+ (length expr) (length prompt) 1 (- (window-width))))) |
| 851 | (if calculator-input-radix | 849 | (concat prompt (if (<= trim 0) expr (substring expr trim))))) |
| 852 | (char-to-string | ||
| 853 | (car (rassq calculator-input-radix | ||
| 854 | calculator-char-radix))) | ||
| 855 | "=") | ||
| 856 | (char-to-string | ||
| 857 | (car (rassq calculator-output-radix | ||
| 858 | calculator-char-radix)))))) | ||
| 859 | (calculator-deg "D=") | ||
| 860 | (t "==")))) | ||
| 861 | (prompt | ||
| 862 | (concat calculator-prompt | ||
| 863 | (cdr calculator-stack-display) | ||
| 864 | (cond (calculator-curnum | ||
| 865 | ;; number being typed | ||
| 866 | (concat calculator-curnum "_")) | ||
| 867 | ((and (= 1 (length calculator-stack)) | ||
| 868 | calculator-display-fragile) | ||
| 869 | ;; only the result is shown, next number will | ||
| 870 | ;; restart | ||
| 871 | nil) | ||
| 872 | (t | ||
| 873 | ;; waiting for a number or an operator | ||
| 874 | "?")))) | ||
| 875 | (trim (- (length prompt) (1- (window-width))))) | ||
| 876 | (if (<= trim 0) | ||
| 877 | prompt | ||
| 878 | (concat calculator-prompt | ||
| 879 | (substring prompt (+ trim (length calculator-prompt))))))) | ||
| 880 | 850 | ||
| 881 | (defun calculator-string-to-number (str) | 851 | (defun calculator-string-to-number (str) |
| 882 | "Convert the given STR to a number, according to the value of | 852 | "Convert the given STR to a number, according to the value of |
| @@ -902,7 +872,7 @@ The string is set not to exceed the screen width." | |||
| 902 | "Warning: Ignoring bad input character `%c'." ch) | 872 | "Warning: Ignoring bad input character `%c'." ch) |
| 903 | (sit-for 1) | 873 | (sit-for 1) |
| 904 | value)))) | 874 | value)))) |
| 905 | (if (if (< new-value 0) (> value 0) (< value 0)) | 875 | (when (if (< new-value 0) (> value 0) (< value 0)) |
| 906 | (calculator-message "Warning: Overflow in input.")) | 876 | (calculator-message "Warning: Overflow in input.")) |
| 907 | (setq value new-value)) | 877 | (setq value new-value)) |
| 908 | value) | 878 | value) |
| @@ -916,9 +886,12 @@ The string is set not to exceed the screen width." | |||
| 916 | ((stringp str) (concat str ".0")) | 886 | ((stringp str) (concat str ".0")) |
| 917 | (t "0.0")))))) | 887 | (t "0.0")))))) |
| 918 | 888 | ||
| 919 | (defun calculator-curnum-value () | 889 | (defun calculator-push-curnum () |
| 920 | "Get the numeric value of the displayed number string as a float." | 890 | "Push the numeric value of the displayed number to the stack." |
| 921 | (calculator-string-to-number calculator-curnum)) | 891 | (when calculator-curnum |
| 892 | (push (calculator-string-to-number calculator-curnum) | ||
| 893 | calculator-stack) | ||
| 894 | (setq calculator-curnum nil))) | ||
| 922 | 895 | ||
| 923 | (defun calculator-rotate-displayer (&optional new-disp) | 896 | (defun calculator-rotate-displayer (&optional new-disp) |
| 924 | "Switch to the next displayer on the `calculator-displayers' list. | 897 | "Switch to the next displayer on the `calculator-displayers' list. |
| @@ -956,7 +929,7 @@ If radix output mode is active, toggle digit grouping." | |||
| 956 | (calculator-rotate-displayer (car (last calculator-displayers)))) | 929 | (calculator-rotate-displayer (car (last calculator-displayers)))) |
| 957 | 930 | ||
| 958 | (defun calculator-displayer-prev () | 931 | (defun calculator-displayer-prev () |
| 959 | "Send the current displayer function a 'left argument. | 932 | "Send the current displayer function a `left' argument. |
| 960 | This is used to modify display arguments (if the current displayer | 933 | This is used to modify display arguments (if the current displayer |
| 961 | function supports this). | 934 | function supports this). |
| 962 | If radix output mode is active, increase the grouping size." | 935 | If radix output mode is active, increase the grouping size." |
| @@ -967,13 +940,12 @@ If radix output mode is active, increase the grouping size." | |||
| 967 | (calculator-enter)) | 940 | (calculator-enter)) |
| 968 | (and (car calculator-displayers) | 941 | (and (car calculator-displayers) |
| 969 | (let ((disp (caar calculator-displayers))) | 942 | (let ((disp (caar calculator-displayers))) |
| 970 | (cond | 943 | (cond ((symbolp disp) (funcall disp 'left)) |
| 971 | ((symbolp disp) (funcall disp 'left)) | 944 | ((and (consp disp) (eq 'std (car disp))) |
| 972 | ((and (consp disp) (eq 'std (car disp))) | 945 | (calculator-standard-displayer 'left))))))) |
| 973 | (calculator-standard-displayer 'left (cadr disp)))))))) | ||
| 974 | 946 | ||
| 975 | (defun calculator-displayer-next () | 947 | (defun calculator-displayer-next () |
| 976 | "Send the current displayer function a 'right argument. | 948 | "Send the current displayer function a `right' argument. |
| 977 | This is used to modify display arguments (if the current displayer | 949 | This is used to modify display arguments (if the current displayer |
| 978 | function supports this). | 950 | function supports this). |
| 979 | If radix output mode is active, decrease the grouping size." | 951 | If radix output mode is active, decrease the grouping size." |
| @@ -984,44 +956,51 @@ If radix output mode is active, decrease the grouping size." | |||
| 984 | (calculator-enter)) | 956 | (calculator-enter)) |
| 985 | (and (car calculator-displayers) | 957 | (and (car calculator-displayers) |
| 986 | (let ((disp (caar calculator-displayers))) | 958 | (let ((disp (caar calculator-displayers))) |
| 987 | (cond | 959 | (cond ((symbolp disp) (funcall disp 'right)) |
| 988 | ((symbolp disp) (funcall disp 'right)) | 960 | ((and (consp disp) (eq 'std (car disp))) |
| 989 | ((and (consp disp) (eq 'std (car disp))) | 961 | (calculator-standard-displayer 'right))))))) |
| 990 | (calculator-standard-displayer 'right (cadr disp)))))))) | ||
| 991 | 962 | ||
| 992 | (defun calculator-remove-zeros (numstr) | 963 | (defun calculator-remove-zeros (numstr) |
| 993 | "Get a number string NUMSTR and remove unnecessary zeros. | 964 | "Get a number string NUMSTR and remove unnecessary zeros. |
| 994 | The behavior of this function is controlled by | 965 | The behavior of this function is controlled by |
| 995 | `calculator-remove-zeros'." | 966 | `calculator-remove-zeros'." |
| 996 | (cond ((and (eq calculator-remove-zeros t) | 967 | (let* ((s (if (not (eq calculator-remove-zeros t)) numstr |
| 997 | (string-match "\\.0+\\([eE][+-]?[0-9]*\\)?$" numstr)) | 968 | ;; remove all redundant zeros leaving an integer |
| 998 | ;; remove all redundant zeros leaving an integer | 969 | (replace-regexp-in-string |
| 999 | (if (match-beginning 1) | 970 | "\\.0+\\([eE].*\\)?$" "\\1" numstr))) |
| 1000 | (concat (substring numstr 0 (match-beginning 0)) | 971 | (s (if (not calculator-remove-zeros) s |
| 1001 | (match-string 1 numstr)) | 972 | ;; remove zeros, except for first after the "." |
| 1002 | (substring numstr 0 (match-beginning 0)))) | 973 | (replace-regexp-in-string |
| 1003 | ((and calculator-remove-zeros | 974 | "\\(\\..[0-9]*?\\)0+\\([eE].*\\)?$" "\\1\\2" s)))) |
| 1004 | (string-match | 975 | s)) |
| 1005 | "\\..\\([0-9]*[1-9]\\)?\\(0+\\)\\([eE][+-]?[0-9]*\\)?$" | 976 | |
| 1006 | numstr)) | 977 | (defun calculator-groupize-number (str n sep &optional fromleft) |
| 1007 | ;; remove zeros, except for first after the "." | 978 | "Return the input string STR with occurrences of SEP that separate |
| 1008 | (if (match-beginning 3) | 979 | every N characters starting from the right, or from the left if |
| 1009 | (concat (substring numstr 0 (match-beginning 2)) | 980 | FROMLEFT is true." |
| 1010 | (match-string 3 numstr)) | 981 | (let* ((len (length str)) (i (/ len n)) (j (% len n)) |
| 1011 | (substring numstr 0 (match-beginning 2)))) | 982 | (r (if (or (not fromleft) (= j 0)) '() |
| 1012 | (t numstr))) | 983 | (list (substring str (- len j)))))) |
| 1013 | 984 | (while (> i 0) | |
| 1014 | (defun calculator-standard-displayer (num char) | 985 | (let* ((e (* i n)) (e (if fromleft e (+ e j)))) |
| 986 | (push (substring str (- e n) e) r)) | ||
| 987 | (setq i (1- i))) | ||
| 988 | (when (and (not fromleft) (> j 0)) | ||
| 989 | (push (substring str 0 j) r)) | ||
| 990 | (mapconcat 'identity r sep))) | ||
| 991 | |||
| 992 | (defun calculator-standard-displayer (num &optional char group-p) | ||
| 1015 | "Standard display function, used to display NUM. | 993 | "Standard display function, used to display NUM. |
| 1016 | Its behavior is determined by `calculator-number-digits' and the given | 994 | Its behavior is determined by `calculator-number-digits' and the given |
| 1017 | CHAR argument (both will be used to compose a format string). If the | 995 | CHAR argument (both will be used to compose a format string). If the |
| 1018 | char is \"n\" then this function will choose one between %f or %e, this | 996 | char is \"n\" then this function will choose one between %f or %e, this |
| 1019 | is a work around %g jumping to exponential notation too fast. | 997 | is a work around %g jumping to exponential notation too fast. |
| 1020 | 998 | ||
| 1021 | The special 'left and 'right symbols will make it change the current | 999 | It will also split digit sequences into comma-separated groups |
| 1022 | number of digits displayed (`calculator-number-digits'). | 1000 | and/or remove redundant zeros. |
| 1023 | 1001 | ||
| 1024 | It will also remove redundant zeros from the result." | 1002 | The special `left' and `right' symbols will make it change the current |
| 1003 | number of digits displayed (`calculator-number-digits')." | ||
| 1025 | (if (symbolp num) | 1004 | (if (symbolp num) |
| 1026 | (cond ((eq num 'left) | 1005 | (cond ((eq num 'left) |
| 1027 | (and (> calculator-number-digits 0) | 1006 | (and (> calculator-number-digits 0) |
| @@ -1032,56 +1011,50 @@ It will also remove redundant zeros from the result." | |||
| 1032 | (setq calculator-number-digits | 1011 | (setq calculator-number-digits |
| 1033 | (1+ calculator-number-digits)) | 1012 | (1+ calculator-number-digits)) |
| 1034 | (calculator-enter))) | 1013 | (calculator-enter))) |
| 1035 | (let ((str (if (zerop num) | 1014 | (let* ((s (if (eq char ?n) |
| 1036 | "0" | 1015 | (let ((n (abs num))) |
| 1037 | (format | 1016 | (if (or (and (< 0 n) (< n 0.001)) (< 1e8 n)) ?e ?f)) |
| 1038 | (concat "%." | 1017 | char)) |
| 1039 | (number-to-string calculator-number-digits) | 1018 | (s (format "%%.%s%c" calculator-number-digits s)) |
| 1040 | (if (eq char ?n) | 1019 | (s (calculator-remove-zeros (format s num))) |
| 1041 | (let ((n (abs num))) | 1020 | (s (if (or (not group-p) (string-match-p "[eE]" s)) s |
| 1042 | (if (or (< n 0.001) (> n 1e8)) "e" "f")) | 1021 | (replace-regexp-in-string |
| 1043 | (string char))) | 1022 | "\\([0-9]+\\)\\(?:\\.\\|$\\)" |
| 1044 | num)))) | 1023 | (lambda (s) (calculator-groupize-number s 3 ",")) |
| 1045 | (calculator-remove-zeros str)))) | 1024 | s nil nil 1)))) |
| 1025 | s))) | ||
| 1046 | 1026 | ||
| 1047 | (defun calculator-eng-display (num) | 1027 | (defun calculator-eng-display (num) |
| 1048 | "Display NUM in engineering notation. | 1028 | "Display NUM in engineering notation. |
| 1049 | The number of decimal digits used is controlled by | 1029 | The number of decimal digits used is controlled by |
| 1050 | `calculator-number-digits', so to change it at runtime you have to use | 1030 | `calculator-number-digits', so to change it at runtime you have to use |
| 1051 | the 'left or 'right when one of the standard modes is used." | 1031 | the `left' or `right' when one of the standard modes is used." |
| 1052 | (if (symbolp num) | 1032 | (if (symbolp num) |
| 1053 | (cond ((eq num 'left) | 1033 | (cond ((eq num 'left) |
| 1054 | (setq calculator-eng-extra | 1034 | (setq calculator-eng-extra |
| 1055 | (if calculator-eng-extra | 1035 | (if calculator-eng-extra (1+ calculator-eng-extra) 1)) |
| 1056 | (1+ calculator-eng-extra) | ||
| 1057 | 1)) | ||
| 1058 | (let ((calculator-eng-tmp-show t)) (calculator-enter))) | 1036 | (let ((calculator-eng-tmp-show t)) (calculator-enter))) |
| 1059 | ((eq num 'right) | 1037 | ((eq num 'right) |
| 1060 | (setq calculator-eng-extra | 1038 | (setq calculator-eng-extra |
| 1061 | (if calculator-eng-extra | 1039 | (if calculator-eng-extra (1- calculator-eng-extra) -1)) |
| 1062 | (1- calculator-eng-extra) | ||
| 1063 | -1)) | ||
| 1064 | (let ((calculator-eng-tmp-show t)) (calculator-enter)))) | 1040 | (let ((calculator-eng-tmp-show t)) (calculator-enter)))) |
| 1065 | (let ((exp 0)) | 1041 | (let ((exp 0)) |
| 1066 | (and (not (= 0 num)) | 1042 | (unless (= 0 num) |
| 1067 | (progn | 1043 | (while (< (abs num) 1.0) |
| 1068 | (while (< (abs num) 1.0) | 1044 | (setq num (* num 1000.0)) (setq exp (- exp 3))) |
| 1069 | (setq num (* num 1000.0)) (setq exp (- exp 3))) | 1045 | (while (> (abs num) 999.0) |
| 1070 | (while (> (abs num) 999.0) | 1046 | (setq num (/ num 1000.0)) (setq exp (+ exp 3))) |
| 1071 | (setq num (/ num 1000.0)) (setq exp (+ exp 3))) | 1047 | (when (and calculator-eng-tmp-show |
| 1072 | (and calculator-eng-tmp-show | 1048 | (not (= 0 calculator-eng-extra))) |
| 1073 | (not (= 0 calculator-eng-extra)) | 1049 | (let ((i calculator-eng-extra)) |
| 1074 | (let ((i calculator-eng-extra)) | 1050 | (while (> i 0) |
| 1075 | (while (> i 0) | 1051 | (setq num (* num 1000.0)) (setq exp (- exp 3)) |
| 1076 | (setq num (* num 1000.0)) (setq exp (- exp 3)) | 1052 | (setq i (1- i))) |
| 1077 | (setq i (1- i))) | 1053 | (while (< i 0) |
| 1078 | (while (< i 0) | 1054 | (setq num (/ num 1000.0)) (setq exp (+ exp 3)) |
| 1079 | (setq num (/ num 1000.0)) (setq exp (+ exp 3)) | 1055 | (setq i (1+ i)))))) |
| 1080 | (setq i (1+ i))))))) | ||
| 1081 | (or calculator-eng-tmp-show (setq calculator-eng-extra nil)) | 1056 | (or calculator-eng-tmp-show (setq calculator-eng-extra nil)) |
| 1082 | (let ((str (format (concat "%." (number-to-string | 1057 | (let ((str (format (format "%%.%sf" calculator-number-digits) |
| 1083 | calculator-number-digits) | ||
| 1084 | "f") | ||
| 1085 | num))) | 1058 | num))) |
| 1086 | (concat (let ((calculator-remove-zeros | 1059 | (concat (let ((calculator-remove-zeros |
| 1087 | ;; make sure we don't leave integers | 1060 | ;; make sure we don't leave integers |
| @@ -1092,56 +1065,48 @@ the 'left or 'right when one of the standard modes is used." | |||
| 1092 | (defun calculator-number-to-string (num) | 1065 | (defun calculator-number-to-string (num) |
| 1093 | "Convert NUM to a displayable string." | 1066 | "Convert NUM to a displayable string." |
| 1094 | (cond | 1067 | (cond |
| 1095 | ((and (numberp num) calculator-output-radix) | 1068 | ;; operators are printed here, the rest is for numbers |
| 1096 | ;; print with radix - for binary I convert the octal number | 1069 | ((not (numberp num)) (prin1-to-string (nth 1 num) t)) |
| 1097 | (let ((str (format (if (eq calculator-output-radix 'hex) "%x" "%o") | 1070 | ;; %f/%e handle these, but avoid them in radix or in user displayers |
| 1098 | (calculator-truncate | 1071 | ((and (floatp num) (isnan num)) "NaN") |
| 1099 | (if calculator-2s-complement num (abs num)))))) | 1072 | ((<= 1.0e+INF num) "Inf") |
| 1100 | (if (eq calculator-output-radix 'bin) | 1073 | ((<= num -1.0e+INF) "-Inf") |
| 1101 | (let ((i -1) (s "")) | 1074 | (calculator-output-radix |
| 1102 | (while (< (setq i (1+ i)) (length str)) | 1075 | ;; print with radix -- for binary, convert the octal number |
| 1103 | (setq s | 1076 | (let* ((fmt (if (eq calculator-output-radix 'hex) "%x" "%o")) |
| 1104 | (concat s | 1077 | (str (if calculator-2s-complement num (abs num))) |
| 1105 | (cdr (assq (aref str i) | 1078 | (str (format fmt (calculator-truncate str))) |
| 1106 | '((?0 . "000") (?1 . "001") | 1079 | (bins '((?0 "000") (?1 "001") (?2 "010") (?3 "011") |
| 1107 | (?2 . "010") (?3 . "011") | 1080 | (?4 "100") (?5 "101") (?6 "110") (?7 "111"))) |
| 1108 | (?4 . "100") (?5 . "101") | 1081 | (str (if (not (eq calculator-output-radix 'bin)) str |
| 1109 | (?6 . "110") (?7 . "111"))))))) | 1082 | (replace-regexp-in-string |
| 1110 | (string-match "^0*\\(.+\\)" s) | 1083 | "^0+\\(.\\)" "\\1" |
| 1111 | (setq str (match-string 1 s)))) | 1084 | (apply 'concat (mapcar (lambda (c) |
| 1112 | (if calculator-radix-grouping-mode | 1085 | (cadr (assq c bins))) |
| 1113 | (let ((d (/ (length str) calculator-radix-grouping-digits)) | 1086 | str))))) |
| 1114 | (r (% (length str) calculator-radix-grouping-digits))) | 1087 | (str (if (not calculator-radix-grouping-mode) str |
| 1115 | (while (>= (setq d (1- d)) (if (zerop r) 1 0)) | 1088 | (calculator-groupize-number |
| 1116 | (let ((i (+ r (* d calculator-radix-grouping-digits)))) | 1089 | str calculator-radix-grouping-digits |
| 1117 | (setq str (concat (substring str 0 i) | 1090 | calculator-radix-grouping-separator)))) |
| 1118 | calculator-radix-grouping-separator | 1091 | (upcase (if (or calculator-2s-complement (>= num 0)) str |
| 1119 | (substring str i))))))) | 1092 | (concat "-" str))))) |
| 1120 | (upcase | 1093 | ((stringp calculator-displayer) (format calculator-displayer num)) |
| 1121 | (if (and (not calculator-2s-complement) (< num 0)) | 1094 | ((symbolp calculator-displayer) (funcall calculator-displayer num)) |
| 1122 | (concat "-" str) | 1095 | ((eq 'std (car-safe calculator-displayer)) |
| 1123 | str)))) | 1096 | (apply 'calculator-standard-displayer |
| 1124 | ((and (numberp num) calculator-displayer) | 1097 | num (cdr calculator-displayer))) |
| 1125 | (cond | 1098 | ((listp calculator-displayer) |
| 1126 | ((stringp calculator-displayer) | 1099 | (eval `(let ((num ',num)) ,calculator-displayer) t)) |
| 1127 | (format calculator-displayer num)) | 1100 | ;; nil (or bad) displayer |
| 1128 | ((symbolp calculator-displayer) | 1101 | (t (prin1-to-string num t)))) |
| 1129 | (funcall calculator-displayer num)) | ||
| 1130 | ((eq 'std (car-safe calculator-displayer)) | ||
| 1131 | (calculator-standard-displayer num (cadr calculator-displayer))) | ||
| 1132 | ((listp calculator-displayer) | ||
| 1133 | (eval calculator-displayer `((num. ,num)))) | ||
| 1134 | (t (prin1-to-string num t)))) | ||
| 1135 | ;; operators are printed here | ||
| 1136 | (t (prin1-to-string (nth 1 num) t)))) | ||
| 1137 | 1102 | ||
| 1138 | (defun calculator-update-display (&optional force) | 1103 | (defun calculator-update-display (&optional force) |
| 1139 | "Update the display. | 1104 | "Update the display. |
| 1140 | If optional argument FORCE is non-nil, don't use the cached string." | 1105 | If optional argument FORCE is non-nil, don't use the cached string." |
| 1141 | (set-buffer calculator-buffer) | 1106 | (set-buffer calculator-buffer) |
| 1142 | ;; update calculator-stack-display | 1107 | ;; update calculator-stack-display |
| 1143 | (if (or force | 1108 | (when (or force (not (eq (car calculator-stack-display) |
| 1144 | (not (eq (car calculator-stack-display) calculator-stack))) | 1109 | calculator-stack))) |
| 1145 | (setq calculator-stack-display | 1110 | (setq calculator-stack-display |
| 1146 | (cons calculator-stack | 1111 | (cons calculator-stack |
| 1147 | (if calculator-stack | 1112 | (if calculator-stack |
| @@ -1170,165 +1135,97 @@ If optional argument FORCE is non-nil, don't use the cached string." | |||
| 1170 | "")))) | 1135 | "")))) |
| 1171 | (let ((inhibit-read-only t)) | 1136 | (let ((inhibit-read-only t)) |
| 1172 | (erase-buffer) | 1137 | (erase-buffer) |
| 1173 | (insert (calculator-get-prompt))) | 1138 | (insert (calculator-get-display))) |
| 1174 | (set-buffer-modified-p nil) | 1139 | (set-buffer-modified-p nil) |
| 1175 | (if calculator-display-fragile | 1140 | (goto-char (if calculator-display-fragile |
| 1176 | (goto-char (1+ (length calculator-prompt))) | 1141 | (1+ (length calculator-prompt)) |
| 1177 | (goto-char (1- (point))))) | 1142 | (1- (point))))) |
| 1178 | 1143 | ||
| 1179 | ;;;--------------------------------------------------------------------- | 1144 | ;;;--------------------------------------------------------------------- |
| 1180 | ;;; Stack computations | 1145 | ;;; Stack computations |
| 1181 | 1146 | ||
| 1147 | (defun calculator-reduce-stack-once (prec) | ||
| 1148 | "Worker for `calculator-reduce-stack'." | ||
| 1149 | (cl-flet ((check (ar op) (and (listp op) | ||
| 1150 | (<= prec (calculator-op-prec op)) | ||
| 1151 | (= ar (calculator-op-arity op)))) | ||
| 1152 | (call (op &rest args) (apply 'calculator-funcall | ||
| 1153 | (nth 2 op) args))) | ||
| 1154 | (pcase calculator-stack | ||
| 1155 | ;; reduce "... ( x )" --> "... x" | ||
| 1156 | (`((,_ \) . ,_) ,(and X (pred numberp)) (,_ \( . ,_) . ,rest) | ||
| 1157 | (cons X rest)) | ||
| 1158 | ;; reduce "... x op y" --> "... r", r is the result | ||
| 1159 | (`(,(and Y (pred numberp)) | ||
| 1160 | ,(and O (pred (check 2))) | ||
| 1161 | ,(and X (pred numberp)) | ||
| 1162 | . ,rest) | ||
| 1163 | (cons (call O X Y) rest)) | ||
| 1164 | ;; reduce "... op x" --> "... r" for prefix op | ||
| 1165 | (`(,(and X (pred numberp)) ,(and O (pred (check -1))) . ,rest) | ||
| 1166 | (cons (call O X) rest)) | ||
| 1167 | ;; reduce "... x op" --> "... r" for postfix op | ||
| 1168 | (`(,(and O (pred (check +1))) ,(and X (pred numberp)) . ,rest) | ||
| 1169 | (cons (call O X) rest)) | ||
| 1170 | ;; reduce "... op" --> "... r" for 0-ary op | ||
| 1171 | (`(,(and O (pred (check 0))) . ,rest) | ||
| 1172 | (cons (call O) rest)) | ||
| 1173 | ;; reduce "... y x" --> "... x" | ||
| 1174 | ;; (needed for 0-ary ops: replace current number with result) | ||
| 1175 | (`(,(and X (pred numberp)) ,(and _Y (pred numberp)) . ,rest) | ||
| 1176 | (cons X rest)) | ||
| 1177 | (_ nil)))) ; nil = done | ||
| 1178 | |||
| 1182 | (defun calculator-reduce-stack (prec) | 1179 | (defun calculator-reduce-stack (prec) |
| 1183 | "Reduce the stack using top operator. | 1180 | "Reduce the stack using top operators as long as possible. |
| 1184 | PREC is a precedence - reduce everything with higher precedence." | 1181 | PREC is a precedence -- reduce everything with higher precedence." |
| 1185 | (while | 1182 | (let ((new nil)) |
| 1186 | (cond | 1183 | (while (setq new (calculator-reduce-stack-once prec)) |
| 1187 | ((and (cdr (cdr calculator-stack)) ; have three values | 1184 | (setq calculator-stack new)))) |
| 1188 | (consp (nth 0 calculator-stack)) ; two operators & num | ||
| 1189 | (numberp (nth 1 calculator-stack)) | ||
| 1190 | (consp (nth 2 calculator-stack)) | ||
| 1191 | (eq '\) (nth 1 (nth 0 calculator-stack))) | ||
| 1192 | (eq '\( (nth 1 (nth 2 calculator-stack)))) | ||
| 1193 | ;; reduce "... ( x )" --> "... x" | ||
| 1194 | (setq calculator-stack | ||
| 1195 | (cons (nth 1 calculator-stack) | ||
| 1196 | (nthcdr 3 calculator-stack))) | ||
| 1197 | ;; another iteration | ||
| 1198 | t) | ||
| 1199 | ((and (cdr (cdr calculator-stack)) ; have three values | ||
| 1200 | (numberp (nth 0 calculator-stack)) ; two nums & operator | ||
| 1201 | (consp (nth 1 calculator-stack)) | ||
| 1202 | (numberp (nth 2 calculator-stack)) | ||
| 1203 | (= 2 (calculator-op-arity ; binary operator | ||
| 1204 | (nth 1 calculator-stack))) | ||
| 1205 | (<= prec ; with higher prec. | ||
| 1206 | (calculator-op-prec (nth 1 calculator-stack)))) | ||
| 1207 | ;; reduce "... x op y" --> "... r", r is the result | ||
| 1208 | (setq calculator-stack | ||
| 1209 | (cons (calculator-funcall | ||
| 1210 | (nth 2 (nth 1 calculator-stack)) | ||
| 1211 | (nth 2 calculator-stack) | ||
| 1212 | (nth 0 calculator-stack)) | ||
| 1213 | (nthcdr 3 calculator-stack))) | ||
| 1214 | ;; another iteration | ||
| 1215 | t) | ||
| 1216 | ((and (>= (length calculator-stack) 2) ; have two values | ||
| 1217 | (numberp (nth 0 calculator-stack)) ; number & operator | ||
| 1218 | (consp (nth 1 calculator-stack)) | ||
| 1219 | (= -1 (calculator-op-arity ; prefix-unary op | ||
| 1220 | (nth 1 calculator-stack))) | ||
| 1221 | (<= prec ; with higher prec. | ||
| 1222 | (calculator-op-prec (nth 1 calculator-stack)))) | ||
| 1223 | ;; reduce "... op x" --> "... r" for prefix op | ||
| 1224 | (setq calculator-stack | ||
| 1225 | (cons (calculator-funcall | ||
| 1226 | (nth 2 (nth 1 calculator-stack)) | ||
| 1227 | (nth 0 calculator-stack)) | ||
| 1228 | (nthcdr 2 calculator-stack))) | ||
| 1229 | ;; another iteration | ||
| 1230 | t) | ||
| 1231 | ((and (cdr calculator-stack) ; have two values | ||
| 1232 | (consp (nth 0 calculator-stack)) ; operator & number | ||
| 1233 | (numberp (nth 1 calculator-stack)) | ||
| 1234 | (= +1 (calculator-op-arity ; postfix-unary op | ||
| 1235 | (nth 0 calculator-stack))) | ||
| 1236 | (<= prec ; with higher prec. | ||
| 1237 | (calculator-op-prec (nth 0 calculator-stack)))) | ||
| 1238 | ;; reduce "... x op" --> "... r" for postfix op | ||
| 1239 | (setq calculator-stack | ||
| 1240 | (cons (calculator-funcall | ||
| 1241 | (nth 2 (nth 0 calculator-stack)) | ||
| 1242 | (nth 1 calculator-stack)) | ||
| 1243 | (nthcdr 2 calculator-stack))) | ||
| 1244 | ;; another iteration | ||
| 1245 | t) | ||
| 1246 | ((and calculator-stack ; have one value | ||
| 1247 | (consp (nth 0 calculator-stack)) ; an operator | ||
| 1248 | (= 0 (calculator-op-arity ; 0-ary op | ||
| 1249 | (nth 0 calculator-stack)))) | ||
| 1250 | ;; reduce "... op" --> "... r" for 0-ary op | ||
| 1251 | (setq calculator-stack | ||
| 1252 | (cons (calculator-funcall | ||
| 1253 | (nth 2 (nth 0 calculator-stack))) | ||
| 1254 | (nthcdr 1 calculator-stack))) | ||
| 1255 | ;; another iteration | ||
| 1256 | t) | ||
| 1257 | ((and (cdr calculator-stack) ; have two values | ||
| 1258 | (numberp (nth 0 calculator-stack)) ; both numbers | ||
| 1259 | (numberp (nth 1 calculator-stack))) | ||
| 1260 | ;; get rid of redundant numbers: | ||
| 1261 | ;; reduce "... y x" --> "... x" | ||
| 1262 | ;; needed for 0-ary ops that puts more values | ||
| 1263 | (setcdr calculator-stack (cdr (cdr calculator-stack)))) | ||
| 1264 | (t ;; no more iterations | ||
| 1265 | nil)))) | ||
| 1266 | 1185 | ||
| 1267 | (defun calculator-funcall (f &optional X Y) | 1186 | (defun calculator-funcall (f &optional X Y) |
| 1268 | "If F is a symbol, evaluate (F X Y). | 1187 | "If F is a symbol, evaluate (F X Y). |
| 1269 | Otherwise, it should be a list, evaluate it with X, Y bound to the | 1188 | Otherwise, it should be a list, evaluate it with X, Y bound to the |
| 1270 | arguments." | 1189 | arguments." |
| 1271 | ;; remember binary ops for calculator-repR/L | 1190 | ;; remember binary ops for calculator-repR/L |
| 1272 | (if Y (setq calculator-last-opXY (list f X Y))) | 1191 | (when Y (setq calculator-last-opXY (list f X Y))) |
| 1273 | (condition-case nil | 1192 | (if (symbolp f) |
| 1274 | ;; there used to be code here that returns 0 if the result was | 1193 | (cond ((and X Y) (funcall f X Y)) |
| 1275 | ;; smaller than calculator-epsilon (1e-15). I don't think this is | 1194 | (X (funcall f X)) |
| 1276 | ;; necessary now. | 1195 | (t (funcall f))) |
| 1277 | (if (symbolp f) | 1196 | ;; f is an expression |
| 1278 | (cond ((and X Y) (funcall f X Y)) | 1197 | (let ((TX (and X (calculator-truncate X))) |
| 1279 | (X (funcall f X)) | 1198 | (TY (and Y (calculator-truncate Y))) |
| 1280 | (t (funcall f))) | 1199 | (DX (if (and X calculator-deg) (/ (* X pi) 180) X)) |
| 1281 | ;; f is an expression | 1200 | (L calculator-saved-list)) |
| 1282 | (let* ((TX (calculator-truncate X)) | 1201 | (cl-flet ((F (&optional x y) (calculator-funcall f x y)) |
| 1283 | (TY (and Y (calculator-truncate Y))) | 1202 | (D (x) (if calculator-deg (/ (* x 180) float-pi) x))) |
| 1284 | (DX (if calculator-deg (/ (* X pi) 180) X)) | 1203 | (eval `(let ((X ,X) (Y ,Y) (DX ,DX) (TX ,TX) (TY ,TY) (L ',L)) |
| 1285 | (L calculator-saved-list)) | 1204 | ,f) |
| 1286 | (cl-letf (((symbol-function 'F) | 1205 | t))))) |
| 1287 | (lambda (&optional x y) (calculator-funcall f x y))) | ||
| 1288 | ((symbol-function 'D) | ||
| 1289 | (lambda (x) (if calculator-deg (/ (* x 180) float-pi) x)))) | ||
| 1290 | (eval f `((X . ,X) | ||
| 1291 | (Y . ,Y) | ||
| 1292 | (TX . ,TX) | ||
| 1293 | (TY . ,TY) | ||
| 1294 | (DX . ,DX) | ||
| 1295 | (L . ,L)))))) | ||
| 1296 | (error 0))) | ||
| 1297 | 1206 | ||
| 1298 | ;;;--------------------------------------------------------------------- | 1207 | ;;;--------------------------------------------------------------------- |
| 1299 | ;;; Input interaction | 1208 | ;;; Input interaction |
| 1300 | 1209 | ||
| 1301 | (defun calculator-last-input (&optional keys) | 1210 | (defun calculator-last-input (&optional keys) |
| 1302 | "Last char (or event or event sequence) that was read. | 1211 | "Last char (or event or event sequence) that was read. |
| 1303 | Optional string argument KEYS will force using it as the keys entered." | 1212 | Use KEYS if given, otherwise use `this-command-keys'." |
| 1304 | (let ((inp (or keys (this-command-keys)))) | 1213 | (let ((inp (or keys (this-command-keys)))) |
| 1305 | (if (or (stringp inp) (not (arrayp inp))) | 1214 | (if (or (stringp inp) (not (arrayp inp))) |
| 1306 | inp | 1215 | inp |
| 1307 | ;; this translates kp-x to x and [tries to] create a string to | 1216 | ;; translates kp-x to x and [tries to] create a string to lookup |
| 1308 | ;; lookup operators | 1217 | ;; operators; assume all symbols are translatable via |
| 1309 | (let* ((i -1) (converted-str (make-string (length inp) ? )) k) | 1218 | ;; `function-key-map' or with an 'ascii-character property |
| 1310 | ;; converts an array to a string the ops lookup with keypad | 1219 | (concat (mapcar (lambda (k) |
| 1311 | ;; input | 1220 | (if (numberp k) k (or (get k 'ascii-character) |
| 1312 | (while (< (setq i (1+ i)) (length inp)) | 1221 | (error "??bad key??")))) |
| 1313 | (setq k (aref inp i)) | 1222 | (or (lookup-key function-key-map inp) inp)))))) |
| 1314 | ;; if Emacs will someday have a event-key, then this would | ||
| 1315 | ;; probably be modified anyway | ||
| 1316 | (and (if (fboundp 'key-press-event-p) (key-press-event-p k)) | ||
| 1317 | (if (fboundp 'event-key) | ||
| 1318 | (and (event-key k) (setq k (event-key k))))) | ||
| 1319 | ;; assume all symbols are translatable with an ascii-character | ||
| 1320 | (and (symbolp k) | ||
| 1321 | (setq k (or (get k 'ascii-character) ? ))) | ||
| 1322 | (aset converted-str i k)) | ||
| 1323 | converted-str)))) | ||
| 1324 | 1223 | ||
| 1325 | (defun calculator-clear-fragile (&optional op) | 1224 | (defun calculator-clear-fragile (&optional op) |
| 1326 | "Clear the fragile flag if it was set, then maybe reset all. | 1225 | "Clear the fragile flag if it was set, then maybe reset all. |
| 1327 | OP is the operator (if any) that caused this call." | 1226 | OP is the operator (if any) that caused this call." |
| 1328 | (if (and calculator-display-fragile | 1227 | (when (and calculator-display-fragile |
| 1329 | (or (not op) | 1228 | (or (not op) (memq (calculator-op-arity op) '(-1 0)))) |
| 1330 | (= -1 (calculator-op-arity op)) | ||
| 1331 | (= 0 (calculator-op-arity op)))) | ||
| 1332 | ;; reset if last calc finished, and now get a num or prefix or 0-ary | 1229 | ;; reset if last calc finished, and now get a num or prefix or 0-ary |
| 1333 | ;; op | 1230 | ;; op |
| 1334 | (calculator-reset)) | 1231 | (calculator-reset)) |
| @@ -1338,53 +1235,44 @@ OP is the operator (if any) that caused this call." | |||
| 1338 | "Enter a single digit." | 1235 | "Enter a single digit." |
| 1339 | (interactive) | 1236 | (interactive) |
| 1340 | (let ((inp (aref (calculator-last-input) 0))) | 1237 | (let ((inp (aref (calculator-last-input) 0))) |
| 1341 | (if (and (or calculator-display-fragile | 1238 | (when (and (or calculator-display-fragile |
| 1342 | (not (numberp (car calculator-stack)))) | 1239 | (not (numberp (car calculator-stack)))) |
| 1343 | (cond | 1240 | (<= inp (pcase calculator-input-radix |
| 1344 | ((not calculator-input-radix) (<= inp ?9)) | 1241 | (`nil ?9) (`bin ?1) (`oct ?7) (_ 999)))) |
| 1345 | ((eq calculator-input-radix 'bin) (<= inp ?1)) | 1242 | (calculator-clear-fragile) |
| 1346 | ((eq calculator-input-radix 'oct) (<= inp ?7)) | 1243 | (setq calculator-curnum |
| 1347 | (t t))) | 1244 | (concat (if (equal calculator-curnum "0") "" |
| 1348 | ;; enter digit if starting a new computation or have an op on the | 1245 | calculator-curnum) |
| 1349 | ;; stack | 1246 | (list (upcase inp)))) |
| 1350 | (progn | 1247 | (calculator-update-display)))) |
| 1351 | (calculator-clear-fragile) | ||
| 1352 | (let ((digit (upcase (char-to-string inp)))) | ||
| 1353 | (if (equal calculator-curnum "0") | ||
| 1354 | (setq calculator-curnum nil)) | ||
| 1355 | (setq calculator-curnum | ||
| 1356 | (concat (or calculator-curnum "") digit))) | ||
| 1357 | (calculator-update-display))))) | ||
| 1358 | 1248 | ||
| 1359 | (defun calculator-decimal () | 1249 | (defun calculator-decimal () |
| 1360 | "Enter a decimal period." | 1250 | "Enter a decimal period." |
| 1361 | (interactive) | 1251 | (interactive) |
| 1362 | (if (and (not calculator-input-radix) | 1252 | (when (and (not calculator-input-radix) |
| 1363 | (or calculator-display-fragile | 1253 | (or calculator-display-fragile |
| 1364 | (not (numberp (car calculator-stack)))) | 1254 | (not (numberp (car calculator-stack)))) |
| 1365 | (not (and calculator-curnum | 1255 | (not (and calculator-curnum |
| 1366 | (string-match-p "[.eE]" calculator-curnum)))) | 1256 | (string-match-p "[.eE]" calculator-curnum)))) |
| 1367 | ;; enter the period on the same condition as a digit, only if no | 1257 | ;; enter the period on the same condition as a digit, only if no |
| 1368 | ;; period or exponent entered yet | 1258 | ;; period or exponent entered yet |
| 1369 | (progn | 1259 | (calculator-clear-fragile) |
| 1370 | (calculator-clear-fragile) | 1260 | (setq calculator-curnum (concat (or calculator-curnum "0") ".")) |
| 1371 | (setq calculator-curnum (concat (or calculator-curnum "0") ".")) | 1261 | (calculator-update-display))) |
| 1372 | (calculator-update-display)))) | ||
| 1373 | 1262 | ||
| 1374 | (defun calculator-exp () | 1263 | (defun calculator-exp () |
| 1375 | "Enter an `E' exponent character, or a digit in hex input mode." | 1264 | "Enter an `E' exponent character, or a digit in hex input mode." |
| 1376 | (interactive) | 1265 | (interactive) |
| 1377 | (if calculator-input-radix | 1266 | (cond |
| 1378 | (calculator-digit) | 1267 | (calculator-input-radix (calculator-digit)) |
| 1379 | (if (and (or calculator-display-fragile | 1268 | ((and (or calculator-display-fragile |
| 1380 | (not (numberp (car calculator-stack)))) | 1269 | (not (numberp (car calculator-stack)))) |
| 1381 | (not (and calculator-curnum | 1270 | (not (and calculator-curnum |
| 1382 | (string-match-p "[eE]" calculator-curnum)))) | 1271 | (string-match-p "[eE]" calculator-curnum)))) |
| 1383 | ;; same condition as above, also no E so far | 1272 | ;; same condition as above, also no E so far |
| 1384 | (progn | 1273 | (calculator-clear-fragile) |
| 1385 | (calculator-clear-fragile) | 1274 | (setq calculator-curnum (concat (or calculator-curnum "1") "e")) |
| 1386 | (setq calculator-curnum (concat (or calculator-curnum "1") "e")) | 1275 | (calculator-update-display)))) |
| 1387 | (calculator-update-display))))) | ||
| 1388 | 1276 | ||
| 1389 | (defun calculator-op (&optional keys) | 1277 | (defun calculator-op (&optional keys) |
| 1390 | "Enter an operator on the stack, doing all necessary reductions. | 1278 | "Enter an operator on the stack, doing all necessary reductions. |
| @@ -1394,42 +1282,29 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1394 | (let* ((last-inp (calculator-last-input keys)) | 1282 | (let* ((last-inp (calculator-last-input keys)) |
| 1395 | (op (assoc last-inp calculator-operators))) | 1283 | (op (assoc last-inp calculator-operators))) |
| 1396 | (calculator-clear-fragile op) | 1284 | (calculator-clear-fragile op) |
| 1397 | (if (and calculator-curnum (/= (calculator-op-arity op) 0)) | 1285 | (calculator-push-curnum) |
| 1398 | (setq calculator-stack | 1286 | (when (and (= 2 (calculator-op-arity op)) |
| 1399 | (cons (calculator-curnum-value) calculator-stack))) | 1287 | (not (numberp (car calculator-stack)))) |
| 1400 | (setq calculator-curnum nil) | 1288 | ;; we have a binary operator but no number -- search for a |
| 1401 | (if (and (= 2 (calculator-op-arity op)) | 1289 | ;; prefix version |
| 1402 | (not (and calculator-stack | 1290 | (setq op (assoc last-inp (cdr (memq op calculator-operators)))) |
| 1403 | (numberp (nth 0 calculator-stack))))) | 1291 | (unless (and op (= -1 (calculator-op-arity op))) |
| 1404 | ;; we have a binary operator but no number - search for a prefix | 1292 | (calculator-message "Binary operator without a first operand") |
| 1405 | ;; version | 1293 | (throw 'op-error nil))) |
| 1406 | (let ((rest-ops calculator-operators)) | ||
| 1407 | (while (not (equal last-inp (car (car rest-ops)))) | ||
| 1408 | (setq rest-ops (cdr rest-ops))) | ||
| 1409 | (setq op (assoc last-inp (cdr rest-ops))) | ||
| 1410 | (if (not (and op (= -1 (calculator-op-arity op)))) | ||
| 1411 | ;;(error "Binary operator without a first operand") | ||
| 1412 | (progn | ||
| 1413 | (calculator-message | ||
| 1414 | "Binary operator without a first operand") | ||
| 1415 | (throw 'op-error nil))))) | ||
| 1416 | (calculator-reduce-stack | 1294 | (calculator-reduce-stack |
| 1417 | (cond ((eq (nth 1 op) '\() 10) | 1295 | (cond ((eq (nth 1 op) '\() 10) |
| 1418 | ((eq (nth 1 op) '\)) 0) | 1296 | ((eq (nth 1 op) '\)) 0) |
| 1419 | (t (calculator-op-prec op)))) | 1297 | (t (calculator-op-prec op)))) |
| 1420 | (if (or (and (= -1 (calculator-op-arity op)) | 1298 | (when (let ((hasnum (numberp (car calculator-stack)))) |
| 1421 | (numberp (car calculator-stack))) | 1299 | (pcase (calculator-op-arity op) |
| 1422 | (and (/= (calculator-op-arity op) -1) | 1300 | (-1 hasnum) |
| 1423 | (/= (calculator-op-arity op) 0) | 1301 | ((or 1 2) (not hasnum)))) |
| 1424 | (not (numberp (car calculator-stack))))) | 1302 | (calculator-message "Incomplete expression") |
| 1425 | ;;(error "Unterminated expression") | 1303 | (throw 'op-error nil)) |
| 1426 | (progn | 1304 | (push op calculator-stack) |
| 1427 | (calculator-message "Unterminated expression") | ||
| 1428 | (throw 'op-error nil))) | ||
| 1429 | (setq calculator-stack (cons op calculator-stack)) | ||
| 1430 | (calculator-reduce-stack (calculator-op-prec op)) | 1305 | (calculator-reduce-stack (calculator-op-prec op)) |
| 1431 | (and (= (length calculator-stack) 1) | 1306 | (and (= (length calculator-stack) 1) |
| 1432 | (numberp (nth 0 calculator-stack)) | 1307 | (numberp (car calculator-stack)) |
| 1433 | ;; the display is fragile if it contains only one number | 1308 | ;; the display is fragile if it contains only one number |
| 1434 | (setq calculator-display-fragile t) | 1309 | (setq calculator-display-fragile t) |
| 1435 | ;; add number to the saved-list | 1310 | ;; add number to the saved-list |
| @@ -1445,7 +1320,8 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1445 | (defun calculator-op-or-exp () | 1320 | (defun calculator-op-or-exp () |
| 1446 | "Either enter an operator or a digit. | 1321 | "Either enter an operator or a digit. |
| 1447 | Used with +/- for entering them as digits in numbers like 1e-3 (there is | 1322 | Used with +/- for entering them as digits in numbers like 1e-3 (there is |
| 1448 | no need for negative numbers since these are handled by unary operators)." | 1323 | no need for negative numbers since these are handled by unary |
| 1324 | operators)." | ||
| 1449 | (interactive) | 1325 | (interactive) |
| 1450 | (if (and (not calculator-display-fragile) | 1326 | (if (and (not calculator-display-fragile) |
| 1451 | calculator-curnum | 1327 | calculator-curnum |
| @@ -1459,14 +1335,11 @@ no need for negative numbers since these are handled by unary operators)." | |||
| 1459 | (defun calculator-dec/deg-mode () | 1335 | (defun calculator-dec/deg-mode () |
| 1460 | "Set decimal mode for display & input, if decimal, toggle deg mode." | 1336 | "Set decimal mode for display & input, if decimal, toggle deg mode." |
| 1461 | (interactive) | 1337 | (interactive) |
| 1462 | (if calculator-curnum | 1338 | (calculator-push-curnum) |
| 1463 | (setq calculator-stack | ||
| 1464 | (cons (calculator-curnum-value) calculator-stack))) | ||
| 1465 | (setq calculator-curnum nil) | ||
| 1466 | (if (or calculator-input-radix calculator-output-radix) | 1339 | (if (or calculator-input-radix calculator-output-radix) |
| 1467 | (progn (setq calculator-input-radix nil) | 1340 | (progn (setq calculator-input-radix nil) |
| 1468 | (setq calculator-output-radix nil)) | 1341 | (setq calculator-output-radix nil)) |
| 1469 | ;; already decimal - toggle degrees mode | 1342 | ;; already decimal -- toggle degrees mode |
| 1470 | (setq calculator-deg (not calculator-deg))) | 1343 | (setq calculator-deg (not calculator-deg))) |
| 1471 | (calculator-update-display t)) | 1344 | (calculator-update-display t)) |
| 1472 | 1345 | ||
| @@ -1481,10 +1354,7 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1481 | "Set input radix modes. | 1354 | "Set input radix modes. |
| 1482 | Optional string argument KEYS will force using it as the keys entered." | 1355 | Optional string argument KEYS will force using it as the keys entered." |
| 1483 | (interactive) | 1356 | (interactive) |
| 1484 | (if calculator-curnum | 1357 | (calculator-push-curnum) |
| 1485 | (setq calculator-stack | ||
| 1486 | (cons (calculator-curnum-value) calculator-stack))) | ||
| 1487 | (setq calculator-curnum nil) | ||
| 1488 | (setq calculator-input-radix | 1358 | (setq calculator-input-radix |
| 1489 | (let ((inp (calculator-last-input keys))) | 1359 | (let ((inp (calculator-last-input keys))) |
| 1490 | (cdr (assq (upcase (aref inp (1- (length inp)))) | 1360 | (cdr (assq (upcase (aref inp (1- (length inp)))) |
| @@ -1495,10 +1365,7 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1495 | "Set display radix modes. | 1365 | "Set display radix modes. |
| 1496 | Optional string argument KEYS will force using it as the keys entered." | 1366 | Optional string argument KEYS will force using it as the keys entered." |
| 1497 | (interactive) | 1367 | (interactive) |
| 1498 | (if calculator-curnum | 1368 | (calculator-push-curnum) |
| 1499 | (setq calculator-stack | ||
| 1500 | (cons (calculator-curnum-value) calculator-stack))) | ||
| 1501 | (setq calculator-curnum nil) | ||
| 1502 | (setq calculator-output-radix | 1369 | (setq calculator-output-radix |
| 1503 | (let ((inp (calculator-last-input keys))) | 1370 | (let ((inp (calculator-last-input keys))) |
| 1504 | (cdr (assq (upcase (aref inp (1- (length inp)))) | 1371 | (cdr (assq (upcase (aref inp (1- (length inp)))) |
| @@ -1524,19 +1391,18 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1524 | (defun calculator-saved-move (n) | 1391 | (defun calculator-saved-move (n) |
| 1525 | "Go N elements up the list of saved values." | 1392 | "Go N elements up the list of saved values." |
| 1526 | (interactive) | 1393 | (interactive) |
| 1527 | (and calculator-saved-list | 1394 | (when (and calculator-saved-list |
| 1528 | (or (null calculator-stack) calculator-display-fragile) | 1395 | (or (null calculator-stack) calculator-display-fragile)) |
| 1529 | (progn | 1396 | (setq calculator-saved-ptr |
| 1530 | (setq calculator-saved-ptr | 1397 | (max (min (+ n calculator-saved-ptr) |
| 1531 | (max (min (+ n calculator-saved-ptr) | 1398 | (length calculator-saved-list)) |
| 1532 | (length calculator-saved-list)) | 1399 | 0)) |
| 1533 | 0)) | 1400 | (if (nth calculator-saved-ptr calculator-saved-list) |
| 1534 | (if (nth calculator-saved-ptr calculator-saved-list) | 1401 | (setq calculator-stack (list (nth calculator-saved-ptr |
| 1535 | (setq calculator-stack | 1402 | calculator-saved-list)) |
| 1536 | (list (nth calculator-saved-ptr calculator-saved-list)) | 1403 | calculator-display-fragile t) |
| 1537 | calculator-display-fragile t) | 1404 | (calculator-reset)) |
| 1538 | (calculator-reset)) | 1405 | (calculator-update-display))) |
| 1539 | (calculator-update-display)))) | ||
| 1540 | 1406 | ||
| 1541 | (defun calculator-saved-up () | 1407 | (defun calculator-saved-up () |
| 1542 | "Go up the list of saved values." | 1408 | "Go up the list of saved values." |
| @@ -1583,7 +1449,7 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1583 | (interactive) | 1449 | (interactive) |
| 1584 | (setq calculator-curnum nil) | 1450 | (setq calculator-curnum nil) |
| 1585 | (cond | 1451 | (cond |
| 1586 | ;; if the current number is from the saved-list - remove it | 1452 | ;; if the current number is from the saved-list remove it |
| 1587 | ((and calculator-display-fragile | 1453 | ((and calculator-display-fragile |
| 1588 | calculator-saved-list | 1454 | calculator-saved-list |
| 1589 | (= (car calculator-stack) | 1455 | (= (car calculator-stack) |
| @@ -1592,7 +1458,7 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1592 | (setq calculator-saved-list (cdr calculator-saved-list)) | 1458 | (setq calculator-saved-list (cdr calculator-saved-list)) |
| 1593 | (let ((p (nthcdr (1- calculator-saved-ptr) | 1459 | (let ((p (nthcdr (1- calculator-saved-ptr) |
| 1594 | calculator-saved-list))) | 1460 | calculator-saved-list))) |
| 1595 | (setcdr p (cdr (cdr p))) | 1461 | (setcdr p (cddr p)) |
| 1596 | (setq calculator-saved-ptr (1- calculator-saved-ptr)))) | 1462 | (setq calculator-saved-ptr (1- calculator-saved-ptr)))) |
| 1597 | (if calculator-saved-list | 1463 | (if calculator-saved-list |
| 1598 | (setq calculator-stack | 1464 | (setq calculator-stack |
| @@ -1613,15 +1479,16 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1613 | (calculator-enter) | 1479 | (calculator-enter) |
| 1614 | ;; remove trailing spaces and an index | 1480 | ;; remove trailing spaces and an index |
| 1615 | (let ((s (cdr calculator-stack-display))) | 1481 | (let ((s (cdr calculator-stack-display))) |
| 1616 | (and s | 1482 | (when s |
| 1617 | (if (string-match "^\\([^ ]+\\) *\\(\\[[0-9/]+\\]\\)? *$" s) | 1483 | (kill-new (replace-regexp-in-string |
| 1618 | (setq s (match-string 1 s))) | 1484 | "^\\([^ ]+\\) *\\(\\[[0-9/]+\\]\\)? *$" "\\1" s)))))) |
| 1619 | (kill-new s))))) | ||
| 1620 | 1485 | ||
| 1621 | ;; FIXME this should use register-read-with-preview, but it | ||
| 1622 | ;; uses calculator-registers rather than register-alist. | ||
| 1623 | (defun calculator-set-register (reg) | 1486 | (defun calculator-set-register (reg) |
| 1624 | "Set a register value for REG." | 1487 | "Set a register value for REG." |
| 1488 | ;; FIXME: this should use `register-read-with-preview', but it uses | ||
| 1489 | ;; calculator-registers rather than `register-alist'. (Maybe | ||
| 1490 | ;; dynamically rebinding it will get blessed?) Also in to | ||
| 1491 | ;; `calculator-get-register'. | ||
| 1625 | (interactive "cRegister to store into: ") | 1492 | (interactive "cRegister to store into: ") |
| 1626 | (let* ((as (assq reg calculator-registers)) | 1493 | (let* ((as (assq reg calculator-registers)) |
| 1627 | (val (progn (calculator-enter) (car calculator-stack)))) | 1494 | (val (progn (calculator-enter) (car calculator-stack)))) |
| @@ -1634,15 +1501,14 @@ Optional string argument KEYS will force using it as the keys entered." | |||
| 1634 | (defun calculator-put-value (val) | 1501 | (defun calculator-put-value (val) |
| 1635 | "Paste VAL as if entered. | 1502 | "Paste VAL as if entered. |
| 1636 | Used by `calculator-paste' and `get-register'." | 1503 | Used by `calculator-paste' and `get-register'." |
| 1637 | (if (and (numberp val) | 1504 | (when (and (numberp val) |
| 1638 | ;; (not calculator-curnum) | 1505 | ;; (not calculator-curnum) |
| 1639 | (or calculator-display-fragile | 1506 | (or calculator-display-fragile |
| 1640 | (not (numberp (car calculator-stack))))) | 1507 | (not (numberp (car calculator-stack))))) |
| 1641 | (progn | 1508 | (calculator-clear-fragile) |
| 1642 | (calculator-clear-fragile) | 1509 | (setq calculator-curnum (let ((calculator-displayer "%S")) |
| 1643 | (setq calculator-curnum (let ((calculator-displayer "%S")) | 1510 | (calculator-number-to-string val))) |
| 1644 | (calculator-number-to-string val))) | 1511 | (calculator-update-display))) |
| 1645 | (calculator-update-display)))) | ||
| 1646 | 1512 | ||
| 1647 | (defun calculator-paste () | 1513 | (defun calculator-paste () |
| 1648 | "Paste a value from the `kill-ring'." | 1514 | "Paste a value from the `kill-ring'." |
| @@ -1662,8 +1528,6 @@ Used by `calculator-paste' and `get-register'." | |||
| 1662 | (or (match-string 3 str) "")))) | 1528 | (or (match-string 3 str) "")))) |
| 1663 | (ignore-errors (calculator-string-to-number str))))) | 1529 | (ignore-errors (calculator-string-to-number str))))) |
| 1664 | 1530 | ||
| 1665 | ;; FIXME this should use register-read-with-preview, but it | ||
| 1666 | ;; uses calculator-registers rather than register-alist. | ||
| 1667 | (defun calculator-get-register (reg) | 1531 | (defun calculator-get-register (reg) |
| 1668 | "Get a value from a register REG." | 1532 | "Get a value from a register REG." |
| 1669 | (interactive "cRegister to get value from: ") | 1533 | (interactive "cRegister to get value from: ") |
| @@ -1696,16 +1560,13 @@ Used by `calculator-paste' and `get-register'." | |||
| 1696 | (g-map (current-global-map)) | 1560 | (g-map (current-global-map)) |
| 1697 | (win (selected-window))) | 1561 | (win (selected-window))) |
| 1698 | (require 'ehelp) | 1562 | (require 'ehelp) |
| 1699 | (if calculator-electric-mode | 1563 | (when calculator-electric-mode |
| 1700 | (use-global-map calculator-saved-global-map)) | 1564 | (use-global-map calculator-saved-global-map)) |
| 1701 | (if (or (not calculator-electric-mode) | ||
| 1702 | ;; XEmacs has a problem with electric-describe-mode | ||
| 1703 | (featurep 'xemacs)) | ||
| 1704 | (describe-mode) | ||
| 1705 | (electric-describe-mode)) | ||
| 1706 | (if calculator-electric-mode | 1565 | (if calculator-electric-mode |
| 1707 | (use-global-map g-map)) | 1566 | (electric-describe-mode) |
| 1708 | (select-window win) ; these are for XEmacs (also below) | 1567 | (describe-mode)) |
| 1568 | (when calculator-electric-mode (use-global-map g-map)) | ||
| 1569 | (select-window win) | ||
| 1709 | (message nil)) | 1570 | (message nil)) |
| 1710 | (let ((one (one-window-p t)) | 1571 | (let ((one (one-window-p t)) |
| 1711 | (win (selected-window)) | 1572 | (win (selected-window)) |
| @@ -1713,12 +1574,11 @@ Used by `calculator-paste' and `get-register'." | |||
| 1713 | (save-window-excursion | 1574 | (save-window-excursion |
| 1714 | (with-output-to-temp-buffer "*Help*" | 1575 | (with-output-to-temp-buffer "*Help*" |
| 1715 | (princ (documentation 'calculator-help))) | 1576 | (princ (documentation 'calculator-help))) |
| 1716 | (if one | 1577 | (when one (shrink-window-if-larger-than-buffer |
| 1717 | (shrink-window-if-larger-than-buffer | 1578 | (get-buffer-window help-buf))) |
| 1718 | (get-buffer-window help-buf))) | 1579 | (message "`%s' again for more help, %s." |
| 1719 | (message | 1580 | (calculator-last-input) |
| 1720 | "`%s' again for more help, any other key continues normally." | 1581 | "any other key continues normally") |
| 1721 | (calculator-last-input)) | ||
| 1722 | (select-window win) | 1582 | (select-window win) |
| 1723 | (sit-for 360)) | 1583 | (sit-for 360)) |
| 1724 | (select-window win)))) | 1584 | (select-window win)))) |
| @@ -1731,11 +1591,12 @@ Used by `calculator-paste' and `get-register'." | |||
| 1731 | (unless calculator-electric-mode | 1591 | (unless calculator-electric-mode |
| 1732 | (ignore-errors | 1592 | (ignore-errors |
| 1733 | (while (get-buffer-window calculator-buffer) | 1593 | (while (get-buffer-window calculator-buffer) |
| 1734 | (delete-window (get-buffer-window calculator-buffer)))) | 1594 | (delete-window (get-buffer-window calculator-buffer))))) |
| 1735 | (kill-buffer calculator-buffer)) | 1595 | (kill-buffer calculator-buffer) |
| 1736 | (setq calculator-buffer nil) | ||
| 1737 | (message "Calculator done.") | 1596 | (message "Calculator done.") |
| 1738 | (if calculator-electric-mode (throw 'calculator-done nil))) | 1597 | (if calculator-electric-mode |
| 1598 | (throw 'calculator-done nil) ; will kill the buffer | ||
| 1599 | (setq calculator-buffer nil))) | ||
| 1739 | 1600 | ||
| 1740 | (defun calculator-save-and-quit () | 1601 | (defun calculator-save-and-quit () |
| 1741 | "Quit the calculator, saving the result on the `kill-ring'." | 1602 | "Quit the calculator, saving the result on the `kill-ring'." |
| @@ -1764,58 +1625,47 @@ To use this, apply a binary operator (evaluate it), then call this." | |||
| 1764 | (car calculator-last-opXY) (nth 1 calculator-last-opXY) x)) | 1625 | (car calculator-last-opXY) (nth 1 calculator-last-opXY) x)) |
| 1765 | x)) | 1626 | x)) |
| 1766 | 1627 | ||
| 1767 | (defun calculator-integer-p (x) | ||
| 1768 | "Non-nil if X is equal to an integer." | ||
| 1769 | (ignore-errors (= x (ftruncate x)))) | ||
| 1770 | |||
| 1771 | (defun calculator-expt (x y) | 1628 | (defun calculator-expt (x y) |
| 1772 | "Compute X^Y, dealing with errors appropriately." | 1629 | "Compute X^Y, dealing with errors appropriately." |
| 1773 | (condition-case nil | 1630 | (condition-case nil |
| 1774 | (expt x y) | 1631 | (expt x y) |
| 1775 | (domain-error 0.0e+NaN) | 1632 | (domain-error 0.0e+NaN) |
| 1776 | (range-error | 1633 | (range-error |
| 1777 | (cond | 1634 | (cond ((and (< x 1.0) (> x -1.0)) |
| 1778 | ((and (< x 1.0) (> x -1.0)) | 1635 | ;; For small x, the range error comes from large y. |
| 1779 | ;; For small x, the range error comes from large y. | 1636 | 0.0) |
| 1780 | 0.0) | 1637 | ((and (> x 0.0) (< y 0.0)) |
| 1781 | ((and (> x 0.0) (< y 0.0)) | 1638 | ;; For large positive x and negative y, the range error |
| 1782 | ;; For large positive x and negative y, the range error | 1639 | ;; comes from large negative y. |
| 1783 | ;; comes from large negative y. | 1640 | 0.0) |
| 1784 | 0.0) | 1641 | ((and (> x 0.0) (> y 0.0)) |
| 1785 | ((and (> x 0.0) (> y 0.0)) | 1642 | ;; For large positive x and positive y, the range error |
| 1786 | ;; For large positive x and positive y, the range error | 1643 | ;; comes from large y. |
| 1787 | ;; comes from large y. | 1644 | 1.0e+INF) |
| 1788 | 1.0e+INF) | 1645 | ;; For the rest, x must be large and negative. |
| 1789 | ;; For the rest, x must be large and negative. | 1646 | ;; The range errors come from large integer y. |
| 1790 | ;; The range errors come from large integer y. | 1647 | ((< y 0.0) |
| 1791 | ((< y 0.0) | 1648 | 0.0) |
| 1792 | 0.0) | 1649 | ((eq (logand (truncate y) 1) 1) ; expansion of cl `oddp' |
| 1793 | ((eq (logand (truncate y) 1) 1) ; expansion of cl `oddp' | 1650 | ;; If y is odd |
| 1794 | ;; If y is odd | 1651 | -1.0e+INF) |
| 1795 | -1.0e+INF) | 1652 | (t |
| 1796 | (t | 1653 | ;; |
| 1797 | ;; | 1654 | 1.0e+INF))) |
| 1798 | 1.0e+INF))) | ||
| 1799 | (error 0.0e+NaN))) | 1655 | (error 0.0e+NaN))) |
| 1800 | 1656 | ||
| 1801 | (defun calculator-fact (x) | 1657 | (defun calculator-fact (x) |
| 1802 | "Simple factorial of X." | 1658 | "Simple factorial of X." |
| 1803 | (if (and (>= x 0) | 1659 | (cond ((>= x 1.0e+INF) x) |
| 1804 | (calculator-integer-p x)) | 1660 | ((or (and (floatp x) (isnan x)) (< x 0)) 0.0e+NaN) |
| 1805 | (if (= (calculator-expt (/ x 3.0) x) 1.0e+INF) | 1661 | ((>= (calculator-expt (/ x 3.0) x) 1.0e+INF) 1.0e+INF) |
| 1806 | 1.0e+INF | 1662 | (t (let ((x (truncate x)) (r 1.0)) |
| 1807 | (let ((r (if (<= x 10) 1 1.0))) | 1663 | (while (> x 0) (setq r (* r x) x (1- x))) |
| 1808 | (while (> x 0) | 1664 | r)))) |
| 1809 | (setq r (* r (truncate x))) | ||
| 1810 | (setq x (1- x))) | ||
| 1811 | (+ 0.0 r))) | ||
| 1812 | (if (= x 1.0e+INF) | ||
| 1813 | x | ||
| 1814 | 0.0e+NaN))) | ||
| 1815 | 1665 | ||
| 1816 | (defun calculator-truncate (n) | 1666 | (defun calculator-truncate (n) |
| 1817 | "Truncate N, return 0 in case of overflow." | 1667 | "Truncate N, return 0 in case of overflow." |
| 1818 | (condition-case nil (truncate n) (error 0))) | 1668 | (condition-case nil (truncate n) (range-error 0))) |
| 1819 | 1669 | ||
| 1820 | 1670 | ||
| 1821 | (provide 'calculator) | 1671 | (provide 'calculator) |