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