More distinguished handling of real and complex values.
[bpt/guile.git] / libguile / numbers.c
CommitLineData
f81e080b
DH
1/* Copyright (C) 1995,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
2 *
0f2d19dd
JB
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
48#include <math.h>
a0599745 49#include "libguile/_scm.h"
a0599745
MD
50#include "libguile/feature.h"
51#include "libguile/ports.h"
52#include "libguile/root.h"
53#include "libguile/smob.h"
54#include "libguile/strings.h"
55#include "libguile/vectors.h"
56
57#include "libguile/validate.h"
58#include "libguile/numbers.h"
f4c627b3 59
0f2d19dd 60\f
f4c627b3
DH
61
62static SCM scm_divbigbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn, int modes);
63static SCM scm_divbigint (SCM x, long z, int sgn, int mode);
64
65
0f2d19dd
JB
66#define DIGITS '0':case '1':case '2':case '3':case '4':\
67 case '5':case '6':case '7':case '8':case '9'
68
69
09fb7599
DH
70#define SCM_SWAP(x,y) do { SCM __t = x; x = y; y = __t; } while (0)
71
72
0f2d19dd
JB
73/* IS_INF tests its floating point number for infiniteness
74 */
75#ifndef IS_INF
7235ee58 76#define IS_INF(x) ((x) == (x) / 2)
0f2d19dd
JB
77#endif
78
e6f3ef58
MD
79/* Return true if X is not infinite and is not a NaN
80 */
81#ifndef isfinite
82#define isfinite(x) (!IS_INF (x) && (x) == (x))
83#endif
84
0f2d19dd
JB
85\f
86
f872b822 87
a1ec6916 88SCM_DEFINE (scm_exact_p, "exact?", 1, 0, 0,
1bbd0b84 89 (SCM x),
4219f20d 90 "Return #t if X is an exact number, #f otherwise.")
1bbd0b84 91#define FUNC_NAME s_scm_exact_p
0f2d19dd 92{
4219f20d 93 if (SCM_INUMP (x)) {
f872b822 94 return SCM_BOOL_T;
4219f20d 95 } else if (SCM_BIGP (x)) {
f872b822 96 return SCM_BOOL_T;
4219f20d
DH
97 } else {
98 return SCM_BOOL_F;
99 }
0f2d19dd 100}
1bbd0b84 101#undef FUNC_NAME
0f2d19dd 102
4219f20d 103
a1ec6916 104SCM_DEFINE (scm_odd_p, "odd?", 1, 0, 0,
1bbd0b84 105 (SCM n),
4219f20d 106 "Return #t if N is an odd number, #f otherwise.")
1bbd0b84 107#define FUNC_NAME s_scm_odd_p
0f2d19dd 108{
4219f20d
DH
109 if (SCM_INUMP (n)) {
110 return SCM_BOOL ((4 & SCM_UNPACK (n)) != 0);
4219f20d
DH
111 } else if (SCM_BIGP (n)) {
112 return SCM_BOOL ((1 & SCM_BDIGITS (n) [0]) != 0);
4219f20d 113 } else {
a1a33b0f 114 SCM_WRONG_TYPE_ARG (1, n);
4219f20d 115 }
0f2d19dd 116}
1bbd0b84 117#undef FUNC_NAME
0f2d19dd 118
4219f20d 119
a1ec6916 120SCM_DEFINE (scm_even_p, "even?", 1, 0, 0,
1bbd0b84 121 (SCM n),
4219f20d 122 "Return #t if N is an even number, #f otherwise.")
1bbd0b84 123#define FUNC_NAME s_scm_even_p
0f2d19dd 124{
4219f20d
DH
125 if (SCM_INUMP (n)) {
126 return SCM_BOOL ((4 & SCM_UNPACK (n)) == 0);
4219f20d
DH
127 } else if (SCM_BIGP (n)) {
128 return SCM_BOOL ((1 & SCM_BDIGITS (n) [0]) == 0);
4219f20d 129 } else {
a1a33b0f 130 SCM_WRONG_TYPE_ARG (1, n);
4219f20d 131 }
0f2d19dd 132}
1bbd0b84 133#undef FUNC_NAME
0f2d19dd 134
4219f20d 135
9de33deb 136SCM_GPROC (s_abs, "abs", 1, 0, 0, scm_abs, g_abs);
1cc91f1b 137
0f2d19dd 138SCM
6e8d25a6 139scm_abs (SCM x)
0f2d19dd 140{
4219f20d
DH
141 if (SCM_INUMP (x)) {
142 long int xx = SCM_INUM (x);
143 if (xx >= 0) {
144 return x;
145 } else if (SCM_POSFIXABLE (-xx)) {
146 return SCM_MAKINUM (-xx);
147 } else {
0f2d19dd 148#ifdef SCM_BIGDIG
4219f20d 149 return scm_long2big (-xx);
0f2d19dd 150#else
4219f20d 151 scm_num_overflow (s_abs);
0f2d19dd 152#endif
4219f20d 153 }
4219f20d
DH
154 } else if (SCM_BIGP (x)) {
155 if (!SCM_BIGSIGN (x)) {
156 return x;
157 } else {
158 return scm_copybig (x, 0);
159 }
4219f20d
DH
160 } else {
161 SCM_WTA_DISPATCH_1 (g_abs, x, 1, s_abs);
162 }
0f2d19dd
JB
163}
164
4219f20d 165
9de33deb 166SCM_GPROC (s_quotient, "quotient", 2, 0, 0, scm_quotient, g_quotient);
1cc91f1b 167
0f2d19dd 168SCM
6e8d25a6 169scm_quotient (SCM x, SCM y)
0f2d19dd 170{
828865c3
DH
171 if (SCM_INUMP (x)) {
172 long xx = SCM_INUM (x);
173 if (SCM_INUMP (y)) {
174 long yy = SCM_INUM (y);
175 if (yy == 0) {
176 scm_num_overflow (s_quotient);
177 } else {
178 long z = xx / yy;
4219f20d
DH
179 if (SCM_FIXABLE (z)) {
180 return SCM_MAKINUM (z);
181 } else {
828865c3
DH
182#ifdef SCM_BIGDIG
183 return scm_long2big (z);
184#else
185 scm_num_overflow (s_quotient);
186#endif
828865c3
DH
187 }
188 }
4219f20d
DH
189 } else if (SCM_BIGP (y)) {
190 return SCM_INUM0;
4219f20d
DH
191 } else {
192 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
828865c3 193 }
4219f20d
DH
194 } else if (SCM_BIGP (x)) {
195 if (SCM_INUMP (y)) {
828865c3
DH
196 long yy = SCM_INUM (y);
197 if (yy == 0) {
198 scm_num_overflow (s_quotient);
199 } else if (yy == 1) {
f872b822 200 return x;
828865c3
DH
201 } else {
202 long z = yy < 0 ? -yy : yy;
203
204 if (z < SCM_BIGRAD) {
205 SCM sw = scm_copybig (x, SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0));
c209c88e
GB
206 scm_divbigdig (SCM_BDIGITS (sw), SCM_NUMDIGS (sw), (SCM_BIGDIG) z);
207 return scm_normbig (sw);
828865c3 208 } else {
0f2d19dd 209#ifndef SCM_DIGSTOOBIG
828865c3
DH
210 long w = scm_pseudolong (z);
211 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
212 (SCM_BIGDIG *) & w, SCM_DIGSPERLONG,
213 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 2);
0f2d19dd 214#else
828865c3
DH
215 SCM_BIGDIG zdigs[SCM_DIGSPERLONG];
216 scm_longdigs (z, zdigs);
217 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
218 zdigs, SCM_DIGSPERLONG,
219 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 2);
f872b822 220#endif
f872b822 221 }
828865c3 222 }
4219f20d
DH
223 } else if (SCM_BIGP (y)) {
224 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
225 SCM_BDIGITS (y), SCM_NUMDIGS (y),
226 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y), 2);
227 } else {
228 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
f872b822 229 }
4219f20d 230 } else {
89a7e495 231 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG1, s_quotient);
0f2d19dd 232 }
0f2d19dd
JB
233}
234
4219f20d 235
9de33deb 236SCM_GPROC (s_remainder, "remainder", 2, 0, 0, scm_remainder, g_remainder);
1cc91f1b 237
0f2d19dd 238SCM
6e8d25a6 239scm_remainder (SCM x, SCM y)
0f2d19dd 240{
89a7e495
DH
241 if (SCM_INUMP (x)) {
242 if (SCM_INUMP (y)) {
243 long yy = SCM_INUM (y);
244 if (yy == 0) {
245 scm_num_overflow (s_remainder);
246 } else {
247#if (__TURBOC__ == 1)
248 long z = SCM_INUM (x) % (yy < 0 ? -yy : yy);
249#else
250 long z = SCM_INUM (x) % yy;
251#endif
252 return SCM_MAKINUM (z);
253 }
89a7e495 254 } else if (SCM_BIGP (y)) {
f872b822 255 return x;
89a7e495
DH
256 } else {
257 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
258 }
89a7e495
DH
259 } else if (SCM_BIGP (x)) {
260 if (SCM_INUMP (y)) {
261 long yy = SCM_INUM (y);
262 if (yy == 0) {
263 scm_num_overflow (s_remainder);
264 } else {
265 return scm_divbigint (x, yy, SCM_BIGSIGN (x), 0);
266 }
267 } else if (SCM_BIGP (y)) {
268 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
269 SCM_BDIGITS (y), SCM_NUMDIGS (y),
270 SCM_BIGSIGN (x), 0);
271 } else {
272 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
f872b822 273 }
89a7e495
DH
274 } else {
275 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG1, s_remainder);
276 }
0f2d19dd
JB
277}
278
89a7e495 279
9de33deb 280SCM_GPROC (s_modulo, "modulo", 2, 0, 0, scm_modulo, g_modulo);
1cc91f1b 281
0f2d19dd 282SCM
6e8d25a6 283scm_modulo (SCM x, SCM y)
0f2d19dd 284{
828865c3
DH
285 if (SCM_INUMP (x)) {
286 long xx = SCM_INUM (x);
287 if (SCM_INUMP (y)) {
288 long yy = SCM_INUM (y);
289 if (yy == 0) {
290 scm_num_overflow (s_modulo);
291 } else {
292#if (__TURBOC__ == 1)
293 long z = ((yy < 0) ? -xx : xx) % yy;
294#else
295 long z = xx % yy;
296#endif
297 return SCM_MAKINUM (((yy < 0) ? (z > 0) : (z < 0)) ? z + yy : z);
298 }
09fb7599
DH
299 } else if (SCM_BIGP (y)) {
300 return (SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0)) ? scm_sum (x, y) : x;
09fb7599
DH
301 } else {
302 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
f872b822 303 }
09fb7599
DH
304 } else if (SCM_BIGP (x)) {
305 if (SCM_INUMP (y)) {
828865c3
DH
306 long yy = SCM_INUM (y);
307 if (yy == 0) {
308 scm_num_overflow (s_modulo);
309 } else {
310 return scm_divbigint (x, yy, yy < 0,
311 (SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0)) ? 1 : 0);
312 }
09fb7599
DH
313 } else if (SCM_BIGP (y)) {
314 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
315 SCM_BDIGITS (y), SCM_NUMDIGS (y),
316 SCM_BIGSIGN (y),
317 (SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y)) ? 1 : 0);
318 } else {
319 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
828865c3 320 }
09fb7599
DH
321 } else {
322 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG1, s_modulo);
828865c3 323 }
0f2d19dd
JB
324}
325
09fb7599 326
9de33deb 327SCM_GPROC1 (s_gcd, "gcd", scm_tc7_asubr, scm_gcd, g_gcd);
1cc91f1b 328
0f2d19dd 329SCM
6e8d25a6 330scm_gcd (SCM x, SCM y)
0f2d19dd 331{
09fb7599
DH
332 if (SCM_UNBNDP (y)) {
333 if (SCM_UNBNDP (x)) {
334 return SCM_INUM0;
335 } else {
336 return x;
337 }
338 }
f8de44c1 339
0f2d19dd 340 tailrec:
09fb7599
DH
341 if (SCM_INUMP (x)) {
342 if (SCM_INUMP (y)) {
343 long xx = SCM_INUM (x);
344 long yy = SCM_INUM (y);
345 long u = xx < 0 ? -xx : xx;
346 long v = yy < 0 ? -yy : yy;
347 long result;
348
349 if (xx == 0) {
350 result = v;
351 } else if (yy == 0) {
352 result = u;
353 } else {
354 int k = 1;
355 long t;
356
357 /* Determine a common factor 2^k */
358 while (!(1 & (u | v))) {
359 k <<= 1;
360 u >>= 1;
361 v >>= 1;
f872b822 362 }
09fb7599
DH
363
364 /* Now, any factor 2^n can be eliminated */
365 if (u & 1) {
366 t = -v;
367 } else {
368 t = u;
369 b3:
370 t = SCM_SRS (t, 1);
371 }
372 if (!(1 & t))
373 goto b3;
374 if (t > 0)
375 u = t;
376 else
377 v = -t;
378 t = u - v;
379 if (t != 0)
380 goto b3;
381
382 result = u * k;
383 }
384 if (SCM_POSFIXABLE (result)) {
385 return SCM_MAKINUM (result);
386 } else {
387#ifdef SCM_BIGDIG
388 return scm_long2big (result);
f872b822 389#else
09fb7599
DH
390 scm_num_overflow (s_gcd);
391#endif
392 }
09fb7599
DH
393 } else if (SCM_BIGP (y)) {
394 SCM_SWAP (x, y);
395 goto big_gcd;
09fb7599
DH
396 } else {
397 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 398 }
09fb7599
DH
399 } else if (SCM_BIGP (x)) {
400 big_gcd:
401 if (SCM_BIGSIGN (x))
402 x = scm_copybig (x, 0);
403 newy:
404 if (SCM_INUMP (y)) {
405 if (SCM_EQ_P (y, SCM_INUM0)) {
406 return x;
407 } else {
408 goto swaprec;
409 }
410 } else if (SCM_BIGP (y)) {
411 if (SCM_BIGSIGN (y))
412 y = scm_copybig (y, 0);
413 switch (scm_bigcomp (x, y))
414 {
415 case -1: /* x > y */
416 swaprec:
417 {
418 SCM t = scm_remainder (x, y);
419 x = y;
420 y = t;
421 }
422 goto tailrec;
423 case 1: /* x < y */
424 y = scm_remainder (y, x);
425 goto newy;
426 default: /* x == y */
427 return x;
428 }
429 /* instead of the switch, we could just
430 return scm_gcd (y, scm_modulo (x, y)); */
431 } else {
432 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
433 }
09fb7599
DH
434 } else {
435 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
436 }
0f2d19dd
JB
437}
438
09fb7599 439
9de33deb 440SCM_GPROC1 (s_lcm, "lcm", scm_tc7_asubr, scm_lcm, g_lcm);
1cc91f1b 441
0f2d19dd 442SCM
6e8d25a6 443scm_lcm (SCM n1, SCM n2)
0f2d19dd 444{
09fb7599
DH
445 if (SCM_UNBNDP (n2)) {
446 if (SCM_UNBNDP (n1)) {
447 return SCM_MAKINUM (1L);
448 } else {
449 n2 = SCM_MAKINUM (1L);
450 }
451 };
452
02a3305a 453#ifndef SCM_BIGDIG
09fb7599
DH
454 SCM_GASSERT2 (SCM_INUMP (n1), g_lcm, n1, n2, SCM_ARG1, s_lcm);
455 SCM_GASSERT2 (SCM_INUMP (n2), g_lcm, n1, n2, SCM_ARGn, s_lcm);
9de33deb 456#else
09fb7599 457 SCM_GASSERT2 (SCM_INUMP (n1) || SCM_BIGP (n1),
9de33deb 458 g_lcm, n1, n2, SCM_ARG1, s_lcm);
09fb7599 459 SCM_GASSERT2 (SCM_INUMP (n2) || SCM_BIGP (n2),
9de33deb
MD
460 g_lcm, n1, n2, SCM_ARGn, s_lcm);
461#endif
09fb7599
DH
462
463 {
464 SCM d = scm_gcd (n1, n2);
465 if (SCM_EQ_P (d, SCM_INUM0)) {
466 return d;
467 } else {
468 return scm_abs (scm_product (n1, scm_quotient (n2, d)));
f872b822 469 }
09fb7599 470 }
0f2d19dd
JB
471}
472
09fb7599 473
0f2d19dd 474#ifndef scm_long2num
c1bfcf60
GB
475#define SCM_LOGOP_RETURN(x) scm_ulong2num(x)
476#else
477#define SCM_LOGOP_RETURN(x) SCM_MAKINUM(x)
478#endif
479
8a525303
GB
480
481/* Emulating 2's complement bignums with sign magnitude arithmetic:
482
483 Logand:
484 X Y Result Method:
485 (len)
486 + + + x (map digit:logand X Y)
487 + - + x (map digit:logand X (lognot (+ -1 Y)))
488 - + + y (map digit:logand (lognot (+ -1 X)) Y)
489 - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y)))
490
491 Logior:
492 X Y Result Method:
493
494 + + + (map digit:logior X Y)
495 + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y)))
496 - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y)))
497 - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y)))
498
499 Logxor:
500 X Y Result Method:
501
502 + + + (map digit:logxor X Y)
503 + - - (+ 1 (map digit:logxor X (+ -1 Y)))
504 - + - (+ 1 (map digit:logxor (+ -1 X) Y))
505 - - + (map digit:logxor (+ -1 X) (+ -1 Y))
506
507 Logtest:
508 X Y Result
509
510 + + (any digit:logand X Y)
511 + - (any digit:logand X (lognot (+ -1 Y)))
512 - + (any digit:logand (lognot (+ -1 X)) Y)
513 - - #t
514
515*/
516
517#ifdef SCM_BIGDIG
518
519SCM scm_copy_big_dec(SCM b, int sign);
520SCM scm_copy_smaller(SCM_BIGDIG *x, scm_sizet nx, int zsgn);
521SCM scm_big_ior(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy);
522SCM scm_big_xor(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy);
523SCM scm_big_and(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int zsgn);
524SCM scm_big_test(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy);
525
526SCM scm_copy_big_dec(SCM b, int sign)
527{
528 long num = -1;
529 scm_sizet nx = SCM_NUMDIGS(b);
530 scm_sizet i = 0;
531 SCM ans = scm_mkbig(nx, sign);
532 SCM_BIGDIG *src = SCM_BDIGITS(b), *dst = SCM_BDIGITS(ans);
533 if SCM_BIGSIGN(b) do {
534 num += src[i];
535 if (num < 0) {dst[i] = num + SCM_BIGRAD; num = -1;}
536 else {dst[i] = SCM_BIGLO(num); num = 0;}
537 } while (++i < nx);
538 else
539 while (nx--) dst[nx] = src[nx];
540 return ans;
541}
542
543SCM scm_copy_smaller(SCM_BIGDIG *x, scm_sizet nx, int zsgn)
544{
545 long num = -1;
546 scm_sizet i = 0;
547 SCM z = scm_mkbig(nx, zsgn);
548 SCM_BIGDIG *zds = SCM_BDIGITS(z);
549 if (zsgn) do {
550 num += x[i];
551 if (num < 0) {zds[i] = num + SCM_BIGRAD; num = -1;}
552 else {zds[i] = SCM_BIGLO(num); num = 0;}
553 } while (++i < nx);
554 else do zds[i] = x[i]; while (++i < nx);
555 return z;
556}
557
558SCM scm_big_ior(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy)
559/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 560/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
561{
562 long num = -1;
563 scm_sizet i = 0, ny = SCM_NUMDIGS(bigy);
f3ae5d60 564 SCM z = scm_copy_big_dec (bigy, xsgn & SCM_BIGSIGN (bigy));
8a525303
GB
565 SCM_BIGDIG *zds = SCM_BDIGITS(z);
566 if (xsgn) {
567 do {
568 num += x[i];
569 if (num < 0) {zds[i] |= num + SCM_BIGRAD; num = -1;}
570 else {zds[i] |= SCM_BIGLO(num); num = 0;}
571 } while (++i < nx);
572 /* ========= Need to increment zds now =========== */
573 i = 0; num = 1;
574 while (i < ny) {
575 num += zds[i];
576 zds[i++] = SCM_BIGLO(num);
577 num = SCM_BIGDN(num);
578 if (!num) return z;
579 }
580 scm_adjbig(z, 1 + ny); /* OOPS, overflowed into next digit. */
581 SCM_BDIGITS(z)[ny] = 1;
582 return z;
583 }
584 else do zds[i] = zds[i] | x[i]; while (++i < nx);
585 return z;
586}
587
588SCM scm_big_xor(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy)
589/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 590/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
591{
592 long num = -1;
593 scm_sizet i = 0, ny = SCM_NUMDIGS(bigy);
594 SCM z = scm_copy_big_dec(bigy, xsgn ^ SCM_BIGSIGN(bigy));
595 SCM_BIGDIG *zds = SCM_BDIGITS(z);
596 if (xsgn) do {
597 num += x[i];
598 if (num < 0) {zds[i] ^= num + SCM_BIGRAD; num = -1;}
599 else {zds[i] ^= SCM_BIGLO(num); num = 0;}
600 } while (++i < nx);
601 else do {
602 zds[i] = zds[i] ^ x[i];
603 } while (++i < nx);
604
605 if (xsgn ^ SCM_BIGSIGN(bigy)) {
606 /* ========= Need to increment zds now =========== */
607 i = 0; num = 1;
608 while (i < ny) {
609 num += zds[i];
610 zds[i++] = SCM_BIGLO(num);
611 num = SCM_BIGDN(num);
612 if (!num) return scm_normbig(z);
613 }
614 }
615 return scm_normbig(z);
616}
617
618SCM scm_big_and(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int zsgn)
619/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60
MD
620/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
621/* return sign equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
622{
623 long num = -1;
624 scm_sizet i = 0;
625 SCM z;
626 SCM_BIGDIG *zds;
627 if (xsgn==zsgn) {
628 z = scm_copy_smaller(x, nx, zsgn);
629 x = SCM_BDIGITS(bigy);
630 xsgn = SCM_BIGSIGN(bigy);
631 }
632 else z = scm_copy_big_dec(bigy, zsgn);
633 zds = SCM_BDIGITS(z);
634
635 if (zsgn) {
636 if (xsgn) do {
637 num += x[i];
638 if (num < 0) {zds[i] &= num + SCM_BIGRAD; num = -1;}
639 else {zds[i] &= SCM_BIGLO(num); num = 0;}
640 } while (++i < nx);
641 else do zds[i] = zds[i] & ~x[i]; while (++i < nx);
642 /* ========= need to increment zds now =========== */
643 i = 0; num = 1;
644 while (i < nx) {
645 num += zds[i];
646 zds[i++] = SCM_BIGLO(num);
647 num = SCM_BIGDN(num);
648 if (!num) return scm_normbig(z);
649 }
650 }
651 else if (xsgn) do {
652 num += x[i];
653 if (num < 0) {zds[i] &= num + SCM_BIGRAD; num = -1;}
654 else {zds[i] &= ~SCM_BIGLO(num); num = 0;}
655 } while (++i < nx);
656 else do zds[i] = zds[i] & x[i]; while (++i < nx);
657 return scm_normbig(z);
658}
659
660SCM scm_big_test(SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy)
661/* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 662/* Assumes xsgn equals either 0 or SCM_BIGSIGNFLAG */
8a525303
GB
663{
664 SCM_BIGDIG *y;
665 scm_sizet i = 0;
666 long num = -1;
667 if (SCM_BIGSIGN(bigy) & xsgn) return SCM_BOOL_T;
668 if (SCM_NUMDIGS(bigy) != nx && xsgn) return SCM_BOOL_T;
669 y = SCM_BDIGITS(bigy);
670 if (xsgn)
671 do {
672 num += x[i];
673 if (num < 0) {
674 if (y[i] & ~(num + SCM_BIGRAD)) return SCM_BOOL_T;
675 num = -1;
676 }
677 else {
678 if (y[i] & ~SCM_BIGLO(num)) return SCM_BOOL_T;
679 num = 0;
680 }
681 } while (++i < nx);
682 else if SCM_BIGSIGN(bigy)
683 do {
684 num += y[i];
685 if (num < 0) {
686 if (x[i] & ~(num + SCM_BIGRAD)) return SCM_BOOL_T;
687 num = -1;
688 }
689 else {
690 if (x[i] & ~SCM_BIGLO(num)) return SCM_BOOL_T;
691 num = 0;
692 }
693 } while (++i < nx);
694 else
695 do if (x[i] & y[i]) return SCM_BOOL_T;
696 while (++i < nx);
697 return SCM_BOOL_F;
698}
699
700#endif
701
09fb7599 702
c3ee7520 703SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
1bbd0b84 704 (SCM n1, SCM n2),
b380b885
MD
705 "Returns the integer which is the bit-wise AND of the two integer\n"
706 "arguments.\n\n"
707 "Example:\n"
708 "@lisp\n"
709 "(number->string (logand #b1100 #b1010) 2)\n"
710 " @result{} \"1000\"")
1bbd0b84 711#define FUNC_NAME s_scm_logand
0f2d19dd 712{
9a00c9fc
DH
713 long int nn1;
714
09fb7599
DH
715 if (SCM_UNBNDP (n2)) {
716 if (SCM_UNBNDP (n1)) {
717 return SCM_MAKINUM (-1);
718 } else if (!SCM_NUMBERP (n1)) {
719 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
8a525303 720#ifndef SCM_RECKLESS
09fb7599 721 } else if (SCM_NUMBERP (n1)) {
d28da049 722 return n1;
09fb7599
DH
723 } else {
724 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
725#else
726 } else {
727 return n1;
728#endif
d28da049 729 }
8a525303 730 }
09fb7599
DH
731
732 if (SCM_INUMP (n1)) {
9a00c9fc 733 nn1 = SCM_INUM (n1);
09fb7599
DH
734 if (SCM_INUMP (n2)) {
735 long nn2 = SCM_INUM (n2);
736 return SCM_MAKINUM (nn1 & nn2);
09fb7599
DH
737 } else if SCM_BIGP (n2) {
738 intbig:
739 {
8a525303 740# ifndef SCM_DIGSTOOBIG
09fb7599
DH
741 long z = scm_pseudolong (nn1);
742 if ((nn1 < 0) && SCM_BIGSIGN (n2)) {
743 return scm_big_ior ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
744 SCM_BIGSIGNFLAG, n2);
745 } else {
746 return scm_big_and ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
747 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, 0);
748 }
8a525303 749# else
09fb7599
DH
750 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
751 scm_longdigs (nn1, zdigs);
752 if ((nn1 < 0) && SCM_BIGSIGN (n2)) {
753 return scm_big_ior (zdigs, SCM_DIGSPERLONG, SCM_BIGSIGNFLAG, n2);
754 } else {
755 return scm_big_and (zdigs, SCM_DIGSPERLONG,
756 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, 0);
757 }
8a525303 758# endif
09fb7599 759 }
09fb7599
DH
760 } else {
761 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
762 }
09fb7599
DH
763 } else if (SCM_BIGP (n1)) {
764 if (SCM_INUMP (n2)) {
765 SCM_SWAP (n1, n2);
9a00c9fc 766 nn1 = SCM_INUM (n1);
09fb7599
DH
767 goto intbig;
768 } else if (SCM_BIGP (n2)) {
769 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
770 SCM_SWAP (n1, n2);
771 };
772 if ((SCM_BIGSIGN (n1)) && SCM_BIGSIGN (n2)) {
773 return scm_big_ior (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
774 SCM_BIGSIGNFLAG, n2);
775 } else {
776 return scm_big_and (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
777 SCM_BIGSIGN (n1), n2, 0);
778 }
779 } else {
780 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
781 }
09fb7599
DH
782 } else {
783 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
784 }
0f2d19dd 785}
1bbd0b84 786#undef FUNC_NAME
0f2d19dd 787
09fb7599 788
c3ee7520 789SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
1bbd0b84 790 (SCM n1, SCM n2),
b380b885
MD
791 "Returns the integer which is the bit-wise OR of the two integer\n"
792 "arguments.\n\n"
793 "Example:\n"
794 "@lisp\n"
795 "(number->string (logior #b1100 #b1010) 2)\n"
796 " @result{} \"1110\"\n"
797 "@end lisp")
1bbd0b84 798#define FUNC_NAME s_scm_logior
0f2d19dd 799{
9a00c9fc
DH
800 long int nn1;
801
09fb7599
DH
802 if (SCM_UNBNDP (n2)) {
803 if (SCM_UNBNDP (n1)) {
804 return SCM_INUM0;
8a525303 805#ifndef SCM_RECKLESS
09fb7599 806 } else if (SCM_NUMBERP (n1)) {
d28da049 807 return n1;
09fb7599
DH
808 } else {
809 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
810#else
811 } else {
812 return n1;
813#endif
d28da049 814 }
8a525303 815 }
09fb7599
DH
816
817 if (SCM_INUMP (n1)) {
9a00c9fc 818 nn1 = SCM_INUM (n1);
09fb7599
DH
819 if (SCM_INUMP (n2)) {
820 long nn2 = SCM_INUM (n2);
821 return SCM_MAKINUM (nn1 | nn2);
09fb7599
DH
822 } else if (SCM_BIGP (n2)) {
823 intbig:
824 {
8a525303 825# ifndef SCM_DIGSTOOBIG
09fb7599
DH
826 long z = scm_pseudolong (nn1);
827 if ((!(nn1 < 0)) && !SCM_BIGSIGN (n2)) {
828 return scm_big_ior ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
829 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
830 } else {
831 return scm_big_and ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
832 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, SCM_BIGSIGNFLAG);
833 }
8a525303 834# else
09fb7599
DH
835 BIGDIG zdigs [DIGSPERLONG];
836 scm_longdigs (nn1, zdigs);
837 if ((!(nn1 < 0)) && !SCM_BIGSIGN (n2)) {
838 return scm_big_ior (zdigs, SCM_DIGSPERLONG,
839 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
840 } else {
841 return scm_big_and (zdigs, SCM_DIGSPERLONG,
842 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, SCM_BIGSIGNFLAG);
843 }
8a525303 844# endif
09fb7599 845 }
09fb7599
DH
846 } else {
847 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
848 }
09fb7599
DH
849 } else if (SCM_BIGP (n1)) {
850 if (SCM_INUMP (n2)) {
851 SCM_SWAP (n1, n2);
9a00c9fc 852 nn1 = SCM_INUM (n1);
09fb7599
DH
853 goto intbig;
854 } else if (SCM_BIGP (n2)) {
855 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
856 SCM_SWAP (n1, n2);
857 };
858 if ((!SCM_BIGSIGN (n1)) && !SCM_BIGSIGN (n2)) {
859 return scm_big_ior (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
860 SCM_BIGSIGN (n1), n2);
861 } else {
862 return scm_big_and (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
863 SCM_BIGSIGN (n1), n2, SCM_BIGSIGNFLAG);
864 }
865 } else {
866 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
867 }
09fb7599
DH
868 } else {
869 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
870 }
0f2d19dd 871}
1bbd0b84 872#undef FUNC_NAME
0f2d19dd 873
09fb7599 874
c3ee7520 875SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
1bbd0b84 876 (SCM n1, SCM n2),
b380b885
MD
877 "Returns the integer which is the bit-wise XOR of the two integer\n"
878 "arguments.\n\n"
879 "Example:\n"
880 "@lisp\n"
881 "(number->string (logxor #b1100 #b1010) 2)\n"
882 " @result{} \"110\"\n"
883 "@end lisp")
1bbd0b84 884#define FUNC_NAME s_scm_logxor
0f2d19dd 885{
9a00c9fc
DH
886 long int nn1;
887
09fb7599
DH
888 if (SCM_UNBNDP (n2)) {
889 if (SCM_UNBNDP (n1)) {
890 return SCM_INUM0;
8a525303 891#ifndef SCM_RECKLESS
09fb7599
DH
892 } else if (SCM_NUMBERP (n1)) {
893 return n1;
894 } else {
895 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
896#else
897 } else {
d28da049 898 return n1;
09fb7599 899#endif
d28da049 900 }
8a525303 901 }
09fb7599
DH
902
903 if (SCM_INUMP (n1)) {
9a00c9fc 904 nn1 = SCM_INUM (n1);
09fb7599
DH
905 if (SCM_INUMP (n2)) {
906 long nn2 = SCM_INUM (n2);
907 return SCM_MAKINUM (nn1 ^ nn2);
09fb7599
DH
908 } else if (SCM_BIGP (n2)) {
909 intbig:
8a525303
GB
910 {
911# ifndef SCM_DIGSTOOBIG
09fb7599
DH
912 long z = scm_pseudolong (nn1);
913 return scm_big_xor ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
914 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 915# else
09fb7599
DH
916 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
917 scm_longdigs (nn1, zdigs);
918 return scm_big_xor (zdigs, SCM_DIGSPERLONG,
919 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303
GB
920# endif
921 }
09fb7599
DH
922 } else {
923 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
924 }
09fb7599
DH
925 } else if (SCM_BIGP (n1)) {
926 if (SCM_INUMP (n2)) {
927 SCM_SWAP (n1, n2);
9a00c9fc 928 nn1 = SCM_INUM (n1);
09fb7599
DH
929 goto intbig;
930 } else if (SCM_BIGP (n2)) {
931 if (SCM_NUMDIGS(n1) > SCM_NUMDIGS(n2)) {
932 SCM_SWAP (n1, n2);
933 }
934 return scm_big_xor (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
935 SCM_BIGSIGN (n1), n2);
936 } else {
937 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
938 }
09fb7599
DH
939 } else {
940 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
941 }
0f2d19dd 942}
1bbd0b84 943#undef FUNC_NAME
0f2d19dd 944
09fb7599 945
a1ec6916 946SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1bbd0b84 947 (SCM n1, SCM n2),
b380b885
MD
948 "@example\n"
949 "(logtest j k) @equiv{} (not (zero? (logand j k)))\n\n"
950 "(logtest #b0100 #b1011) @result{} #f\n"
951 "(logtest #b0100 #b0111) @result{} #t\n"
952 "@end example")
1bbd0b84 953#define FUNC_NAME s_scm_logtest
0f2d19dd 954{
9a00c9fc
DH
955 long int nn1;
956
f8de44c1 957 if (SCM_INUMP (n1)) {
9a00c9fc 958 nn1 = SCM_INUM (n1);
f8de44c1
DH
959 if (SCM_INUMP (n2)) {
960 long nn2 = SCM_INUM (n2);
961 return SCM_BOOL (nn1 & nn2);
f8de44c1
DH
962 } else if (SCM_BIGP (n2)) {
963 intbig:
964 {
8a525303 965# ifndef SCM_DIGSTOOBIG
f8de44c1
DH
966 long z = scm_pseudolong (nn1);
967 return scm_big_test ((SCM_BIGDIG *)&z, SCM_DIGSPERLONG,
968 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 969# else
f8de44c1
DH
970 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
971 scm_longdigs (nn1, zdigs);
972 return scm_big_test (zdigs, SCM_DIGSPERLONG,
973 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 974# endif
f8de44c1 975 }
f8de44c1
DH
976 } else {
977 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
978 }
f8de44c1
DH
979 } else if (SCM_BIGP (n1)) {
980 if (SCM_INUMP (n2)) {
981 SCM_SWAP (n1, n2);
9a00c9fc 982 nn1 = SCM_INUM (n1);
f8de44c1
DH
983 goto intbig;
984 } else if (SCM_BIGP (n2)) {
985 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
986 SCM_SWAP (n1, n2);
987 }
988 return scm_big_test (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
989 SCM_BIGSIGN (n1), n2);
990 } else {
991 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
992 }
f8de44c1
DH
993 } else {
994 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
995 }
0f2d19dd 996}
1bbd0b84 997#undef FUNC_NAME
0f2d19dd 998
c1bfcf60 999
a1ec6916 1000SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 1001 (SCM index, SCM j),
b380b885
MD
1002 "@example\n"
1003 "(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j)\n\n"
1004 "(logbit? 0 #b1101) @result{} #t\n"
1005 "(logbit? 1 #b1101) @result{} #f\n"
1006 "(logbit? 2 #b1101) @result{} #t\n"
1007 "(logbit? 3 #b1101) @result{} #t\n"
1008 "(logbit? 4 #b1101) @result{} #f\n"
1009 "@end example")
1bbd0b84 1010#define FUNC_NAME s_scm_logbit_p
0f2d19dd 1011{
8a525303
GB
1012 SCM_ASSERT(SCM_INUMP(index) && SCM_INUM(index) >= 0, index, SCM_ARG1, FUNC_NAME);
1013#ifdef SCM_BIGDIG
1014 if SCM_NINUMP(j) {
09fb7599 1015 SCM_ASSERT(SCM_BIGP (j), j, SCM_ARG2, FUNC_NAME);
8a525303
GB
1016 if (SCM_NUMDIGS(j) * SCM_BITSPERDIG < SCM_INUM(index)) return SCM_BOOL_F;
1017 else if SCM_BIGSIGN(j) {
1018 long num = -1;
1019 scm_sizet i = 0;
1020 SCM_BIGDIG *x = SCM_BDIGITS(j);
1021 scm_sizet nx = SCM_INUM(index)/SCM_BITSPERDIG;
1022 while (!0) {
1023 num += x[i];
1024 if (nx==i++)
1025 return ((1L << (SCM_INUM(index)%SCM_BITSPERDIG)) & num) ? SCM_BOOL_F : SCM_BOOL_T;
1026 if (num < 0) num = -1;
1027 else num = 0;
1028 }
1029 }
1030 else return (SCM_BDIGITS(j)[SCM_INUM(index)/SCM_BITSPERDIG] &
1031 (1L << (SCM_INUM(index)%SCM_BITSPERDIG))) ? SCM_BOOL_T : SCM_BOOL_F;
1032 }
1033#else
1034 SCM_ASSERT(SCM_INUMP(j), j, SCM_ARG2, FUNC_NAME);
1035#endif
1036 return ((1L << SCM_INUM(index)) & SCM_INUM(j)) ? SCM_BOOL_T : SCM_BOOL_F;
0f2d19dd 1037}
1bbd0b84 1038#undef FUNC_NAME
0f2d19dd 1039
a1ec6916 1040SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 1041 (SCM n),
b380b885
MD
1042 "Returns the integer which is the 2s-complement of the integer argument.\n\n"
1043 "Example:\n"
1044 "@lisp\n"
1045 "(number->string (lognot #b10000000) 2)\n"
1046 " @result{} \"-10000001\"\n"
1047 "(number->string (lognot #b0) 2)\n"
1048 " @result{} \"-1\"\n"
1049 "@end lisp\n"
1050 "")
1bbd0b84 1051#define FUNC_NAME s_scm_lognot
0f2d19dd 1052{
f872b822 1053 return scm_difference (SCM_MAKINUM (-1L), n);
0f2d19dd 1054}
1bbd0b84 1055#undef FUNC_NAME
0f2d19dd 1056
a1ec6916 1057SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 1058 (SCM n, SCM k),
b380b885
MD
1059 "Returns @var{n} raised to the non-negative integer exponent @var{k}.\n\n"
1060 "Example:\n"
1061 "@lisp\n"
1062 "(integer-expt 2 5)\n"
1063 " @result{} 32\n"
1064 "(integer-expt -3 3)\n"
1065 " @result{} -27\n"
1066 "@end lisp")
1bbd0b84 1067#define FUNC_NAME s_scm_integer_expt
0f2d19dd 1068{
f872b822 1069 SCM acc = SCM_MAKINUM (1L);
1bbd0b84 1070 int i2;
0f2d19dd 1071#ifdef SCM_BIGDIG
4260a7fc 1072 if (SCM_EQ_P (n, SCM_INUM0) || SCM_EQ_P (n, acc))
2cd04b42 1073 return n;
4260a7fc
DH
1074 else if (SCM_EQ_P (n, SCM_MAKINUM (-1L)))
1075 return SCM_FALSEP (scm_even_p (k)) ? n : acc;
0f2d19dd 1076#endif
2cd04b42 1077 SCM_VALIDATE_ULONG_COPY (2,k,i2);
1bbd0b84 1078 if (i2 < 0)
f872b822 1079 {
1bbd0b84 1080 i2 = -i2;
2cd04b42 1081 n = scm_divide (n, SCM_UNDEFINED);
f872b822
MD
1082 }
1083 while (1)
1084 {
1bbd0b84 1085 if (0 == i2)
f872b822 1086 return acc;
1bbd0b84 1087 if (1 == i2)
2cd04b42 1088 return scm_product (acc, n);
1bbd0b84 1089 if (i2 & 1)
2cd04b42
GB
1090 acc = scm_product (acc, n);
1091 n = scm_product (n, n);
1bbd0b84 1092 i2 >>= 1;
f872b822 1093 }
0f2d19dd 1094}
1bbd0b84 1095#undef FUNC_NAME
0f2d19dd 1096
a1ec6916 1097SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 1098 (SCM n, SCM cnt),
3ab9f56e
DH
1099 "The function ash performs an arithmetic shift left by CNT bits\n"
1100 "(or shift right, if CNT is negative). 'Arithmetic' means, that\n"
1101 "the function does not guarantee to keep the bit structure of N,\n"
1102 "but rather guarantees that the result will always be rounded\n"
1103 "towards minus infinity. Therefore, the results of ash and a\n"
1104 "corresponding bitwise shift will differ if N is negative.\n\n"
1105 "Formally, the function returns an integer equivalent to\n"
1106 "@code{(inexact->exact (floor (* N (expt 2 CNT))))}.@refill\n\n"
b380b885
MD
1107 "Example:\n"
1108 "@lisp\n"
1109 "(number->string (ash #b1 3) 2)\n"
a3c8b9fc
MD
1110 " @result{} \"1000\""
1111 "(number->string (ash #b1010 -1) 2)"
1112 " @result{} \"101\""
1113 "@end lisp")
1bbd0b84 1114#define FUNC_NAME s_scm_ash
0f2d19dd 1115{
3ab9f56e
DH
1116 long bits_to_shift;
1117
1118#ifndef SCM_BIGDIG
1119 SCM_VALIDATE_INUM (1, n)
1120#endif
1121 SCM_VALIDATE_INUM (2, cnt);
1122
1123 bits_to_shift = SCM_INUM (cnt);
0f2d19dd 1124#ifdef SCM_BIGDIG
3ab9f56e
DH
1125 if (bits_to_shift < 0) {
1126 /* Shift right by abs(cnt) bits. This is realized as a division by
1127 div:=2^abs(cnt). However, to guarantee the floor rounding, negative
1128 values require some special treatment.
1129 */
1130 SCM div = scm_integer_expt (SCM_MAKINUM (2), SCM_MAKINUM (-bits_to_shift));
1131 if (SCM_FALSEP (scm_negative_p (n)))
1132 return scm_quotient (n, div);
1133 else
1134 return scm_sum (SCM_MAKINUM (-1L),
1135 scm_quotient (scm_sum (SCM_MAKINUM (1L), n), div));
1136 } else
1137 /* Shift left is done by multiplication with 2^CNT */
f872b822 1138 return scm_product (n, scm_integer_expt (SCM_MAKINUM (2), cnt));
0f2d19dd 1139#else
3ab9f56e
DH
1140 if (bits_to_shift < 0)
1141 /* Signed right shift (SCM_SRS does it right) by abs(cnt) bits. */
1142 return SCM_MAKINUM (SCM_SRS (SCM_INUM (n), -bits_to_shift));
1143 else {
1144 /* Shift left, but make sure not to leave the range of inums */
1145 SCM res = SCM_MAKINUM (SCM_INUM (n) << cnt);
1146 if (SCM_INUM (res) >> cnt != SCM_INUM (n))
1147 scm_num_overflow (FUNC_NAME);
1148 return res;
1149 }
0f2d19dd
JB
1150#endif
1151}
1bbd0b84 1152#undef FUNC_NAME
0f2d19dd 1153
1bbd0b84 1154/* GJB:FIXME: do not use SCMs as integers! */
a1ec6916 1155SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 1156 (SCM n, SCM start, SCM end),
b380b885
MD
1157 "Returns the integer composed of the @var{start} (inclusive) through\n"
1158 "@var{end} (exclusive) bits of @var{n}. The @var{start}th bit becomes\n"
1159 "the 0-th bit in the result.@refill\n\n"
1160 "Example:\n"
1161 "@lisp\n"
1162 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
1163 " @result{} \"1010\"\n"
1164 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
1165 " @result{} \"10110\"\n"
1166 "@end lisp")
1bbd0b84 1167#define FUNC_NAME s_scm_bit_extract
0f2d19dd 1168{
c1bfcf60 1169 int istart, iend;
3b3b36dd 1170 SCM_VALIDATE_INUM (1,n);
c1bfcf60
GB
1171 SCM_VALIDATE_INUM_MIN_COPY (2,start,0,istart);
1172 SCM_VALIDATE_INUM_MIN_COPY (3, end, 0, iend);
1173 SCM_ASSERT_RANGE (3, end, (iend >= istart));
0f2d19dd 1174#ifdef SCM_BIGDIG
f872b822 1175 if (SCM_NINUMP (n))
0f2d19dd 1176 return
f872b822 1177 scm_logand (scm_difference (scm_integer_expt (SCM_MAKINUM (2),
c1bfcf60 1178 SCM_MAKINUM (iend - istart)),
f872b822 1179 SCM_MAKINUM (1L)),
c1bfcf60 1180 scm_ash (n, SCM_MAKINUM (-istart)));
0f2d19dd 1181#else
3b3b36dd 1182 SCM_VALIDATE_INUM (1,n);
0f2d19dd 1183#endif
c1bfcf60 1184 return SCM_MAKINUM ((SCM_INUM (n) >> istart) & ((1L << (iend - istart)) - 1));
0f2d19dd 1185}
1bbd0b84 1186#undef FUNC_NAME
0f2d19dd 1187
e4755e5c
JB
1188static const char scm_logtab[] = {
1189 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
1190};
1cc91f1b 1191
a1ec6916 1192SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 1193 (SCM n),
b380b885
MD
1194 "Returns the number of bits in integer @var{n}. If integer is positive,\n"
1195 "the 1-bits in its binary representation are counted. If negative, the\n"
1196 "0-bits in its two's-complement binary representation are counted. If 0,\n"
1197 "0 is returned.\n\n"
1198 "Example:\n"
1199 "@lisp\n"
1200 "(logcount #b10101010)\n"
1201 " @result{} 4\n"
1202 "(logcount 0)\n"
1203 " @result{} 0\n"
1204 "(logcount -2)\n"
1205 " @result{} 1\n"
1206 "@end lisp")
1bbd0b84 1207#define FUNC_NAME s_scm_logcount
0f2d19dd
JB
1208{
1209 register unsigned long c = 0;
1210 register long nn;
1211#ifdef SCM_BIGDIG
f872b822
MD
1212 if (SCM_NINUMP (n))
1213 {
1214 scm_sizet i;
1215 SCM_BIGDIG *ds, d;
3b3b36dd 1216 SCM_VALIDATE_BIGINT (1,n);
f872b822
MD
1217 if (SCM_BIGSIGN (n))
1218 return scm_logcount (scm_difference (SCM_MAKINUM (-1L), n));
1219 ds = SCM_BDIGITS (n);
1220 for (i = SCM_NUMDIGS (n); i--;)
1221 for (d = ds[i]; d; d >>= 4)
1222 c += scm_logtab[15 & d];
1223 return SCM_MAKINUM (c);
1224 }
0f2d19dd 1225#else
3b3b36dd 1226 SCM_VALIDATE_INUM (1,n);
0f2d19dd 1227#endif
f872b822
MD
1228 if ((nn = SCM_INUM (n)) < 0)
1229 nn = -1 - nn;
1230 for (; nn; nn >>= 4)
1231 c += scm_logtab[15 & nn];
1232 return SCM_MAKINUM (c);
0f2d19dd 1233}
1bbd0b84
GB
1234#undef FUNC_NAME
1235
0f2d19dd 1236
e4755e5c
JB
1237static const char scm_ilentab[] = {
1238 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
1239};
1cc91f1b 1240
a1ec6916 1241SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
1bbd0b84 1242 (SCM n),
b380b885
MD
1243 "Returns the number of bits neccessary to represent @var{n}.\n\n"
1244 "Example:\n"
1245 "@lisp\n"
1246 "(integer-length #b10101010)\n"
1247 " @result{} 8\n"
1248 "(integer-length 0)\n"
1249 " @result{} 0\n"
1250 "(integer-length #b1111)\n"
1251 " @result{} 4\n"
1252 "@end lisp")
1bbd0b84 1253#define FUNC_NAME s_scm_integer_length
0f2d19dd
JB
1254{
1255 register unsigned long c = 0;
1256 register long nn;
1257 unsigned int l = 4;
1258#ifdef SCM_BIGDIG
f872b822
MD
1259 if (SCM_NINUMP (n))
1260 {
1261 SCM_BIGDIG *ds, d;
3b3b36dd 1262 SCM_VALIDATE_BIGINT (1,n);
f872b822
MD
1263 if (SCM_BIGSIGN (n))
1264 return scm_integer_length (scm_difference (SCM_MAKINUM (-1L), n));
1265 ds = SCM_BDIGITS (n);
1266 d = ds[c = SCM_NUMDIGS (n) - 1];
1267 for (c *= SCM_BITSPERDIG; d; d >>= 4)
1268 {
1269 c += 4;
1270 l = scm_ilentab[15 & d];
1271 }
1272 return SCM_MAKINUM (c - 4 + l);
1273 }
0f2d19dd 1274#else
3b3b36dd 1275 SCM_VALIDATE_INUM (1,n);
0f2d19dd 1276#endif
f872b822
MD
1277 if ((nn = SCM_INUM (n)) < 0)
1278 nn = -1 - nn;
1279 for (; nn; nn >>= 4)
1280 {
1281 c += 4;
1282 l = scm_ilentab[15 & nn];
1283 }
1284 return SCM_MAKINUM (c - 4 + l);
0f2d19dd 1285}
1bbd0b84 1286#undef FUNC_NAME
0f2d19dd
JB
1287
1288
1289#ifdef SCM_BIGDIG
e4755e5c 1290static const char s_bignum[] = "bignum";
1cc91f1b 1291
0f2d19dd 1292SCM
1bbd0b84 1293scm_mkbig (scm_sizet nlen, int sign)
0f2d19dd 1294{
c209c88e
GB
1295 SCM v;
1296 /* Cast to long int to avoid signed/unsigned comparison warnings. */
f3ae5d60
MD
1297 if ((( ((long int) nlen) << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD)
1298 != (long int) nlen)
e4755e5c 1299 scm_wta (SCM_MAKINUM (nlen), (char *) SCM_NALLOC, s_bignum);
c209c88e 1300
f872b822 1301 SCM_NEWCELL (v);
0f2d19dd 1302 SCM_DEFER_INTS;
f872b822 1303 SCM_SETCHARS (v, scm_must_malloc ((long) (nlen * sizeof (SCM_BIGDIG)),
e4755e5c 1304 s_bignum));
f3ae5d60 1305 SCM_SETNUMDIGS (v, nlen, sign);
0f2d19dd
JB
1306 SCM_ALLOW_INTS;
1307 return v;
1308}
1309
1cc91f1b 1310
0f2d19dd 1311SCM
1bbd0b84 1312scm_big2inum (SCM b, scm_sizet l)
0f2d19dd
JB
1313{
1314 unsigned long num = 0;
f872b822
MD
1315 SCM_BIGDIG *tmp = SCM_BDIGITS (b);
1316 while (l--)
1317 num = SCM_BIGUP (num) + tmp[l];
f3ae5d60 1318 if (!SCM_BIGSIGN (b))
f872b822
MD
1319 {
1320 if (SCM_POSFIXABLE (num))
1321 return SCM_MAKINUM (num);
1322 }
1323 else if (SCM_UNEGFIXABLE (num))
1324 return SCM_MAKINUM (-num);
0f2d19dd
JB
1325 return b;
1326}
1327
1328
e4755e5c 1329static const char s_adjbig[] = "scm_adjbig";
1cc91f1b 1330
0f2d19dd 1331SCM
1bbd0b84 1332scm_adjbig (SCM b, scm_sizet nlen)
0f2d19dd 1333{
2bf746cc 1334 scm_sizet nsiz = nlen;
f3ae5d60 1335 if (((nsiz << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD) != nlen)
f872b822 1336 scm_wta (scm_ulong2num (nsiz), (char *) SCM_NALLOC, s_adjbig);
2bf746cc 1337
0f2d19dd 1338 SCM_DEFER_INTS;
2bf746cc
JB
1339 {
1340 SCM_BIGDIG *digits
1341 = ((SCM_BIGDIG *)
f872b822
MD
1342 scm_must_realloc ((char *) SCM_CHARS (b),
1343 (long) (SCM_NUMDIGS (b) * sizeof (SCM_BIGDIG)),
495ffc6e 1344 (long) (nsiz * sizeof (SCM_BIGDIG)), s_bignum));
2bf746cc
JB
1345
1346 SCM_SETCHARS (b, digits);
f3ae5d60 1347 SCM_SETNUMDIGS (b, nsiz, SCM_BIGSIGN (b));
2bf746cc 1348 }
0f2d19dd
JB
1349 SCM_ALLOW_INTS;
1350 return b;
1351}
1352
1353
1cc91f1b 1354
0f2d19dd 1355SCM
1bbd0b84 1356scm_normbig (SCM b)
0f2d19dd 1357{
f872b822
MD
1358#ifndef _UNICOS
1359 scm_sizet nlen = SCM_NUMDIGS (b);
0f2d19dd 1360#else
f872b822 1361 int nlen = SCM_NUMDIGS (b); /* unsigned nlen breaks on Cray when nlen => 0 */
0f2d19dd 1362#endif
f872b822
MD
1363 SCM_BIGDIG *zds = SCM_BDIGITS (b);
1364 while (nlen-- && !zds[nlen]);
1365 nlen++;
1366 if (nlen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
1367 if (SCM_INUMP (b = scm_big2inum (b, (scm_sizet) nlen)))
1368 return b;
1369 if (SCM_NUMDIGS (b) == nlen)
1370 return b;
1371 return scm_adjbig (b, (scm_sizet) nlen);
0f2d19dd
JB
1372}
1373
1374
1cc91f1b 1375
0f2d19dd 1376SCM
1bbd0b84 1377scm_copybig (SCM b, int sign)
0f2d19dd 1378{
f872b822
MD
1379 scm_sizet i = SCM_NUMDIGS (b);
1380 SCM ans = scm_mkbig (i, sign);
1381 SCM_BIGDIG *src = SCM_BDIGITS (b), *dst = SCM_BDIGITS (ans);
1382 while (i--)
1383 dst[i] = src[i];
0f2d19dd
JB
1384 return ans;
1385}
1386
1387
1cc91f1b 1388
0f2d19dd 1389SCM
1bbd0b84 1390scm_long2big (long n)
0f2d19dd
JB
1391{
1392 scm_sizet i = 0;
1393 SCM_BIGDIG *digits;
f872b822
MD
1394 SCM ans = scm_mkbig (SCM_DIGSPERLONG, n < 0);
1395 digits = SCM_BDIGITS (ans);
1396 if (n < 0)
1397 n = -n;
1398 while (i < SCM_DIGSPERLONG)
1399 {
1400 digits[i++] = SCM_BIGLO (n);
1401 n = SCM_BIGDN ((unsigned long) n);
1402 }
0f2d19dd
JB
1403 return ans;
1404}
1405
5c11cc9d 1406#ifdef HAVE_LONG_LONGS
1cc91f1b 1407
0f2d19dd 1408SCM
1bbd0b84 1409scm_long_long2big (long_long n)
0f2d19dd
JB
1410{
1411 scm_sizet i;
1412 SCM_BIGDIG *digits;
1413 SCM ans;
1414 int n_digits;
1415
1416 {
1417 long tn;
1418 tn = (long) n;
f872b822 1419 if ((long long) tn == n)
0f2d19dd
JB
1420 return scm_long2big (tn);
1421 }
1422
1423 {
1424 long_long tn;
1425
1426 for (tn = n, n_digits = 0;
1427 tn;
f872b822 1428 ++n_digits, tn = SCM_BIGDN ((ulong_long) tn))
0f2d19dd
JB
1429 ;
1430 }
1431
1432 i = 0;
f872b822
MD
1433 ans = scm_mkbig (n_digits, n < 0);
1434 digits = SCM_BDIGITS (ans);
0f2d19dd
JB
1435 if (n < 0)
1436 n = -n;
f872b822
MD
1437 while (i < n_digits)
1438 {
1439 digits[i++] = SCM_BIGLO (n);
1440 n = SCM_BIGDN ((ulong_long) n);
1441 }
0f2d19dd
JB
1442 return ans;
1443}
1444#endif
1445
1cc91f1b 1446
0f2d19dd 1447SCM
1bbd0b84 1448scm_2ulong2big (unsigned long *np)
0f2d19dd
JB
1449{
1450 unsigned long n;
1451 scm_sizet i;
1452 SCM_BIGDIG *digits;
1453 SCM ans;
1454
f872b822
MD
1455 ans = scm_mkbig (2 * SCM_DIGSPERLONG, 0);
1456 digits = SCM_BDIGITS (ans);
0f2d19dd
JB
1457
1458 n = np[0];
1459 for (i = 0; i < SCM_DIGSPERLONG; ++i)
1460 {
f872b822
MD
1461 digits[i] = SCM_BIGLO (n);
1462 n = SCM_BIGDN ((unsigned long) n);
0f2d19dd
JB
1463 }
1464 n = np[1];
1465 for (i = 0; i < SCM_DIGSPERLONG; ++i)
1466 {
f872b822
MD
1467 digits[i + SCM_DIGSPERLONG] = SCM_BIGLO (n);
1468 n = SCM_BIGDN ((unsigned long) n);
0f2d19dd
JB
1469 }
1470 return ans;
1471}
1472
1473
1cc91f1b 1474
0f2d19dd 1475SCM
1bbd0b84 1476scm_ulong2big (unsigned long n)
0f2d19dd
JB
1477{
1478 scm_sizet i = 0;
1479 SCM_BIGDIG *digits;
f872b822
MD
1480 SCM ans = scm_mkbig (SCM_DIGSPERLONG, 0);
1481 digits = SCM_BDIGITS (ans);
1482 while (i < SCM_DIGSPERLONG)
1483 {
1484 digits[i++] = SCM_BIGLO (n);
1485 n = SCM_BIGDN (n);
1486 }
0f2d19dd
JB
1487 return ans;
1488}
1489
1490
1cc91f1b 1491
0f2d19dd 1492int
1bbd0b84 1493scm_bigcomp (SCM x, SCM y)
0f2d19dd 1494{
f872b822
MD
1495 int xsign = SCM_BIGSIGN (x);
1496 int ysign = SCM_BIGSIGN (y);
0f2d19dd 1497 scm_sizet xlen, ylen;
2bf746cc
JB
1498
1499 /* Look at the signs, first. */
f872b822
MD
1500 if (ysign < xsign)
1501 return 1;
1502 if (ysign > xsign)
1503 return -1;
2bf746cc
JB
1504
1505 /* They're the same sign, so see which one has more digits. Note
1506 that, if they are negative, the longer number is the lesser. */
f872b822
MD
1507 ylen = SCM_NUMDIGS (y);
1508 xlen = SCM_NUMDIGS (x);
2bf746cc
JB
1509 if (ylen > xlen)
1510 return (xsign) ? -1 : 1;
f872b822
MD
1511 if (ylen < xlen)
1512 return (xsign) ? 1 : -1;
2bf746cc
JB
1513
1514 /* They have the same number of digits, so find the most significant
1515 digit where they differ. */
1516 while (xlen)
1517 {
1518 --xlen;
1519 if (SCM_BDIGITS (y)[xlen] != SCM_BDIGITS (x)[xlen])
1520 /* Make the discrimination based on the digit that differs. */
f872b822
MD
1521 return ((SCM_BDIGITS (y)[xlen] > SCM_BDIGITS (x)[xlen])
1522 ? (xsign ? -1 : 1)
1523 : (xsign ? 1 : -1));
2bf746cc
JB
1524 }
1525
1526 /* The numbers are identical. */
1527 return 0;
0f2d19dd
JB
1528}
1529
1530#ifndef SCM_DIGSTOOBIG
1531
1cc91f1b 1532
0f2d19dd 1533long
1bbd0b84 1534scm_pseudolong (long x)
0f2d19dd 1535{
f872b822
MD
1536 union
1537 {
0f2d19dd
JB
1538 long l;
1539 SCM_BIGDIG bd[SCM_DIGSPERLONG];
f872b822
MD
1540 }
1541 p;
0f2d19dd 1542 scm_sizet i = 0;
f872b822
MD
1543 if (x < 0)
1544 x = -x;
1545 while (i < SCM_DIGSPERLONG)
1546 {
1547 p.bd[i++] = SCM_BIGLO (x);
1548 x = SCM_BIGDN (x);
1549 }
0f2d19dd
JB
1550 /* p.bd[0] = SCM_BIGLO(x); p.bd[1] = SCM_BIGDN(x); */
1551 return p.l;
1552}
1553
1554#else
1555
1cc91f1b 1556
0f2d19dd 1557void
1bbd0b84 1558scm_longdigs (long x, SCM_BIGDIG digs[])
0f2d19dd
JB
1559{
1560 scm_sizet i = 0;
f872b822
MD
1561 if (x < 0)
1562 x = -x;
1563 while (i < SCM_DIGSPERLONG)
1564 {
1565 digs[i++] = SCM_BIGLO (x);
1566 x = SCM_BIGDN (x);
1567 }
0f2d19dd
JB
1568}
1569#endif
1570
1571
1cc91f1b 1572
0f2d19dd 1573SCM
1bbd0b84 1574scm_addbig (SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int sgny)
0f2d19dd
JB
1575{
1576 /* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 1577 /* Assumes xsgn and sgny scm_equal either 0 or SCM_BIGSIGNFLAG */
0f2d19dd 1578 long num = 0;
f872b822
MD
1579 scm_sizet i = 0, ny = SCM_NUMDIGS (bigy);
1580 SCM z = scm_copybig (bigy, SCM_BIGSIGN (bigy) ^ sgny);
1581 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1582 if (xsgn ^ SCM_BIGSIGN (z))
1583 {
1584 do
1585 {
1586 num += (long) zds[i] - x[i];
1587 if (num < 0)
1588 {
1589 zds[i] = num + SCM_BIGRAD;
1590 num = -1;
1591 }
1592 else
1593 {
1594 zds[i] = SCM_BIGLO (num);
1595 num = 0;
1596 }
1597 }
1598 while (++i < nx);
1599 if (num && nx == ny)
1600 {
1601 num = 1;
1602 i = 0;
4260a7fc 1603 SCM_SET_CELL_WORD_0 (z, SCM_CELL_WORD_0 (z) ^ SCM_BIGSIGNFLAG);
f872b822
MD
1604 do
1605 {
1606 num += (SCM_BIGRAD - 1) - zds[i];
1607 zds[i++] = SCM_BIGLO (num);
1608 num = SCM_BIGDN (num);
1609 }
1610 while (i < ny);
1611 }
1612 else
1613 while (i < ny)
1614 {
1615 num += zds[i];
1616 if (num < 0)
1617 {
1618 zds[i++] = num + SCM_BIGRAD;
1619 num = -1;
1620 }
1621 else
1622 {
1623 zds[i++] = SCM_BIGLO (num);
1624 num = 0;
1625 }
1626 }
1627 }
1628 else
1629 {
1630 do
1631 {
1632 num += (long) zds[i] + x[i];
1633 zds[i++] = SCM_BIGLO (num);
1634 num = SCM_BIGDN (num);
1635 }
1636 while (i < nx);
1637 if (!num)
1638 return z;
1639 while (i < ny)
1640 {
1641 num += zds[i];
1642 zds[i++] = SCM_BIGLO (num);
1643 num = SCM_BIGDN (num);
1644 if (!num)
1645 return z;
1646 }
1647 if (num)
1648 {
1649 z = scm_adjbig (z, ny + 1);
1650 SCM_BDIGITS (z)[ny] = num;
1651 return z;
1652 }
1653 }
1654 return scm_normbig (z);
0f2d19dd
JB
1655}
1656
1cc91f1b 1657
0f2d19dd 1658SCM
1bbd0b84 1659scm_mulbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn)
0f2d19dd
JB
1660{
1661 scm_sizet i = 0, j = nx + ny;
1662 unsigned long n = 0;
f872b822
MD
1663 SCM z = scm_mkbig (j, sgn);
1664 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1665 while (j--)
1666 zds[j] = 0;
1667 do
1668 {
1669 j = 0;
1670 if (x[i])
1671 {
1672 do
1673 {
1674 n += zds[i + j] + ((unsigned long) x[i] * y[j]);
1675 zds[i + j++] = SCM_BIGLO (n);
1676 n = SCM_BIGDN (n);
1677 }
1678 while (j < ny);
1679 if (n)
1680 {
1681 zds[i + j] = n;
1682 n = 0;
1683 }
1684 }
0f2d19dd 1685 }
f872b822
MD
1686 while (++i < nx);
1687 return scm_normbig (z);
0f2d19dd
JB
1688}
1689
1cc91f1b 1690
0f2d19dd 1691unsigned int
bb628794 1692scm_divbigdig (SCM_BIGDIG * ds, scm_sizet h, SCM_BIGDIG div)
0f2d19dd
JB
1693{
1694 register unsigned long t2 = 0;
f872b822
MD
1695 while (h--)
1696 {
1697 t2 = SCM_BIGUP (t2) + ds[h];
1698 ds[h] = t2 / div;
1699 t2 %= div;
1700 }
0f2d19dd
JB
1701 return t2;
1702}
1703
1704
1cc91f1b 1705
f4c627b3 1706static SCM
1bbd0b84 1707scm_divbigint (SCM x, long z, int sgn, int mode)
0f2d19dd 1708{
f872b822
MD
1709 if (z < 0)
1710 z = -z;
1711 if (z < SCM_BIGRAD)
1712 {
1713 register unsigned long t2 = 0;
1714 register SCM_BIGDIG *ds = SCM_BDIGITS (x);
1715 scm_sizet nd = SCM_NUMDIGS (x);
1716 while (nd--)
1717 t2 = (SCM_BIGUP (t2) + ds[nd]) % z;
1718 if (mode && t2)
1719 t2 = z - t2;
1720 return SCM_MAKINUM (sgn ? -t2 : t2);
1721 }
0f2d19dd
JB
1722 {
1723#ifndef SCM_DIGSTOOBIG
f872b822
MD
1724 unsigned long t2 = scm_pseudolong (z);
1725 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1726 (SCM_BIGDIG *) & t2, SCM_DIGSPERLONG,
1727 sgn, mode);
0f2d19dd
JB
1728#else
1729 SCM_BIGDIG t2[SCM_DIGSPERLONG];
f872b822
MD
1730 scm_longdigs (z, t2);
1731 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1732 t2, SCM_DIGSPERLONG,
1733 sgn, mode);
0f2d19dd
JB
1734#endif
1735 }
1736}
1737
1cc91f1b 1738
f4c627b3 1739static SCM
1bbd0b84 1740scm_divbigbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn, int modes)
0f2d19dd
JB
1741{
1742 /* modes description
f872b822
MD
1743 0 remainder
1744 1 scm_modulo
1745 2 quotient
f4c627b3 1746 3 quotient but returns SCM_UNDEFINED if division is not exact. */
0f2d19dd
JB
1747 scm_sizet i = 0, j = 0;
1748 long num = 0;
1749 unsigned long t2 = 0;
1750 SCM z, newy;
f872b822 1751 SCM_BIGDIG d = 0, qhat, *zds, *yds;
0f2d19dd
JB
1752 /* algorithm requires nx >= ny */
1753 if (nx < ny)
f872b822
MD
1754 switch (modes)
1755 {
1756 case 0: /* remainder -- just return x */
1757 z = scm_mkbig (nx, sgn);
1758 zds = SCM_BDIGITS (z);
1759 do
1760 {
1761 zds[i] = x[i];
1762 }
1763 while (++i < nx);
1764 return z;
1765 case 1: /* scm_modulo -- return y-x */
1766 z = scm_mkbig (ny, sgn);
1767 zds = SCM_BDIGITS (z);
1768 do
1769 {
1770 num += (long) y[i] - x[i];
1771 if (num < 0)
1772 {
1773 zds[i] = num + SCM_BIGRAD;
1774 num = -1;
1775 }
1776 else
1777 {
1778 zds[i] = num;
1779 num = 0;
1780 }
1781 }
1782 while (++i < nx);
1783 while (i < ny)
1784 {
1785 num += y[i];
1786 if (num < 0)
1787 {
1788 zds[i++] = num + SCM_BIGRAD;
1789 num = -1;
1790 }
1791 else
1792 {
1793 zds[i++] = num;
1794 num = 0;
1795 }
1796 }
1797 goto doadj;
1798 case 2:
1799 return SCM_INUM0; /* quotient is zero */
1800 case 3:
f4c627b3 1801 return SCM_UNDEFINED; /* the division is not exact */
0f2d19dd 1802 }
f872b822
MD
1803
1804 z = scm_mkbig (nx == ny ? nx + 2 : nx + 1, sgn);
1805 zds = SCM_BDIGITS (z);
1806 if (nx == ny)
1807 zds[nx + 1] = 0;
1808 while (!y[ny - 1])
1809 ny--; /* in case y came in as a psuedolong */
1810 if (y[ny - 1] < (SCM_BIGRAD >> 1))
1811 { /* normalize operands */
1812 d = SCM_BIGRAD / (y[ny - 1] + 1);
1813 newy = scm_mkbig (ny, 0);
1814 yds = SCM_BDIGITS (newy);
1815 while (j < ny)
1816 {
1817 t2 += (unsigned long) y[j] * d;
1818 yds[j++] = SCM_BIGLO (t2);
1819 t2 = SCM_BIGDN (t2);
1820 }
1821 y = yds;
1822 j = 0;
1823 t2 = 0;
1824 while (j < nx)
1825 {
1826 t2 += (unsigned long) x[j] * d;
1827 zds[j++] = SCM_BIGLO (t2);
1828 t2 = SCM_BIGDN (t2);
1829 }
1830 zds[j] = t2;
1831 }
1832 else
1833 {
1834 zds[j = nx] = 0;
1835 while (j--)
1836 zds[j] = x[j];
1837 }
1838 j = nx == ny ? nx + 1 : nx; /* dividend needs more digits than divisor */
1839 do
1840 { /* loop over digits of quotient */
1841 if (zds[j] == y[ny - 1])
1842 qhat = SCM_BIGRAD - 1;
1843 else
1844 qhat = (SCM_BIGUP (zds[j]) + zds[j - 1]) / y[ny - 1];
1845 if (!qhat)
1846 continue;
1847 i = 0;
1848 num = 0;
1849 t2 = 0;
1850 do
1851 { /* multiply and subtract */
1852 t2 += (unsigned long) y[i] * qhat;
1853 num += zds[j - ny + i] - SCM_BIGLO (t2);
1854 if (num < 0)
1855 {
1856 zds[j - ny + i] = num + SCM_BIGRAD;
1857 num = -1;
1858 }
1859 else
1860 {
1861 zds[j - ny + i] = num;
1862 num = 0;
1863 }
1864 t2 = SCM_BIGDN (t2);
1865 }
1866 while (++i < ny);
1867 num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
1868 while (num)
1869 { /* "add back" required */
1870 i = 0;
1871 num = 0;
1872 qhat--;
1873 do
1874 {
1875 num += (long) zds[j - ny + i] + y[i];
1876 zds[j - ny + i] = SCM_BIGLO (num);
1877 num = SCM_BIGDN (num);
1878 }
1879 while (++i < ny);
1880 num--;
1881 }
1882 if (modes & 2)
1883 zds[j] = qhat;
1884 }
1885 while (--j >= ny);
1886 switch (modes)
1887 {
1888 case 3: /* check that remainder==0 */
1889 for (j = ny; j && !zds[j - 1]; --j);
1890 if (j)
f4c627b3 1891 return SCM_UNDEFINED;
f872b822
MD
1892 case 2: /* move quotient down in z */
1893 j = (nx == ny ? nx + 2 : nx + 1) - ny;
1894 for (i = 0; i < j; i++)
1895 zds[i] = zds[i + ny];
1896 ny = i;
1897 break;
1898 case 1: /* subtract for scm_modulo */
1899 i = 0;
1900 num = 0;
1901 j = 0;
1902 do
1903 {
1904 num += y[i] - zds[i];
1905 j = j | zds[i];
1906 if (num < 0)
1907 {
1908 zds[i] = num + SCM_BIGRAD;
1909 num = -1;
1910 }
1911 else
1912 {
1913 zds[i] = num;
1914 num = 0;
1915 }
1916 }
1917 while (++i < ny);
1918 if (!j)
1919 return SCM_INUM0;
1920 case 0: /* just normalize remainder */
1921 if (d)
1922 scm_divbigdig (zds, ny, d);
1923 }
0f2d19dd 1924 doadj:
f872b822
MD
1925 for (j = ny; j && !zds[j - 1]; --j);
1926 if (j * SCM_BITSPERDIG <= sizeof (SCM) * SCM_CHAR_BIT)
1927 if (SCM_INUMP (z = scm_big2inum (z, j)))
1928 return z;
1929 return scm_adjbig (z, j);
0f2d19dd
JB
1930}
1931#endif
f872b822 1932\f
0f2d19dd
JB
1933
1934
1935
0f2d19dd
JB
1936
1937/*** NUMBERS -> STRINGS ***/
0f2d19dd 1938int scm_dblprec;
e4755e5c 1939static const double fx[] =
f872b822
MD
1940{ 0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5,
1941 5e-6, 5e-7, 5e-8, 5e-9, 5e-10,
1942 5e-11, 5e-12, 5e-13, 5e-14, 5e-15,
1943 5e-16, 5e-17, 5e-18, 5e-19, 5e-20};
0f2d19dd
JB
1944
1945
1946
1cc91f1b 1947
0f2d19dd 1948static scm_sizet
1bbd0b84 1949idbl2str (double f, char *a)
0f2d19dd
JB
1950{
1951 int efmt, dpt, d, i, wp = scm_dblprec;
1952 scm_sizet ch = 0;
1953 int exp = 0;
1954
f872b822
MD
1955 if (f == 0.0)
1956 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
1957 if (f < 0.0)
1958 {
1959 f = -f;
1960 a[ch++] = '-';
1961 }
1962 else if (f > 0.0);
1963 else
1964 goto funny;
1965 if (IS_INF (f))
1966 {
1967 if (ch == 0)
1968 a[ch++] = '+';
1969 funny:
1970 a[ch++] = '#';
1971 a[ch++] = '.';
1972 a[ch++] = '#';
1973 return ch;
1974 }
1975#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
1976 make-uniform-vector, from causing infinite loops. */
1977 while (f < 1.0)
1978 {
1979 f *= 10.0;
1980 if (exp-- < DBL_MIN_10_EXP)
1981 goto funny;
1982 }
1983 while (f > 10.0)
1984 {
1985 f *= 0.10;
1986 if (exp++ > DBL_MAX_10_EXP)
1987 goto funny;
1988 }
1989#else
1990 while (f < 1.0)
1991 {
1992 f *= 10.0;
1993 exp--;
1994 }
1995 while (f > 10.0)
1996 {
1997 f /= 10.0;
1998 exp++;
1999 }
2000#endif
2001 if (f + fx[wp] >= 10.0)
2002 {
2003 f = 1.0;
2004 exp++;
2005 }
0f2d19dd 2006 zero:
f872b822
MD
2007#ifdef ENGNOT
2008 dpt = (exp + 9999) % 3;
0f2d19dd
JB
2009 exp -= dpt++;
2010 efmt = 1;
f872b822
MD
2011#else
2012 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 2013 if (!efmt)
cda139a7
MD
2014 {
2015 if (exp < 0)
2016 {
2017 a[ch++] = '0';
2018 a[ch++] = '.';
2019 dpt = exp;
f872b822
MD
2020 while (++dpt)
2021 a[ch++] = '0';
cda139a7
MD
2022 }
2023 else
f872b822 2024 dpt = exp + 1;
cda139a7 2025 }
0f2d19dd
JB
2026 else
2027 dpt = 1;
f872b822
MD
2028#endif
2029
2030 do
2031 {
2032 d = f;
2033 f -= d;
2034 a[ch++] = d + '0';
2035 if (f < fx[wp])
2036 break;
2037 if (f + fx[wp] >= 1.0)
2038 {
2039 a[ch - 1]++;
2040 break;
2041 }
2042 f *= 10.0;
2043 if (!(--dpt))
2044 a[ch++] = '.';
0f2d19dd 2045 }
f872b822 2046 while (wp--);
0f2d19dd
JB
2047
2048 if (dpt > 0)
cda139a7 2049 {
f872b822 2050#ifndef ENGNOT
cda139a7
MD
2051 if ((dpt > 4) && (exp > 6))
2052 {
f872b822 2053 d = (a[0] == '-' ? 2 : 1);
cda139a7 2054 for (i = ch++; i > d; i--)
f872b822 2055 a[i] = a[i - 1];
cda139a7
MD
2056 a[d] = '.';
2057 efmt = 1;
2058 }
2059 else
f872b822 2060#endif
cda139a7 2061 {
f872b822
MD
2062 while (--dpt)
2063 a[ch++] = '0';
cda139a7
MD
2064 a[ch++] = '.';
2065 }
2066 }
f872b822
MD
2067 if (a[ch - 1] == '.')
2068 a[ch++] = '0'; /* trailing zero */
2069 if (efmt && exp)
2070 {
2071 a[ch++] = 'e';
2072 if (exp < 0)
2073 {
2074 exp = -exp;
2075 a[ch++] = '-';
2076 }
2077 for (i = 10; i <= exp; i *= 10);
2078 for (i /= 10; i; i /= 10)
2079 {
2080 a[ch++] = exp / i + '0';
2081 exp %= i;
2082 }
0f2d19dd 2083 }
0f2d19dd
JB
2084 return ch;
2085}
2086
1cc91f1b 2087
0f2d19dd 2088static scm_sizet
1bbd0b84 2089iflo2str (SCM flt, char *str)
0f2d19dd
JB
2090{
2091 scm_sizet i;
f3ae5d60
MD
2092 if (SCM_SLOPPY_REALP (flt))
2093 i = idbl2str (SCM_REAL_VALUE (flt), str);
0f2d19dd 2094 else
f872b822 2095 {
f3ae5d60
MD
2096 i = idbl2str (SCM_COMPLEX_REAL (flt), str);
2097 if (SCM_COMPLEX_IMAG (flt) != 0.0)
2098 {
2099 if (0 <= SCM_COMPLEX_IMAG (flt))
2100 str[i++] = '+';
2101 i += idbl2str (SCM_COMPLEX_IMAG (flt), &str[i]);
2102 str[i++] = 'i';
2103 }
f872b822 2104 }
0f2d19dd
JB
2105 return i;
2106}
0f2d19dd 2107
5c11cc9d 2108/* convert a long to a string (unterminated). returns the number of
1bbd0b84
GB
2109 characters in the result.
2110 rad is output base
2111 p is destination: worst case (base 2) is SCM_INTBUFLEN */
0f2d19dd 2112scm_sizet
1bbd0b84 2113scm_iint2str (long num, int rad, char *p)
0f2d19dd 2114{
5c11cc9d
GH
2115 scm_sizet j = 1;
2116 scm_sizet i;
2117 unsigned long n = (num < 0) ? -num : num;
2118
f872b822 2119 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2120 j++;
2121
2122 i = j;
2123 if (num < 0)
f872b822 2124 {
f872b822 2125 *p++ = '-';
5c11cc9d
GH
2126 j++;
2127 n = -num;
f872b822 2128 }
5c11cc9d
GH
2129 else
2130 n = num;
f872b822
MD
2131 while (i--)
2132 {
5c11cc9d
GH
2133 int d = n % rad;
2134
f872b822
MD
2135 n /= rad;
2136 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2137 }
0f2d19dd
JB
2138 return j;
2139}
2140
2141
2142#ifdef SCM_BIGDIG
1cc91f1b 2143
0f2d19dd 2144static SCM
1bbd0b84 2145big2str (SCM b, unsigned int radix)
0f2d19dd 2146{
f872b822
MD
2147 SCM t = scm_copybig (b, 0); /* sign of temp doesn't matter */
2148 register SCM_BIGDIG *ds = SCM_BDIGITS (t);
2149 scm_sizet i = SCM_NUMDIGS (t);
2150 scm_sizet j = radix == 16 ? (SCM_BITSPERDIG * i) / 4 + 2
2151 : radix >= 10 ? (SCM_BITSPERDIG * i * 241L) / 800 + 2
2152 : (SCM_BITSPERDIG * i) + 2;
0f2d19dd
JB
2153 scm_sizet k = 0;
2154 scm_sizet radct = 0;
2155 scm_sizet ch; /* jeh */
2156 SCM_BIGDIG radpow = 1, radmod = 0;
f872b822
MD
2157 SCM ss = scm_makstr ((long) j, 0);
2158 char *s = SCM_CHARS (ss), c;
2159 while ((long) radpow * radix < SCM_BIGRAD)
2160 {
2161 radpow *= radix;
2162 radct++;
2163 }
f3ae5d60 2164 s[0] = SCM_BIGSIGN (b) ? '-' : '+';
f872b822
MD
2165 while ((i || radmod) && j)
2166 {
2167 if (k == 0)
2168 {
2169 radmod = (SCM_BIGDIG) scm_divbigdig (ds, i, radpow);
2170 k = radct;
2171 if (!ds[i - 1])
2172 i--;
2173 }
2174 c = radmod % radix;
2175 radmod /= radix;
2176 k--;
2177 s[--j] = c < 10 ? c + '0' : c + 'a' - 10;
2178 }
0f2d19dd 2179 ch = s[0] == '-' ? 1 : 0; /* jeh */
f872b822
MD
2180 if (ch < j)
2181 { /* jeh */
2182 for (i = j; j < SCM_LENGTH (ss); j++)
2183 s[ch + j - i] = s[j]; /* jeh */
2184 scm_vector_set_length_x (ss, /* jeh */
4260a7fc 2185 SCM_MAKINUM (ch + SCM_LENGTH (ss) - i));
f872b822 2186 }
b098016b
JB
2187
2188 return scm_return_first (ss, t);
0f2d19dd
JB
2189}
2190#endif
2191
2192
a1ec6916 2193SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
2194 (SCM n, SCM radix),
2195 "Return a string holding the external representation of the\n"
2196 "number N in the given RADIX. If N is inexact, a radix of 10\n"
2197 "will be used.")
1bbd0b84 2198#define FUNC_NAME s_scm_number_to_string
0f2d19dd 2199{
1bbd0b84 2200 int base;
98cb6e75
DH
2201
2202 if (SCM_UNBNDP (radix)) {
2203 base = 10;
2204 } else {
2205 SCM_VALIDATE_INUM (2, radix);
2206 base = SCM_INUM (radix);
2207 SCM_ASSERT_RANGE (2, radix, base >= 2);
2208 }
2209
bb628794 2210 if (SCM_INUMP (n)) {
98cb6e75 2211 char num_buf [SCM_INTBUFLEN];
bb628794 2212 scm_sizet length = scm_iint2str (SCM_INUM (n), base, num_buf);
98cb6e75 2213 return scm_makfromstr (num_buf, length, 0);
bb628794
DH
2214 } else if (SCM_BIGP (n)) {
2215 return big2str (n, (unsigned int) base);
2216 } else if (SCM_INEXACTP (n)) {
98cb6e75 2217 char num_buf [SCM_FLOBUFLEN];
bb628794 2218 return scm_makfromstr (num_buf, iflo2str (n, num_buf), 0);
98cb6e75 2219 } else {
bb628794 2220 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd
JB
2221 }
2222}
1bbd0b84 2223#undef FUNC_NAME
0f2d19dd
JB
2224
2225
2226/* These print routines are stubbed here so that scm_repl.c doesn't need
f3ae5d60 2227 SCM_BIGDIG conditionals */
1cc91f1b 2228
0f2d19dd 2229int
f3ae5d60 2230scm_print_real (SCM sexp, SCM port, scm_print_state *pstate)
0f2d19dd 2231{
0f2d19dd 2232 char num_buf[SCM_FLOBUFLEN];
f872b822 2233 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
0f2d19dd
JB
2234 return !0;
2235}
2236
f3ae5d60
MD
2237int
2238scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate)
2239{
2240 char num_buf[SCM_FLOBUFLEN];
2241 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
2242 return !0;
2243}
1cc91f1b 2244
0f2d19dd 2245int
1bbd0b84 2246scm_bigprint (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd
JB
2247{
2248#ifdef SCM_BIGDIG
f872b822
MD
2249 exp = big2str (exp, (unsigned int) 10);
2250 scm_lfwrite (SCM_CHARS (exp), (scm_sizet) SCM_LENGTH (exp), port);
0f2d19dd 2251#else
f872b822 2252 scm_ipruk ("bignum", exp, port);
0f2d19dd
JB
2253#endif
2254 return !0;
2255}
2256/*** END nums->strs ***/
2257
2258/*** STRINGS -> NUMBERS ***/
2a8fecee
JB
2259
2260static SCM
1bbd0b84 2261scm_small_istr2int (char *str, long len, long radix)
2a8fecee
JB
2262{
2263 register long n = 0, ln;
2264 register int c;
2265 register int i = 0;
2266 int lead_neg = 0;
f872b822
MD
2267 if (0 >= len)
2268 return SCM_BOOL_F; /* zero scm_length */
2269 switch (*str)
2270 { /* leading sign */
2271 case '-':
2272 lead_neg = 1;
2273 case '+':
2274 if (++i == len)
2275 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2276 }
2a8fecee 2277
f872b822
MD
2278 do
2279 {
2280 switch (c = str[i++])
2281 {
2282 case DIGITS:
2283 c = c - '0';
2284 goto accumulate;
2285 case 'A':
2286 case 'B':
2287 case 'C':
2288 case 'D':
2289 case 'E':
2290 case 'F':
2291 c = c - 'A' + 10;
2292 goto accumulate;
2293 case 'a':
2294 case 'b':
2295 case 'c':
2296 case 'd':
2297 case 'e':
2298 case 'f':
2299 c = c - 'a' + 10;
2300 accumulate:
2301 if (c >= radix)
2302 return SCM_BOOL_F; /* bad digit for radix */
2303 ln = n;
2304 n = n * radix - c;
2305 /* Negation is a workaround for HP700 cc bug */
2306 if (n > ln || (-n > -SCM_MOST_NEGATIVE_FIXNUM))
2307 goto ovfl;
2308 break;
2309 default:
2310 return SCM_BOOL_F; /* not a digit */
2311 }
2a8fecee 2312 }
f872b822
MD
2313 while (i < len);
2314 if (!lead_neg)
2315 if ((n = -n) > SCM_MOST_POSITIVE_FIXNUM)
2316 goto ovfl;
2317 return SCM_MAKINUM (n);
2a8fecee
JB
2318 ovfl: /* overflow scheme integer */
2319 return SCM_BOOL_F;
2320}
2321
2322
1cc91f1b 2323
0f2d19dd 2324SCM
1bbd0b84 2325scm_istr2int (char *str, long len, long radix)
0f2d19dd
JB
2326{
2327 scm_sizet j;
2328 register scm_sizet k, blen = 1;
2329 scm_sizet i = 0;
2330 int c;
2331 SCM res;
2332 register SCM_BIGDIG *ds;
2333 register unsigned long t2;
2334
f872b822
MD
2335 if (0 >= len)
2336 return SCM_BOOL_F; /* zero scm_length */
2a8fecee
JB
2337
2338 /* Short numbers we parse directly into an int, to avoid the overhead
2339 of creating a bignum. */
2340 if (len < 6)
2341 return scm_small_istr2int (str, len, radix);
2342
f872b822
MD
2343 if (16 == radix)
2344 j = 1 + (4 * len * sizeof (char)) / (SCM_BITSPERDIG);
0f2d19dd 2345 else if (10 <= radix)
f872b822
MD
2346 j = 1 + (84 * len * sizeof (char)) / (SCM_BITSPERDIG * 25);
2347 else
2348 j = 1 + (len * sizeof (char)) / (SCM_BITSPERDIG);
2349 switch (str[0])
2350 { /* leading sign */
2351 case '-':
2352 case '+':
2353 if (++i == (unsigned) len)
2354 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2355 }
2356 res = scm_mkbig (j, '-' == str[0]);
2357 ds = SCM_BDIGITS (res);
2358 for (k = j; k--;)
2359 ds[k] = 0;
2360 do
2361 {
2362 switch (c = str[i++])
2363 {
2364 case DIGITS:
2365 c = c - '0';
2366 goto accumulate;
2367 case 'A':
2368 case 'B':
2369 case 'C':
2370 case 'D':
2371 case 'E':
2372 case 'F':
2373 c = c - 'A' + 10;
2374 goto accumulate;
2375 case 'a':
2376 case 'b':
2377 case 'c':
2378 case 'd':
2379 case 'e':
2380 case 'f':
2381 c = c - 'a' + 10;
2382 accumulate:
2383 if (c >= radix)
2384 return SCM_BOOL_F; /* bad digit for radix */
2385 k = 0;
2386 t2 = c;
2387 moretodo:
2388 while (k < blen)
2389 {
2390/* printf ("k = %d, blen = %d, t2 = %ld, ds[k] = %d\n", k, blen, t2, ds[k]); */
2391 t2 += ds[k] * radix;
2392 ds[k++] = SCM_BIGLO (t2);
2393 t2 = SCM_BIGDN (t2);
2394 }
2395 if (blen > j)
2396 scm_num_overflow ("bignum");
2397 if (t2)
2398 {
2399 blen++;
2400 goto moretodo;
2401 }
2402 break;
2403 default:
2404 return SCM_BOOL_F; /* not a digit */
2405 }
0f2d19dd 2406 }
f872b822
MD
2407 while (i < (unsigned) len);
2408 if (blen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
2409 if (SCM_INUMP (res = scm_big2inum (res, blen)))
2410 return res;
2411 if (j == blen)
2412 return res;
2413 return scm_adjbig (res, blen);
0f2d19dd 2414}
0f2d19dd 2415
0f2d19dd 2416SCM
1bbd0b84 2417scm_istr2flo (char *str, long len, long radix)
0f2d19dd
JB
2418{
2419 register int c, i = 0;
2420 double lead_sgn;
2421 double res = 0.0, tmp = 0.0;
2422 int flg = 0;
2423 int point = 0;
2424 SCM second;
2425
f872b822
MD
2426 if (i >= len)
2427 return SCM_BOOL_F; /* zero scm_length */
0f2d19dd 2428
f872b822
MD
2429 switch (*str)
2430 { /* leading sign */
2431 case '-':
2432 lead_sgn = -1.0;
2433 i++;
2434 break;
2435 case '+':
2436 lead_sgn = 1.0;
2437 i++;
0f2d19dd
JB
2438 break;
2439 default:
f872b822 2440 lead_sgn = 0.0;
0f2d19dd 2441 }
f872b822
MD
2442 if (i == len)
2443 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2444
2445 if (str[i] == 'i' || str[i] == 'I')
2446 { /* handle `+i' and `-i' */
2447 if (lead_sgn == 0.0)
2448 return SCM_BOOL_F; /* must have leading sign */
2449 if (++i < len)
2450 return SCM_BOOL_F; /* `i' not last character */
f8de44c1 2451 return scm_make_complex (0.0, lead_sgn);
f872b822
MD
2452 }
2453 do
2454 { /* check initial digits */
2455 switch (c = str[i])
2456 {
2457 case DIGITS:
2458 c = c - '0';
2459 goto accum1;
2460 case 'D':
2461 case 'E':
2462 case 'F':
2463 if (radix == 10)
2464 goto out1; /* must be exponent */
2465 case 'A':
2466 case 'B':
2467 case 'C':
2468 c = c - 'A' + 10;
2469 goto accum1;
2470 case 'd':
2471 case 'e':
2472 case 'f':
2473 if (radix == 10)
2474 goto out1;
2475 case 'a':
2476 case 'b':
2477 case 'c':
2478 c = c - 'a' + 10;
2479 accum1:
2480 if (c >= radix)
2481 return SCM_BOOL_F; /* bad digit for radix */
2482 res = res * radix + c;
2483 flg = 1; /* res is valid */
2484 break;
2485 default:
2486 goto out1;
2487 }
2488 }
2489 while (++i < len);
0f2d19dd
JB
2490 out1:
2491
2492 /* if true, then we did see a digit above, and res is valid */
f872b822
MD
2493 if (i == len)
2494 goto done;
0f2d19dd
JB
2495
2496 /* By here, must have seen a digit,
2497 or must have next char be a `.' with radix==10 */
2498 if (!flg)
f872b822 2499 if (!(str[i] == '.' && radix == 10))
0f2d19dd
JB
2500 return SCM_BOOL_F;
2501
f872b822
MD
2502 while (str[i] == '#')
2503 { /* optional sharps */
2504 res *= radix;
2505 if (++i == len)
2506 goto done;
0f2d19dd 2507 }
0f2d19dd 2508
f872b822
MD
2509 if (str[i] == '/')
2510 {
2511 while (++i < len)
2512 {
2513 switch (c = str[i])
2514 {
2515 case DIGITS:
2516 c = c - '0';
2517 goto accum2;
2518 case 'A':
2519 case 'B':
2520 case 'C':
2521 case 'D':
2522 case 'E':
2523 case 'F':
2524 c = c - 'A' + 10;
2525 goto accum2;
2526 case 'a':
2527 case 'b':
2528 case 'c':
2529 case 'd':
2530 case 'e':
2531 case 'f':
2532 c = c - 'a' + 10;
2533 accum2:
2534 if (c >= radix)
2535 return SCM_BOOL_F;
2536 tmp = tmp * radix + c;
2537 break;
2538 default:
2539 goto out2;
2540 }
2541 }
2542 out2:
2543 if (tmp == 0.0)
2544 return SCM_BOOL_F; /* `slash zero' not allowed */
2545 if (i < len)
2546 while (str[i] == '#')
2547 { /* optional sharps */
2548 tmp *= radix;
2549 if (++i == len)
2550 break;
2551 }
2552 res /= tmp;
2553 goto done;
0f2d19dd 2554 }
f872b822
MD
2555
2556 if (str[i] == '.')
2557 { /* decimal point notation */
2558 if (radix != 10)
2559 return SCM_BOOL_F; /* must be radix 10 */
2560 while (++i < len)
2561 {
2562 switch (c = str[i])
2563 {
2564 case DIGITS:
2565 point--;
2566 res = res * 10.0 + c - '0';
2567 flg = 1;
2568 break;
2569 default:
2570 goto out3;
2571 }
2572 }
2573 out3:
2574 if (!flg)
2575 return SCM_BOOL_F; /* no digits before or after decimal point */
2576 if (i == len)
2577 goto adjust;
2578 while (str[i] == '#')
2579 { /* ignore remaining sharps */
2580 if (++i == len)
2581 goto adjust;
2582 }
0f2d19dd 2583 }
0f2d19dd 2584
f872b822
MD
2585 switch (str[i])
2586 { /* exponent */
2587 case 'd':
2588 case 'D':
2589 case 'e':
2590 case 'E':
2591 case 'f':
2592 case 'F':
2593 case 'l':
2594 case 'L':
2595 case 's':
2596 case 'S':
2597 {
2598 int expsgn = 1, expon = 0;
2599 if (radix != 10)
2600 return SCM_BOOL_F; /* only in radix 10 */
2601 if (++i == len)
2602 return SCM_BOOL_F; /* bad exponent */
2603 switch (str[i])
2604 {
2605 case '-':
2606 expsgn = (-1);
2607 case '+':
2608 if (++i == len)
2609 return SCM_BOOL_F; /* bad exponent */
2610 }
2611 if (str[i] < '0' || str[i] > '9')
2612 return SCM_BOOL_F; /* bad exponent */
2613 do
2614 {
2615 switch (c = str[i])
2616 {
2617 case DIGITS:
2618 expon = expon * 10 + c - '0';
f3ae5d60 2619 if (expon > SCM_MAXEXP)
f872b822
MD
2620 return SCM_BOOL_F; /* exponent too large */
2621 break;
2622 default:
2623 goto out4;
2624 }
2625 }
2626 while (++i < len);
2627 out4:
2628 point += expsgn * expon;
0f2d19dd 2629 }
f872b822 2630 }
0f2d19dd
JB
2631
2632 adjust:
2633 if (point >= 0)
f872b822
MD
2634 while (point--)
2635 res *= 10.0;
0f2d19dd 2636 else
f872b822
MD
2637#ifdef _UNICOS
2638 while (point++)
2639 res *= 0.1;
2640#else
2641 while (point++)
2642 res /= 10.0;
2643#endif
0f2d19dd
JB
2644
2645 done:
2646 /* at this point, we have a legitimate floating point result */
f872b822
MD
2647 if (lead_sgn == -1.0)
2648 res = -res;
2649 if (i == len)
f8de44c1 2650 return scm_make_real (res);
f872b822
MD
2651
2652 if (str[i] == 'i' || str[i] == 'I')
2653 { /* pure imaginary number */
2654 if (lead_sgn == 0.0)
2655 return SCM_BOOL_F; /* must have leading sign */
2656 if (++i < len)
2657 return SCM_BOOL_F; /* `i' not last character */
f8de44c1 2658 return scm_make_complex (0.0, res);
f872b822 2659 }
0f2d19dd 2660
f872b822
MD
2661 switch (str[i++])
2662 {
2663 case '-':
2664 lead_sgn = -1.0;
2665 break;
2666 case '+':
2667 lead_sgn = 1.0;
2668 break;
2669 case '@':
2670 { /* polar input for complex number */
2671 /* get a `real' for scm_angle */
2672 second = scm_istr2flo (&str[i], (long) (len - i), radix);
f3ae5d60 2673 if (!SCM_SLOPPY_INEXACTP (second))
f872b822 2674 return SCM_BOOL_F; /* not `real' */
f3ae5d60 2675 if (SCM_SLOPPY_COMPLEXP (second))
f872b822
MD
2676 return SCM_BOOL_F; /* not `real' */
2677 tmp = SCM_REALPART (second);
f8de44c1 2678 return scm_make_complex (res * cos (tmp), res * sin (tmp));
f872b822
MD
2679 }
2680 default:
2681 return SCM_BOOL_F;
2682 }
0f2d19dd
JB
2683
2684 /* at this point, last char must be `i' */
f872b822
MD
2685 if (str[len - 1] != 'i' && str[len - 1] != 'I')
2686 return SCM_BOOL_F;
0f2d19dd 2687 /* handles `x+i' and `x-i' */
f872b822 2688 if (i == (len - 1))
f8de44c1 2689 return scm_make_complex (res, lead_sgn);
0f2d19dd 2690 /* get a `ureal' for complex part */
f872b822 2691 second = scm_istr2flo (&str[i], (long) ((len - i) - 1), radix);
f3ae5d60 2692 if (!SCM_INEXACTP (second))
f872b822 2693 return SCM_BOOL_F; /* not `ureal' */
f3ae5d60 2694 if (SCM_SLOPPY_COMPLEXP (second))
f872b822
MD
2695 return SCM_BOOL_F; /* not `ureal' */
2696 tmp = SCM_REALPART (second);
2697 if (tmp < 0.0)
2698 return SCM_BOOL_F; /* not `ureal' */
f8de44c1 2699 return scm_make_complex (res, (lead_sgn * tmp));
0f2d19dd 2700}
0f2d19dd
JB
2701
2702
1cc91f1b 2703
0f2d19dd 2704SCM
1bbd0b84 2705scm_istring2number (char *str, long len, long radix)
0f2d19dd
JB
2706{
2707 int i = 0;
2708 char ex = 0;
2709 char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */
2710 SCM res;
f872b822
MD
2711 if (len == 1)
2712 if (*str == '+' || *str == '-') /* Catches lone `+' and `-' for speed */
0f2d19dd
JB
2713 return SCM_BOOL_F;
2714
f872b822
MD
2715 while ((len - i) >= 2 && str[i] == '#' && ++i)
2716 switch (str[i++])
2717 {
2718 case 'b':
2719 case 'B':
2720 if (rx_p++)
2721 return SCM_BOOL_F;
2722 radix = 2;
2723 break;
2724 case 'o':
2725 case 'O':
2726 if (rx_p++)
2727 return SCM_BOOL_F;
2728 radix = 8;
2729 break;
2730 case 'd':
2731 case 'D':
2732 if (rx_p++)
2733 return SCM_BOOL_F;
2734 radix = 10;
2735 break;
2736 case 'x':
2737 case 'X':
2738 if (rx_p++)
2739 return SCM_BOOL_F;
2740 radix = 16;
2741 break;
2742 case 'i':
2743 case 'I':
2744 if (ex_p++)
2745 return SCM_BOOL_F;
2746 ex = 2;
2747 break;
2748 case 'e':
2749 case 'E':
2750 if (ex_p++)
2751 return SCM_BOOL_F;
2752 ex = 1;
2753 break;
2754 default:
2755 return SCM_BOOL_F;
2756 }
2757
2758 switch (ex)
2759 {
2760 case 1:
2761 return scm_istr2int (&str[i], len - i, radix);
2762 case 0:
2763 res = scm_istr2int (&str[i], len - i, radix);
2764 if (SCM_NFALSEP (res))
2765 return res;
f872b822
MD
2766 case 2:
2767 return scm_istr2flo (&str[i], len - i, radix);
f872b822 2768 }
0f2d19dd
JB
2769 return SCM_BOOL_F;
2770}
2771
2772
a1ec6916 2773SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794
DH
2774 (SCM string, SCM radix),
2775 "Returns a number of the maximally precise representation\n"
2776 "expressed by the given STRING. RADIX must be an exact integer,\n"
2777 "either 2, 8, 10, or 16. If supplied, RADIX is a default radix\n"
2778 "that may be overridden by an explicit radix prefix in STRING\n"
2779 "(e.g. \"#o177\"). If RADIX is not supplied, then the default\n"
2780 "radix is 10. If string is not a syntactically valid notation\n"
2781 "for a number, then `string->number' returns #f. (r5rs)")
1bbd0b84 2782#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2783{
2784 SCM answer;
1bbd0b84 2785 int base;
bb628794 2786 SCM_VALIDATE_ROSTRING (1,string);
3b3b36dd 2787 SCM_VALIDATE_INUM_MIN_DEF_COPY (2,radix,2,10,base);
bb628794
DH
2788 answer = scm_istring2number (SCM_ROCHARS (string),
2789 SCM_ROLENGTH (string),
1bbd0b84 2790 base);
bb628794 2791 return scm_return_first (answer, string);
0f2d19dd 2792}
1bbd0b84 2793#undef FUNC_NAME
0f2d19dd
JB
2794/*** END strs->nums ***/
2795
0f2d19dd 2796SCM
f3ae5d60 2797scm_make_real (double x)
0f2d19dd
JB
2798{
2799 SCM z;
f3ae5d60 2800 SCM_NEWREAL (z, x);
0f2d19dd
JB
2801 return z;
2802}
0f2d19dd 2803
f3ae5d60
MD
2804SCM
2805scm_make_complex (double x, double y)
2806{
2807 SCM z;
2808 SCM_NEWCOMPLEX (z, x, y);
2809 return z;
2810}
1cc91f1b 2811
0f2d19dd 2812SCM
1bbd0b84 2813scm_bigequal (SCM x, SCM y)
0f2d19dd
JB
2814{
2815#ifdef SCM_BIGDIG
f872b822
MD
2816 if (0 == scm_bigcomp (x, y))
2817 return SCM_BOOL_T;
0f2d19dd
JB
2818#endif
2819 return SCM_BOOL_F;
2820}
2821
0f2d19dd 2822SCM
f3ae5d60 2823scm_real_equalp (SCM x, SCM y)
0f2d19dd 2824{
f3ae5d60 2825 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
2826}
2827
f3ae5d60
MD
2828SCM
2829scm_complex_equalp (SCM x, SCM y)
2830{
2831 return SCM_BOOL (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
2832 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
2833}
0f2d19dd
JB
2834
2835
2836
1bbd0b84 2837SCM_REGISTER_PROC (s_number_p, "number?", 1, 0, 0, scm_number_p);
1cc91f1b 2838
a1ec6916 2839SCM_DEFINE (scm_number_p, "complex?", 1, 0, 0,
1bbd0b84 2840 (SCM x),
bb628794
DH
2841 "Return #t if X is a complex number, #f else. Note that the\n"
2842 "sets of real, rational and integer values form subsets of the\n"
2843 "set of complex numbers, i. e. the predicate will also be\n"
2844 "fulfilled if X is a real, rational or integer number.")
1bbd0b84 2845#define FUNC_NAME s_scm_number_p
0f2d19dd 2846{
bb628794 2847 return SCM_BOOL (SCM_NUMBERP (x));
0f2d19dd 2848}
1bbd0b84 2849#undef FUNC_NAME
0f2d19dd
JB
2850
2851
1bbd0b84 2852SCM_REGISTER_PROC (s_real_p, "real?", 1, 0, 0, scm_real_p);
1cc91f1b 2853
a1ec6916 2854SCM_DEFINE (scm_real_p, "rational?", 1, 0, 0,
1bbd0b84 2855 (SCM x),
bb628794
DH
2856 "Return #t if X is a rational number, #f else. Note that the\n"
2857 "set of integer values forms a subset of the set of rational\n"
2858 "numbers, i. e. the predicate will also be fulfilled if X is an\n"
2859 "integer number.")
1bbd0b84 2860#define FUNC_NAME s_scm_real_p
0f2d19dd 2861{
bb628794 2862 if (SCM_INUMP (x)) {
0f2d19dd 2863 return SCM_BOOL_T;
bb628794 2864 } else if (SCM_IMP (x)) {
0f2d19dd 2865 return SCM_BOOL_F;
bb628794 2866 } else if (SCM_SLOPPY_REALP (x)) {
0f2d19dd 2867 return SCM_BOOL_T;
bb628794 2868 } else if (SCM_BIGP (x)) {
0f2d19dd 2869 return SCM_BOOL_T;
bb628794
DH
2870 } else {
2871 return SCM_BOOL_F;
2872 }
0f2d19dd 2873}
1bbd0b84 2874#undef FUNC_NAME
0f2d19dd
JB
2875
2876
a1ec6916 2877SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 2878 (SCM x),
bb628794 2879 "Return #t if X is an integer number, #f else.")
1bbd0b84 2880#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
2881{
2882 double r;
f872b822
MD
2883 if (SCM_INUMP (x))
2884 return SCM_BOOL_T;
2885 if (SCM_IMP (x))
2886 return SCM_BOOL_F;
f872b822
MD
2887 if (SCM_BIGP (x))
2888 return SCM_BOOL_T;
f3ae5d60 2889 if (!SCM_SLOPPY_INEXACTP (x))
f872b822 2890 return SCM_BOOL_F;
f3ae5d60 2891 if (SCM_SLOPPY_COMPLEXP (x))
f872b822
MD
2892 return SCM_BOOL_F;
2893 r = SCM_REALPART (x);
2894 if (r == floor (r))
2895 return SCM_BOOL_T;
0f2d19dd
JB
2896 return SCM_BOOL_F;
2897}
1bbd0b84 2898#undef FUNC_NAME
0f2d19dd
JB
2899
2900
a1ec6916 2901SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 2902 (SCM x),
bb628794 2903 "Return #t if X is an inexact number, #f else.")
1bbd0b84 2904#define FUNC_NAME s_scm_inexact_p
0f2d19dd 2905{
f4c627b3 2906 return SCM_BOOL (SCM_INEXACTP (x));
0f2d19dd 2907}
1bbd0b84 2908#undef FUNC_NAME
0f2d19dd
JB
2909
2910
152f82bf 2911SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
1cc91f1b 2912
0f2d19dd 2913SCM
6e8d25a6 2914scm_num_eq_p (SCM x, SCM y)
0f2d19dd 2915{
f4c627b3
DH
2916 if (SCM_INUMP (x)) {
2917 long xx = SCM_INUM (x);
2918 if (SCM_INUMP (y)) {
2919 long yy = SCM_INUM (y);
2920 return SCM_BOOL (xx == yy);
2921 } else if (SCM_BIGP (y)) {
2922 return SCM_BOOL_F;
2923 } else if (SCM_REALP (y)) {
2924 return SCM_BOOL ((double) xx == SCM_REAL_VALUE (y));
2925 } else if (SCM_COMPLEXP (y)) {
2926 return SCM_BOOL (((double) xx == SCM_COMPLEX_REAL (y))
2927 && (0.0 == SCM_COMPLEX_IMAG (y)));
2928 } else {
2929 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2930 }
f4c627b3
DH
2931 } else if (SCM_BIGP (x)) {
2932 if (SCM_INUMP (y)) {
2933 return SCM_BOOL_F;
2934 } else if (SCM_BIGP (y)) {
2935 return SCM_BOOL (0 == scm_bigcomp (x, y));
2936 } else if (SCM_REALP (y)) {
2937 return SCM_BOOL (scm_big2dbl (x) == SCM_REAL_VALUE (y));
2938 } else if (SCM_COMPLEXP (y)) {
2939 return SCM_BOOL ((scm_big2dbl (x) == SCM_COMPLEX_REAL (y))
2940 && (0.0 == SCM_COMPLEX_IMAG (y)));
2941 } else {
2942 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
2943 }
2944 } else if (SCM_REALP (x)) {
2945 if (SCM_INUMP (y)) {
2946 return SCM_BOOL (SCM_REAL_VALUE (x) == (double) SCM_INUM (y));
2947 } else if (SCM_BIGP (y)) {
2948 return SCM_BOOL (SCM_REAL_VALUE (x) == scm_big2dbl (y));
2949 } else if (SCM_REALP (y)) {
2950 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
2951 } else if (SCM_COMPLEXP (y)) {
2952 return SCM_BOOL ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
2953 && (0.0 == SCM_COMPLEX_IMAG (y)));
2954 } else {
2955 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2956 }
f4c627b3
DH
2957 } else if (SCM_COMPLEXP (x)) {
2958 if (SCM_INUMP (y)) {
2959 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == (double) SCM_INUM (y))
2960 && (SCM_COMPLEX_IMAG (x) == 0.0));
2961 } else if (SCM_BIGP (y)) {
2962 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == scm_big2dbl (y))
2963 && (SCM_COMPLEX_IMAG (x) == 0.0));
2964 } else if (SCM_REALP (y)) {
2965 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
2966 && (SCM_COMPLEX_IMAG (x) == 0.0));
2967 } else if (SCM_COMPLEXP (y)) {
2968 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
2969 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
2970 } else {
2971 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
2972 }
2973 } else {
2974 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
2975 }
0f2d19dd
JB
2976}
2977
2978
152f82bf 2979SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
1cc91f1b 2980
0f2d19dd 2981SCM
6e8d25a6 2982scm_less_p (SCM x, SCM y)
0f2d19dd 2983{
f4c627b3
DH
2984 if (SCM_INUMP (x)) {
2985 long xx = SCM_INUM (x);
2986 if (SCM_INUMP (y)) {
2987 long yy = SCM_INUM (y);
2988 return SCM_BOOL (xx < yy);
2989 } else if (SCM_BIGP (y)) {
2990 return SCM_BOOL (!SCM_BIGSIGN (y));
2991 } else if (SCM_REALP (y)) {
2992 return SCM_BOOL ((double) xx < SCM_REAL_VALUE (y));
2993 } else {
2994 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 2995 }
f4c627b3
DH
2996 } else if (SCM_BIGP (x)) {
2997 if (SCM_INUMP (y)) {
2998 return SCM_BOOL (SCM_BIGSIGN (x));
2999 } else if (SCM_BIGP (y)) {
3000 return SCM_BOOL (1 == scm_bigcomp (x, y));
3001 } else if (SCM_REALP (y)) {
3002 return SCM_BOOL (scm_big2dbl (x) < SCM_REAL_VALUE (y));
3003 } else {
3004 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3005 }
3006 } else if (SCM_REALP (x)) {
3007 if (SCM_INUMP (y)) {
3008 return SCM_BOOL (SCM_REAL_VALUE (x) < (double) SCM_INUM (y));
3009 } else if (SCM_BIGP (y)) {
3010 return SCM_BOOL (SCM_REAL_VALUE (x) < scm_big2dbl (y));
3011 } else if (SCM_REALP (y)) {
3012 return SCM_BOOL (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
3013 } else {
3014 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3015 }
f4c627b3
DH
3016 } else {
3017 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
3018 }
0f2d19dd
JB
3019}
3020
3021
c3ee7520 3022SCM_DEFINE1 (scm_gr_p, ">", scm_tc7_rpsubr,
1bbd0b84 3023 (SCM x, SCM y),
bb628794
DH
3024 "Return #t if the list of parameters is monotonically\n"
3025 "increasing.")
1bbd0b84 3026#define FUNC_NAME s_scm_gr_p
0f2d19dd 3027{
f872b822 3028 return scm_less_p (y, x);
0f2d19dd 3029}
1bbd0b84 3030#undef FUNC_NAME
0f2d19dd
JB
3031
3032
c3ee7520 3033SCM_DEFINE1 (scm_leq_p, "<=", scm_tc7_rpsubr,
1bbd0b84 3034 (SCM x, SCM y),
bb628794
DH
3035 "Return #t if the list of parameters is monotonically\n"
3036 "non-decreasing.")
1bbd0b84 3037#define FUNC_NAME s_scm_leq_p
0f2d19dd 3038{
f872b822 3039 return SCM_BOOL_NOT (scm_less_p (y, x));
0f2d19dd 3040}
1bbd0b84 3041#undef FUNC_NAME
0f2d19dd
JB
3042
3043
c3ee7520 3044SCM_DEFINE1 (scm_geq_p, ">=", scm_tc7_rpsubr,
1bbd0b84 3045 (SCM x, SCM y),
bb628794
DH
3046 "Return #t if the list of parameters is monotonically\n"
3047 "non-increasing.")
1bbd0b84 3048#define FUNC_NAME s_scm_geq_p
0f2d19dd 3049{
f872b822 3050 return SCM_BOOL_NOT (scm_less_p (x, y));
0f2d19dd 3051}
1bbd0b84 3052#undef FUNC_NAME
0f2d19dd
JB
3053
3054
152f82bf 3055SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
1cc91f1b 3056
0f2d19dd 3057SCM
6e8d25a6 3058scm_zero_p (SCM z)
0f2d19dd 3059{
c2ff8ab0
DH
3060 if (SCM_INUMP (z)) {
3061 return SCM_BOOL (SCM_EQ_P (z, SCM_INUM0));
3062 } else if (SCM_BIGP (z)) {
3063 return SCM_BOOL_F;
3064 } else if (SCM_REALP (z)) {
3065 return SCM_BOOL (SCM_REAL_VALUE (z) == 0.0);
3066 } else if (SCM_COMPLEXP (z)) {
3067 return SCM_BOOL (SCM_COMPLEX_REAL (z) == 0.0
3068 && SCM_COMPLEX_IMAG (z) == 0.0);
3069 } else {
3070 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
3071 }
0f2d19dd
JB
3072}
3073
3074
152f82bf 3075SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
1cc91f1b 3076
0f2d19dd 3077SCM
6e8d25a6 3078scm_positive_p (SCM x)
0f2d19dd 3079{
c2ff8ab0
DH
3080 if (SCM_INUMP (x)) {
3081 return SCM_BOOL (SCM_INUM (x) > 0);
3082 } else if (SCM_BIGP (x)) {
3083 return SCM_BOOL (!SCM_BIGSIGN (x));
3084 } else if (SCM_REALP (x)) {
3085 return SCM_BOOL(SCM_REAL_VALUE (x) > 0.0);
3086 } else {
3087 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
3088 }
0f2d19dd
JB
3089}
3090
3091
152f82bf 3092SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
1cc91f1b 3093
0f2d19dd 3094SCM
6e8d25a6 3095scm_negative_p (SCM x)
0f2d19dd 3096{
c2ff8ab0
DH
3097 if (SCM_INUMP (x)) {
3098 return SCM_BOOL (SCM_INUM (x) < 0);
3099 } else if (SCM_BIGP (x)) {
3100 return SCM_BOOL (SCM_BIGSIGN (x));
3101 } else if (SCM_REALP (x)) {
3102 return SCM_BOOL(SCM_REAL_VALUE (x) < 0.0);
3103 } else {
3104 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
3105 }
0f2d19dd
JB
3106}
3107
3108
9de33deb 3109SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
1cc91f1b 3110
0f2d19dd 3111SCM
6e8d25a6 3112scm_max (SCM x, SCM y)
0f2d19dd 3113{
f4c627b3
DH
3114 if (SCM_UNBNDP (y)) {
3115 if (SCM_UNBNDP (x)) {
3116 SCM_WTA_DISPATCH_0 (g_max, x, SCM_ARG1, s_max);
3117 } else if (SCM_NUMBERP (x)) {
f872b822 3118 return x;
f4c627b3
DH
3119 } else {
3120 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3121 }
f4c627b3
DH
3122 }
3123
3124 if (SCM_INUMP (x)) {
3125 long xx = SCM_INUM (x);
3126 if (SCM_INUMP (y)) {
3127 long yy = SCM_INUM (y);
3128 return (xx < yy) ? y : x;
3129 } else if (SCM_BIGP (y)) {
3130 return SCM_BIGSIGN (y) ? x : y;
3131 } else if (SCM_REALP (y)) {
3132 double z = xx;
3133 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3134 } else {
3135 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3136 }
f4c627b3
DH
3137 } else if (SCM_BIGP (x)) {
3138 if (SCM_INUMP (y)) {
3139 return SCM_BIGSIGN (x) ? y : x;
3140 } else if (SCM_BIGP (y)) {
3141 return (1 == scm_bigcomp (x, y)) ? y : x;
3142 } else if (SCM_REALP (y)) {
3143 double z = scm_big2dbl (x);
3144 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3145 } else {
3146 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3147 }
3148 } else if (SCM_REALP (x)) {
3149 if (SCM_INUMP (y)) {
3150 double z = SCM_INUM (y);
3151 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3152 } else if (SCM_BIGP (y)) {
3153 double z = scm_big2dbl (y);
3154 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3155 } else if (SCM_REALP (y)) {
3156 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? y : x;
3157 } else {
3158 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3159 }
f4c627b3
DH
3160 } else {
3161 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
3162 }
0f2d19dd
JB
3163}
3164
3165
9de33deb 3166SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
1cc91f1b 3167
0f2d19dd 3168SCM
6e8d25a6 3169scm_min (SCM x, SCM y)
0f2d19dd 3170{
f4c627b3
DH
3171 if (SCM_UNBNDP (y)) {
3172 if (SCM_UNBNDP (x)) {
3173 SCM_WTA_DISPATCH_0 (g_min, x, SCM_ARG1, s_min);
3174 } else if (SCM_NUMBERP (x)) {
f872b822 3175 return x;
f4c627b3
DH
3176 } else {
3177 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3178 }
f4c627b3
DH
3179 }
3180
3181 if (SCM_INUMP (x)) {
3182 long xx = SCM_INUM (x);
3183 if (SCM_INUMP (y)) {
3184 long yy = SCM_INUM (y);
3185 return (xx < yy) ? x : y;
3186 } else if (SCM_BIGP (y)) {
3187 return SCM_BIGSIGN (y) ? y : x;
3188 } else if (SCM_REALP (y)) {
3189 double z = xx;
3190 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3191 } else {
3192 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3193 }
f4c627b3
DH
3194 } else if (SCM_BIGP (x)) {
3195 if (SCM_INUMP (y)) {
3196 return SCM_BIGSIGN (x) ? x : y;
3197 } else if (SCM_BIGP (y)) {
3198 return (-1 == scm_bigcomp (x, y)) ? y : x;
3199 } else if (SCM_REALP (y)) {
3200 double z = scm_big2dbl (x);
3201 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3202 } else {
3203 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
3204 }
3205 } else if (SCM_REALP (x)) {
3206 if (SCM_INUMP (y)) {
3207 double z = SCM_INUM (y);
3208 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3209 } else if (SCM_BIGP (y)) {
3210 double z = scm_big2dbl (y);
3211 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3212 } else if (SCM_REALP (y)) {
3213 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? x : y;
3214 } else {
3215 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3216 }
f4c627b3
DH
3217 } else {
3218 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
3219 }
0f2d19dd
JB
3220}
3221
3222
9de33deb 3223SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
1cc91f1b 3224
0f2d19dd 3225SCM
6e8d25a6 3226scm_sum (SCM x, SCM y)
0f2d19dd 3227{
98cb6e75
DH
3228 if (SCM_UNBNDP (y)) {
3229 if (SCM_UNBNDP (x)) {
3230 return SCM_INUM0;
3231 } else if (SCM_NUMBERP (x)) {
f872b822 3232 return x;
98cb6e75
DH
3233 } else {
3234 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3235 }
98cb6e75 3236 }
c209c88e 3237
98cb6e75
DH
3238 if (SCM_INUMP (x)) {
3239 long int xx = SCM_INUM (x);
3240 if (SCM_INUMP (y)) {
3241 long int yy = SCM_INUM (y);
3242 long int z = xx + yy;
3243 if (SCM_FIXABLE (z)) {
3244 return SCM_MAKINUM (z);
3245 } else {
3246#ifdef SCM_BIGDIG
3247 return scm_long2big (z);
3248#else /* SCM_BIGDIG */
3249 return scm_make_real ((double) z);
3250#endif /* SCM_BIGDIG */
3251 }
3252 } else if (SCM_BIGP (y)) {
3253 intbig:
f872b822 3254 {
98cb6e75
DH
3255 long int xx = SCM_INUM (x);
3256#ifndef SCM_DIGSTOOBIG
3257 long z = scm_pseudolong (xx);
3258 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3259 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3260#else /* SCM_DIGSTOOBIG */
3261 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3262 scm_longdigs (xx, zdigs);
3263 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3264 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3265#endif /* SCM_DIGSTOOBIG */
0f2d19dd 3266 }
98cb6e75
DH
3267 } else if (SCM_REALP (y)) {
3268 return scm_make_real (xx + SCM_REAL_VALUE (y));
3269 } else if (SCM_COMPLEXP (y)) {
3270 return scm_make_complex (xx + SCM_COMPLEX_REAL (y),
3271 SCM_COMPLEX_IMAG (y));
3272 } else {
3273 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3274 }
98cb6e75
DH
3275 } else if (SCM_BIGP (x)) {
3276 if (SCM_INUMP (y)) {
3277 SCM_SWAP (x, y);
3278 goto intbig;
3279 } else if (SCM_BIGP (y)) {
3280 if (SCM_NUMDIGS (x) > SCM_NUMDIGS (y)) {
3281 SCM_SWAP (x, y);
3282 }
3283 return scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3284 SCM_BIGSIGN (x), y, 0);
3285 } else if (SCM_REALP (y)) {
3286 return scm_make_real (scm_big2dbl (x) + SCM_REAL_VALUE (y));
3287 } else if (SCM_COMPLEXP (y)) {
3288 return scm_make_complex (scm_big2dbl (x) + SCM_COMPLEX_REAL (y),
3289 SCM_COMPLEX_IMAG (y));
3290 } else {
3291 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3292 }
98cb6e75
DH
3293 } else if (SCM_REALP (x)) {
3294 if (SCM_INUMP (y)) {
3295 return scm_make_real (SCM_REAL_VALUE (x) + SCM_INUM (y));
3296 } else if (SCM_BIGP (y)) {
3297 return scm_make_real (SCM_REAL_VALUE (x) + scm_big2dbl (y));
3298 } else if (SCM_REALP (y)) {
3299 return scm_make_real (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
3300 } else if (SCM_COMPLEXP (y)) {
3301 return scm_make_complex (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
3302 SCM_COMPLEX_IMAG (y));
3303 } else {
3304 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3305 }
3306 } else if (SCM_COMPLEXP (x)) {
3307 if (SCM_INUMP (y)) {
3308 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_INUM (y),
3309 SCM_COMPLEX_IMAG (x));
3310 } else if (SCM_BIGP (y)) {
3311 return scm_make_complex (SCM_COMPLEX_REAL (x) + scm_big2dbl (y),
3312 SCM_COMPLEX_IMAG (x));
3313 } else if (SCM_REALP (y)) {
3314 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
3315 SCM_COMPLEX_IMAG (x));
3316 } else if (SCM_COMPLEXP (y)) {
3317 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
3318 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
3319 } else {
3320 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3321 }
3322 } else {
3323 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
3324 }
0f2d19dd
JB
3325}
3326
3327
9de33deb 3328SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
1cc91f1b 3329
0f2d19dd 3330SCM
6e8d25a6 3331scm_difference (SCM x, SCM y)
0f2d19dd 3332{
98cb6e75
DH
3333 if (SCM_UNBNDP (y)) {
3334 if (SCM_INUMP (x)) {
3335 long xx = -SCM_INUM (x);
3336 if (SCM_FIXABLE (xx)) {
3337 return SCM_MAKINUM (xx);
3338 } else {
f872b822 3339#ifdef SCM_BIGDIG
98cb6e75 3340 return scm_long2big (xx);
f3ae5d60 3341#else
98cb6e75 3342 return scm_make_real ((double) xx);
f3ae5d60 3343#endif
f3ae5d60 3344 }
98cb6e75
DH
3345 } else if (SCM_BIGP (x)) {
3346 SCM z = scm_copybig (x, !SCM_BIGSIGN (x));
3347 unsigned int digs = SCM_NUMDIGS (z);
3348 unsigned int size = digs * SCM_BITSPERDIG / SCM_CHAR_BIT;
3349 return size <= sizeof (SCM) ? scm_big2inum (z, digs) : z;
3350 } else if (SCM_REALP (x)) {
3351 return scm_make_real (-SCM_REAL_VALUE (x));
3352 } else if (SCM_COMPLEXP (x)) {
3353 return scm_make_complex (-SCM_COMPLEX_REAL (x), -SCM_COMPLEX_IMAG (x));
3354 } else {
3355 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 3356 }
98cb6e75
DH
3357 }
3358
3359 if (SCM_INUMP (x)) {
3360 long int xx = SCM_INUM (x);
3361 if (SCM_INUMP (y)) {
3362 long int yy = SCM_INUM (y);
3363 long int z = xx - yy;
3364 if (SCM_FIXABLE (z)) {
3365 return SCM_MAKINUM (z);
3366 } else {
f872b822 3367#ifdef SCM_BIGDIG
98cb6e75 3368 return scm_long2big (z);
f872b822 3369#else
98cb6e75 3370 return scm_make_real ((double) z);
f872b822 3371#endif
98cb6e75
DH
3372 }
3373 } else if (SCM_BIGP (y)) {
3374#ifndef SCM_DIGSTOOBIG
3375 long z = scm_pseudolong (xx);
3376 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3377 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3378#else
98cb6e75
DH
3379 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3380 scm_longdigs (xx, zdigs);
3381 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3382 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3383#endif
98cb6e75
DH
3384 } else if (SCM_REALP (y)) {
3385 return scm_make_real (xx - SCM_REAL_VALUE (y));
3386 } else if (SCM_COMPLEXP (y)) {
3387 return scm_make_complex (xx - SCM_COMPLEX_REAL (y),
3388 -SCM_COMPLEX_IMAG (y));
3389 } else {
3390 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 3391 }
98cb6e75
DH
3392 } else if (SCM_BIGP (x)) {
3393 if (SCM_INUMP (y)) {
3394 long int yy = SCM_INUM (y);
3395#ifndef SCM_DIGSTOOBIG
3396 long z = scm_pseudolong (yy);
3397 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3398 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
f872b822 3399#else
98cb6e75
DH
3400 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3401 scm_longdigs (yy, zdigs);
3402 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3403 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
0f2d19dd 3404#endif
98cb6e75
DH
3405 } else if (SCM_BIGP (y)) {
3406 return (SCM_NUMDIGS (x) < SCM_NUMDIGS (y))
3407 ? scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3408 SCM_BIGSIGN (x), y, SCM_BIGSIGNFLAG)
3409 : scm_addbig (SCM_BDIGITS (y), SCM_NUMDIGS (y),
3410 SCM_BIGSIGN (y) ^ SCM_BIGSIGNFLAG, x, 0);
3411 } else if (SCM_REALP (y)) {
3412 return scm_make_real (scm_big2dbl (x) - SCM_REAL_VALUE (y));
3413 } else if (SCM_COMPLEXP (y)) {
3414 return scm_make_complex (scm_big2dbl (x) - SCM_COMPLEX_REAL (y),
3415 - SCM_COMPLEX_IMAG (y));
3416 } else {
3417 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3418 }
3419 } else if (SCM_REALP (x)) {
3420 if (SCM_INUMP (y)) {
3421 return scm_make_real (SCM_REAL_VALUE (x) - SCM_INUM (y));
3422 } else if (SCM_BIGP (y)) {
3423 return scm_make_real (SCM_REAL_VALUE (x) - scm_big2dbl (y));
3424 } else if (SCM_REALP (y)) {
3425 return scm_make_real (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
3426 } else if (SCM_COMPLEXP (y)) {
3427 return scm_make_complex (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
3428 -SCM_COMPLEX_IMAG (y));
3429 } else {
3430 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3431 }
3432 } else if (SCM_COMPLEXP (x)) {
3433 if (SCM_INUMP (y)) {
3434 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_INUM (y),
3435 SCM_COMPLEX_IMAG (x));
3436 } else if (SCM_BIGP (y)) {
3437 return scm_make_complex (SCM_COMPLEX_REAL (x) - scm_big2dbl (y),
3438 SCM_COMPLEX_IMAG (x));
3439 } else if (SCM_REALP (y)) {
3440 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
3441 SCM_COMPLEX_IMAG (x));
3442 } else if (SCM_COMPLEXP (y)) {
3443 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
3444 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
3445 } else {
3446 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3447 }
3448 } else {
3449 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
3450 }
0f2d19dd
JB
3451}
3452
3453
9de33deb 3454SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
1cc91f1b 3455
0f2d19dd 3456SCM
6e8d25a6 3457scm_product (SCM x, SCM y)
0f2d19dd 3458{
f4c627b3
DH
3459 if (SCM_UNBNDP (y)) {
3460 if (SCM_UNBNDP (x)) {
3461 return SCM_MAKINUM (1L);
3462 } else if (SCM_NUMBERP (x)) {
f872b822 3463 return x;
f4c627b3
DH
3464 } else {
3465 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 3466 }
f4c627b3
DH
3467 }
3468
3469 if (SCM_INUMP (x)) {
3470 long xx;
3471
3472 intbig:
3473 xx = SCM_INUM (x);
3474
3475 if (xx == 0) {
f872b822 3476 return x;
f4c627b3
DH
3477 } else if (xx == 1) {
3478 return y;
3479 }
3480
3481 if (SCM_INUMP (y)) {
3482 long yy = SCM_INUM (y);
3483 long kk = xx * yy;
3484 SCM k = SCM_MAKINUM (kk);
3485 if (kk != SCM_INUM (k) || kk / xx != yy) {
f872b822 3486#ifdef SCM_BIGDIG
f4c627b3 3487 int sgn = (xx < 0) ^ (yy < 0);
f872b822 3488#ifndef SCM_DIGSTOOBIG
f4c627b3
DH
3489 long i = scm_pseudolong (xx);
3490 long j = scm_pseudolong (yy);
f872b822
MD
3491 return scm_mulbig ((SCM_BIGDIG *) & i, SCM_DIGSPERLONG,
3492 (SCM_BIGDIG *) & j, SCM_DIGSPERLONG, sgn);
3493#else /* SCM_DIGSTOOBIG */
f4c627b3
DH
3494 SCM_BIGDIG xdigs [SCM_DIGSPERLONG];
3495 SCM_BIGDIG ydigs [SCM_DIGSPERLONG];
3496 scm_longdigs (xx, xdigs);
3497 scm_longdigs (yy, ydigs);
3498 return scm_mulbig (xdigs, SCM_DIGSPERLONG,
3499 ydigs, SCM_DIGSPERLONG,
f872b822
MD
3500 sgn);
3501#endif
f4c627b3
DH
3502#else
3503 return scm_make_real (((double) xx) * ((double) yy));
3504#endif
3505 } else {
3506 return k;
0f2d19dd 3507 }
f4c627b3
DH
3508 } else if (SCM_BIGP (y)) {
3509#ifndef SCM_DIGSTOOBIG
3510 long z = scm_pseudolong (xx);
3511 return scm_mulbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3512 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3513 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3514#else
f4c627b3
DH
3515 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3516 scm_longdigs (xx, zdigs);
3517 return scm_mulbig (zdigs, SCM_DIGSPERLONG,
3518 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3519 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3520#endif
f4c627b3
DH
3521 } else if (SCM_REALP (y)) {
3522 return scm_make_real (xx * SCM_REAL_VALUE (y));
3523 } else if (SCM_COMPLEXP (y)) {
3524 return scm_make_complex (xx * SCM_COMPLEX_REAL (y),
3525 xx * SCM_COMPLEX_IMAG (y));
3526 } else {
3527 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3528 }
3529 } else if (SCM_BIGP (x)) {
3530 if (SCM_INUMP (y)) {
3531 SCM_SWAP (x, y);
3532 goto intbig;
3533 } else if (SCM_BIGP (y)) {
3534 return scm_mulbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3535 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3536 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y));
3537 } else if (SCM_REALP (y)) {
3538 return scm_make_real (scm_big2dbl (x) * SCM_REAL_VALUE (y));
3539 } else if (SCM_COMPLEXP (y)) {
3540 double z = scm_big2dbl (x);
3541 return scm_make_complex (z * SCM_COMPLEX_REAL (y),
3542 z * SCM_COMPLEX_IMAG (y));
3543 } else {
3544 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3545 }
3546 } else if (SCM_REALP (x)) {
3547 if (SCM_INUMP (y)) {
3548 return scm_make_real (SCM_INUM (y) * SCM_REAL_VALUE (x));
3549 } else if (SCM_BIGP (y)) {
3550 return scm_make_real (scm_big2dbl (y) * SCM_REAL_VALUE (x));
3551 } else if (SCM_REALP (y)) {
3552 return scm_make_real (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
3553 } else if (SCM_COMPLEXP (y)) {
3554 return scm_make_complex (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
3555 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
3556 } else {
3557 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3558 }
3559 } else if (SCM_COMPLEXP (x)) {
3560 if (SCM_INUMP (y)) {
3561 return scm_make_complex (SCM_INUM (y) * SCM_COMPLEX_REAL (x),
3562 SCM_INUM (y) * SCM_COMPLEX_IMAG (x));
3563 } else if (SCM_BIGP (y)) {
3564 double z = scm_big2dbl (y);
3565 return scm_make_complex (z * SCM_COMPLEX_REAL (x),
3566 z * SCM_COMPLEX_IMAG (x));
3567 } else if (SCM_REALP (y)) {
3568 return scm_make_complex (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
3569 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
3570 } else if (SCM_COMPLEXP (y)) {
3571 return scm_make_complex (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
3572 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
3573 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
3574 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
3575 } else {
3576 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3577 }
3578 } else {
3579 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
3580 }
3581}
3582
3583
0f2d19dd 3584double
6e8d25a6 3585scm_num2dbl (SCM a, const char *why)
f4c627b3 3586#define FUNC_NAME why
0f2d19dd 3587{
f4c627b3 3588 if (SCM_INUMP (a)) {
0f2d19dd 3589 return (double) SCM_INUM (a);
f4c627b3
DH
3590 } else if (SCM_BIGP (a)) {
3591 return scm_big2dbl (a);
3592 } else if (SCM_REALP (a)) {
3593 return (SCM_REAL_VALUE (a));
3594 } else {
3595 SCM_WRONG_TYPE_ARG (SCM_ARGn, a);
3596 }
0f2d19dd 3597}
f4c627b3 3598#undef FUNC_NAME
0f2d19dd
JB
3599
3600
9de33deb 3601SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
1cc91f1b 3602
0f2d19dd 3603SCM
6e8d25a6 3604scm_divide (SCM x, SCM y)
0f2d19dd 3605{
f8de44c1
DH
3606 double a;
3607
3608 if (SCM_UNBNDP (y)) {
3609 if (SCM_UNBNDP (x)) {
3610 SCM_WTA_DISPATCH_0 (g_divide, x, SCM_ARG1, s_divide);
3611 } else if (SCM_INUMP (x)) {
3612 if (SCM_EQ_P (x, SCM_MAKINUM (1L)) || SCM_EQ_P (x, SCM_MAKINUM (-1L))) {
3613 return x;
3614 } else {
3615 return scm_make_real (1.0 / (double) SCM_INUM (x));
3616 }
f8de44c1
DH
3617 } else if (SCM_BIGP (x)) {
3618 return scm_make_real (1.0 / scm_big2dbl (x));
f8de44c1
DH
3619 } else if (SCM_REALP (x)) {
3620 return scm_make_real (1.0 / SCM_REAL_VALUE (x));
3621 } else if (SCM_COMPLEXP (x)) {
3622 double r = SCM_COMPLEX_REAL (x);
3623 double i = SCM_COMPLEX_IMAG (x);
3624 double d = r * r + i * i;
3625 return scm_make_complex (r / d, -i / d);
3626 } else {
3627 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
3628 }
3629 }
3630
3631 if (SCM_INUMP (x)) {
3632 long xx = SCM_INUM (x);
3633 if (SCM_INUMP (y)) {
3634 long yy = SCM_INUM (y);
3635 if (yy == 0) {
f4c627b3 3636 scm_num_overflow (s_divide);
f8de44c1
DH
3637 } else if (xx % yy != 0) {
3638 return scm_make_real ((double) xx / (double) yy);
3639 } else {
3640 long z = xx / yy;
3641 if (SCM_FIXABLE (z)) {
3642 return SCM_MAKINUM (z);
3643 } else {
f872b822 3644#ifdef SCM_BIGDIG
f8de44c1 3645 return scm_long2big (z);
f872b822 3646#else
f8de44c1 3647 return scm_make_real ((double) xx / (double) yy);
f872b822 3648#endif
f872b822 3649 }
f8de44c1 3650 }
f8de44c1
DH
3651 } else if (SCM_BIGP (y)) {
3652 return scm_make_real ((double) xx / scm_big2dbl (y));
f8de44c1
DH
3653 } else if (SCM_REALP (y)) {
3654 return scm_make_real ((double) xx / SCM_REAL_VALUE (y));
3655 } else if (SCM_COMPLEXP (y)) {
3656 a = xx;
3657 complex_div: /* y _must_ be a complex number */
3658 {
3659 double r = SCM_COMPLEX_REAL (y);
3660 double i = SCM_COMPLEX_IMAG (y);
3661 double d = r * r + i * i;
3662 return scm_make_complex ((a * r) / d, (-a * i) / d);
3663 }
3664 } else {
3665 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
3666 }
f8de44c1
DH
3667 } else if (SCM_BIGP (x)) {
3668 if (SCM_INUMP (y)) {
3669 long int yy = SCM_INUM (y);
3670 if (yy == 0) {
3671 scm_num_overflow (s_divide);
3672 } else if (yy == 1) {
3673 return x;
3674 } else {
3675 long z = yy < 0 ? -yy : yy;
3676 if (z < SCM_BIGRAD) {
3677 SCM w = scm_copybig (x, SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0));
3678 return scm_divbigdig (SCM_BDIGITS (w), SCM_NUMDIGS (w),
3679 (SCM_BIGDIG) z)
3680 ? scm_make_real (scm_big2dbl (x) / (double) yy)
3681 : scm_normbig (w);
3682 } else {
3683 SCM w;
3684#ifndef SCM_DIGSTOOBIG
3685 z = scm_pseudolong (z);
3686 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3687 (SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3688 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 3689#else
f8de44c1
DH
3690 SCM_BIGDIG zdigs[SCM_DIGSPERLONG];
3691 scm_longdigs (z, zdigs);
3692 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3693 zdigs, SCM_DIGSPERLONG,
3694 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 3695#endif
f4c627b3
DH
3696 return (!SCM_UNBNDP (w))
3697 ? w
3698 : scm_make_real (scm_big2dbl (x) / (double) yy);
f872b822 3699 }
f8de44c1
DH
3700 }
3701 } else if (SCM_BIGP (y)) {
3702 SCM w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3703 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3704 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y), 3);
f4c627b3
DH
3705 return (!SCM_UNBNDP (w))
3706 ? w
3707 : scm_make_real (scm_big2dbl (x) / scm_big2dbl (y));
f8de44c1
DH
3708 } else if (SCM_REALP (y)) {
3709 return scm_make_real (scm_big2dbl (x) / SCM_REAL_VALUE (y));
3710 } else if (SCM_COMPLEXP (y)) {
3711 a = scm_big2dbl (x);
3712 goto complex_div;
3713 } else {
3714 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 3715 }
f8de44c1
DH
3716 } else if (SCM_REALP (x)) {
3717 double rx = SCM_REAL_VALUE (x);
3718 if (SCM_INUMP (y)) {
3719 return scm_make_real (rx / (double) SCM_INUM (y));
f8de44c1
DH
3720 } else if (SCM_BIGP (y)) {
3721 return scm_make_real (rx / scm_big2dbl (y));
f8de44c1
DH
3722 } else if (SCM_REALP (y)) {
3723 return scm_make_real (rx / SCM_REAL_VALUE (y));
3724 } else if (SCM_COMPLEXP (y)) {
3725 a = rx;
3726 goto complex_div;
3727 } else {
3728 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 3729 }
f8de44c1
DH
3730 } else if (SCM_COMPLEXP (x)) {
3731 double rx = SCM_COMPLEX_REAL (x);
3732 double ix = SCM_COMPLEX_IMAG (x);
3733 if (SCM_INUMP (y)) {
3734 double d = SCM_INUM (y);
3735 return scm_make_complex (rx / d, ix / d);
f8de44c1
DH
3736 } else if (SCM_BIGP (y)) {
3737 double d = scm_big2dbl (y);
3738 return scm_make_complex (rx / d, ix / d);
f8de44c1
DH
3739 } else if (SCM_REALP (y)) {
3740 double d = SCM_REAL_VALUE (y);
3741 return scm_make_complex (rx / d, ix / d);
3742 } else if (SCM_COMPLEXP (y)) {
3743 double ry = SCM_COMPLEX_REAL (y);
3744 double iy = SCM_COMPLEX_IMAG (y);
3745 double d = ry * ry + iy * iy;
3746 return scm_make_complex ((rx * ry + ix * iy) / d,
3747 (ix * ry - rx * iy) / d);
3748 } else {
3749 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
3750 }
3751 } else {
3752 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd
JB
3753 }
3754}
3755
3756
9de33deb 3757SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_cxr, (SCM (*)()) scm_asinh, g_asinh);
1cc91f1b 3758
0f2d19dd 3759double
6e8d25a6 3760scm_asinh (double x)
0f2d19dd 3761{
f872b822 3762 return log (x + sqrt (x * x + 1));
0f2d19dd
JB
3763}
3764
3765
3766
3767
9de33deb 3768SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_cxr, (SCM (*)()) scm_acosh, g_acosh);
1cc91f1b 3769
0f2d19dd 3770double
6e8d25a6 3771scm_acosh (double x)
0f2d19dd 3772{
f872b822 3773 return log (x + sqrt (x * x - 1));
0f2d19dd
JB
3774}
3775
3776
3777
3778
9de33deb 3779SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_cxr, (SCM (*)()) scm_atanh, g_atanh);
1cc91f1b 3780
0f2d19dd 3781double
6e8d25a6 3782scm_atanh (double x)
0f2d19dd 3783{
f872b822 3784 return 0.5 * log ((1 + x) / (1 - x));
0f2d19dd
JB
3785}
3786
3787
3788
3789
9de33deb 3790SCM_GPROC1 (s_truncate, "truncate", scm_tc7_cxr, (SCM (*)()) scm_truncate, g_truncate);
1cc91f1b 3791
0f2d19dd 3792double
6e8d25a6 3793scm_truncate (double x)
0f2d19dd 3794{
f872b822
MD
3795 if (x < 0.0)
3796 return -floor (-x);
3797 return floor (x);
0f2d19dd
JB
3798}
3799
3800
3801
9de33deb 3802SCM_GPROC1 (s_round, "round", scm_tc7_cxr, (SCM (*)()) scm_round, g_round);
1cc91f1b 3803
0f2d19dd 3804double
6e8d25a6 3805scm_round (double x)
0f2d19dd
JB
3806{
3807 double plus_half = x + 0.5;
f872b822 3808 double result = floor (plus_half);
0f2d19dd 3809 /* Adjust so that the scm_round is towards even. */
f872b822 3810 return (plus_half == result && plus_half / 2 != floor (plus_half / 2))
0f2d19dd
JB
3811 ? result - 1 : result;
3812}
3813
3814
3815
9de33deb 3816SCM_GPROC1 (s_exact_to_inexact, "exact->inexact", scm_tc7_cxr, (SCM (*)()) scm_exact_to_inexact, g_exact_to_inexact);
1cc91f1b 3817
0f2d19dd 3818double
6e8d25a6 3819scm_exact_to_inexact (double z)
0f2d19dd
JB
3820{
3821 return z;
3822}
3823
3824
9de33deb
MD
3825SCM_GPROC1 (s_i_floor, "floor", scm_tc7_cxr, (SCM (*)()) floor, g_i_floor);
3826SCM_GPROC1 (s_i_ceil, "ceiling", scm_tc7_cxr, (SCM (*)()) ceil, g_i_ceil);
3827SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_cxr, (SCM (*)()) sqrt, g_i_sqrt);
3828SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_cxr, (SCM (*)()) fabs, g_i_abs);
3829SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_cxr, (SCM (*)()) exp, g_i_exp);
3830SCM_GPROC1 (s_i_log, "$log", scm_tc7_cxr, (SCM (*)()) log, g_i_log);
3831SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_cxr, (SCM (*)()) sin, g_i_sin);
3832SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_cxr, (SCM (*)()) cos, g_i_cos);
3833SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_cxr, (SCM (*)()) tan, g_i_tan);
3834SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_cxr, (SCM (*)()) asin, g_i_asin);
3835SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_cxr, (SCM (*)()) acos, g_i_acos);
3836SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_cxr, (SCM (*)()) atan, g_i_atan);
3837SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_cxr, (SCM (*)()) sinh, g_i_sinh);
3838SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_cxr, (SCM (*)()) cosh, g_i_cosh);
3839SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_cxr, (SCM (*)()) tanh, g_i_tanh);
f872b822
MD
3840
3841struct dpair
3842{
3843 double x, y;
3844};
3845
3eeba8d4
JB
3846static void scm_two_doubles (SCM z1,
3847 SCM z2,
3848 const char *sstring,
3849 struct dpair * xy);
f872b822
MD
3850
3851static void
6e8d25a6 3852scm_two_doubles (SCM z1, SCM z2, const char *sstring, struct dpair *xy)
0f2d19dd 3853{
98cb6e75 3854 if (SCM_INUMP (z1)) {
f872b822 3855 xy->x = SCM_INUM (z1);
98cb6e75
DH
3856 } else if (SCM_BIGP (z1)) {
3857 xy->x = scm_big2dbl (z1);
3858 } else if (SCM_REALP (z1)) {
3859 xy->x = SCM_REAL_VALUE (z1);
3860 } else {
3861 scm_wrong_type_arg (sstring, SCM_ARG1, z1);
3862 }
3863
3864 if (SCM_INUMP (z2)) {
f872b822 3865 xy->y = SCM_INUM (z2);
98cb6e75
DH
3866 } else if (SCM_BIGP (z2)) {
3867 xy->y = scm_big2dbl (z2);
3868 } else if (SCM_REALP (z2)) {
3869 xy->y = SCM_REAL_VALUE (z2);
3870 } else {
3871 scm_wrong_type_arg (sstring, SCM_ARG2, z2);
3872 }
0f2d19dd
JB
3873}
3874
3875
a1ec6916 3876SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
1bbd0b84 3877 (SCM z1, SCM z2),
bb628794 3878 "")
1bbd0b84 3879#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
3880{
3881 struct dpair xy;
1bbd0b84 3882 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3883 return scm_make_real (pow (xy.x, xy.y));
0f2d19dd 3884}
1bbd0b84 3885#undef FUNC_NAME
0f2d19dd
JB
3886
3887
a1ec6916 3888SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
1bbd0b84 3889 (SCM z1, SCM z2),
b380b885 3890 "")
1bbd0b84 3891#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
3892{
3893 struct dpair xy;
1bbd0b84 3894 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3895 return scm_make_real (atan2 (xy.x, xy.y));
0f2d19dd 3896}
1bbd0b84 3897#undef FUNC_NAME
0f2d19dd
JB
3898
3899
a1ec6916 3900SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794
DH
3901 (SCM real, SCM imaginary),
3902 "Return a complex number constructed of the given REAL and\n"
3903 "IMAGINARY parts.")
1bbd0b84 3904#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
3905{
3906 struct dpair xy;
bb628794 3907 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
f8de44c1 3908 return scm_make_complex (xy.x, xy.y);
0f2d19dd 3909}
1bbd0b84 3910#undef FUNC_NAME
0f2d19dd
JB
3911
3912
3913
a1ec6916 3914SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
1bbd0b84 3915 (SCM z1, SCM z2),
bb628794 3916 "Return the complex number Z1 * e^(i * Z2).")
1bbd0b84 3917#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
3918{
3919 struct dpair xy;
1bbd0b84 3920 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3921 return scm_make_complex (xy.x * cos (xy.y), xy.x * sin (xy.y));
0f2d19dd 3922}
1bbd0b84 3923#undef FUNC_NAME
0f2d19dd
JB
3924
3925
152f82bf 3926SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
1cc91f1b 3927
0f2d19dd 3928SCM
6e8d25a6 3929scm_real_part (SCM z)
0f2d19dd 3930{
c2ff8ab0
DH
3931 if (SCM_INUMP (z)) {
3932 return z;
3933 } else if (SCM_BIGP (z)) {
3934 return z;
3935 } else if (SCM_REALP (z)) {
3936 return z;
3937 } else if (SCM_COMPLEXP (z)) {
3938 return scm_make_real (SCM_COMPLEX_REAL (z));
3939 } else {
3940 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
3941 }
0f2d19dd
JB
3942}
3943
3944
152f82bf 3945SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
1cc91f1b 3946
0f2d19dd 3947SCM
6e8d25a6 3948scm_imag_part (SCM z)
0f2d19dd 3949{
c2ff8ab0 3950 if (SCM_INUMP (z)) {
f872b822 3951 return SCM_INUM0;
c2ff8ab0 3952 } else if (SCM_BIGP (z)) {
f872b822 3953 return SCM_INUM0;
c2ff8ab0
DH
3954 } else if (SCM_REALP (z)) {
3955 return scm_flo0;
3956 } else if (SCM_COMPLEXP (z)) {
3957 return scm_make_real (SCM_COMPLEX_IMAG (z));
3958 } else {
3959 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
3960 }
0f2d19dd
JB
3961}
3962
3963
9de33deb 3964SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
1cc91f1b 3965
0f2d19dd 3966SCM
6e8d25a6 3967scm_magnitude (SCM z)
0f2d19dd 3968{
c2ff8ab0 3969 if (SCM_INUMP (z)) {
f872b822 3970 return scm_abs (z);
c2ff8ab0 3971 } else if (SCM_BIGP (z)) {
f872b822 3972 return scm_abs (z);
c2ff8ab0
DH
3973 } else if (SCM_REALP (z)) {
3974 return scm_make_real (fabs (SCM_REAL_VALUE (z)));
3975 } else if (SCM_COMPLEXP (z)) {
3976 double r = SCM_COMPLEX_REAL (z);
3977 double i = SCM_COMPLEX_IMAG (z);
3978 return scm_make_real (sqrt (i * i + r * r));
3979 } else {
3980 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
3981 }
0f2d19dd
JB
3982}
3983
3984
9de33deb 3985SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
1cc91f1b 3986
0f2d19dd 3987SCM
6e8d25a6 3988scm_angle (SCM z)
0f2d19dd 3989{
f4c627b3
DH
3990 if (SCM_INUMP (z)) {
3991 if (SCM_INUM (z) >= 0) {
3992 return scm_make_real (atan2 (0.0, 1.0));
3993 } else {
3994 return scm_make_real (atan2 (0.0, -1.0));
f872b822 3995 }
f4c627b3
DH
3996 } else if (SCM_BIGP (z)) {
3997 if (SCM_BIGSIGN (z)) {
3998 return scm_make_real (atan2 (0.0, -1.0));
3999 } else {
4000 return scm_make_real (atan2 (0.0, 1.0));
0f2d19dd 4001 }
f4c627b3
DH
4002 } else if (SCM_REALP (z)) {
4003 return scm_make_real (atan2 (0.0, SCM_REAL_VALUE (z)));
4004 } else if (SCM_COMPLEXP (z)) {
4005 return scm_make_real (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
4006 } else {
4007 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
4008 }
0f2d19dd
JB
4009}
4010
4011
a1ec6916 4012SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 4013 (SCM z),
bb628794 4014 "Returns an exact number that is numerically closest to Z.")
1bbd0b84 4015#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 4016{
c2ff8ab0 4017 if (SCM_INUMP (z)) {
f872b822 4018 return z;
c2ff8ab0 4019 } else if (SCM_BIGP (z)) {
f872b822 4020 return z;
c2ff8ab0
DH
4021 } else if (SCM_REALP (z)) {
4022 double u = floor (SCM_REAL_VALUE (z) + 0.5);
4023 long lu = (long) u;
4024 if (SCM_FIXABLE (lu)) {
4025 return SCM_MAKINUM (lu);
f872b822 4026#ifdef SCM_BIGDIG
c2ff8ab0
DH
4027 } else if (isfinite (u)) {
4028 return scm_dbl2big (u);
f872b822 4029#endif
c2ff8ab0
DH
4030 } else {
4031 scm_num_overflow (s_scm_inexact_to_exact);
4032 }
4033 } else {
4034 SCM_WRONG_TYPE_ARG (1, z);
4035 }
0f2d19dd 4036}
1bbd0b84 4037#undef FUNC_NAME
0f2d19dd
JB
4038
4039
0f2d19dd 4040#ifdef SCM_BIGDIG
0f2d19dd 4041/* d must be integer */
1cc91f1b 4042
0f2d19dd 4043SCM
6e8d25a6 4044scm_dbl2big (double d)
0f2d19dd
JB
4045{
4046 scm_sizet i = 0;
4047 long c;
4048 SCM_BIGDIG *digits;
4049 SCM ans;
f872b822
MD
4050 double u = (d < 0) ? -d : d;
4051 while (0 != floor (u))
4052 {
4053 u /= SCM_BIGRAD;
4054 i++;
4055 }
4056 ans = scm_mkbig (i, d < 0);
4057 digits = SCM_BDIGITS (ans);
4058 while (i--)
4059 {
4060 u *= SCM_BIGRAD;
4061 c = floor (u);
4062 u -= c;
4063 digits[i] = c;
4064 }
cf7c17e9 4065#ifndef SCM_RECKLESS
e1724d20 4066 if (u != 0)
52859adf 4067 scm_num_overflow ("dbl2big");
e1724d20 4068#endif
0f2d19dd
JB
4069 return ans;
4070}
4071
4072
4073
0f2d19dd 4074double
6e8d25a6 4075scm_big2dbl (SCM b)
0f2d19dd
JB
4076{
4077 double ans = 0.0;
f872b822
MD
4078 scm_sizet i = SCM_NUMDIGS (b);
4079 SCM_BIGDIG *digits = SCM_BDIGITS (b);
4080 while (i--)
4081 ans = digits[i] + SCM_BIGRAD * ans;
f3ae5d60
MD
4082 if (SCM_BIGSIGN (b))
4083 return - ans;
0f2d19dd
JB
4084 return ans;
4085}
f872b822 4086#endif
0f2d19dd 4087
1cc91f1b 4088
0f2d19dd 4089SCM
6e8d25a6 4090scm_long2num (long sl)
0f2d19dd 4091{
f872b822
MD
4092 if (!SCM_FIXABLE (sl))
4093 {
0f2d19dd 4094#ifdef SCM_BIGDIG
f872b822 4095 return scm_long2big (sl);
0f2d19dd 4096#else
f8de44c1 4097 return scm_make_real ((double) sl);
f872b822
MD
4098#endif
4099 }
4100 return SCM_MAKINUM (sl);
0f2d19dd
JB
4101}
4102
4103
5c11cc9d 4104#ifdef HAVE_LONG_LONGS
1cc91f1b 4105
0f2d19dd 4106SCM
6e8d25a6 4107scm_long_long2num (long_long sl)
0f2d19dd 4108{
f872b822
MD
4109 if (!SCM_FIXABLE (sl))
4110 {
0f2d19dd 4111#ifdef SCM_BIGDIG
f872b822 4112 return scm_long_long2big (sl);
0f2d19dd 4113#else
f8de44c1 4114 return scm_make_real ((double) sl);
f872b822
MD
4115#endif
4116 }
f2961ccd
DH
4117 else
4118 {
4119 /* we know that sl fits into an inum */
4120 return SCM_MAKINUM ((scm_bits_t) sl);
4121 }
0f2d19dd 4122}
0f2d19dd 4123
98cb6e75 4124#endif
0f2d19dd 4125
1cc91f1b 4126
0f2d19dd 4127SCM
6e8d25a6 4128scm_ulong2num (unsigned long sl)
0f2d19dd 4129{
f872b822
MD
4130 if (!SCM_POSFIXABLE (sl))
4131 {
0f2d19dd 4132#ifdef SCM_BIGDIG
f872b822 4133 return scm_ulong2big (sl);
0f2d19dd 4134#else
f8de44c1 4135 return scm_make_real ((double) sl);
f872b822
MD
4136#endif
4137 }
4138 return SCM_MAKINUM (sl);
0f2d19dd
JB
4139}
4140
1cc91f1b 4141
0f2d19dd 4142long
6e8d25a6 4143scm_num2long (SCM num, char *pos, const char *s_caller)
0f2d19dd 4144{
98cb6e75
DH
4145 if (SCM_INUMP (num)) {
4146 return SCM_INUM (num);
4147 } else if (SCM_BIGP (num)) {
4148 long int res;
4149 /* can't use res directly in case num is -2^31. */
4150 unsigned long int pos_res = 0;
4151 unsigned long int old_res = 0;
4152 scm_sizet l;
4153
4154 for (l = SCM_NUMDIGS (num); l--;) {
4155 pos_res = SCM_BIGUP (pos_res) + SCM_BDIGITS (num)[l];
4156 if (pos_res >= old_res) {
4157 old_res = pos_res;
4158 } else {
4159 /* overflow. */
4160 scm_out_of_range (s_caller, num);
4161 }
0f2d19dd 4162 }
98cb6e75
DH
4163 if (SCM_BIGSIGN (num)) {
4164 res = -pos_res;
4165 if (res <= 0) {
4166 return res;
4167 } else {
4168 scm_out_of_range (s_caller, num);
4169 }
4170 } else {
4171 res = pos_res;
4172 if (res >= 0) {
4173 return res;
4174 } else {
4175 scm_out_of_range (s_caller, num);
4176 }
0f2d19dd 4177 }
98cb6e75
DH
4178 } else if (SCM_REALP (num)) {
4179 double u = SCM_REAL_VALUE (num);
4180 long int res = u;
4181 if ((double) res == u) {
5c11cc9d 4182 return res;
98cb6e75
DH
4183 } else {
4184 scm_out_of_range (s_caller, num);
f872b822 4185 }
98cb6e75
DH
4186 } else {
4187 scm_wrong_type_arg (s_caller, (int) pos, num);
4188 }
0f2d19dd
JB
4189}
4190
4191
5c11cc9d 4192#ifdef HAVE_LONG_LONGS
1cc91f1b 4193
0f2d19dd 4194long_long
6e8d25a6 4195scm_num2long_long (SCM num, char *pos, const char *s_caller)
0f2d19dd 4196{
98cb6e75
DH
4197 if (SCM_INUMP (num)) {
4198 return SCM_INUM (num);
4199 } else if (SCM_BIGP (num)) {
4200 long long res;
4201 /* can't use res directly in case num is -2^63. */
4202 unsigned long long int pos_res = 0;
4203 unsigned long long int old_res = 0;
4204 scm_sizet l;
4205
4206 for (l = SCM_NUMDIGS (num); l--;) {
4207 pos_res = SCM_LONGLONGBIGUP (pos_res) + SCM_BDIGITS (num)[l];
4208 if (pos_res >= old_res) {
4209 old_res = pos_res;
4210 } else {
4211 /* overflow. */
4212 scm_out_of_range (s_caller, num);
4213 }
0f2d19dd 4214 }
98cb6e75
DH
4215 if (SCM_BIGSIGN (num)) {
4216 res = -pos_res;
4217 if (res <= 0) {
4218 return res;
4219 } else {
4220 scm_out_of_range (s_caller, num);
4221 }
4222 } else {
4223 res = pos_res;
4224 if (res >= 0) {
4225 return res;
4226 } else {
4227 scm_out_of_range (s_caller, num);
4228 }
f872b822 4229 }
98cb6e75
DH
4230 } else if (SCM_REALP (num)) {
4231 double u = SCM_REAL_VALUE (num);
4232 long long int res = u;
4233 if ((double) res == u) {
f872b822 4234 return res;
98cb6e75
DH
4235 } else {
4236 scm_out_of_range (s_caller, num);
f872b822 4237 }
98cb6e75
DH
4238 } else {
4239 scm_wrong_type_arg (s_caller, (int) pos, num);
4240 }
0f2d19dd 4241}
0f2d19dd 4242
98cb6e75 4243#endif
0f2d19dd 4244
1cc91f1b 4245
0f2d19dd 4246unsigned long
6e8d25a6 4247scm_num2ulong (SCM num, char *pos, const char *s_caller)
0f2d19dd 4248{
98cb6e75
DH
4249 if (SCM_INUMP (num)) {
4250 long nnum = SCM_INUM (num);
4251 if (nnum >= 0) {
4252 return nnum;
4253 } else {
4254 scm_out_of_range (s_caller, num);
4255 }
4256 } else if (SCM_BIGP (num)) {
4257 unsigned long int res = 0;
4258 unsigned long int old_res = 0;
4259 scm_sizet l;
4260
4261 for (l = SCM_NUMDIGS (num); l--;) {
4262 res = SCM_BIGUP (res) + SCM_BDIGITS (num)[l];
4263 if (res >= old_res) {
4264 old_res = res;
4265 } else {
4266 scm_out_of_range (s_caller, num);
4267 }
0f2d19dd 4268 }
98cb6e75
DH
4269 return res;
4270 } else if (SCM_REALP (num)) {
4271 double u = SCM_REAL_VALUE (num);
4272 unsigned long int res = u;
4273 if ((double) res == u) {
f872b822 4274 return res;
98cb6e75
DH
4275 } else {
4276 scm_out_of_range (s_caller, num);
f872b822 4277 }
98cb6e75
DH
4278 } else {
4279 scm_wrong_type_arg (s_caller, (int) pos, num);
4280 }
0f2d19dd
JB
4281}
4282
4283
0f2d19dd
JB
4284void
4285scm_init_numbers ()
0f2d19dd 4286{
f3ae5d60
MD
4287 scm_add_feature ("complex");
4288 scm_add_feature ("inexact");
4289 SCM_NEWREAL (scm_flo0, 0.0);
f872b822 4290#ifdef DBL_DIG
0f2d19dd 4291 scm_dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
f872b822 4292#else
0f2d19dd
JB
4293 { /* determine floating point precision */
4294 double f = 0.1;
f872b822 4295 double fsum = 1.0 + f;
bb628794
DH
4296 while (fsum != 1.0) {
4297 if (++scm_dblprec > 20) {
4298 fsum = 1.0;
4299 } else {
f872b822 4300 f /= 10.0;
bb628794 4301 fsum = f + 1.0;
f872b822 4302 }
bb628794 4303 }
f872b822 4304 scm_dblprec = scm_dblprec - 1;
0f2d19dd 4305 }
f872b822 4306#endif /* DBL_DIG */
a0599745 4307#include "libguile/numbers.x"
0f2d19dd 4308}
89e00824
ML
4309
4310/*
4311 Local Variables:
4312 c-file-style: "gnu"
4313 End:
4314*/