1 | ;;;; numbers.scm |
---|
2 | ; |
---|
3 | ; Copyright (c) 2008-2014 The CHICKEN Team |
---|
4 | ; Copyright (c) 2000-2007, Felix L. Winkelmann |
---|
5 | ; All rights reserved. |
---|
6 | ; |
---|
7 | ; Redistribution and use in source and binary forms, with or without |
---|
8 | ; modification, are permitted provided that the following conditions |
---|
9 | ; are met: |
---|
10 | ; 1. Redistributions of source code must retain the above copyright |
---|
11 | ; notice, this list of conditions and the following disclaimer. |
---|
12 | ; 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | ; notice, this list of conditions and the following disclaimer in the |
---|
14 | ; documentation and/or other materials provided with the distribution. |
---|
15 | ; 3. The name of the authors may not be used to endorse or promote products |
---|
16 | ; derived from this software without specific prior written permission. |
---|
17 | ; |
---|
18 | ; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
---|
19 | ; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
20 | ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
21 | ; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
22 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
23 | ; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
24 | ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
25 | ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
26 | ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
27 | ; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
28 | |
---|
29 | |
---|
30 | (declare |
---|
31 | (no-bound-checks) |
---|
32 | (no-procedure-checks)) |
---|
33 | |
---|
34 | (module numbers |
---|
35 | (+ - * / = > < >= <= eqv? |
---|
36 | add1 sub1 signum number->string string->number integer-length |
---|
37 | bitwise-and bitwise-ior bitwise-xor bitwise-not arithmetic-shift |
---|
38 | equal? ; From scheme. Structural & bytevector comparisons Just Work |
---|
39 | exp log sin cos tan atan acos asin conj |
---|
40 | expt sqrt exact-integer-sqrt exact-integer-nth-root |
---|
41 | quotient modulo remainder quotient&modulo quotient&remainder |
---|
42 | floor/ floor-quotient floor-remainder |
---|
43 | truncate/ truncate-quotient truncate-remainder |
---|
44 | numerator denominator |
---|
45 | abs max min gcd lcm |
---|
46 | positive? negative? odd? even? zero? |
---|
47 | exact? inexact? |
---|
48 | rationalize |
---|
49 | random randomize |
---|
50 | floor ceiling truncate round |
---|
51 | inexact->exact inexact exact->inexact exact |
---|
52 | number? complex? real? rational? integer? exact-integer? |
---|
53 | make-rectangular make-polar real-part imag-part magnitude angle |
---|
54 | bignum? ratnum? cflonum? rectnum? compnum? cintnum? cplxnum? |
---|
55 | nan? finite? infinite? |
---|
56 | |
---|
57 | ;; Specialization hooks, to be removed when integrating into core |
---|
58 | @fixnum-2-plus @integer-2-plus @basic-2-plus @bignum-2-plus |
---|
59 | @fixnum-negate @integer-negate @basic-negate @bignum-negate |
---|
60 | @fixnum-abs @integer-abs @basic-abs @bignum-abs |
---|
61 | @fixnum-2-minus @integer-2-minus @basic-2-minus @bignum-2-minus |
---|
62 | @fixnum-2-times @integer-2-times @basic-2-times @bignum-2-times |
---|
63 | @fixnum-quotient @flonum-quotient @integer-quotient @basic-quotient @bignum-quotient) |
---|
64 | |
---|
65 | (import (except scheme |
---|
66 | + - * / = > < >= <= eqv? |
---|
67 | number->string string->number |
---|
68 | exp log sin cos tan atan acos asin expt sqrt |
---|
69 | quotient modulo remainder |
---|
70 | numerator denominator |
---|
71 | abs max min gcd lcm |
---|
72 | positive? negative? odd? even? zero? |
---|
73 | exact? inexact? |
---|
74 | rationalize |
---|
75 | floor ceiling truncate round |
---|
76 | inexact->exact exact->inexact |
---|
77 | number? complex? real? rational? integer? |
---|
78 | make-rectangular make-polar real-part imag-part magnitude angle) |
---|
79 | (except chicken add1 sub1 random randomize conj signum finite? |
---|
80 | bitwise-and bitwise-ior bitwise-xor bitwise-not arithmetic-shift) |
---|
81 | foreign) |
---|
82 | |
---|
83 | (foreign-declare "#include \"numbers-c.c\"") |
---|
84 | |
---|
85 | ;;; THESE SERVE AS SPECIALIZATION ENTRIES. |
---|
86 | ;;; Once this is integrated into core, they can be killed and the |
---|
87 | ;;; C functions inlined directly. Remember to fix the allocations! |
---|
88 | (define @basic-2-plus (##core#primitive "C_2_basic_plus")) |
---|
89 | (define (@fixnum-2-plus a b) (##core#inline_allocate ("C_a_u_i_2_fixnum_plus" 8) a b)) |
---|
90 | (define @integer-2-plus (##core#primitive "C_u_2_integer_plus")) |
---|
91 | (define @bignum-2-plus (##core#primitive "C_u_2_bignum_plus")) |
---|
92 | |
---|
93 | (define @basic-abs (##core#primitive "C_basic_abs")) |
---|
94 | (define (@fixnum-abs x) (##core#inline_allocate ("C_a_u_i_fixnum_abs" 8) x)) |
---|
95 | (define @integer-abs (##core#primitive "C_u_integer_abs")) |
---|
96 | (define @bignum-abs (##core#primitive "C_u_bignum_abs")) |
---|
97 | |
---|
98 | (define @basic-negate (##core#primitive "C_basic_negate")) |
---|
99 | (define (@fixnum-negate x) (##core#inline_allocate ("C_a_u_i_fixnum_negate" 8) x)) |
---|
100 | (define @integer-negate (##core#primitive "C_u_integer_negate")) |
---|
101 | (define @bignum-negate (##core#primitive "C_u_bignum_negate")) |
---|
102 | |
---|
103 | (define @basic-2-minus (##core#primitive "C_2_basic_minus")) |
---|
104 | (define (@fixnum-2-minus a b) (##core#inline_allocate ("C_a_u_i_2_fixnum_minus" 8) a b)) |
---|
105 | (define @integer-2-minus (##core#primitive "C_u_2_integer_minus")) |
---|
106 | (define @bignum-2-minus (##core#primitive "C_u_2_bignum_minus")) |
---|
107 | |
---|
108 | (define @basic-2-times (##core#primitive "C_2_basic_times")) |
---|
109 | (define (@fixnum-2-times a b) (##core#inline_allocate ("C_a_u_i_2_fixnum_times" 32) a b)) ; Over-estimated |
---|
110 | (define @integer-2-times (##core#primitive "C_u_2_integer_times")) |
---|
111 | (define @bignum-2-times (##core#primitive "C_u_2_bignum_times")) |
---|
112 | |
---|
113 | (define @basic-quotient (##core#primitive "C_basic_quotient")) |
---|
114 | (define (@fixnum-quotient loc a b) (##core#inline "C_u_i_fixnum_quotient_checked_loc" loc a b)) |
---|
115 | (define (@flonum-quotient loc a b) (##core#inline_allocate ("C_a_i_flonum_quotient_checked_loc" 4) loc a b)) |
---|
116 | (define @integer-quotient (##core#primitive "C_u_integer_quotient")) |
---|
117 | (define @bignum-quotient (##core#primitive "C_u_bignum_quotient")) |
---|
118 | |
---|
119 | (define-foreign-variable FIX integer) |
---|
120 | (define-foreign-variable FLO integer) |
---|
121 | (define-foreign-variable BIG integer) |
---|
122 | (define-foreign-variable RAT integer) |
---|
123 | (define-foreign-variable COMP integer) |
---|
124 | (define-foreign-variable NONE integer) |
---|
125 | |
---|
126 | ;;; Error handling |
---|
127 | |
---|
128 | (define (bad-number loc x) (##sys#signal-hook #:type-error loc "bad argument type - not a number" x)) |
---|
129 | (define (bad-real loc x) (##sys#signal-hook #:type-error loc "bad argument type - not a real number" x)) |
---|
130 | (define (bad-ratnum loc x) (##sys#signal-hook #:type-error loc "bad argument type - not a rational number" x)) |
---|
131 | (define (bad-integer loc x) (##sys#signal-hook #:type-error loc "bad argument type - not an integer" x)) |
---|
132 | (define (bad-natural loc x) (##sys#signal-hook #:type-error loc "bad argument type - must be an nonnegative integer" x)) |
---|
133 | (define (bad-positive loc x) (##sys#signal-hook #:type-error loc "bad argument type - must be a positive (non-zero) integer" x)) |
---|
134 | (define (bad-complex/o loc x) (##sys#signal-hook #:type-error loc "bad argument type - complex number has no ordering" x)) |
---|
135 | (define (bad-base loc x) (##sys#signal-hook #:type-error loc "bad argument type - not a valid base" x)) |
---|
136 | (define (bad-inexact loc x) (##sys#signal-hook #:type-error loc "bad argument type - inexact number has no exact representation" x)) |
---|
137 | (define (bad-exact loc x) (##sys#signal-hook #:type-error loc "bad argument type - must be an exact number" x)) |
---|
138 | (define (log0 loc x) (##sys#signal-hook #:arithmetic-error loc "log of exact 0 is undefined" x)) |
---|
139 | (define (expt0 loc x y) (##sys#signal-hook #:arithmetic-error loc "exponent of exact 0 with complex argument is undefined" x y)) |
---|
140 | (define (div/0 loc x y) (##sys#signal-hook #:arithmetic-error loc "division by zero" x y)) |
---|
141 | |
---|
142 | (define-inline (%init-tags tagvec) (##core#inline "init_tags" tagvec)) |
---|
143 | (define-inline (%check-number x) (##core#inline "check_number" x)) |
---|
144 | |
---|
145 | (define-inline (assert-number x loc) |
---|
146 | (when (eq? NONE (%check-number x)) |
---|
147 | (bad-number loc x) ) ) |
---|
148 | |
---|
149 | (define-inline (fix-div/0 x y loc) |
---|
150 | (if (eq? y 0) |
---|
151 | (div/0 loc x y) |
---|
152 | y) ) |
---|
153 | |
---|
154 | ;;; Primitives |
---|
155 | |
---|
156 | (define-inline (fp/ x y) (##core#inline_allocate ("C_a_i_flonum_quotient" 4) x y)) |
---|
157 | (define-inline (fp+ x y) (##core#inline_allocate ("C_a_i_flonum_plus" 4) x y)) |
---|
158 | (define-inline (fp- x y) (##core#inline_allocate ("C_a_i_flonum_difference" 4) x y)) |
---|
159 | (define-inline (fp* x y) (##core#inline_allocate ("C_a_i_flonum_times" 4) x y)) |
---|
160 | (define-inline (fp= x y) (##core#inline "C_flonum_equalp" x y)) |
---|
161 | (define-inline (fp> x y) (##core#inline "C_flonum_greaterp" x y)) |
---|
162 | (define-inline (fp< x y) (##core#inline "C_flonum_lessp" x y)) |
---|
163 | |
---|
164 | (define-inline (%flonum? x) (##core#inline "C_i_flonump" x)) |
---|
165 | (define-inline (%flo-integer? x) (##core#inline "C_u_i_fpintegerp" x)) |
---|
166 | |
---|
167 | (define-inline (compnum-real c) (##sys#slot c 1)) |
---|
168 | (define-inline (compnum-imag c) (##sys#slot c 2)) |
---|
169 | (define-inline (%make-complex r i) (##sys#make-structure 'compnum r i)) |
---|
170 | |
---|
171 | (define-inline (ratnum-numerator c) (##sys#slot c 1)) |
---|
172 | (define-inline (ratnum-denominator c) (##sys#slot c 2)) |
---|
173 | (define-inline (%make-ratnum r i) (##sys#make-structure 'ratnum r i)) |
---|
174 | |
---|
175 | (define-inline (%fix->flo n) (##core#inline_allocate ("C_a_i_fix_to_flo" 4) n)) |
---|
176 | (define-inline (%big->flo n) (##core#inline_allocate ("C_a_u_i_big_to_flo" 4) n)) |
---|
177 | |
---|
178 | (define %big-remainder-fix (##core#primitive "C_u_bignum_remainder_fixnum")) |
---|
179 | (define %big-remainder-big (##core#primitive "C_u_bignum_remainder_bignum")) |
---|
180 | |
---|
181 | (define %big-divrem-fix (##core#primitive "C_u_bignum_divrem_fixnum")) |
---|
182 | (define %big-divrem-big (##core#primitive "C_u_bignum_divrem_bignum")) |
---|
183 | |
---|
184 | ;; This one should really be part of Chicken, hence the name |
---|
185 | (define (fxgcd x y) (##core#inline "C_u_i_2_fixnum_gcd" x y)) |
---|
186 | (define (fpgcd x y) (##core#inline_allocate ("C_a_u_i_2_flonum_gcd" 4) x y)) |
---|
187 | |
---|
188 | (define-inline (%big-cmp x y) (##core#inline "C_u_i_bignum_cmp" x y)) |
---|
189 | |
---|
190 | (define %big-abs (##core#primitive "C_u_bignum_abs")) |
---|
191 | |
---|
192 | (define-inline (%big-odd? x) (##core#inline "C_u_i_bignum_oddp" x)) |
---|
193 | (define-inline (%big-negative? x) (##core#inline "C_u_i_bignum_negativep" x)) |
---|
194 | |
---|
195 | (define %%expt-0 (##core#primitive "C_expt")) |
---|
196 | |
---|
197 | (define (%expt-0 a b) |
---|
198 | (if (and (negative? a) (not (##sys#integer? b))) |
---|
199 | (%exp (%* b (%log a))) |
---|
200 | (%%expt-0 a b))) |
---|
201 | |
---|
202 | (define %flo->integer (##core#primitive "C_u_flo_to_int")) |
---|
203 | |
---|
204 | (define %int-bitwise-int (##core#primitive "C_u_2_integer_bitwise_op")) |
---|
205 | (define %int-shift-fix (##core#primitive "C_u_int_shift_fix")) |
---|
206 | (define-inline (%int-length i) (##core#inline "C_u_i_int_length" i)) |
---|
207 | |
---|
208 | (define number->string-0 (##core#primitive "C_number_to_string")) |
---|
209 | |
---|
210 | (define %big->string (##core#primitive "C_u_bignum_to_digits")) |
---|
211 | (define %digits->integer (##core#primitive "C_digits_to_integer")) |
---|
212 | |
---|
213 | (define-inline (%subchar s i) (##core#inline "C_subchar" s i)) |
---|
214 | |
---|
215 | (define-inline (%fix-randomize n) (##core#inline "C_randomize" n)) |
---|
216 | (define-inline (%big-randomize n) (##core#inline "big_randomize" n)) |
---|
217 | |
---|
218 | (define-inline (%fix-random n) (##core#inline "C_random_fixnum" n)) |
---|
219 | (define %big-random (##core#primitive "C_u_bignum_random")) |
---|
220 | |
---|
221 | |
---|
222 | ;;; Support macros |
---|
223 | |
---|
224 | (define-syntax switchq |
---|
225 | (syntax-rules (else) |
---|
226 | ((_ "aux" _) (##core#undefined)) |
---|
227 | ((_ "aux" _ (else body ...)) |
---|
228 | (begin body ...)) |
---|
229 | ((_ "aux" tmp (val body ...) more ...) |
---|
230 | (if (eq? tmp val) |
---|
231 | (begin body ...) |
---|
232 | (switchq "aux" tmp more ...))) |
---|
233 | ((_ exp body ...) |
---|
234 | (let ((tmp exp)) |
---|
235 | (switchq "aux" tmp body ...))))) |
---|
236 | |
---|
237 | |
---|
238 | ;;; Setup |
---|
239 | |
---|
240 | (%init-tags |
---|
241 | (vector 'bignum ; BIG_TAG |
---|
242 | 'ratnum ; RAT_TAG |
---|
243 | 'compnum)) ; COMP_TAG |
---|
244 | |
---|
245 | (##sys#gc #f) ; move tag-vector into 2nd generation |
---|
246 | |
---|
247 | |
---|
248 | ;;; Basic arithmetic: |
---|
249 | |
---|
250 | (define (+ . args) |
---|
251 | (if (null? args) |
---|
252 | 0 |
---|
253 | (let ((x (##sys#slot args 0)) |
---|
254 | (rest (##sys#slot args 1))) |
---|
255 | (cond ((null? rest) |
---|
256 | (assert-number x '+) |
---|
257 | x) |
---|
258 | (else |
---|
259 | (let loop ((args rest) (x x)) |
---|
260 | (if (null? args) |
---|
261 | x |
---|
262 | (loop (##sys#slot args 1) (%+ x (##sys#slot args 0))) ) ) ) ) ) ) ) |
---|
263 | |
---|
264 | (define (%+ x y) |
---|
265 | (or ((##core#primitive "C_2_basic_plus") x y) |
---|
266 | (switchq (%check-number x) |
---|
267 | (RAT (switchq (%check-number y) |
---|
268 | (RAT (rat+/- '+ %+ x y)) |
---|
269 | (COMP (make-complex (%+ x (compnum-real y)) (compnum-imag y))) |
---|
270 | (NONE (bad-number '+ y)) |
---|
271 | ;; a/b + c/d = (a*d + b*c)/(b*d) [with d = 1] |
---|
272 | (else (let ((b (ratnum-denominator x))) |
---|
273 | (%/ (%+ (ratnum-numerator x) (%* b y)) b))) )) |
---|
274 | (COMP (switchq (%check-number y) |
---|
275 | ;; Just add real and imag parts together |
---|
276 | (COMP (let ((r (%+ (compnum-real x) (compnum-real y))) |
---|
277 | (i (%+ (compnum-imag x) (compnum-imag y))) ) |
---|
278 | (make-complex r i) )) |
---|
279 | (NONE (bad-number '+ y)) |
---|
280 | ;; Simplified version of generic comp+comp [with imag(y) = 0] |
---|
281 | (else (make-complex (%+ (compnum-real x) y) (compnum-imag x))) )) |
---|
282 | (NONE (bad-number '+ x)) |
---|
283 | (else (switchq (%check-number y) ; x is a basic number, y isn't |
---|
284 | ;; a/b + c/d = (a*d + b*c)/(b*d) [with b = 1] |
---|
285 | (RAT (let ((d (ratnum-denominator y))) |
---|
286 | (%/ (%+ (%* x d) (ratnum-numerator y)) d))) |
---|
287 | ;; Simplified version of generic comp+comp [with imag(x) = 0] |
---|
288 | (COMP (make-complex (%+ x (compnum-real y)) (compnum-imag y))) |
---|
289 | (else (bad-number '+ y)) ) ) ) ) ) |
---|
290 | |
---|
291 | (define (- arg1 . args) |
---|
292 | (if (null? args) |
---|
293 | (negate arg1) |
---|
294 | (let loop ((args (##sys#slot args 1)) (x (%- arg1 (##sys#slot args 0)))) |
---|
295 | (if (null? args) |
---|
296 | x |
---|
297 | (loop (##sys#slot args 1) (%- x (##sys#slot args 0))) ) ) ) ) |
---|
298 | |
---|
299 | (define (negate x) |
---|
300 | (or ((##core#primitive "C_basic_negate") x) |
---|
301 | (switchq (%check-number x) |
---|
302 | (RAT (%make-ratnum ((##core#primitive "C_basic_negate") |
---|
303 | (ratnum-numerator x)) |
---|
304 | (ratnum-denominator x))) |
---|
305 | (COMP (%make-complex (negate (compnum-real x)) |
---|
306 | (negate (compnum-imag x)))) |
---|
307 | (else (bad-number '- x)) ) ) ) |
---|
308 | |
---|
309 | (define (%- x y) |
---|
310 | (or ((##core#primitive "C_2_basic_minus") x y) |
---|
311 | (switchq (%check-number x) |
---|
312 | (RAT (switchq (%check-number y) |
---|
313 | (RAT (rat+/- '- %- x y)) |
---|
314 | ;; Simplified version of generic comp-comp [with imag(x) = 0] |
---|
315 | (COMP (make-complex (%- x (compnum-real y)) |
---|
316 | (negate (compnum-imag y)))) |
---|
317 | (NONE (bad-number '- y)) |
---|
318 | ;; a/b - c/d = (a*d - b*c)/(b*d) [with d = 1] |
---|
319 | (else (let ((b (ratnum-denominator x))) |
---|
320 | (%/ (%- (ratnum-numerator x) (%* b y)) b))) ) ) |
---|
321 | (COMP (switchq (%check-number y) |
---|
322 | ;; Just subtract real and imag parts from eachother |
---|
323 | (COMP (let ((r (%- (compnum-real x) (compnum-real y))) |
---|
324 | (i (%- (compnum-imag x) (compnum-imag y))) ) |
---|
325 | (make-complex r i) )) |
---|
326 | (NONE (bad-number '- y)) |
---|
327 | (else (make-complex (%- (compnum-real x) y) (compnum-imag x))) )) |
---|
328 | (NONE (bad-number '- x)) |
---|
329 | (else (switchq (%check-number y) |
---|
330 | ;; a/b - c/d = (a*d - b*c)/(b*d) [with b = 1] |
---|
331 | (RAT (let ((d (ratnum-denominator y))) |
---|
332 | (%/ (%- (%* x d) (ratnum-numerator y)) d))) |
---|
333 | ;; Simplified version of generic comp-comp [with imag(y) = 0] |
---|
334 | (COMP (make-complex (%- x (compnum-real y)) |
---|
335 | (negate (compnum-imag y)))) |
---|
336 | (else (bad-number '- y)) ) ) )) ) |
---|
337 | |
---|
338 | (define (* . args) |
---|
339 | (if (null? args) |
---|
340 | 1 |
---|
341 | (let ((x (##sys#slot args 0)) |
---|
342 | (rest (##sys#slot args 1))) |
---|
343 | (cond ((null? rest) |
---|
344 | (assert-number x '*) |
---|
345 | x) |
---|
346 | (else |
---|
347 | (let loop ((args rest) (x x)) |
---|
348 | (if (null? args) |
---|
349 | x |
---|
350 | (loop (##sys#slot args 1) (%* x (##sys#slot args 0))) ) ) ) ) ) ) ) |
---|
351 | |
---|
352 | |
---|
353 | (define (%* x y) |
---|
354 | (define (%nonrat*rat x y) |
---|
355 | ;; a/b * c/d = a*c / b*d [with b = 1] |
---|
356 | ;; = ((a / g) * c) / (d / g) |
---|
357 | ;; With g = gcd(a, d) and a = x [Knuth, 4.5.1] |
---|
358 | (let* ((d (ratnum-denominator y)) |
---|
359 | (g (%gcd-0 '* x d))) |
---|
360 | (ratnum (%* (%quotient '* x g) (ratnum-numerator y)) |
---|
361 | (%quotient '* d g)))) |
---|
362 | |
---|
363 | (or ((##core#primitive "C_2_basic_times") x y) |
---|
364 | (switchq (%check-number x) |
---|
365 | (RAT (switchq (%check-number y) |
---|
366 | ;; a/b * c/d = a*c / b*d [generic] |
---|
367 | ;; = ((a / g1) * (c / g2)) / ((b / g2) * (d / g1)) |
---|
368 | ;; With g1 = gcd(a, d) and g2 = gcd(b, c) [Knuth, 4.5.1] |
---|
369 | (RAT (let* ((a (ratnum-numerator x)) (b (ratnum-denominator x)) |
---|
370 | (c (ratnum-numerator y)) (d (ratnum-denominator y)) |
---|
371 | (g1 (%gcd-0 '* a d)) (g2 (%gcd-0 '* b c))) |
---|
372 | (ratnum (%* (%quotient '* a g1) (%quotient '* c g2)) |
---|
373 | (%* (%quotient '* b g2) (%quotient '* d g1))))) |
---|
374 | ;; Simplified version of generic comp*comp [with b = 0] |
---|
375 | (COMP (make-complex (%* x (compnum-real y)) |
---|
376 | (%* x (compnum-imag y)))) |
---|
377 | ;; TODO: This can be incorrect when the ratnum consists of bignums |
---|
378 | (FLO (fp* y (%rat->flo x))) ; Special! |
---|
379 | (NONE (bad-number '* y)) |
---|
380 | (else (%nonrat*rat y x))) ) |
---|
381 | (COMP (switchq (%check-number y) |
---|
382 | (COMP (let* ((a (compnum-real x)) (b (compnum-imag x)) |
---|
383 | (c (compnum-real y)) (d (compnum-imag y)) |
---|
384 | (r (%- (%* a c) (%* b d))) |
---|
385 | (i (%+ (%* a d) (%* b c))) ) |
---|
386 | (make-complex r i) )) |
---|
387 | (NONE (bad-number '* y)) |
---|
388 | ;; Simplified version of comp*comp [with d = 0] |
---|
389 | (else (make-complex (%* (compnum-real x) y) |
---|
390 | (%* (compnum-imag x) y)) ) ) ) |
---|
391 | (FLO (switchq (%check-number y) |
---|
392 | ;; TODO: This can be incorrect when the ratnum consists of bignums |
---|
393 | (RAT (fp* x (%rat->flo y))) ; Special! |
---|
394 | ;; Simplified version of generic comp*comp [with b = 0] |
---|
395 | (COMP (make-complex (%* x (compnum-real y)) |
---|
396 | (%* x (compnum-imag y)))) |
---|
397 | (else (bad-number '* y)) ) ) |
---|
398 | (NONE (bad-number '* x)) |
---|
399 | (else (switchq (%check-number y) |
---|
400 | (RAT (%nonrat*rat x y)) |
---|
401 | ;; Simplified version of generic comp*comp [with b = 0] |
---|
402 | (COMP (make-complex (%* x (compnum-real y)) |
---|
403 | (%* x (compnum-imag y)))) |
---|
404 | (else (bad-number '* y)) ) ) )) ) |
---|
405 | |
---|
406 | (define (/ arg1 . args) |
---|
407 | (if (null? args) |
---|
408 | (%/ 1 arg1) |
---|
409 | (let loop ((args (##sys#slot args 1)) (x (%/ arg1 (##sys#slot args 0)))) |
---|
410 | (if (null? args) |
---|
411 | x |
---|
412 | (loop (##sys#slot args 1) (%/ x (##sys#slot args 0))) ) ) ) ) |
---|
413 | |
---|
414 | (define-inline (%nonrat/rat x y) |
---|
415 | ;; a/b / c/d = a*d / b*c [with b = 1] |
---|
416 | ;; = ((a / g1) * d * sign(a)) / abs(c / g1) |
---|
417 | ;; With g1 = gcd(a, c) and a = x [Knuth, 4.5.1 ex. 4] |
---|
418 | (let* ((c (ratnum-numerator y)) |
---|
419 | (g (%gcd-0 '/ x c))) |
---|
420 | (%/ (%* (%quotient '/ x g) (ratnum-denominator y)) |
---|
421 | (%quotient '/ c g)))) |
---|
422 | |
---|
423 | (define (%/ x y) |
---|
424 | (switchq (%check-number x) |
---|
425 | [FIX |
---|
426 | (switchq (%check-number y) |
---|
427 | [FIX (let ((g (fxgcd x (fix-div/0 x y '/)))) |
---|
428 | (ratnum (fx/ x g) (fx/ y g)))] |
---|
429 | [FLO (fp/ (%fix->flo x) y)] |
---|
430 | ;; XXX TODO: Get rid of the gcd call here, which also divides! |
---|
431 | [BIG (let ((g (%gcd-0 '/ x y))) |
---|
432 | (ratnum (%quotient '/ x g) (%quotient '/ y g)))] |
---|
433 | [RAT (%nonrat/rat x y)] |
---|
434 | [COMP (%comp/comp (%make-complex x 0) y)] |
---|
435 | [else (bad-number '/ y)] ) ] |
---|
436 | [FLO |
---|
437 | (switchq (%check-number y) |
---|
438 | [FIX (fp/ x (%fix->flo (fix-div/0 x y '/)))] |
---|
439 | [FLO (fp/ x y)] |
---|
440 | [BIG (fp/ x (%big->flo y))] |
---|
441 | ;; TODO: This can be incorrect when the ratnum consists of bignums |
---|
442 | [RAT (fp/ x (%exact->inexact y))] |
---|
443 | [COMP (%comp/comp (%make-complex x 0) y)] |
---|
444 | [else (bad-number '/ y)] ) ] |
---|
445 | [BIG |
---|
446 | (switchq (%check-number y) |
---|
447 | [FIX (let ((g (%gcd-0 '/ x (fix-div/0 x y '/)))) |
---|
448 | (ratnum (%quotient '/ x g) (%quotient '/ y g)))] |
---|
449 | [FLO (fp/ (%big->flo x) y)] |
---|
450 | [BIG (let ((g (%gcd-0 '/ x y))) |
---|
451 | (ratnum (%quotient '/ x g) (%quotient '/ y g)))] |
---|
452 | [RAT (%nonrat/rat x y)] |
---|
453 | [COMP (%comp/comp (%make-complex x 0) y)] |
---|
454 | [else (bad-number '/ y)] ) ] |
---|
455 | [RAT |
---|
456 | (switchq (%check-number y) |
---|
457 | ;; a/b / c/d = a*d / b*c [generic] |
---|
458 | ;; = ((a / g1) * (d / g2) * sign(a)) / abs((b / g2) * (c / g1)) |
---|
459 | ;; With g1 = gcd(a, c) and g2 = gcd(b, d) [Knuth, 4.5.1 ex. 4] |
---|
460 | [RAT (let* ((a (ratnum-numerator x)) (b (ratnum-denominator x)) |
---|
461 | (c (ratnum-numerator y)) (d (ratnum-denominator y)) |
---|
462 | (g1 (%gcd-0 '/ a c)) (g2 (%gcd-0 '/ b d))) |
---|
463 | (%/ (%* (%quotient '/ a g1) (%quotient '/ d g2)) |
---|
464 | (%* (%quotient '/ b g2) (%quotient '/ c g1))))] |
---|
465 | [COMP (%comp/comp (%make-complex x 0) y)] |
---|
466 | ;; TODO: This can be incorrect when the ratnum consists of bignums |
---|
467 | [FLO (fp/ (%exact->inexact x) y)] |
---|
468 | [NONE (bad-number '/ y)] |
---|
469 | ;; a/b / c/d = a*d / b*c [with d = 1] |
---|
470 | ;; = ((a / g) * sign(a)) / abs(b * (c / g)) |
---|
471 | ;; With g = gcd(a, c) and c = y [Knuth, 4.5.1 ex. 4] |
---|
472 | [else (let* ((a (ratnum-numerator x)) |
---|
473 | (g (%gcd-0 '/ a y))) ;; TODO: Improve error message if /0 |
---|
474 | (%/ (%quotient '/ a g) |
---|
475 | (%* (ratnum-denominator x) (%quotient '/ y g))))] ) ] |
---|
476 | [COMP |
---|
477 | (switchq (%check-number y) |
---|
478 | [COMP (%comp/comp x y)] |
---|
479 | [NONE (bad-number '/ y)] |
---|
480 | [else (%comp/comp x (%make-complex y 0))] ) ] |
---|
481 | [else (bad-number '/ x)] ) ) |
---|
482 | |
---|
483 | (define (%comp/comp p q) |
---|
484 | (let* ([a (compnum-real p)] |
---|
485 | [b (compnum-imag p)] |
---|
486 | [c (compnum-real q)] |
---|
487 | [d (compnum-imag q)] |
---|
488 | [r (%+ (%* c c) (%* d d))] |
---|
489 | [x (%/ (%+ (%* a c) (%* b d)) r)] |
---|
490 | [y (%/ (%- (%* b c) (%* a d)) r)] ) |
---|
491 | (make-complex x y) ) ) |
---|
492 | |
---|
493 | |
---|
494 | ;;; Comparisons: |
---|
495 | |
---|
496 | (define (%= x y) |
---|
497 | (switchq (%check-number x) |
---|
498 | [FIX |
---|
499 | (switchq (%check-number y) |
---|
500 | [FIX (fx= x y)] |
---|
501 | [FLO (and (finite? y) |
---|
502 | (%= x (%flo->rat '= y)))] ; Compare as ratnums (overflow) |
---|
503 | [BIG #f] ;; Needs bignum representation? Can't be equal to a fixnum! |
---|
504 | [RAT #f] ;; Rats are never x/1, because those are normalised to just x |
---|
505 | [COMP #f] ;; Comps are only ever equal to other comps |
---|
506 | [else (bad-number '= y)] ) ] |
---|
507 | [FLO |
---|
508 | (switchq (%check-number y) |
---|
509 | [FIX (and (finite? x) |
---|
510 | (%= (%flo->rat '= x) y))] ; Compare as ratnums (overflow) |
---|
511 | [FLO (fp= x y)] |
---|
512 | [BIG (and (%flo-integer? x) (= (%flo->integer x) y))] |
---|
513 | [RAT (and (not (or (fp= x +inf.0) (fp= x -inf.0))) |
---|
514 | (%= (%flo->rat '= x) y))] ; Compare as ratnums |
---|
515 | [COMP #f] ;; Comps are only ever equal to other comps |
---|
516 | [else (bad-number '= y)] ) ] |
---|
517 | [BIG |
---|
518 | (switchq (%check-number y) |
---|
519 | [FIX #f] ;; Needs bignum representation? Can't be equal to a fixnum! |
---|
520 | [FLO (and (%flo-integer? y) (= x (%flo->integer y)))] |
---|
521 | [BIG (fx= (%big-cmp x y) 0)] |
---|
522 | [RAT #f] ;; Rats are never x/1, because those are normalised to just x |
---|
523 | [COMP #f] ;; Comps are only ever equal to other comps |
---|
524 | [else (bad-number '= y)] ) ] |
---|
525 | [RAT |
---|
526 | (switchq (%check-number y) |
---|
527 | [FIX #f] ;; Rats are never x/1, because those are normalised to just x |
---|
528 | [FLO (and (not (or (fp= y +inf.0) (fp= y -inf.0))) |
---|
529 | (%= x (%flo->rat '= y)))] ; Compare as ratnums |
---|
530 | [BIG #f] ;; Rats are never x/1, because those are normalised to just x |
---|
531 | ;; TODO: Use integer= here, when we write it |
---|
532 | [RAT (and (%= (ratnum-numerator x) (ratnum-numerator y)) |
---|
533 | (%= (ratnum-denominator x) (ratnum-denominator y)))] |
---|
534 | [COMP #f] ;; Comps are only ever equal to other comps |
---|
535 | [else (bad-number '= y)] ) ] |
---|
536 | [COMP |
---|
537 | (switchq (%check-number y) |
---|
538 | [COMP (and (%= (compnum-real x) (compnum-real y)) |
---|
539 | (%= (compnum-imag x) (compnum-imag y)))] |
---|
540 | [NONE (bad-number '= y)] |
---|
541 | [else #f] ) ] |
---|
542 | [else (bad-number '= x)] )) |
---|
543 | |
---|
544 | (define (= x1 x2 . xs) |
---|
545 | (and (%= x1 x2) |
---|
546 | (let loop ([x x2] [xs xs]) |
---|
547 | (or (null? xs) |
---|
548 | (let ([h (##sys#slot xs 0)]) |
---|
549 | (and (%= x h) |
---|
550 | (loop h (##sys#slot xs 1)) ) ) ) ) )) |
---|
551 | |
---|
552 | (define (eqv? a b) |
---|
553 | (let ((ta (%check-number a)) |
---|
554 | (tb (%check-number b))) |
---|
555 | ;; If both are numbers of the same type and exactness, compare. |
---|
556 | ;; Otherwise use eq? Characters are already compared correctly by eq? |
---|
557 | (and (eq? ta tb) |
---|
558 | (switchq ta |
---|
559 | (NONE (eq? a b)) |
---|
560 | (FLO (fp= a b)) |
---|
561 | (FIX (fx= a b)) |
---|
562 | (BIG (fx= (%big-cmp a b) 0)) |
---|
563 | ;; TODO: Use integer= here, when we write it |
---|
564 | (RAT (and (%= (ratnum-numerator a) (ratnum-numerator b)) |
---|
565 | (%= (ratnum-denominator a) (ratnum-denominator b)))) |
---|
566 | ;; We use eqv? here because exactness of components needs to match |
---|
567 | (COMP (and (eqv? (compnum-real a) (compnum-real b)) |
---|
568 | (eqv? (compnum-imag a) (compnum-imag b)))) |
---|
569 | (else (error "This should not happen")))))) |
---|
570 | |
---|
571 | (define (> x1 x2 . xs) |
---|
572 | (and (%> x1 x2 '>) |
---|
573 | (let loop ([x x2] [xs xs]) |
---|
574 | (or (null? xs) |
---|
575 | (let ([h (##sys#slot xs 0)]) |
---|
576 | (and (%> x h '>) |
---|
577 | (loop h (##sys#slot xs 1)) ) ) ) ) ) ) |
---|
578 | |
---|
579 | (define (%> x y loc) |
---|
580 | (switchq (%check-number x) |
---|
581 | (FIX |
---|
582 | (switchq (%check-number y) |
---|
583 | (FIX (fx> x y)) |
---|
584 | ;; Compare as ratnum, to prevent overflows |
---|
585 | (FLO (or (fp= y -inf.0) |
---|
586 | (and (not (fp= y +inf.0)) (fp= y y) |
---|
587 | (%> x (%flo->rat loc y) loc)))) |
---|
588 | ;; x neg? y neg? x > y? reason |
---|
589 | ;; --------------------------------------------------------------- |
---|
590 | ;; no no no abs(y) > abs(x), both positive |
---|
591 | ;; no yes yes (a > b) true if (a > 0) & (b < 0) |
---|
592 | ;; yes no no (a > b) false if (a < 0) & (b > 0) |
---|
593 | ;; yes yes yes abs(y) > abs(x), both negative |
---|
594 | ;; |
---|
595 | ;; It follows that x is only bigger than y when y is negative |
---|
596 | (BIG (%big-negative? y)) |
---|
597 | ;; a/b > c/d when a*d > b*c [with b = 1] |
---|
598 | (RAT (%> (%* x (ratnum-denominator y)) |
---|
599 | (ratnum-numerator y) loc)) |
---|
600 | (COMP (bad-complex/o loc y)) |
---|
601 | (else (bad-number loc y)) ) ) |
---|
602 | (FLO |
---|
603 | (switchq (%check-number y) |
---|
604 | (FLO (fp> x y)) |
---|
605 | (COMP (bad-complex/o loc y)) |
---|
606 | (NONE (bad-number loc y)) |
---|
607 | ;; Compare as ratnums, to avoid errors when overflowing |
---|
608 | ;; (this can happen for bignums, but also for fixnums on 64-bit) |
---|
609 | (else (or (fp= x +inf.0) |
---|
610 | (and (not (fp= x -inf.0)) (fp= x x) |
---|
611 | (%> (%flo->rat loc x) y loc)))) ) ) |
---|
612 | (BIG |
---|
613 | (switchq (%check-number y) |
---|
614 | ;; x neg? y neg? x > y? reason |
---|
615 | ;; --------------------------------------------------------------- |
---|
616 | ;; no no yes abs(x) > abs(y), both positive |
---|
617 | ;; no yes yes (a > b) true if (a > 0) & (b < 0) |
---|
618 | ;; yes no no (a > b) false if (a < 0) & (b > 0) |
---|
619 | ;; yes yes no abs(x) > abs(y), both negative |
---|
620 | ;; |
---|
621 | ;; It follows that x is only bigger than y when x is not negative |
---|
622 | (FIX (not (%big-negative? x))) |
---|
623 | (FLO (or (fp= y -inf.0) |
---|
624 | (and (not (fp= y +inf.0)) (fp= y y) |
---|
625 | (%> x (%flo->rat loc y) loc)))) ; Compare as ratnums |
---|
626 | (BIG (fx> (%big-cmp x y) 0)) |
---|
627 | ;; a/b > c/d when a*d > b*c [with b = 1] |
---|
628 | (RAT (%> (%* x (ratnum-denominator y)) |
---|
629 | (ratnum-numerator y) loc)) |
---|
630 | (COMP (bad-complex/o loc y)) |
---|
631 | (else (bad-number loc y)) ) ) |
---|
632 | (RAT |
---|
633 | (switchq (%check-number y) |
---|
634 | ;; a/b > c/d when a*d > b*c [generic] |
---|
635 | (RAT (%> (%* (ratnum-numerator x) (ratnum-denominator y)) |
---|
636 | (%* (ratnum-denominator x) (ratnum-numerator y)) loc)) |
---|
637 | (FLO (or (fp= y -inf.0) |
---|
638 | (and (not (fp= y +inf.0)) (fp= y y) |
---|
639 | (%> x (%flo->rat loc y) loc)))) ; Compare as ratnums |
---|
640 | (COMP (bad-complex/o loc y)) |
---|
641 | (NONE (bad-number loc y)) |
---|
642 | ;; a/b > c/d when a*d > b*c [with d = 1] |
---|
643 | (else (%> (ratnum-numerator x) |
---|
644 | (%* (ratnum-denominator x) y) loc)) ) ) |
---|
645 | (COMP (bad-complex/o loc x)) |
---|
646 | (else (bad-number loc x)) ) ) |
---|
647 | |
---|
648 | (define (< x1 x2 . xs) |
---|
649 | (and (%< x1 x2 '<) |
---|
650 | (let loop ([x x2] [xs xs]) |
---|
651 | (or (null? xs) |
---|
652 | (let ([h (##sys#slot xs 0)]) |
---|
653 | (and (%< x h '<) |
---|
654 | (loop h (##sys#slot xs 1)) ) ) ) ) ) ) |
---|
655 | |
---|
656 | (define (%< x y loc) |
---|
657 | (switchq (%check-number x) |
---|
658 | (FIX |
---|
659 | (switchq (%check-number y) |
---|
660 | (FIX (fx< x y)) |
---|
661 | ;; Compare as ratnum, to prevent overflows |
---|
662 | (FLO (or (fp= y +inf.0) |
---|
663 | (and (not (fp= y -inf.0)) (fp= y y) |
---|
664 | (%< x (%flo->rat loc y) loc)))) |
---|
665 | ;; x neg? y neg? x < y? reason |
---|
666 | ;; --------------------------------------------------------------- |
---|
667 | ;; no no yes abs(x) < abs(y), both positive |
---|
668 | ;; no yes no (a < b) false if (a > 0) & (b < 0) |
---|
669 | ;; yes no yes (a < b) true if (a < 0) & (b > 0) |
---|
670 | ;; yes yes no abs(x) < abs(y), both negative |
---|
671 | ;; |
---|
672 | ;; It follows that x is only smaller than y when y is not negative |
---|
673 | (BIG (not (%big-negative? y))) |
---|
674 | ;; a/b < c/d when a*d < b*c [with b = 1] |
---|
675 | (RAT (%< (%* x (ratnum-denominator y)) |
---|
676 | (ratnum-numerator y) loc)) |
---|
677 | (COMP (bad-complex/o loc y)) |
---|
678 | (else (bad-number loc y)) ) ) |
---|
679 | (FLO |
---|
680 | (switchq (%check-number y) |
---|
681 | (FLO (fp< x y)) |
---|
682 | (COMP (bad-complex/o loc y)) |
---|
683 | (NONE (bad-number loc y)) |
---|
684 | ;; Compare as ratnums, to avoid errors when overflowing |
---|
685 | ;; (this can happen for bignums, but also for fixnums on 64-bit) |
---|
686 | (else (or (fp= x -inf.0) |
---|
687 | (and (not (fp= x +inf.0)) (fp= x x) |
---|
688 | (%< (%flo->rat loc x) y loc))))) ) |
---|
689 | (BIG |
---|
690 | (switchq (%check-number y) |
---|
691 | ;; x neg? y neg? x < y? reason |
---|
692 | ;; --------------------------------------------------------------- |
---|
693 | ;; no no no abs(y) < abs(x), both positive |
---|
694 | ;; no yes no (a < b) false if (a > 0) & (b < 0) |
---|
695 | ;; yes no yes (a < b) true if (a < 0) & (b > 0) |
---|
696 | ;; yes yes yes abs(y) < abs(x), both negative |
---|
697 | ;; |
---|
698 | ;; It follows that x is only smaller than y when x is negative |
---|
699 | (FIX (%big-negative? x)) |
---|
700 | (FLO (or (fp= y +inf.0) |
---|
701 | (and (not (fp= y -inf.0)) (fp= y y) |
---|
702 | (%< x (%flo->rat loc y) loc)))) ; Compare as ratnums |
---|
703 | (BIG (fx< (%big-cmp x y) 0)) |
---|
704 | ;; a/b < c/d when a*d < b*c [with b = 1] |
---|
705 | (RAT (%< (%* x (ratnum-denominator y)) |
---|
706 | (ratnum-numerator y) loc)) |
---|
707 | (COMP (bad-complex/o loc y)) |
---|
708 | (else (bad-number loc y)) ) ) |
---|
709 | (RAT |
---|
710 | (switchq (%check-number y) |
---|
711 | ;; a/b < c/d when a*d < b*c [generic] |
---|
712 | (RAT (%< (%* (ratnum-numerator x) (ratnum-denominator y)) |
---|
713 | (%* (ratnum-denominator x) (ratnum-numerator y)) loc)) |
---|
714 | (COMP (bad-complex/o loc y)) |
---|
715 | (FLO (or (fp= y +inf.0) |
---|
716 | (and (not (fp= y -inf.0)) (fp= y y) |
---|
717 | (%< x (%flo->rat loc y) loc)))) ; Compare as ratnums |
---|
718 | (NONE (bad-number loc y)) |
---|
719 | ;; a/b < c/d when a*d < b*c [with d = 1] |
---|
720 | (else (%< (ratnum-numerator x) |
---|
721 | (%* (ratnum-denominator x) y) loc)) ) ) |
---|
722 | (COMP (bad-complex/o loc x)) |
---|
723 | (else (bad-number loc x)) ) ) |
---|
724 | |
---|
725 | (define (>= x1 x2 . xs) |
---|
726 | (and (or (not (%flonum? x1)) (fp= x1 x1)) |
---|
727 | (or (not (%flonum? x2)) (fp= x2 x2)) |
---|
728 | (not (%< x1 x2 '>=)) |
---|
729 | (let loop ([x x2] [xs xs]) |
---|
730 | (or (null? xs) |
---|
731 | (let ([h (##sys#slot xs 0)]) |
---|
732 | (and (or (not (%flonum? h)) (fp= h h)) ; not nan? |
---|
733 | (not (%< x h '>=)) |
---|
734 | (loop h (##sys#slot xs 1)) ) ) ) ) ) ) |
---|
735 | |
---|
736 | (define (<= x1 x2 . xs) |
---|
737 | (and (or (not (%flonum? x1)) (fp= x1 x1)) |
---|
738 | (or (not (%flonum? x2)) (fp= x2 x2)) |
---|
739 | (not (%> x1 x2 '<=)) |
---|
740 | (let loop ([x x2] [xs xs]) |
---|
741 | (or (null? xs) |
---|
742 | (let ([h (##sys#slot xs 0)]) |
---|
743 | (and (or (not (%flonum? h)) (fp= h h)) ; not nan? |
---|
744 | (not (%> x h '<=)) |
---|
745 | (loop h (##sys#slot xs 1)) ) ) ) ) ) ) |
---|
746 | |
---|
747 | |
---|
748 | ;;; Complex numbers |
---|
749 | |
---|
750 | (define (make-complex r i) |
---|
751 | (if (or (eq? i 0) (and (%flonum? i) (fp= i 0.0))) |
---|
752 | r |
---|
753 | (%make-complex (if (inexact? i) (exact->inexact r) r) |
---|
754 | (if (inexact? r) (exact->inexact i) i)) ) ) |
---|
755 | |
---|
756 | (define (make-rectangular r i) |
---|
757 | (unless (real? r) (bad-real 'make-rectangular r)) |
---|
758 | (unless (real? i) (bad-real 'make-rectangular i)) |
---|
759 | (make-complex r i) ) |
---|
760 | |
---|
761 | (define (%make-polar r phi) |
---|
762 | (unless (real? r) (bad-real 'make-rectangular r)) |
---|
763 | (unless (real? phi) (bad-real 'make-rectangular phi)) |
---|
764 | (let ((fphi (exact->inexact phi))) |
---|
765 | (make-complex (%* r (##core#inline_allocate ("C_a_i_cos" 4) fphi)) |
---|
766 | (%* r (##core#inline_allocate ("C_a_i_sin" 4) fphi))))) |
---|
767 | |
---|
768 | (define make-polar %make-polar) |
---|
769 | |
---|
770 | (define (real-part x) |
---|
771 | (switchq (%check-number x) |
---|
772 | (COMP (compnum-real x)) |
---|
773 | (NONE (bad-number 'real-part x)) |
---|
774 | (else x) ) ) |
---|
775 | |
---|
776 | (define (imag-part x) |
---|
777 | (switchq (%check-number x) |
---|
778 | (NONE (bad-number 'imag-part x)) |
---|
779 | (COMP (compnum-imag x)) |
---|
780 | (FLO 0.0) |
---|
781 | (else 0) ) ) |
---|
782 | |
---|
783 | (define (%magnitude x) |
---|
784 | (switchq (%check-number x) |
---|
785 | (COMP (let ((r (compnum-real x)) |
---|
786 | (i (compnum-imag x)) ) |
---|
787 | (%sqrt 'magnitude (%+ (%* r r) (%* i i))) ) ) |
---|
788 | (NONE (bad-number 'magnitude x)) |
---|
789 | (else (%abs x)) ) ) |
---|
790 | |
---|
791 | (define magnitude %magnitude) |
---|
792 | |
---|
793 | (define (%angle x) |
---|
794 | (switchq (%check-number x) |
---|
795 | (NONE (bad-number 'angle x)) |
---|
796 | (COMP (##core#inline_allocate ("C_a_i_atan2" 4) |
---|
797 | (%exact->inexact (compnum-imag x)) |
---|
798 | (%exact->inexact (compnum-real x)))) |
---|
799 | (else (##core#inline_allocate ("C_a_i_atan2" 4) 0.0 (%exact->inexact x))) ) ) |
---|
800 | |
---|
801 | (define angle %angle) |
---|
802 | |
---|
803 | |
---|
804 | ;;; Rationals |
---|
805 | |
---|
806 | (define (ratnum m n) |
---|
807 | (cond |
---|
808 | ((eq? n 1) m) |
---|
809 | ((eq? n -1) (negate m)) |
---|
810 | ((negative? n) (%make-ratnum (negate m) (negate n))) |
---|
811 | (else (%make-ratnum m n)))) |
---|
812 | |
---|
813 | ;; Knuth, 4.5.1 |
---|
814 | (define (rat+/- loc op x y) |
---|
815 | (let ((a (ratnum-numerator x)) (b (ratnum-denominator x)) |
---|
816 | (c (ratnum-numerator y)) (d (ratnum-denominator y))) |
---|
817 | (let ((g1 (%gcd-0 loc b d))) |
---|
818 | (cond |
---|
819 | ((eq? g1 1) (%make-ratnum (op (%* a d) (%* b c)) (%* b d))) |
---|
820 | ;; Save a quotient and multiplication if the gcd is equal |
---|
821 | ;; to one of the denominators since quotient of b or d and g1 = 1 |
---|
822 | ;; TODO: Check properties of the gcd to see if g2 and t are needed |
---|
823 | ((%= g1 b) (let* ((t (op (%* a (%quotient loc d g1)) c)) |
---|
824 | (g2 (%gcd-0 loc t g1))) |
---|
825 | (ratnum (%quotient loc t g2) (%quotient loc d g2)))) |
---|
826 | ((%= g1 d) (let* ((b/g1 (%quotient loc b g1)) |
---|
827 | (t (op a (%* c b/g1))) ;; Is this worth it? |
---|
828 | (g2 (%gcd-0 loc t g1))) |
---|
829 | (ratnum (%quotient loc t g2) |
---|
830 | (%* b/g1 (%quotient loc d g2))))) |
---|
831 | (else (let* ((b/g1 (%quotient loc b g1)) |
---|
832 | (t (op (%* a (%quotient loc d g1)) |
---|
833 | (%* c b/g1))) |
---|
834 | (g2 (%gcd-0 loc t g1))) |
---|
835 | (%make-ratnum (%quotient loc t g2) |
---|
836 | (%* b/g1 (%quotient loc d g2))))))))) |
---|
837 | |
---|
838 | (define (numerator x) |
---|
839 | (switchq (%check-number x) |
---|
840 | (FIX x) |
---|
841 | (FLO (cond |
---|
842 | ((not (finite? x)) (bad-inexact 'numerator x)) |
---|
843 | ((%flo-integer? x) x) |
---|
844 | (else (exact->inexact (numerator (%flo->rat 'numerator x)))))) |
---|
845 | (BIG x) |
---|
846 | (RAT (ratnum-numerator x)) |
---|
847 | (COMP (bad-ratnum 'numerator x)) |
---|
848 | (else (bad-number 'numerator x)) ) ) |
---|
849 | |
---|
850 | (define (denominator x) |
---|
851 | (switchq (%check-number x) |
---|
852 | (FIX 1) |
---|
853 | (FLO (cond |
---|
854 | ((not (finite? x)) (bad-inexact 'denominator x)) |
---|
855 | ((%flo-integer? x) 1.0) |
---|
856 | (else (exact->inexact (denominator (%flo->rat 'denominator x)))))) |
---|
857 | (BIG 1) |
---|
858 | (RAT (ratnum-denominator x)) |
---|
859 | (COMP (bad-ratnum 'denominator x)) |
---|
860 | (else (bad-number 'denominator x)) ) ) |
---|
861 | |
---|
862 | |
---|
863 | ;;; Enhanced versions of other standard procedures |
---|
864 | |
---|
865 | (define (%abs x) |
---|
866 | (or ((##core#primitive "C_basic_abs") x) |
---|
867 | (switchq (%check-number x) |
---|
868 | (RAT (%make-ratnum |
---|
869 | ((##core#primitive "C_basic_abs") (ratnum-numerator x)) |
---|
870 | (ratnum-denominator x))) |
---|
871 | (COMP (##sys#signal-hook |
---|
872 | #:type-error 'abs |
---|
873 | "can not compute absolute value of complex number" x)) |
---|
874 | (else (bad-number 'abs x)) ) ) ) |
---|
875 | |
---|
876 | (define abs %abs) |
---|
877 | |
---|
878 | (define (number? x) |
---|
879 | (or (##core#inline "C_i_basic_numberp" x) (extended-number? x))) |
---|
880 | |
---|
881 | ;; TODO: Extend C_i_integerp |
---|
882 | (define (%integer? x) |
---|
883 | (and (##core#inline "C_i_basic_numberp" x) |
---|
884 | (or (not (##core#inline "C_i_flonump" x)) |
---|
885 | (##core#inline "C_u_i_fpintegerp" x)))) |
---|
886 | |
---|
887 | (set! ##sys#integer? %integer?) |
---|
888 | (define integer? %integer?) |
---|
889 | |
---|
890 | (set! ##sys#number? number?) |
---|
891 | (define complex? number?) |
---|
892 | |
---|
893 | ;; All numbers are real, except for compnums |
---|
894 | (define (real? x) |
---|
895 | (or (##core#inline "C_i_basic_numberp" x) |
---|
896 | (##sys#structure? x 'ratnum) ) ) |
---|
897 | |
---|
898 | (define (rational? x) (and (real? x) (finite? x))) |
---|
899 | |
---|
900 | (define (exact-integer? x) |
---|
901 | (or (##core#inline "C_fixnump" x) (##core#inline "C_i_bignump" x)) ) |
---|
902 | |
---|
903 | |
---|
904 | (define (%exact? x) |
---|
905 | (switchq (%check-number x) |
---|
906 | (FLO #f) |
---|
907 | (COMP (and (%exact? (compnum-real x)) (%exact? (compnum-imag x)))) |
---|
908 | (NONE (bad-number 'exact? x)) |
---|
909 | (else #t) ) ) |
---|
910 | |
---|
911 | (define exact? %exact?) |
---|
912 | (define ##sys#exact? %exact?) |
---|
913 | |
---|
914 | (define (%inexact? x) |
---|
915 | (switchq (%check-number x) |
---|
916 | (FLO #t) |
---|
917 | (COMP (and (%inexact? (compnum-real x)) (%inexact? (compnum-imag x)))) |
---|
918 | (NONE (bad-number 'inexact? x)) |
---|
919 | (else #f) ) ) |
---|
920 | |
---|
921 | (define inexact? %inexact?) |
---|
922 | (define ##sys#inexact? %inexact?) |
---|
923 | |
---|
924 | (define (positive? x) (%> x 0 'positive?)) |
---|
925 | (define (negative? x) (%< x 0 'negative?)) |
---|
926 | |
---|
927 | (define (%zero? x) |
---|
928 | (switchq (%check-number x) |
---|
929 | (FIX (eq? x 0)) |
---|
930 | (FLO (fp= x 0.0)) |
---|
931 | (NONE (bad-number 'zero? x)) |
---|
932 | (else #f) ) ) |
---|
933 | |
---|
934 | (define zero? %zero?) |
---|
935 | |
---|
936 | (define (odd? x) |
---|
937 | (switchq (%check-number x) |
---|
938 | (FIX (##core#inline "C_i_oddp" x)) |
---|
939 | (FLO (##core#inline "C_i_oddp" x)) |
---|
940 | (BIG (%big-odd? x)) |
---|
941 | (else (bad-integer 'odd? x)) ) ) |
---|
942 | |
---|
943 | (define (even? x) |
---|
944 | (switchq (%check-number x) |
---|
945 | (FIX (##core#inline "C_i_evenp" x)) |
---|
946 | (FLO (##core#inline "C_i_evenp" x)) |
---|
947 | (BIG (not (%big-odd? x))) |
---|
948 | (else (bad-integer 'even? x)) ) ) |
---|
949 | |
---|
950 | (define (max x1 . xs) |
---|
951 | (let ((i (%flonum? x1))) |
---|
952 | (let loop ((m x1) (xs xs)) |
---|
953 | (if (null? xs) |
---|
954 | (if i (%exact->inexact m) m) |
---|
955 | (let ((h (##sys#slot xs 0))) |
---|
956 | (switchq (%check-number h) |
---|
957 | (FLO (set! i #t)) |
---|
958 | (COMP (bad-complex/o 'max h)) ) |
---|
959 | (loop (if (%> h m 'max) h m) (##sys#slot xs 1)) ) ) ) ) ) |
---|
960 | |
---|
961 | (define (min x1 . xs) |
---|
962 | (let ((i (%flonum? x1))) |
---|
963 | (let loop ((m x1) (xs xs)) |
---|
964 | (if (null? xs) |
---|
965 | (if i (%exact->inexact m) m) |
---|
966 | (let ((h (##sys#slot xs 0))) |
---|
967 | (switchq (%check-number h) |
---|
968 | (FLO (set! i #t)) |
---|
969 | (COMP (bad-complex/o 'min h)) ) |
---|
970 | (loop (if (%< h m 'min) h m) (##sys#slot xs 1)) ) ) ) ) ) |
---|
971 | |
---|
972 | (define (%quotient loc x y) |
---|
973 | (or ((##core#primitive "C_basic_quotient") loc x y) |
---|
974 | (cond ((number? x) ; XXX What about non-integral flonums? |
---|
975 | (if (extended-number? y) |
---|
976 | (bad-integer loc y) |
---|
977 | (bad-number loc y))) |
---|
978 | ((number? y) |
---|
979 | (if (extended-number? x) |
---|
980 | (bad-integer loc x) |
---|
981 | (bad-number loc x))) |
---|
982 | (else (bad-number loc y))))) |
---|
983 | |
---|
984 | (define (quotient x y) (%quotient 'quotient x y)) |
---|
985 | (define (truncate-quotient x y) (%quotient 'truncate-quotient x y)) |
---|
986 | |
---|
987 | (define (%remainder loc x y) |
---|
988 | (switchq (%check-number x) |
---|
989 | [FIX (switchq (%check-number y) |
---|
990 | [FIX (fx- x (fx* (fx/ x y) y))] |
---|
991 | [FLO (let ((flx (%fix->flo x))) |
---|
992 | (if (%flo-integer? y) |
---|
993 | (fp- flx (fp* (##sys#truncate (fp/ flx y)) y)) |
---|
994 | (bad-integer loc y)))] |
---|
995 | ;; If abs(x) < abs(y), then remainder is always just x |
---|
996 | ;; except when y happens to be -most-negative-fixnum |
---|
997 | [BIG (if (and (eq? most-negative-fixnum x) (= (negate x) y)) 0 x)] |
---|
998 | [else (bad-integer loc y)])] |
---|
999 | [FLO (unless (%flo-integer? x) |
---|
1000 | (bad-integer loc x)) |
---|
1001 | (switchq (%check-number y) |
---|
1002 | [FLO (if (%flo-integer? y) |
---|
1003 | (fp- x (fp* (##sys#truncate (fp/ x y)) y)) |
---|
1004 | (bad-integer loc y))] |
---|
1005 | [FIX (let ((fly (%fix->flo (fix-div/0 x y loc)))) |
---|
1006 | (fp- x (fp* (##sys#truncate (fp/ x fly)) fly)))] |
---|
1007 | [BIG (%exact->inexact (%remainder loc (%flo->integer x) y))] |
---|
1008 | [else (bad-integer loc y)])] |
---|
1009 | [BIG (switchq (%check-number y) |
---|
1010 | [FIX (%big-remainder-fix x (fix-div/0 x y loc))] |
---|
1011 | [FLO (if (%flo-integer? y) |
---|
1012 | (%exact->inexact (%remainder loc x (%flo->integer y))) |
---|
1013 | (bad-integer loc y))] |
---|
1014 | [BIG (%big-remainder-big x y)] |
---|
1015 | [else (bad-integer loc y)])] |
---|
1016 | [else (bad-integer loc x)]) ) |
---|
1017 | |
---|
1018 | (define (remainder x y) (%remainder 'remainder x y)) |
---|
1019 | (define (truncate-remainder x y) (%remainder 'truncate-remainder x y)) |
---|
1020 | |
---|
1021 | ;; Modulo's sign follows y (whereas remainder's sign follows x) |
---|
1022 | (define (%modulo loc x y) |
---|
1023 | (let ((r (%remainder loc x y))) |
---|
1024 | (if (%> y 0 loc) |
---|
1025 | (if (%< r 0 loc) |
---|
1026 | (%+ r y) |
---|
1027 | r) |
---|
1028 | (if (%> r 0 loc) |
---|
1029 | (%+ r y) |
---|
1030 | r)))) |
---|
1031 | |
---|
1032 | (define (modulo x y) (%modulo 'modulo x y)) |
---|
1033 | (define (floor-remainder x y) (%modulo 'floor-remainder x y)) |
---|
1034 | |
---|
1035 | (define (%quotient&remainder loc x y) |
---|
1036 | (switchq (%check-number x) |
---|
1037 | [FIX (switchq (%check-number y) |
---|
1038 | [FIX (values (fx/ x y) (%remainder loc x y))] |
---|
1039 | [FLO (values (quotient x y) (%remainder loc x y))] |
---|
1040 | ;; If abs(x) < abs(y), then remainder is always just x |
---|
1041 | ;; except when y happens to be -most-negative-fixnum |
---|
1042 | [BIG (if (and (eq? most-negative-fixnum x) (= (negate x) y)) |
---|
1043 | (values -1 0) |
---|
1044 | (values 0 x))] |
---|
1045 | [else (bad-integer loc y)])] |
---|
1046 | [FLO (switchq (%check-number y) |
---|
1047 | [FLO (values (%quotient loc x y) |
---|
1048 | (%remainder loc x y))] |
---|
1049 | [FIX (values (%quotient loc x y) |
---|
1050 | (%remainder loc x y))] |
---|
1051 | [BIG (if (%flo-integer? x) |
---|
1052 | (receive (div rem) |
---|
1053 | (%quotient&remainder loc (%flo->integer x) y) |
---|
1054 | (values (%exact->inexact div) (%exact->inexact rem))) |
---|
1055 | (bad-integer loc x))] |
---|
1056 | [else (bad-integer loc y)])] |
---|
1057 | [BIG (switchq (%check-number y) |
---|
1058 | [FIX (%big-divrem-fix x (fix-div/0 x y loc))] |
---|
1059 | [FLO (if (%flo-integer? y) |
---|
1060 | (receive (div rem) |
---|
1061 | (%quotient&remainder loc x (%flo->integer y)) |
---|
1062 | (values (%exact->inexact div) (%exact->inexact rem))) |
---|
1063 | (bad-integer loc y))] |
---|
1064 | [BIG (%big-divrem-big x y)] |
---|
1065 | [else (bad-integer loc y)])] |
---|
1066 | [else (bad-integer loc x)])) |
---|
1067 | |
---|
1068 | (define (quotient&remainder x y) (%quotient&remainder 'quotient&remainder x y)) |
---|
1069 | (define (truncate/ x y) (%quotient&remainder 'truncate/ x y)) |
---|
1070 | |
---|
1071 | ;; Modulo's sign follows y (whereas remainder's sign follows x) |
---|
1072 | (define (quotient&modulo x y) |
---|
1073 | (receive (div rem) |
---|
1074 | (%quotient&remainder 'quotient&modulo x y) |
---|
1075 | (if (%> y 0 'quotient&modulo) |
---|
1076 | (if (%< rem 0 'quotient&modulo) |
---|
1077 | (values div (%+ rem y)) |
---|
1078 | (values div rem)) |
---|
1079 | (if (%> rem 0 'quotient&modulo) |
---|
1080 | (values div (%+ rem y)) |
---|
1081 | (values div rem))))) |
---|
1082 | |
---|
1083 | ;; Same as above, but quotient gets adjusted along with the remainder |
---|
1084 | (define (floor/ x y) |
---|
1085 | (receive (div rem) |
---|
1086 | (%quotient&remainder 'floor/ x y) |
---|
1087 | (if (%> y 0 'floor/) |
---|
1088 | (if (%< rem 0 'floor/) |
---|
1089 | (values (%- div 1) (%+ rem y)) |
---|
1090 | (values div rem)) |
---|
1091 | (if (%> rem 0 'floor/) |
---|
1092 | (values (%- div 1) (%+ rem y)) |
---|
1093 | (values div rem))))) |
---|
1094 | |
---|
1095 | ;; XXX This is a bad bad bad definition; very inefficient But to |
---|
1096 | ;; improve it we would need to provide another implementation of the |
---|
1097 | ;; quotient procedure which floors instead of truncates. |
---|
1098 | (define (floor-quotient x y) |
---|
1099 | (receive (div rem) (floor/ x y) div)) |
---|
1100 | |
---|
1101 | ;; Try to multiply by two until we reach an integer |
---|
1102 | (define (%float-fraction-length x) |
---|
1103 | (do ((x x (fp* x 2.0)) |
---|
1104 | (i 0 (+ i 1))) |
---|
1105 | ((%flo-integer? x) i) |
---|
1106 | ;; 3000 -> %float-precision? |
---|
1107 | (if (> i 3000) (error "I'm bored." x)))) |
---|
1108 | |
---|
1109 | (define (%flo->rat loc x) |
---|
1110 | (define (deliver y d) |
---|
1111 | (let ((q (expt 2 (%float-fraction-length y)))) |
---|
1112 | (if (%exact? q) ; XXX Ever untrue? float-fraction-length returns natnums |
---|
1113 | (let ((e (%/ (%/ (%flo->integer |
---|
1114 | (%* y (%exact->inexact q))) |
---|
1115 | q) |
---|
1116 | d))) |
---|
1117 | (if (%exact? e) |
---|
1118 | e |
---|
1119 | (bad-inexact loc x))) |
---|
1120 | (bad-inexact loc x)))) |
---|
1121 | (if (and (< x (%fix->flo 1)) ; watch out for denormalized numbers |
---|
1122 | (> x (%fix->flo -1))) |
---|
1123 | (deliver (%* x (expt (%fix->flo 2) flonum-precision)) |
---|
1124 | ;; Can be bignum (is on 32-bit), so must wait until after init. |
---|
1125 | ;; We shouldn't need to calculate this every single time, tho.. |
---|
1126 | (expt 2 flonum-precision)) |
---|
1127 | (deliver x 1))) |
---|
1128 | |
---|
1129 | (define (%inexact->exact x) |
---|
1130 | (switchq (%check-number x) |
---|
1131 | (FIX x) |
---|
1132 | (FLO (cond |
---|
1133 | ((not (finite? x)) (bad-inexact 'inexact->exact x)) |
---|
1134 | ((%flo-integer? x) (%flo->integer x)) |
---|
1135 | (else (%flo->rat 'inexact->exact x)))) |
---|
1136 | (BIG x) |
---|
1137 | (RAT x) |
---|
1138 | (COMP (make-complex (%inexact->exact (compnum-real x)) |
---|
1139 | (%inexact->exact (compnum-imag x)))) |
---|
1140 | (NONE (bad-number 'inexact->exact x)) ) ) |
---|
1141 | |
---|
1142 | (define inexact->exact %inexact->exact) |
---|
1143 | (define ##sys#inexact->exact %inexact->exact) |
---|
1144 | |
---|
1145 | ;; Exponent of the lowest allowed flonum; if we get any lower we get zero. |
---|
1146 | ;; In other words, this is the first (smallest) flonum after 0. |
---|
1147 | ;; Equal to (expt 2.0 (- flonum-minimum-exponent flonum-precision)) |
---|
1148 | (define minimum-denorm-flonum-expt (fx- flonum-minimum-exponent flonum-precision)) |
---|
1149 | |
---|
1150 | ;; This tries to keep the numbers within representable ranges and tries |
---|
1151 | ;; to drop as few significant digits as possible by bringing the two numbers |
---|
1152 | ;; to within the same powers of two. See algorithms M & N in Knuth, 4.2.1 |
---|
1153 | ;; |
---|
1154 | ;; TODO: Use (fp/ n d) if both are finite after conversion to flonums |
---|
1155 | (define (%rat->flo x) |
---|
1156 | (let* ((n1 (ratnum-numerator x)) |
---|
1157 | (an (%abs n1)) |
---|
1158 | (d1 (ratnum-denominator x)) |
---|
1159 | ;; Approximate distance between the numbers in powers of 2 |
---|
1160 | ;; ie, 2^e-1 < n/d < 2^e+1 (e is the *un*biased value of e_w in M2) |
---|
1161 | ;; XXX: What if b != 2 (ie, flonum-radix is not 2) |
---|
1162 | (e (fx- (integer-length an) (integer-length d1))) |
---|
1163 | (rnd (lambda (n d e) ; Here, 1 <= n/d < 2 (normalized) [N5] |
---|
1164 | ;; Cannot shift above the available precision, and can't have |
---|
1165 | ;; an exponent that's below the minimum flonum exponent. |
---|
1166 | (let* ((s (min (fx- flonum-precision 1) |
---|
1167 | (fx- e minimum-denorm-flonum-expt))) |
---|
1168 | (normalized (%/ (arithmetic-shift n s) d)) |
---|
1169 | (r (round normalized)) |
---|
1170 | (fraction (%exact->inexact r)) |
---|
1171 | (exp (fx- e s))) |
---|
1172 | (let ((res (fp* fraction (expt 2.0 exp)))) |
---|
1173 | (if (negative? n1) (%- 0 res) res))))) |
---|
1174 | (scale (lambda (n d) ; Here, 1/2 <= n/d < 2 [N3] |
---|
1175 | (if (%< n d 'exact->inexact) ; n/d < 1? |
---|
1176 | ;; Scale left [N3]; only needed once (see note in M3) |
---|
1177 | (rnd (arithmetic-shift n 1) d (fx- e 1)) |
---|
1178 | ;; Already normalized |
---|
1179 | (rnd n d e))))) |
---|
1180 | ;; After this step, which shifts the smaller number to align with the |
---|
1181 | ;; larger, "f" in algorithm N is represented in the procedures above by n/d. |
---|
1182 | (if (negative? e) |
---|
1183 | (scale (arithmetic-shift an (%- 0 e)) d1) |
---|
1184 | (scale an (arithmetic-shift d1 e))))) |
---|
1185 | |
---|
1186 | (define (%exact->inexact x) |
---|
1187 | (switchq (%check-number x) |
---|
1188 | (FIX (%fix->flo x)) |
---|
1189 | (FLO x) |
---|
1190 | (BIG (%big->flo x)) |
---|
1191 | (RAT (%rat->flo x)) |
---|
1192 | (COMP (make-complex (%exact->inexact (compnum-real x)) (%exact->inexact (compnum-imag x)))) |
---|
1193 | (NONE (bad-number 'exact->inexact x)) ) ) |
---|
1194 | |
---|
1195 | (define exact->inexact %exact->inexact) |
---|
1196 | (define inexact %exact->inexact) |
---|
1197 | (define ##sys#exact->inexact %exact->inexact) |
---|
1198 | (define exact %inexact->exact) |
---|
1199 | |
---|
1200 | (define (%gcd-0 loc x y) |
---|
1201 | (switchq (%check-number x) |
---|
1202 | [FIX (switchq (%check-number y) |
---|
1203 | [FIX (fxgcd x y)] |
---|
1204 | [FLO (if (%flo-integer? y) |
---|
1205 | (fpgcd (%fix->flo x) y) |
---|
1206 | (bad-integer loc y))] |
---|
1207 | [BIG (if (eq? x 0) y (fxgcd x (%remainder loc y x)))] |
---|
1208 | [else (bad-integer loc y)])] |
---|
1209 | [FLO (switchq (%check-number y) |
---|
1210 | [FIX (if (%flo-integer? x) |
---|
1211 | (fpgcd x (%fix->flo y)) |
---|
1212 | (bad-integer loc x))] |
---|
1213 | [FLO (if (%flo-integer? x) |
---|
1214 | (if (%flo-integer? y) |
---|
1215 | (fpgcd x y) |
---|
1216 | (bad-integer loc x)) |
---|
1217 | (bad-integer loc x))] |
---|
1218 | [BIG (if (fp= x 0.0) y (fpgcd x (%remainder loc y x)))] |
---|
1219 | [else (bad-integer loc y)])] |
---|
1220 | [BIG (switchq (%check-number y) |
---|
1221 | [FIX (if (eq? y 0) x (fxgcd y (%remainder loc x y)))] |
---|
1222 | [FLO (if (fp= y 0.0) x (fpgcd y (%remainder loc x y)))] |
---|
1223 | [BIG (%gcd-0 loc y (%big-remainder-big x y))] |
---|
1224 | [else (bad-integer loc y)])] |
---|
1225 | [else (bad-integer loc x)]) ) |
---|
1226 | |
---|
1227 | (define (gcd . ns) |
---|
1228 | (if (eq? ns '()) |
---|
1229 | 0 |
---|
1230 | (let loop ([ns ns] [f #t]) |
---|
1231 | (let ([head (##sys#slot ns 0)] |
---|
1232 | [next (##sys#slot ns 1)] ) |
---|
1233 | (if (null? next) |
---|
1234 | (if f (%abs (%->integer 'gcd head)) (%abs head)) |
---|
1235 | (let ([n2 (##sys#slot next 0)]) |
---|
1236 | (loop (cons (%gcd-0 'gcd head n2) (##sys#slot next 1)) #f) ) ) ) ) ) ) |
---|
1237 | |
---|
1238 | (define (%lcm-0 loc x y) |
---|
1239 | (%quotient loc (%* x y) (%gcd-0 loc x y)) ) |
---|
1240 | |
---|
1241 | (define (lcm . ns) |
---|
1242 | (if (null? ns) |
---|
1243 | 1 |
---|
1244 | (let loop ([ns ns] [f #t]) |
---|
1245 | (let ([head (##sys#slot ns 0)] |
---|
1246 | [next (##sys#slot ns 1)] ) |
---|
1247 | (if (null? next) |
---|
1248 | (if f (%abs (%->integer 'lcm head)) (%abs head)) |
---|
1249 | (let ([n2 (##sys#slot next 0)]) |
---|
1250 | (loop (cons (%lcm-0 'lcm head (##sys#slot next 0)) (##sys#slot next 1)) #f) ) ) ) ) ) ) |
---|
1251 | |
---|
1252 | (define (%floor x) |
---|
1253 | (switchq (%check-number x) |
---|
1254 | (FIX x) |
---|
1255 | (FLO (##sys#floor x)) |
---|
1256 | (BIG x) |
---|
1257 | ;; (floor x) = greatest integer <= x |
---|
1258 | (RAT (let* ((n (ratnum-numerator x)) |
---|
1259 | (q (quotient n (ratnum-denominator x)))) |
---|
1260 | (if (>= n 0) |
---|
1261 | q |
---|
1262 | (%- q 1)))) |
---|
1263 | (else (bad-real 'floor x))) ) |
---|
1264 | |
---|
1265 | (define floor %floor) |
---|
1266 | |
---|
1267 | (define (ceiling x) |
---|
1268 | (switchq (%check-number x) |
---|
1269 | (FIX x) |
---|
1270 | (FLO (##sys#ceiling x)) |
---|
1271 | (BIG x) |
---|
1272 | ;; (ceiling x) = smallest integer >= x |
---|
1273 | (RAT (let* ((n (ratnum-numerator x)) |
---|
1274 | (q (quotient n (ratnum-denominator x)))) |
---|
1275 | (if (>= n 0) |
---|
1276 | (%+ q 1) |
---|
1277 | q))) |
---|
1278 | (else (bad-real 'ceiling x))) ) |
---|
1279 | |
---|
1280 | (define (truncate x) |
---|
1281 | (switchq (%check-number x) |
---|
1282 | (FIX x) |
---|
1283 | (FLO (##sys#truncate x)) |
---|
1284 | (BIG x) |
---|
1285 | ;; (rational-truncate x) = integer of largest magnitude <= (abs x) |
---|
1286 | (RAT (%quotient 'truncate (ratnum-numerator x) (ratnum-denominator x))) |
---|
1287 | (else (bad-real 'truncate x))) ) |
---|
1288 | |
---|
1289 | (define (round x) |
---|
1290 | (switchq (%check-number x) |
---|
1291 | (FIX x) |
---|
1292 | (FLO (##core#inline_allocate ("C_a_i_flonum_round_proper" 4) x)) |
---|
1293 | (BIG x) |
---|
1294 | (RAT (let* ((x+1/2 (%+ x (%make-ratnum 1 2))) |
---|
1295 | (r (%floor x+1/2))) |
---|
1296 | (if (and (%= r x+1/2) |
---|
1297 | (odd? r)) |
---|
1298 | (%- r 1) |
---|
1299 | r))) |
---|
1300 | (else (bad-real 'round x)) ) ) |
---|
1301 | |
---|
1302 | (define (find-ratio-between x y) |
---|
1303 | (define (sr x y) |
---|
1304 | (let ((fx (%inexact->exact (%floor x))) |
---|
1305 | (fy (%inexact->exact (%floor y)))) |
---|
1306 | (cond ((not (%< fx x 'rationalize)) (list fx 1)) |
---|
1307 | ((%= fx fy) |
---|
1308 | (let ((rat (sr (%/ 1 (%- y fy)) (%/ 1 (%- x fx))))) |
---|
1309 | (list (%+ (cadr rat) (%* fx (car rat))) (car rat)))) |
---|
1310 | (else (list (%+ 1 fx) 1))))) |
---|
1311 | (cond ((%< y x 'rationalize) |
---|
1312 | (find-ratio-between y x)) |
---|
1313 | ((not (%< x y 'rationalize)) |
---|
1314 | (list x 1)) |
---|
1315 | ((%> x 0 'rationalize) |
---|
1316 | (sr x y)) |
---|
1317 | ((%< y 0 'rationalize) |
---|
1318 | (let ((rat (sr (%- 0 y) (%- 0 x)))) |
---|
1319 | (list (%- 0 (car rat)) (cadr rat)))) |
---|
1320 | (else '(0 1)))) |
---|
1321 | |
---|
1322 | (define (find-ratio x e) (find-ratio-between (%- x e) (%+ x e))) |
---|
1323 | |
---|
1324 | (define (rationalize x e) |
---|
1325 | (let ((result (apply %/ (find-ratio x e)))) |
---|
1326 | (if (or (inexact? x) (inexact? e)) |
---|
1327 | (exact->inexact result) |
---|
1328 | result))) |
---|
1329 | |
---|
1330 | (define (%exp n) |
---|
1331 | (switchq (%check-number n) |
---|
1332 | (NONE (bad-number 'exp n)) |
---|
1333 | (COMP (%* (##core#inline_allocate ("C_a_i_exp" 4) (compnum-real n)) |
---|
1334 | (let ((p (compnum-imag n))) |
---|
1335 | (make-complex |
---|
1336 | (##core#inline_allocate ("C_a_i_cos" 4) p) |
---|
1337 | (##core#inline_allocate ("C_a_i_sin" 4) p) ) ) ) ) |
---|
1338 | (else (##core#inline_allocate ("C_a_i_exp" 4) (%exact->inexact n)) ) )) |
---|
1339 | |
---|
1340 | (define exp %exp) |
---|
1341 | |
---|
1342 | (define (%log x) |
---|
1343 | (let ((type (%check-number x))) |
---|
1344 | (cond |
---|
1345 | ;; avoid calling inexact->exact on X here (to avoid overflow?) |
---|
1346 | ((or (eq? type COMP) (%< x 0.0 'log)) ; General case |
---|
1347 | (%+ (%log (%magnitude x)) (* (make-complex 0 1) (%angle x)))) |
---|
1348 | ((eq? x 0) ; Exact zero? That's undefined |
---|
1349 | (log0 'log x)) |
---|
1350 | ((eq? type NONE) |
---|
1351 | (bad-number 'log x)) |
---|
1352 | (else ; Simple real number case |
---|
1353 | (##core#inline_allocate ("C_a_i_log" 4) (%exact->inexact x)))))) |
---|
1354 | |
---|
1355 | (define (log a #!optional b) |
---|
1356 | (if b (%/ (%log a) (%log b)) (%log a))) |
---|
1357 | |
---|
1358 | (define %i (%make-complex 0 1)) |
---|
1359 | (define %-i (%make-complex 0 -1)) |
---|
1360 | (define %i2 (%make-complex 0 2)) |
---|
1361 | |
---|
1362 | (define (%sin n) |
---|
1363 | (switchq (%check-number n) |
---|
1364 | (NONE (bad-number 'sin n)) |
---|
1365 | (COMP (let ((in (%* %i n))) |
---|
1366 | (%/ (%- (%exp in) (%exp (%- 0 in))) %i2))) |
---|
1367 | (else (##core#inline_allocate ("C_a_i_sin" 4) (%exact->inexact n)) ) )) |
---|
1368 | |
---|
1369 | (define sin %sin) |
---|
1370 | |
---|
1371 | (define (%cos n) |
---|
1372 | (switchq (%check-number n) |
---|
1373 | (NONE (bad-number 'cos n)) |
---|
1374 | (COMP (let ((in (%* %i n))) |
---|
1375 | (%/ (%+ (%exp in) (%exp (%- 0 in))) 2) ) ) |
---|
1376 | (else (##core#inline_allocate ("C_a_i_cos" 4) (%exact->inexact n)) ) ) ) |
---|
1377 | |
---|
1378 | (define cos %cos) |
---|
1379 | |
---|
1380 | (define (tan n) |
---|
1381 | (switchq (%check-number n) |
---|
1382 | (NONE (bad-number 'tan n)) |
---|
1383 | (COMP (%/ (%sin n) (%cos n))) |
---|
1384 | (else (##core#inline_allocate ("C_a_i_tan" 4) (%exact->inexact n)) ) )) |
---|
1385 | |
---|
1386 | ;; General case: sin^{-1}(z) = -i\ln(iz + \sqrt{1-z^2}) |
---|
1387 | (define (%asin n) |
---|
1388 | (let ((t (%check-number n))) |
---|
1389 | (cond ((eq? t NONE) (bad-number 'asin n)) |
---|
1390 | ((and (eq? t FLO) (fp>= n -1.0) (fp<= n 1.0)) |
---|
1391 | (##core#inline_allocate ("C_a_i_asin" 4) n)) |
---|
1392 | ((and (eq? t FIX) (fx>= n -1) (fx<= n 1)) |
---|
1393 | (##core#inline_allocate ("C_a_i_asin" 4) (%fix->flo n))) |
---|
1394 | ;; General definition can return compnums |
---|
1395 | (else (%* %-i (%log (%+ (%* %i n) (%sqrt 'asin (%- 1 (%* n n)))))))))) |
---|
1396 | |
---|
1397 | (define asin %asin) |
---|
1398 | |
---|
1399 | ;; General case: |
---|
1400 | ;; cos^{-1}(z) = 1/2\pi + i\ln(iz + \sqrt{1-z^2}) = 1/2\pi - sin^{-1}(z) = sin(1) - sin(z) |
---|
1401 | (define %acos |
---|
1402 | (let ((asin1 (##core#inline_allocate ("C_a_i_asin" 4) 1))) |
---|
1403 | (lambda (n) |
---|
1404 | (let ((t (%check-number n))) |
---|
1405 | (cond ((eq? t NONE) (bad-number 'acos n)) |
---|
1406 | ((and (eq? t FLO) (fp>= n -1.0) (fp<= n 1.0)) |
---|
1407 | (##core#inline_allocate ("C_a_i_acos" 4) n)) |
---|
1408 | ((and (eq? t FIX) (fx>= n -1) (fx<= n 1)) |
---|
1409 | (##core#inline_allocate ("C_a_i_acos" 4) (%fix->flo n))) |
---|
1410 | ;; General definition can return compnums |
---|
1411 | (else (%- asin1 (%asin n)))) ) ) ) ) |
---|
1412 | |
---|
1413 | (define acos %acos) |
---|
1414 | |
---|
1415 | (define (atan n #!optional b) |
---|
1416 | (switchq (%check-number n) |
---|
1417 | (NONE (bad-number 'atan n)) |
---|
1418 | (COMP (if b |
---|
1419 | (bad-real 'atan n) |
---|
1420 | (let ((in (%* %i n))) |
---|
1421 | (%/ (%- (%log (%+ 1 in)) (%log (%- 1 in))) %i2) ) ) ) |
---|
1422 | (else (if b |
---|
1423 | (##core#inline_allocate ("C_a_i_atan2" 4) (%exact->inexact n) (%exact->inexact b)) |
---|
1424 | (##core#inline_allocate ("C_a_i_atan" 4) (%exact->inexact n))))) ) |
---|
1425 | |
---|
1426 | (define (%exact-integer-sqrt loc k) |
---|
1427 | (if (or (eq? 0 k) (eq? 1 k)) |
---|
1428 | (values k 0) |
---|
1429 | ;; Hacker's Delight, figure 11-1 (Newton's method - see also SICP 1.1.7) |
---|
1430 | ;; Initial guess is about the smallest x^2 which is bigger than sqrt(k) |
---|
1431 | ;; We could subtract one from ilen(k) to avoid overshooting by 1, but |
---|
1432 | ;; that's one more operation. |
---|
1433 | (let* ((len (fx+ (quotient (integer-length k) 2) 1)) |
---|
1434 | (g0 (arithmetic-shift 1 len))) |
---|
1435 | (let lp ((g0 g0) |
---|
1436 | (g1 (arithmetic-shift |
---|
1437 | (%+ g0 (arithmetic-shift k (fxneg len))) -1))) |
---|
1438 | (if (%< g1 g0 loc) |
---|
1439 | (lp g1 (arithmetic-shift (%+ g1 (quotient k g1)) -1)) |
---|
1440 | (values g0 (%- k (%* g0 g0)))))))) |
---|
1441 | |
---|
1442 | (define (exact-integer-sqrt x) |
---|
1443 | (switchq (%check-number x) |
---|
1444 | (NONE (bad-number 'exact-integer-sqrt x)) |
---|
1445 | (FIX (if (fx< x 0) |
---|
1446 | (bad-natural 'exact-integer-sqrt x) |
---|
1447 | (%exact-integer-sqrt 'exact-integer-sqrt x))) |
---|
1448 | (BIG (if (%big-negative? x) |
---|
1449 | (bad-natural 'exact-integer-sqrt x) |
---|
1450 | (%exact-integer-sqrt 'exact-integer-sqrt x))) |
---|
1451 | (else (bad-natural 'exact-integer-sqrt x)))) |
---|
1452 | |
---|
1453 | (define (%sqrt loc n) |
---|
1454 | (switchq (%check-number n) |
---|
1455 | (NONE (bad-number 'sqrt n)) |
---|
1456 | (COMP (let ((p (%/ (%angle n) 2)) |
---|
1457 | (m (##core#inline_allocate ("C_a_i_sqrt" 4) (%magnitude n))) ) |
---|
1458 | (make-complex (%* m (%cos p)) (%* m (%sin p)) ) ) ) |
---|
1459 | (RAT (let ((num (ratnum-numerator n)) |
---|
1460 | (den (ratnum-denominator n))) |
---|
1461 | (if (and (>= num 0) (>= den 0)) |
---|
1462 | (receive (ns^2 nr) |
---|
1463 | (%exact-integer-sqrt loc num) |
---|
1464 | (if (eq? nr 0) |
---|
1465 | (receive (ds^2 dr) |
---|
1466 | (%exact-integer-sqrt loc den) |
---|
1467 | (if (eq? dr 0) |
---|
1468 | (%/ ns^2 ds^2) |
---|
1469 | (%sqrt loc (%exact->inexact n)))) |
---|
1470 | (%sqrt loc (%exact->inexact n)))) |
---|
1471 | (%sqrt loc (%exact->inexact n))))) |
---|
1472 | (else |
---|
1473 | (cond |
---|
1474 | ((negative? n) |
---|
1475 | (make-complex |
---|
1476 | 0.0 |
---|
1477 | (##core#inline_allocate ("C_a_i_sqrt" 4) (%exact->inexact (negate n))))) |
---|
1478 | ((integer? n) |
---|
1479 | (receive (s^2 r) |
---|
1480 | (%exact-integer-sqrt loc (%->integer loc n)) |
---|
1481 | (if (eq? 0 r) |
---|
1482 | (if (exact? n) s^2 (%exact->inexact s^2)) |
---|
1483 | (##core#inline_allocate ("C_a_i_sqrt" 4) (%exact->inexact n))))) |
---|
1484 | (else (##core#inline_allocate ("C_a_i_sqrt" 4) (%exact->inexact n))) ) ))) |
---|
1485 | |
---|
1486 | (define (sqrt x) (%sqrt 'sqrt x)) |
---|
1487 | |
---|
1488 | (define (square x) (%* x x)) |
---|
1489 | |
---|
1490 | ;; Generalized Newton's algorithm for positive integers, with a little help |
---|
1491 | ;; from Wikipedia ;) https://en.wikipedia.org/wiki/Nth_root_algorithm |
---|
1492 | (define (%exact-integer-nth-root loc k n) |
---|
1493 | (cond |
---|
1494 | ((or (eq? 0 k) (eq? 1 k) (eq? 1 n)) ; Maybe call exact-integer-sqrt on n=2? |
---|
1495 | (values k 0)) |
---|
1496 | ((< n 1) |
---|
1497 | (bad-positive loc n)) |
---|
1498 | (else |
---|
1499 | (let ((len (integer-length k))) |
---|
1500 | (if (< len n) ; Idea from Gambit: 2^{len-1} <= k < 2^{len} |
---|
1501 | (values 1 (%- k 1)) ; Since we know x >= 2, we know x^{n} can't exist |
---|
1502 | ;; Set initial guess to (at least) 2^ceil(ceil(log2(k))/n) |
---|
1503 | (let* ((shift-amount (ceiling (/ (fx+ len 1) n))) |
---|
1504 | (g0 (arithmetic-shift 1 shift-amount)) |
---|
1505 | (n-1 (%- n 1))) |
---|
1506 | (let lp ((g0 g0) |
---|
1507 | (g1 (%quotient loc (%+ (%* n-1 g0) (%quotient loc k (%integer-power g0 n-1))) n))) |
---|
1508 | (if (%< g1 g0 loc) |
---|
1509 | (lp g1 (%quotient loc (%+ (%* n-1 g1) (%quotient loc k (%integer-power g1 n-1))) n)) |
---|
1510 | (values g0 (%- k (%integer-power g0 n))))))))))) |
---|
1511 | |
---|
1512 | (define (exact-integer-nth-root k n) |
---|
1513 | (unless (exact-integer? n) |
---|
1514 | (bad-natural 'exact-integer-nth-root n)) |
---|
1515 | (switchq (%check-number k) |
---|
1516 | (NONE (bad-number 'exact-integer-nth-root k)) |
---|
1517 | (FIX (if (fx< k 0) |
---|
1518 | (bad-natural 'exact-integer-nth-root k) |
---|
1519 | (%exact-integer-nth-root 'exact-integer-nth-root k n))) |
---|
1520 | (BIG (if (%big-negative? k) |
---|
1521 | (bad-natural 'exact-integer-nth-root k) |
---|
1522 | (%exact-integer-nth-root 'exact-integer-nth-root k n))) |
---|
1523 | (else (bad-natural 'exact-integer-nth-root k)))) |
---|
1524 | |
---|
1525 | (define (%integer-power base e) |
---|
1526 | (if (negative? e) |
---|
1527 | (%/ 1 (%integer-power base (negate e))) |
---|
1528 | (let lp ((res 1) (e2 e)) |
---|
1529 | (cond |
---|
1530 | ((eq? e2 0) res) |
---|
1531 | ((even? e2) ; recursion is faster than iteration here |
---|
1532 | (%* res (square (lp 1 (arithmetic-shift e2 -1))))) |
---|
1533 | (else |
---|
1534 | (lp (%* res base) (%- e2 1))))))) |
---|
1535 | |
---|
1536 | (define (expt a b) |
---|
1537 | (define (slow-expt a b) |
---|
1538 | (if (eq? 0 a) |
---|
1539 | (expt0 'expt a b) |
---|
1540 | (%exp (%* b (%log a))))) |
---|
1541 | (let ((ta (%check-number a)) |
---|
1542 | (tb (%check-number b)) ) |
---|
1543 | (cond ((eq? NONE ta) (bad-number 'expt a)) |
---|
1544 | ((eq? NONE tb) (bad-number 'expt b)) |
---|
1545 | ((and (eq? RAT ta) (not (inexact? b))) |
---|
1546 | ;; (n*d)^b = n^b * d^b = n^b * x^{-b} | x = 1/b |
---|
1547 | ;; Hopefully faster than integer-power |
---|
1548 | (%* (expt (ratnum-numerator a) b) |
---|
1549 | (expt (ratnum-denominator a) (negate b)))) |
---|
1550 | ;; x^{a/b} = (x^{1/b})^a |
---|
1551 | ((eq? RAT tb) |
---|
1552 | (switchq ta |
---|
1553 | (FIX (if (fx< a 0) |
---|
1554 | (%expt-0 (%fix->flo a) (%rat->flo b)) |
---|
1555 | (receive (ds^n r) |
---|
1556 | (%exact-integer-nth-root 'expt a (ratnum-denominator b)) |
---|
1557 | (if (eq? r 0) |
---|
1558 | (expt ds^n (ratnum-numerator b)) |
---|
1559 | (%expt-0 (%fix->flo a) (%rat->flo b)))))) |
---|
1560 | (BIG (if (%big-negative? a) |
---|
1561 | (%expt-0 (%big->flo a) (%rat->flo b)) |
---|
1562 | (receive (ds^n r) |
---|
1563 | (%exact-integer-nth-root 'expt a (ratnum-denominator b)) |
---|
1564 | (if (eq? r 0) |
---|
1565 | (expt ds^n (ratnum-numerator b)) |
---|
1566 | (%expt-0 (%big->flo a) (%rat->flo b)))))) |
---|
1567 | (FLO (%expt-0 a (%rat->flo b))) |
---|
1568 | (else (slow-expt a b)))) |
---|
1569 | ((or (eq? COMP tb) (and (eq? COMP ta) (not (integer? b)))) |
---|
1570 | (slow-expt a b)) |
---|
1571 | ((or (eq? FLO ta) (and (eq? FLO tb) (not (%flo-integer? b)))) |
---|
1572 | (%expt-0 (%exact->inexact a) (%exact->inexact b))) |
---|
1573 | ;; this doesn't work that well, yet... |
---|
1574 | ;; (XXX: What does this mean? why not? I do know this is ugly... :P) |
---|
1575 | (else (if (or (inexact? a) (inexact? b)) |
---|
1576 | (%exact->inexact (%integer-power a b)) |
---|
1577 | (%integer-power a b))) ) ) ) |
---|
1578 | |
---|
1579 | (define (conj n) |
---|
1580 | (switchq (%check-number n) |
---|
1581 | (NONE (bad-number 'conj n)) |
---|
1582 | (COMP (make-complex (compnum-real n) (%- 0 (compnum-imag n)))) |
---|
1583 | (else n) ) ) |
---|
1584 | |
---|
1585 | (define (add1 n) (%+ n 1)) |
---|
1586 | (define (sub1 n) (%- n 1)) |
---|
1587 | |
---|
1588 | (define (signum n) |
---|
1589 | (switchq (%check-number n) |
---|
1590 | (FIX (cond ((eq? 0 n) 0) |
---|
1591 | ((fx< n 0) -1) |
---|
1592 | (else 1) ) ) |
---|
1593 | (FLO (cond ((fp= n 0.0) 0.0) |
---|
1594 | ((fp< n 0.0) -1.0) |
---|
1595 | (else 1.0) ) ) |
---|
1596 | (BIG (if (%big-negative? n) -1 1)) ; Can't be 0; it would be a fixnum then |
---|
1597 | (RAT (signum (ratnum-numerator n))) |
---|
1598 | (COMP (make-polar 1 (angle n))) ; Definition from CLHS signum |
---|
1599 | (else (bad-number 'signum n)) ) ) |
---|
1600 | |
---|
1601 | (define (%->integer loc n) |
---|
1602 | (switchq (%check-number n) |
---|
1603 | (FIX n) |
---|
1604 | (FLO (if (%integer? n) |
---|
1605 | (%flo->integer n) |
---|
1606 | (bad-integer loc n))) |
---|
1607 | (BIG n) |
---|
1608 | (else (bad-integer loc n)) ) ) |
---|
1609 | |
---|
1610 | ;; From SRFI-60 (oddly not in Chicken core) |
---|
1611 | (define (integer-length x) |
---|
1612 | (%int-length (%->integer 'integer-length x))) |
---|
1613 | |
---|
1614 | (define (bitwise-and . xs) |
---|
1615 | (let loop ((x -1) (xs xs)) |
---|
1616 | (if (null? xs) |
---|
1617 | x |
---|
1618 | (let ((xi (##sys#slot xs 0))) |
---|
1619 | (loop |
---|
1620 | (%int-bitwise-int 0 x (%->integer 'bitwise-and xi)) |
---|
1621 | (##sys#slot xs 1) ) ) ) ) ) |
---|
1622 | |
---|
1623 | (define (bitwise-ior . xs) |
---|
1624 | (let loop ((x 0) (xs xs)) |
---|
1625 | (if (null? xs) |
---|
1626 | x |
---|
1627 | (let ((xi (##sys#slot xs 0))) |
---|
1628 | (loop |
---|
1629 | (%int-bitwise-int 1 x (%->integer 'bitwise-ior xi)) |
---|
1630 | (##sys#slot xs 1) ) ) ) ) ) |
---|
1631 | |
---|
1632 | (define (bitwise-xor . xs) |
---|
1633 | (let loop ((x 0) (xs xs)) |
---|
1634 | (if (null? xs) |
---|
1635 | x |
---|
1636 | (let ((xi (##sys#slot xs 0))) |
---|
1637 | (loop |
---|
1638 | (%int-bitwise-int 2 x (%->integer 'bitwise-xor xi)) |
---|
1639 | (##sys#slot xs 1) ) ) ) ) ) |
---|
1640 | |
---|
1641 | (define (bitwise-not n) |
---|
1642 | (- -1 (%->integer 'bitwise-not n)) ) |
---|
1643 | |
---|
1644 | (define (arithmetic-shift n m) |
---|
1645 | (let ((n (%->integer 'arithmetic-shift n))) |
---|
1646 | (switchq (%check-number m) |
---|
1647 | (FIX (%int-shift-fix n m)) |
---|
1648 | (BIG (##sys#signal-hook #:type-error 'arithmetic-shift |
---|
1649 | "can not shift by bignum amounts" n m)) |
---|
1650 | (else (bad-exact 'arithmetic-shift m)))) ) |
---|
1651 | |
---|
1652 | (define %number->string |
---|
1653 | (let ((string-append string-append)) |
---|
1654 | (lambda (n #!optional (base 10)) |
---|
1655 | (unless (memq base '(2 8 10 16)) (bad-base 'number->string base)) |
---|
1656 | (let numstr ((n n)) |
---|
1657 | (switchq (%check-number n) |
---|
1658 | (FIX (number->string-0 n base)) |
---|
1659 | (FLO (cond |
---|
1660 | ((fp= n -inf.0) "-inf.0") ; Core does not handle these right |
---|
1661 | ((fp= n +inf.0) "+inf.0") |
---|
1662 | ((not (fp= n n)) "+nan.0") |
---|
1663 | (else (number->string-0 n base)))) |
---|
1664 | (BIG (%big->string n base)) |
---|
1665 | (RAT (string-append (numstr (ratnum-numerator n)) |
---|
1666 | "/" |
---|
1667 | (numstr (ratnum-denominator n)))) |
---|
1668 | (COMP (let ((r (compnum-real n)) |
---|
1669 | (i (compnum-imag n)) ) |
---|
1670 | (string-append |
---|
1671 | (numstr r) |
---|
1672 | ;; The infinities and NaN always print their sign |
---|
1673 | (if (and (finite? i) (%> i 0 'number->string)) "+" "") |
---|
1674 | (numstr i) "i") ) ) |
---|
1675 | (else (bad-number 'number->string n)) ) ) ) ) ) |
---|
1676 | |
---|
1677 | (define number->string %number->string) |
---|
1678 | (define ##sys#number->string %number->string) ; for printer |
---|
1679 | |
---|
1680 | ;; We try to prevent memory exhaustion attacks by limiting the |
---|
1681 | ;; maximum exponent value. |
---|
1682 | ;; TODO: Make this a parameter? Would probably slow things down even more... |
---|
1683 | (define-constant +maximum-allowed-exponent+ 10000) |
---|
1684 | |
---|
1685 | (define (%string->compnum radix str offset exactness) |
---|
1686 | (define (go-inexact!) |
---|
1687 | ;; Go inexact unless exact was requested (with #e prefix) |
---|
1688 | (unless (eq? exactness 'e) (set! exactness 'i))) |
---|
1689 | (define (safe-exponent value e) |
---|
1690 | (and e (if (not value) |
---|
1691 | 0 |
---|
1692 | (cond |
---|
1693 | ((> e +maximum-allowed-exponent+) |
---|
1694 | (and (eq? exactness 'i) |
---|
1695 | (cond ((zero? value) 0.0) |
---|
1696 | ((> value 0.0) +inf.0) |
---|
1697 | (else -inf.0)))) |
---|
1698 | ((< e (negate +maximum-allowed-exponent+)) |
---|
1699 | (and (eq? exactness 'i) +0.0)) |
---|
1700 | (else (%* value (expt 10 e))))))) |
---|
1701 | (let* ((len (##sys#size str)) |
---|
1702 | (r..9 (integer->char (fx+ (char->integer #\0) radix))) |
---|
1703 | (r..a (integer->char (fx+ (char->integer #\a) (fx- radix 10)))) |
---|
1704 | (r..A (integer->char (fx+ (char->integer #\A) (fx- radix 10)))) |
---|
1705 | ;; Ugly flag which we need (note that "exactness" is mutated too!) |
---|
1706 | ;; Since there is (almost) no backtracking we can do this. |
---|
1707 | (seen-hashes? #f) |
---|
1708 | ;; All these procedures return #f or an object consed onto an end |
---|
1709 | ;; position. If the cdr is false, that's the end of the string. |
---|
1710 | ;; If just #f is returned, the string contains invalid number syntax. |
---|
1711 | (scan-digits |
---|
1712 | (lambda (start) |
---|
1713 | (let lp ((i start)) |
---|
1714 | (if (fx= i len) |
---|
1715 | (and (fx> i start) (cons i #f)) |
---|
1716 | (let ((c (%subchar str i))) |
---|
1717 | (if (fx<= radix 10) |
---|
1718 | (if (and (char>=? c #\0) (char<=? c r..9)) |
---|
1719 | (lp (fx+ i 1)) |
---|
1720 | (and (fx> i start) (cons i i))) |
---|
1721 | (if (or (and (char>=? c #\0) (char<=? c #\9)) |
---|
1722 | (and (char>=? c #\a) (char<=? c r..a)) |
---|
1723 | (and (char>=? c #\A) (char<=? c r..A))) |
---|
1724 | (lp (fx+ i 1)) |
---|
1725 | (and (fx> i start) (cons i i))))))))) |
---|
1726 | (scan-hashes |
---|
1727 | (lambda (start) |
---|
1728 | (let lp ((i start)) |
---|
1729 | (if (fx= i len) |
---|
1730 | (and (fx> i start) (cons i #f)) |
---|
1731 | (let ((c (%subchar str i))) |
---|
1732 | (if (eq? c #\#) |
---|
1733 | (lp (fx+ i 1)) |
---|
1734 | (and (fx> i start) (cons i i)))))))) |
---|
1735 | (scan-digits+hashes |
---|
1736 | (lambda (start neg? all-hashes-ok?) |
---|
1737 | (let* ((digits (and (not seen-hashes?) (scan-digits start))) |
---|
1738 | (hashes (if digits |
---|
1739 | (and (cdr digits) (scan-hashes (cdr digits))) |
---|
1740 | (and all-hashes-ok? (scan-hashes start)))) |
---|
1741 | (end (or hashes digits))) |
---|
1742 | (and-let* ((end) |
---|
1743 | (num (%digits->integer str start (car end) radix neg?))) |
---|
1744 | (when hashes ; Eeewww. Feeling dirty yet? |
---|
1745 | (set! seen-hashes? #t) |
---|
1746 | (go-inexact!)) |
---|
1747 | (cons num (cdr end)))))) |
---|
1748 | (scan-exponent |
---|
1749 | (lambda (start) |
---|
1750 | (and (fx< start len) |
---|
1751 | (let ((sign (case (%subchar str start) |
---|
1752 | ((#\+) 'pos) ((#\-) 'neg) (else #f)))) |
---|
1753 | (and-let* ((start (if sign (fx+ start 1) start)) |
---|
1754 | (end (scan-digits start))) |
---|
1755 | (go-inexact!) |
---|
1756 | (cons (%digits->integer |
---|
1757 | str start (car end) radix (eq? sign 'neg)) |
---|
1758 | (cdr end))))))) |
---|
1759 | (scan-decimal-tail |
---|
1760 | (lambda (start neg? decimal-head) |
---|
1761 | (and (fx< start len) |
---|
1762 | (let* ((tail (scan-digits+hashes start neg? decimal-head)) |
---|
1763 | (next (if tail (cdr tail) start))) |
---|
1764 | (and (or decimal-head (not next) |
---|
1765 | (fx> next start)) ; Don't allow empty "." |
---|
1766 | (case (and next (%subchar str next)) |
---|
1767 | ((#\e #\s #\f #\d #\l |
---|
1768 | #\E #\S #\F #\D #\L) |
---|
1769 | (and-let* (((fx> len next)) |
---|
1770 | (ee (scan-exponent (fx+ next 1))) |
---|
1771 | (e (car ee)) |
---|
1772 | (h (safe-exponent decimal-head e))) |
---|
1773 | (let* ((te (and tail (fx- e (fx- (cdr tail) start)))) |
---|
1774 | (num (and tail (car tail))) |
---|
1775 | (t (safe-exponent num te))) |
---|
1776 | (cons (if t (%+ h t) h) (cdr ee))))) |
---|
1777 | (else (let* ((last (or next len)) |
---|
1778 | (te (and tail (fx- start last))) |
---|
1779 | (num (and tail (car tail))) |
---|
1780 | (t (safe-exponent num te)) |
---|
1781 | (h (or decimal-head 0))) |
---|
1782 | (cons (if t (%+ h t) h) next))))))))) |
---|
1783 | (scan-ureal |
---|
1784 | (lambda (start neg?) |
---|
1785 | (if (and (fx> len (fx+ start 1)) (eq? radix 10) |
---|
1786 | (eq? (%subchar str start) #\.)) |
---|
1787 | (begin |
---|
1788 | (go-inexact!) |
---|
1789 | (scan-decimal-tail (fx+ start 1) neg? #f)) |
---|
1790 | (and-let* ((end (scan-digits+hashes start neg? #f))) |
---|
1791 | (case (and (cdr end) (%subchar str (cdr end))) |
---|
1792 | ((#\.) |
---|
1793 | (go-inexact!) |
---|
1794 | (and (eq? radix 10) |
---|
1795 | (if (fx> len (fx+ (cdr end) 1)) |
---|
1796 | (scan-decimal-tail (fx+ (cdr end) 1) neg? (car end)) |
---|
1797 | (cons (car end) #f)))) |
---|
1798 | ((#\e #\s #\f #\d #\l |
---|
1799 | #\E #\S #\F #\D #\L) |
---|
1800 | (and-let* (((eq? radix 10)) |
---|
1801 | ((fx> len (cdr end))) |
---|
1802 | (ee (scan-exponent (fx+ (cdr end) 1))) |
---|
1803 | (num (car end)) |
---|
1804 | (val (safe-exponent num (car ee)))) |
---|
1805 | (cons val (cdr ee)))) |
---|
1806 | ((#\/) |
---|
1807 | (set! seen-hashes? #f) ; Reset flag for denominator |
---|
1808 | (and-let* (((fx> len (cdr end))) |
---|
1809 | (d (scan-digits+hashes (fx+ (cdr end) 1) #f #f)) |
---|
1810 | (num (car end)) |
---|
1811 | (denom (car d))) |
---|
1812 | (if (not (eq? denom 0)) |
---|
1813 | (cons (%/ num denom) (cdr d)) |
---|
1814 | ;; Hacky: keep around an inexact until we decide we |
---|
1815 | ;; *really* need exact values, then fail at the end. |
---|
1816 | (and (not (eq? exactness 'e)) |
---|
1817 | (case (signum num) |
---|
1818 | ((-1) (cons -inf.0 (cdr d))) |
---|
1819 | ((0) (cons +nan.0 (cdr d))) |
---|
1820 | ((+1) (cons +inf.0 (cdr d)))))))) |
---|
1821 | (else end)))))) |
---|
1822 | (scan-real |
---|
1823 | (lambda (start) |
---|
1824 | (and (fx< start len) |
---|
1825 | (let* ((sign (case (%subchar str start) |
---|
1826 | ((#\+) 'pos) ((#\-) 'neg) (else #f))) |
---|
1827 | (next (if sign (fx+ start 1) start))) |
---|
1828 | (and (fx< next len) |
---|
1829 | (case (%subchar str next) |
---|
1830 | ((#\i #\I) |
---|
1831 | (or (and sign |
---|
1832 | (cond |
---|
1833 | ((fx= (fx+ next 1) len) ; [+-]i |
---|
1834 | (cons (if (eq? sign 'neg) -1 1) next)) |
---|
1835 | ((and (fx<= (fx+ next 5) len) |
---|
1836 | (string-ci=? (substring str next (fx+ next 5)) "inf.0")) |
---|
1837 | (go-inexact!) |
---|
1838 | (cons (fp/ (if (eq? sign 'neg) -1.0 1.0) 0.0) |
---|
1839 | (and (fx< (fx+ next 5) len) |
---|
1840 | (fx+ next 5)))) |
---|
1841 | (else #f))) |
---|
1842 | (scan-ureal next (eq? sign 'neg)))) |
---|
1843 | ((#\n #\N) |
---|
1844 | (or (and sign |
---|
1845 | (fx<= (fx+ next 5) len) |
---|
1846 | (string-ci=? (substring str next (fx+ next 5)) "nan.0") |
---|
1847 | (begin (go-inexact!) |
---|
1848 | (cons (fp/ 0.0 0.0) |
---|
1849 | (and (fx< (fx+ next 5) len) |
---|
1850 | (fx+ next 5))))) |
---|
1851 | (scan-ureal next (eq? sign 'neg)))) |
---|
1852 | (else (scan-ureal next (eq? sign 'neg))))))))) |
---|
1853 | (number (and-let* ((r1 (scan-real offset))) |
---|
1854 | (case (and (cdr r1) (%subchar str (cdr r1))) |
---|
1855 | ((#f) (car r1)) |
---|
1856 | ((#\i #\I) (and (fx= len (fx+ (cdr r1) 1)) |
---|
1857 | (or (eq? (%subchar str offset) #\+) ; ugh |
---|
1858 | (eq? (%subchar str offset) #\-)) |
---|
1859 | (make-rectangular 0 (car r1)))) |
---|
1860 | ((#\+ #\-) |
---|
1861 | (set! seen-hashes? #f) ; Reset flag for imaginary part |
---|
1862 | (and-let* ((r2 (scan-real (cdr r1))) |
---|
1863 | ((cdr r2)) |
---|
1864 | ((fx= len (fx+ (cdr r2) 1))) |
---|
1865 | ((or (eq? (%subchar str (cdr r2)) #\i) |
---|
1866 | (eq? (%subchar str (cdr r2)) #\I)))) |
---|
1867 | (make-rectangular (car r1) (car r2)))) |
---|
1868 | ((#\@) |
---|
1869 | (set! seen-hashes? #f) ; Reset flag for angle |
---|
1870 | (and-let* ((r2 (scan-real (fx+ (cdr r1) 1))) |
---|
1871 | ((not (cdr r2)))) |
---|
1872 | (make-polar (car r1) (car r2)))) |
---|
1873 | (else #f))))) |
---|
1874 | (and number (if (eq? exactness 'i) |
---|
1875 | (exact->inexact number) |
---|
1876 | ;; Ensure we didn't encounter +inf.0 or +nan.0 with #e |
---|
1877 | (and (finite? number) number))))) |
---|
1878 | |
---|
1879 | (define (%string->number str #!optional (base 10)) |
---|
1880 | (##sys#check-string str 'string->number) |
---|
1881 | (##sys#check-exact base 'string->number) |
---|
1882 | (unless (< 1 base 37) ; We only have 0-9 and the alphabet! |
---|
1883 | (bad-base 'string->number base)) |
---|
1884 | (let scan-prefix ((i 0) |
---|
1885 | (exness #f) |
---|
1886 | (radix #f) |
---|
1887 | (len (##sys#size str))) |
---|
1888 | (if (and (fx< (fx+ i 2) len) (eq? (%subchar str i) #\#)) |
---|
1889 | (case (%subchar str (fx+ i 1)) |
---|
1890 | ((#\i #\I) (and (not exness) (scan-prefix (fx+ i 2) 'i radix len))) |
---|
1891 | ((#\e #\E) (and (not exness) (scan-prefix (fx+ i 2) 'e radix len))) |
---|
1892 | ((#\b #\B) (and (not radix) (scan-prefix (fx+ i 2) exness 2 len))) |
---|
1893 | ((#\o #\O) (and (not radix) (scan-prefix (fx+ i 2) exness 8 len))) |
---|
1894 | ((#\d #\D) (and (not radix) (scan-prefix (fx+ i 2) exness 10 len))) |
---|
1895 | ((#\x #\X) (and (not radix) (scan-prefix (fx+ i 2) exness 16 len))) |
---|
1896 | (else #f)) |
---|
1897 | (%string->compnum (or radix base) str i exness)))) |
---|
1898 | |
---|
1899 | (define (randomize #!optional (seed (##sys#fudge 2))) |
---|
1900 | (switchq (%check-number seed) |
---|
1901 | (FIX (%fix-randomize seed)) |
---|
1902 | (BIG (%big-randomize seed)) |
---|
1903 | (else (bad-integer 'randomize seed)) ) ) |
---|
1904 | |
---|
1905 | (define (random n) |
---|
1906 | (switchq (%check-number n) |
---|
1907 | (FIX (%fix-random n)) |
---|
1908 | (BIG (%big-random n)) |
---|
1909 | (else (bad-integer 'random n)) ) ) |
---|
1910 | |
---|
1911 | (define string->number %string->number) |
---|
1912 | |
---|
1913 | ;;; Reader hook |
---|
1914 | (define (##sys#string->number str #!optional (radix 10) exactness) |
---|
1915 | (%string->compnum radix str 0 exactness)) |
---|
1916 | |
---|
1917 | |
---|
1918 | ;;; Non-standard type procedures |
---|
1919 | |
---|
1920 | (define (basic-number? x) (##core#inline "C_i_basic_numberp" x)) |
---|
1921 | |
---|
1922 | (define (extended-number? x) ; This does _not_ "include" basics; see "number?" |
---|
1923 | (and (##core#inline "C_blockp" x) |
---|
1924 | (##sys#generic-structure? x) |
---|
1925 | (or (eq? (##sys#slot x 0) 'ratnum) |
---|
1926 | (eq? (##sys#slot x 0) 'compnum)))) |
---|
1927 | |
---|
1928 | (define (bignum? x) (##core#inline "C_i_bignump" x)) |
---|
1929 | |
---|
1930 | (define (nan? x) |
---|
1931 | (switchq (%check-number x) |
---|
1932 | (NONE (bad-number 'nan? x)) |
---|
1933 | (FLO (not (fp= x x))) |
---|
1934 | (COMP (or (nan? (compnum-real x)) (nan? (compnum-imag x)))) |
---|
1935 | (else #f))) |
---|
1936 | (define (infinite? x) |
---|
1937 | (switchq (%check-number x) |
---|
1938 | (NONE (bad-number 'infinite? x)) |
---|
1939 | (FLO (or (fp= x +inf.0) (fp= x -inf.0))) |
---|
1940 | (COMP (or (infinite? (compnum-real x)) (infinite? (compnum-imag x)))) |
---|
1941 | (else #f))) |
---|
1942 | (define (finite? x) |
---|
1943 | (switchq (%check-number x) |
---|
1944 | (NONE (bad-number 'finite? x)) |
---|
1945 | (FLO (and (fp= x x) (not (fp= x +inf.0)) (not (fp= x -inf.0)))) |
---|
1946 | (COMP (and (finite? (compnum-real x)) (finite? (compnum-imag x)))) |
---|
1947 | (else #t))) |
---|
1948 | |
---|
1949 | (define (ratnum? x) (##sys#structure? x 'ratnum)) ; rational number |
---|
1950 | |
---|
1951 | ;; XXX THE ONES BELOW ARE EXTREMELY CONFUSING |
---|
1952 | ;; Especially considering the type tag in a complex number is "compnum"! |
---|
1953 | ;; Best to rename cplxnum? to compnum? and ditch the rest. |
---|
1954 | ;; A user can easily define them themselves |
---|
1955 | (define (cplxnum? x) (##sys#structure? x 'compnum)) ; complex number |
---|
1956 | |
---|
1957 | (define (rectnum? x) ; "exact" complex number |
---|
1958 | (and (cplxnum? x) |
---|
1959 | (%integer? (compnum-real x)) |
---|
1960 | (%integer? (compnum-imag x)))) |
---|
1961 | |
---|
1962 | (define (compnum? x) ; inexact complex number |
---|
1963 | (and (cplxnum? x) |
---|
1964 | (%inexact? (compnum-real x)) |
---|
1965 | (%inexact? (compnum-imag x)))) |
---|
1966 | |
---|
1967 | (define (cintnum? x) ; integer number |
---|
1968 | (or (%integer? x) (rectnum? x)) ) |
---|
1969 | |
---|
1970 | (define (cflonum? x) ; floatingpoint number |
---|
1971 | (or (##core#inline "C_i_flonump" x) (compnum? x)) ) |
---|
1972 | |
---|
1973 | ;;; What we provide |
---|
1974 | |
---|
1975 | (register-feature! #:full-numeric-tower) |
---|
1976 | |
---|
1977 | ) |
---|