source: trunk/j/src/org/armedbear/lisp/numbers.lisp @ 3586

Last change on this file since 3586 was 3586, checked in by piso, 20 years ago

SIGNUM

File size: 6.9 KB
Line 
1;;; numbers.lisp
2;;;
3;;; Copyright (C) 2003 Peter Graves
4;;; $Id: numbers.lisp,v 1.11 2003-09-06 14:08:25 piso Exp $
5;;;
6;;; This program is free software; you can redistribute it and/or
7;;; modify it under the terms of the GNU General Public License
8;;; as published by the Free Software Foundation; either version 2
9;;; of the License, or (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20;;; From CMUCL.
21
22(in-package "SYSTEM")
23
24(defun signum (number)
25  "If NUMBER is zero, return NUMBER, else return (/ NUMBER (ABS NUMBER))."
26  (if (zerop number)
27      number
28      (if (rationalp number)
29    (if (plusp number) 1 -1)
30    (/ number (abs number)))))
31
32
33;;; If the numbers do not divide exactly and the result of (/ number divisor)
34;;; would be negative then decrement the quotient and augment the remainder by
35;;; the divisor.
36;;;
37(defun floor (number &optional (divisor 1))
38  "Returns the greatest integer not greater than number, or number/divisor.
39  The second returned value is (mod number divisor)."
40  (multiple-value-bind (tru rem) (truncate number divisor)
41    (if (and (not (zerop rem))
42       (if (minusp divisor)
43     (plusp number)
44     (minusp number)))
45  (values (1- tru) (+ rem divisor))
46  (values tru rem))))
47
48
49;;; If the numbers do not divide exactly and the result of (/ number divisor)
50;;; would be positive then increment the quotient and decrement the remainder by
51;;; the divisor.
52;;;
53(defun ceiling (number &optional (divisor 1))
54  "Returns the smallest integer not less than number, or number/divisor.
55  The second returned value is the remainder."
56  (multiple-value-bind (tru rem) (truncate number divisor)
57    (if (and (not (zerop rem))
58       (if (minusp divisor)
59     (minusp number)
60     (plusp number)))
61  (values (+ tru 1) (- rem divisor))
62  (values tru rem))))
63
64
65(defun round (number &optional (divisor 1))
66  "Rounds number (or number/divisor) to nearest integer.
67   The second returned value is the remainder."
68  (multiple-value-bind (tru rem) (truncate number divisor)
69    (if (zerop rem)
70        (values tru rem)
71        (let ((thresh (/ (abs divisor) 2)))
72          (cond ((or (> rem thresh)
73                     (and (= rem thresh) (oddp tru)))
74                 (if (minusp divisor)
75                     (values (- tru 1) (+ rem divisor))
76                     (values (+ tru 1) (- rem divisor))))
77                ((let ((-thresh (- thresh)))
78                   (or (< rem -thresh)
79                       (and (= rem -thresh) (oddp tru))))
80                 (if (minusp divisor)
81                     (values (+ tru 1) (- rem divisor))
82                     (values (- tru 1) (+ rem divisor))))
83                (t (values tru rem)))))))
84
85
86(defun rem (number divisor)
87  "Returns second result of TRUNCATE."
88  (multiple-value-bind (tru rem) (truncate number divisor)
89    (declare (ignore tru))
90    rem))
91
92
93(defun mod (number divisor)
94  "Returns second result of FLOOR."
95  (let ((rem (rem number divisor)))
96    (if (and (not (zerop rem))
97       (if (minusp divisor)
98     (plusp number)
99     (minusp number)))
100  (+ rem divisor)
101  rem)))
102
103
104(defun ftruncate (number &optional (divisor 1))
105  (multiple-value-bind (tru rem) (truncate number divisor)
106    (values (float tru) rem)))
107
108
109(defun ffloor (number &optional (divisor 1))
110  "Same as FLOOR, but returns first value as a float."
111  (multiple-value-bind (tru rem) (ftruncate number divisor)
112    (if (and (not (zerop rem))
113       (if (minusp divisor)
114     (plusp number)
115     (minusp number)))
116  (values (1- tru) (+ rem divisor))
117  (values tru rem))))
118
119
120(defun fceiling (number &optional (divisor 1))
121  "Same as CEILING, but returns first value as a float."
122  (multiple-value-bind (tru rem) (ftruncate number divisor)
123    (if (and (not (zerop rem))
124       (if (minusp divisor)
125     (minusp number)
126     (plusp number)))
127  (values (+ tru 1) (- rem divisor))
128  (values tru rem))))
129
130
131(defun fround (number &optional (divisor 1))
132  "Same as ROUND, but returns first value as a float."
133  (multiple-value-bind (res rem)
134    (round number divisor)
135    (values (float res (if (floatp rem) rem 1.0)) rem)))
136
137
138(defun rational (x)
139  "RATIONAL produces a rational number for any real numeric argument.  This is
140   more efficient than RATIONALIZE, but it assumes that floating-point is
141   completely accurate, giving a result that isn't as pretty."
142  (cond ((floatp x)
143         (multiple-value-bind (bits exp)
144           (integer-decode-float x)
145           (if (eql bits 0)
146               0
147               (let* ((int (if (minusp x) (- bits) bits))
148                      (digits (float-digits x))
149                      (ex (+ exp digits)))
150                 (if (minusp ex)
151                     (/ int (ash 1 (+ digits (- ex))))
152                     (/ (ash int ex) (ash 1 digits)))))))
153        ((rationalp x)
154         x)
155        (t
156         (error 'type-error "wrong type: ~S is not a real number" x))))
157
158;;; FIXME
159(defun rationalize (x)
160  (rational x))
161
162(when (and (find-package "JVM")
163           (fboundp 'jvm::jvm-compile))
164  (mapcar #'jvm::jvm-compile '(floor
165                               ceiling
166                               round
167                               rem
168                               ftruncate
169                               ffloor
170                               fceiling
171                               fround
172                               rational
173                               rationalize)))
174
175
176
177(defun gcd (&rest numbers)
178  "Returns the greatest common divisor of the arguments, which must be
179   integers.  Gcd with no arguments is defined to be 0."
180  (unless (every #'integerp numbers)
181    (error 'type-error))
182  (cond ((null numbers) 0)
183  ((null (cdr numbers)) (abs (car numbers)))
184  (t
185   (do ((gcd (car numbers)
186       (gcd-2 gcd (car rest)))
187        (rest (cdr numbers) (cdr rest)))
188       ((null rest) gcd)))))
189
190
191;;; From discussion on comp.lang.lisp and Akira Kurihara.
192(defun isqrt (n)
193  "Returns the root of the nearest integer less than n which is a perfect
194   square."
195  (declare (type unsigned-byte n) (values unsigned-byte))
196  ;; theoretically (> n 7) ,i.e., n-len-quarter > 0
197  (if (and (fixnump n) (<= n 24))
198      (cond ((> n 15) 4)
199      ((> n  8) 3)
200      ((> n  3) 2)
201      ((> n  0) 1)
202      (t 0))
203      (let* ((n-len-quarter (ash (integer-length n) -2))
204       (n-half (ash n (- (ash n-len-quarter 1))))
205       (n-half-isqrt (isqrt n-half))
206       (init-value (ash (1+ n-half-isqrt) n-len-quarter)))
207  (loop
208    (let ((iterated-value
209     (ash (+ init-value (truncate n init-value)) -1)))
210      (unless (< iterated-value init-value)
211        (return init-value))
212      (setq init-value iterated-value))))))
Note: See TracBrowser for help on using the repository browser.