* Renamed scm_symbols to symbols and made it static in symbols.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;
6a0476fd 1326 SCM_SET_BIGNUM_BASE (v, scm_must_malloc (nlen * sizeof (SCM_BIGDIG), s_bignum));
f3ae5d60 1327 SCM_SETNUMDIGS (v, nlen, sign);
0f2d19dd
JB
1328 SCM_ALLOW_INTS;
1329 return v;
1330}
1331
1cc91f1b 1332
0f2d19dd 1333SCM
1bbd0b84 1334scm_big2inum (SCM b, scm_sizet l)
0f2d19dd
JB
1335{
1336 unsigned long num = 0;
f872b822
MD
1337 SCM_BIGDIG *tmp = SCM_BDIGITS (b);
1338 while (l--)
1339 num = SCM_BIGUP (num) + tmp[l];
f3ae5d60 1340 if (!SCM_BIGSIGN (b))
f872b822
MD
1341 {
1342 if (SCM_POSFIXABLE (num))
1343 return SCM_MAKINUM (num);
1344 }
894a712b 1345 else if (num <= -SCM_MOST_NEGATIVE_FIXNUM)
f872b822 1346 return SCM_MAKINUM (-num);
0f2d19dd
JB
1347 return b;
1348}
1349
1350
e4755e5c 1351static const char s_adjbig[] = "scm_adjbig";
1cc91f1b 1352
0f2d19dd 1353SCM
1bbd0b84 1354scm_adjbig (SCM b, scm_sizet nlen)
0f2d19dd 1355{
2bf746cc 1356 scm_sizet nsiz = nlen;
f3ae5d60 1357 if (((nsiz << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD) != nlen)
2500356c 1358 scm_memory_error (s_adjbig);
2bf746cc 1359
0f2d19dd 1360 SCM_DEFER_INTS;
2bf746cc
JB
1361 {
1362 SCM_BIGDIG *digits
1363 = ((SCM_BIGDIG *)
9eb364fc 1364 scm_must_realloc ((char *) SCM_BDIGITS (b),
f872b822 1365 (long) (SCM_NUMDIGS (b) * sizeof (SCM_BIGDIG)),
495ffc6e 1366 (long) (nsiz * sizeof (SCM_BIGDIG)), s_bignum));
2bf746cc 1367
6a0476fd 1368 SCM_SET_BIGNUM_BASE (b, digits);
f3ae5d60 1369 SCM_SETNUMDIGS (b, nsiz, SCM_BIGSIGN (b));
2bf746cc 1370 }
0f2d19dd
JB
1371 SCM_ALLOW_INTS;
1372 return b;
1373}
1374
1375
1cc91f1b 1376
0f2d19dd 1377SCM
1bbd0b84 1378scm_normbig (SCM b)
0f2d19dd 1379{
f872b822
MD
1380#ifndef _UNICOS
1381 scm_sizet nlen = SCM_NUMDIGS (b);
0f2d19dd 1382#else
f872b822 1383 int nlen = SCM_NUMDIGS (b); /* unsigned nlen breaks on Cray when nlen => 0 */
0f2d19dd 1384#endif
f872b822
MD
1385 SCM_BIGDIG *zds = SCM_BDIGITS (b);
1386 while (nlen-- && !zds[nlen]);
1387 nlen++;
1388 if (nlen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
1389 if (SCM_INUMP (b = scm_big2inum (b, (scm_sizet) nlen)))
1390 return b;
1391 if (SCM_NUMDIGS (b) == nlen)
1392 return b;
1393 return scm_adjbig (b, (scm_sizet) nlen);
0f2d19dd
JB
1394}
1395
1396
1cc91f1b 1397
0f2d19dd 1398SCM
1bbd0b84 1399scm_copybig (SCM b, int sign)
0f2d19dd 1400{
f872b822
MD
1401 scm_sizet i = SCM_NUMDIGS (b);
1402 SCM ans = scm_mkbig (i, sign);
1403 SCM_BIGDIG *src = SCM_BDIGITS (b), *dst = SCM_BDIGITS (ans);
1404 while (i--)
1405 dst[i] = src[i];
0f2d19dd
JB
1406 return ans;
1407}
1408
1409
1cc91f1b 1410
0f2d19dd 1411SCM
1bbd0b84 1412scm_long2big (long n)
0f2d19dd
JB
1413{
1414 scm_sizet i = 0;
1415 SCM_BIGDIG *digits;
f872b822
MD
1416 SCM ans = scm_mkbig (SCM_DIGSPERLONG, n < 0);
1417 digits = SCM_BDIGITS (ans);
1418 if (n < 0)
1419 n = -n;
1420 while (i < SCM_DIGSPERLONG)
1421 {
1422 digits[i++] = SCM_BIGLO (n);
1423 n = SCM_BIGDN ((unsigned long) n);
1424 }
0f2d19dd
JB
1425 return ans;
1426}
1427
5c11cc9d 1428#ifdef HAVE_LONG_LONGS
1cc91f1b 1429
0f2d19dd 1430SCM
1bbd0b84 1431scm_long_long2big (long_long n)
0f2d19dd
JB
1432{
1433 scm_sizet i;
1434 SCM_BIGDIG *digits;
1435 SCM ans;
1436 int n_digits;
1437
1438 {
1439 long tn;
1440 tn = (long) n;
f872b822 1441 if ((long long) tn == n)
0f2d19dd
JB
1442 return scm_long2big (tn);
1443 }
1444
1445 {
1446 long_long tn;
1447
1448 for (tn = n, n_digits = 0;
1449 tn;
f872b822 1450 ++n_digits, tn = SCM_BIGDN ((ulong_long) tn))
0f2d19dd
JB
1451 ;
1452 }
1453
1454 i = 0;
f872b822
MD
1455 ans = scm_mkbig (n_digits, n < 0);
1456 digits = SCM_BDIGITS (ans);
0f2d19dd
JB
1457 if (n < 0)
1458 n = -n;
f872b822
MD
1459 while (i < n_digits)
1460 {
1461 digits[i++] = SCM_BIGLO (n);
1462 n = SCM_BIGDN ((ulong_long) n);
1463 }
0f2d19dd
JB
1464 return ans;
1465}
f69a01b2 1466#endif /* HAVE_LONG_LONGS */
0f2d19dd 1467
1cc91f1b 1468
0f2d19dd 1469SCM
1bbd0b84 1470scm_2ulong2big (unsigned long *np)
0f2d19dd
JB
1471{
1472 unsigned long n;
1473 scm_sizet i;
1474 SCM_BIGDIG *digits;
1475 SCM ans;
1476
f872b822
MD
1477 ans = scm_mkbig (2 * SCM_DIGSPERLONG, 0);
1478 digits = SCM_BDIGITS (ans);
0f2d19dd
JB
1479
1480 n = np[0];
1481 for (i = 0; i < SCM_DIGSPERLONG; ++i)
1482 {
f872b822
MD
1483 digits[i] = SCM_BIGLO (n);
1484 n = SCM_BIGDN ((unsigned long) n);
0f2d19dd
JB
1485 }
1486 n = np[1];
1487 for (i = 0; i < SCM_DIGSPERLONG; ++i)
1488 {
f872b822
MD
1489 digits[i + SCM_DIGSPERLONG] = SCM_BIGLO (n);
1490 n = SCM_BIGDN ((unsigned long) n);
0f2d19dd
JB
1491 }
1492 return ans;
1493}
1494
1495
1cc91f1b 1496
0f2d19dd 1497SCM
1bbd0b84 1498scm_ulong2big (unsigned long n)
0f2d19dd
JB
1499{
1500 scm_sizet i = 0;
1501 SCM_BIGDIG *digits;
f872b822
MD
1502 SCM ans = scm_mkbig (SCM_DIGSPERLONG, 0);
1503 digits = SCM_BDIGITS (ans);
1504 while (i < SCM_DIGSPERLONG)
1505 {
1506 digits[i++] = SCM_BIGLO (n);
1507 n = SCM_BIGDN (n);
1508 }
0f2d19dd
JB
1509 return ans;
1510}
1511
1512
1cc91f1b 1513
0f2d19dd 1514int
1bbd0b84 1515scm_bigcomp (SCM x, SCM y)
0f2d19dd 1516{
f872b822
MD
1517 int xsign = SCM_BIGSIGN (x);
1518 int ysign = SCM_BIGSIGN (y);
0f2d19dd 1519 scm_sizet xlen, ylen;
2bf746cc
JB
1520
1521 /* Look at the signs, first. */
f872b822
MD
1522 if (ysign < xsign)
1523 return 1;
1524 if (ysign > xsign)
1525 return -1;
2bf746cc
JB
1526
1527 /* They're the same sign, so see which one has more digits. Note
1528 that, if they are negative, the longer number is the lesser. */
f872b822
MD
1529 ylen = SCM_NUMDIGS (y);
1530 xlen = SCM_NUMDIGS (x);
2bf746cc
JB
1531 if (ylen > xlen)
1532 return (xsign) ? -1 : 1;
f872b822
MD
1533 if (ylen < xlen)
1534 return (xsign) ? 1 : -1;
2bf746cc
JB
1535
1536 /* They have the same number of digits, so find the most significant
1537 digit where they differ. */
1538 while (xlen)
1539 {
1540 --xlen;
1541 if (SCM_BDIGITS (y)[xlen] != SCM_BDIGITS (x)[xlen])
1542 /* Make the discrimination based on the digit that differs. */
f872b822
MD
1543 return ((SCM_BDIGITS (y)[xlen] > SCM_BDIGITS (x)[xlen])
1544 ? (xsign ? -1 : 1)
1545 : (xsign ? 1 : -1));
2bf746cc
JB
1546 }
1547
1548 /* The numbers are identical. */
1549 return 0;
0f2d19dd
JB
1550}
1551
1552#ifndef SCM_DIGSTOOBIG
1553
1cc91f1b 1554
0f2d19dd 1555long
1bbd0b84 1556scm_pseudolong (long x)
0f2d19dd 1557{
f872b822
MD
1558 union
1559 {
0f2d19dd
JB
1560 long l;
1561 SCM_BIGDIG bd[SCM_DIGSPERLONG];
f872b822
MD
1562 }
1563 p;
0f2d19dd 1564 scm_sizet i = 0;
f872b822
MD
1565 if (x < 0)
1566 x = -x;
1567 while (i < SCM_DIGSPERLONG)
1568 {
1569 p.bd[i++] = SCM_BIGLO (x);
1570 x = SCM_BIGDN (x);
1571 }
0f2d19dd
JB
1572 /* p.bd[0] = SCM_BIGLO(x); p.bd[1] = SCM_BIGDN(x); */
1573 return p.l;
1574}
1575
1576#else
1577
1cc91f1b 1578
0f2d19dd 1579void
1bbd0b84 1580scm_longdigs (long x, SCM_BIGDIG digs[])
0f2d19dd
JB
1581{
1582 scm_sizet i = 0;
f872b822
MD
1583 if (x < 0)
1584 x = -x;
1585 while (i < SCM_DIGSPERLONG)
1586 {
1587 digs[i++] = SCM_BIGLO (x);
1588 x = SCM_BIGDN (x);
1589 }
0f2d19dd
JB
1590}
1591#endif
1592
1593
1cc91f1b 1594
0f2d19dd 1595SCM
1bbd0b84 1596scm_addbig (SCM_BIGDIG *x, scm_sizet nx, int xsgn, SCM bigy, int sgny)
0f2d19dd
JB
1597{
1598 /* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 1599 /* Assumes xsgn and sgny scm_equal either 0 or SCM_BIGSIGNFLAG */
0f2d19dd 1600 long num = 0;
f872b822
MD
1601 scm_sizet i = 0, ny = SCM_NUMDIGS (bigy);
1602 SCM z = scm_copybig (bigy, SCM_BIGSIGN (bigy) ^ sgny);
1603 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1604 if (xsgn ^ SCM_BIGSIGN (z))
1605 {
1606 do
1607 {
1608 num += (long) zds[i] - x[i];
1609 if (num < 0)
1610 {
1611 zds[i] = num + SCM_BIGRAD;
1612 num = -1;
1613 }
1614 else
1615 {
1616 zds[i] = SCM_BIGLO (num);
1617 num = 0;
1618 }
1619 }
1620 while (++i < nx);
1621 if (num && nx == ny)
1622 {
1623 num = 1;
1624 i = 0;
4260a7fc 1625 SCM_SET_CELL_WORD_0 (z, SCM_CELL_WORD_0 (z) ^ SCM_BIGSIGNFLAG);
f872b822
MD
1626 do
1627 {
1628 num += (SCM_BIGRAD - 1) - zds[i];
1629 zds[i++] = SCM_BIGLO (num);
1630 num = SCM_BIGDN (num);
1631 }
1632 while (i < ny);
1633 }
1634 else
1635 while (i < ny)
1636 {
1637 num += zds[i];
1638 if (num < 0)
1639 {
1640 zds[i++] = num + SCM_BIGRAD;
1641 num = -1;
1642 }
1643 else
1644 {
1645 zds[i++] = SCM_BIGLO (num);
1646 num = 0;
1647 }
1648 }
1649 }
1650 else
1651 {
1652 do
1653 {
1654 num += (long) zds[i] + x[i];
1655 zds[i++] = SCM_BIGLO (num);
1656 num = SCM_BIGDN (num);
1657 }
1658 while (i < nx);
1659 if (!num)
1660 return z;
1661 while (i < ny)
1662 {
1663 num += zds[i];
1664 zds[i++] = SCM_BIGLO (num);
1665 num = SCM_BIGDN (num);
1666 if (!num)
1667 return z;
1668 }
1669 if (num)
1670 {
1671 z = scm_adjbig (z, ny + 1);
1672 SCM_BDIGITS (z)[ny] = num;
1673 return z;
1674 }
1675 }
1676 return scm_normbig (z);
0f2d19dd
JB
1677}
1678
1cc91f1b 1679
0f2d19dd 1680SCM
1bbd0b84 1681scm_mulbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn)
0f2d19dd
JB
1682{
1683 scm_sizet i = 0, j = nx + ny;
1684 unsigned long n = 0;
f872b822
MD
1685 SCM z = scm_mkbig (j, sgn);
1686 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1687 while (j--)
1688 zds[j] = 0;
1689 do
1690 {
1691 j = 0;
1692 if (x[i])
1693 {
1694 do
1695 {
1696 n += zds[i + j] + ((unsigned long) x[i] * y[j]);
1697 zds[i + j++] = SCM_BIGLO (n);
1698 n = SCM_BIGDN (n);
1699 }
1700 while (j < ny);
1701 if (n)
1702 {
1703 zds[i + j] = n;
1704 n = 0;
1705 }
1706 }
0f2d19dd 1707 }
f872b822
MD
1708 while (++i < nx);
1709 return scm_normbig (z);
0f2d19dd
JB
1710}
1711
1cc91f1b 1712
0f2d19dd 1713unsigned int
bb628794 1714scm_divbigdig (SCM_BIGDIG * ds, scm_sizet h, SCM_BIGDIG div)
0f2d19dd
JB
1715{
1716 register unsigned long t2 = 0;
f872b822
MD
1717 while (h--)
1718 {
1719 t2 = SCM_BIGUP (t2) + ds[h];
1720 ds[h] = t2 / div;
1721 t2 %= div;
1722 }
0f2d19dd
JB
1723 return t2;
1724}
1725
1726
1cc91f1b 1727
f4c627b3 1728static SCM
1bbd0b84 1729scm_divbigint (SCM x, long z, int sgn, int mode)
0f2d19dd 1730{
f872b822
MD
1731 if (z < 0)
1732 z = -z;
1733 if (z < SCM_BIGRAD)
1734 {
1735 register unsigned long t2 = 0;
1736 register SCM_BIGDIG *ds = SCM_BDIGITS (x);
1737 scm_sizet nd = SCM_NUMDIGS (x);
1738 while (nd--)
1739 t2 = (SCM_BIGUP (t2) + ds[nd]) % z;
1740 if (mode && t2)
1741 t2 = z - t2;
1742 return SCM_MAKINUM (sgn ? -t2 : t2);
1743 }
0f2d19dd
JB
1744 {
1745#ifndef SCM_DIGSTOOBIG
f872b822
MD
1746 unsigned long t2 = scm_pseudolong (z);
1747 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1748 (SCM_BIGDIG *) & t2, SCM_DIGSPERLONG,
1749 sgn, mode);
0f2d19dd
JB
1750#else
1751 SCM_BIGDIG t2[SCM_DIGSPERLONG];
f872b822
MD
1752 scm_longdigs (z, t2);
1753 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1754 t2, SCM_DIGSPERLONG,
1755 sgn, mode);
0f2d19dd
JB
1756#endif
1757 }
1758}
1759
1cc91f1b 1760
f4c627b3 1761static SCM
1bbd0b84 1762scm_divbigbig (SCM_BIGDIG *x, scm_sizet nx, SCM_BIGDIG *y, scm_sizet ny, int sgn, int modes)
0f2d19dd
JB
1763{
1764 /* modes description
f872b822
MD
1765 0 remainder
1766 1 scm_modulo
1767 2 quotient
f4c627b3 1768 3 quotient but returns SCM_UNDEFINED if division is not exact. */
0f2d19dd
JB
1769 scm_sizet i = 0, j = 0;
1770 long num = 0;
1771 unsigned long t2 = 0;
1772 SCM z, newy;
f872b822 1773 SCM_BIGDIG d = 0, qhat, *zds, *yds;
0f2d19dd
JB
1774 /* algorithm requires nx >= ny */
1775 if (nx < ny)
f872b822
MD
1776 switch (modes)
1777 {
1778 case 0: /* remainder -- just return x */
1779 z = scm_mkbig (nx, sgn);
1780 zds = SCM_BDIGITS (z);
1781 do
1782 {
1783 zds[i] = x[i];
1784 }
1785 while (++i < nx);
1786 return z;
1787 case 1: /* scm_modulo -- return y-x */
1788 z = scm_mkbig (ny, sgn);
1789 zds = SCM_BDIGITS (z);
1790 do
1791 {
1792 num += (long) y[i] - x[i];
1793 if (num < 0)
1794 {
1795 zds[i] = num + SCM_BIGRAD;
1796 num = -1;
1797 }
1798 else
1799 {
1800 zds[i] = num;
1801 num = 0;
1802 }
1803 }
1804 while (++i < nx);
1805 while (i < ny)
1806 {
1807 num += y[i];
1808 if (num < 0)
1809 {
1810 zds[i++] = num + SCM_BIGRAD;
1811 num = -1;
1812 }
1813 else
1814 {
1815 zds[i++] = num;
1816 num = 0;
1817 }
1818 }
1819 goto doadj;
1820 case 2:
1821 return SCM_INUM0; /* quotient is zero */
1822 case 3:
f4c627b3 1823 return SCM_UNDEFINED; /* the division is not exact */
0f2d19dd 1824 }
f872b822
MD
1825
1826 z = scm_mkbig (nx == ny ? nx + 2 : nx + 1, sgn);
1827 zds = SCM_BDIGITS (z);
1828 if (nx == ny)
1829 zds[nx + 1] = 0;
1830 while (!y[ny - 1])
1831 ny--; /* in case y came in as a psuedolong */
1832 if (y[ny - 1] < (SCM_BIGRAD >> 1))
1833 { /* normalize operands */
1834 d = SCM_BIGRAD / (y[ny - 1] + 1);
1835 newy = scm_mkbig (ny, 0);
1836 yds = SCM_BDIGITS (newy);
1837 while (j < ny)
1838 {
1839 t2 += (unsigned long) y[j] * d;
1840 yds[j++] = SCM_BIGLO (t2);
1841 t2 = SCM_BIGDN (t2);
1842 }
1843 y = yds;
1844 j = 0;
1845 t2 = 0;
1846 while (j < nx)
1847 {
1848 t2 += (unsigned long) x[j] * d;
1849 zds[j++] = SCM_BIGLO (t2);
1850 t2 = SCM_BIGDN (t2);
1851 }
1852 zds[j] = t2;
1853 }
1854 else
1855 {
1856 zds[j = nx] = 0;
1857 while (j--)
1858 zds[j] = x[j];
1859 }
1860 j = nx == ny ? nx + 1 : nx; /* dividend needs more digits than divisor */
1861 do
1862 { /* loop over digits of quotient */
1863 if (zds[j] == y[ny - 1])
1864 qhat = SCM_BIGRAD - 1;
1865 else
1866 qhat = (SCM_BIGUP (zds[j]) + zds[j - 1]) / y[ny - 1];
1867 if (!qhat)
1868 continue;
1869 i = 0;
1870 num = 0;
1871 t2 = 0;
1872 do
1873 { /* multiply and subtract */
1874 t2 += (unsigned long) y[i] * qhat;
1875 num += zds[j - ny + i] - SCM_BIGLO (t2);
1876 if (num < 0)
1877 {
1878 zds[j - ny + i] = num + SCM_BIGRAD;
1879 num = -1;
1880 }
1881 else
1882 {
1883 zds[j - ny + i] = num;
1884 num = 0;
1885 }
1886 t2 = SCM_BIGDN (t2);
1887 }
1888 while (++i < ny);
1889 num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
1890 while (num)
1891 { /* "add back" required */
1892 i = 0;
1893 num = 0;
1894 qhat--;
1895 do
1896 {
1897 num += (long) zds[j - ny + i] + y[i];
1898 zds[j - ny + i] = SCM_BIGLO (num);
1899 num = SCM_BIGDN (num);
1900 }
1901 while (++i < ny);
1902 num--;
1903 }
1904 if (modes & 2)
1905 zds[j] = qhat;
1906 }
1907 while (--j >= ny);
1908 switch (modes)
1909 {
1910 case 3: /* check that remainder==0 */
1911 for (j = ny; j && !zds[j - 1]; --j);
1912 if (j)
f4c627b3 1913 return SCM_UNDEFINED;
f872b822
MD
1914 case 2: /* move quotient down in z */
1915 j = (nx == ny ? nx + 2 : nx + 1) - ny;
1916 for (i = 0; i < j; i++)
1917 zds[i] = zds[i + ny];
1918 ny = i;
1919 break;
1920 case 1: /* subtract for scm_modulo */
1921 i = 0;
1922 num = 0;
1923 j = 0;
1924 do
1925 {
1926 num += y[i] - zds[i];
1927 j = j | zds[i];
1928 if (num < 0)
1929 {
1930 zds[i] = num + SCM_BIGRAD;
1931 num = -1;
1932 }
1933 else
1934 {
1935 zds[i] = num;
1936 num = 0;
1937 }
1938 }
1939 while (++i < ny);
1940 if (!j)
1941 return SCM_INUM0;
1942 case 0: /* just normalize remainder */
1943 if (d)
1944 scm_divbigdig (zds, ny, d);
1945 }
0f2d19dd 1946 doadj:
f872b822
MD
1947 for (j = ny; j && !zds[j - 1]; --j);
1948 if (j * SCM_BITSPERDIG <= sizeof (SCM) * SCM_CHAR_BIT)
1949 if (SCM_INUMP (z = scm_big2inum (z, j)))
1950 return z;
1951 return scm_adjbig (z, j);
0f2d19dd
JB
1952}
1953#endif
f872b822 1954\f
0f2d19dd
JB
1955
1956
1957
0f2d19dd
JB
1958
1959/*** NUMBERS -> STRINGS ***/
0f2d19dd 1960int scm_dblprec;
e4755e5c 1961static const double fx[] =
f872b822
MD
1962{ 0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5,
1963 5e-6, 5e-7, 5e-8, 5e-9, 5e-10,
1964 5e-11, 5e-12, 5e-13, 5e-14, 5e-15,
1965 5e-16, 5e-17, 5e-18, 5e-19, 5e-20};
0f2d19dd
JB
1966
1967
1968
1cc91f1b 1969
0f2d19dd 1970static scm_sizet
1bbd0b84 1971idbl2str (double f, char *a)
0f2d19dd
JB
1972{
1973 int efmt, dpt, d, i, wp = scm_dblprec;
1974 scm_sizet ch = 0;
1975 int exp = 0;
1976
f872b822
MD
1977 if (f == 0.0)
1978 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
1979 if (f < 0.0)
1980 {
1981 f = -f;
1982 a[ch++] = '-';
1983 }
1984 else if (f > 0.0);
1985 else
1986 goto funny;
1987 if (IS_INF (f))
1988 {
1989 if (ch == 0)
1990 a[ch++] = '+';
1991 funny:
1992 a[ch++] = '#';
1993 a[ch++] = '.';
1994 a[ch++] = '#';
1995 return ch;
1996 }
1997#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
1998 make-uniform-vector, from causing infinite loops. */
1999 while (f < 1.0)
2000 {
2001 f *= 10.0;
2002 if (exp-- < DBL_MIN_10_EXP)
2003 goto funny;
2004 }
2005 while (f > 10.0)
2006 {
2007 f *= 0.10;
2008 if (exp++ > DBL_MAX_10_EXP)
2009 goto funny;
2010 }
2011#else
2012 while (f < 1.0)
2013 {
2014 f *= 10.0;
2015 exp--;
2016 }
2017 while (f > 10.0)
2018 {
2019 f /= 10.0;
2020 exp++;
2021 }
2022#endif
2023 if (f + fx[wp] >= 10.0)
2024 {
2025 f = 1.0;
2026 exp++;
2027 }
0f2d19dd 2028 zero:
f872b822
MD
2029#ifdef ENGNOT
2030 dpt = (exp + 9999) % 3;
0f2d19dd
JB
2031 exp -= dpt++;
2032 efmt = 1;
f872b822
MD
2033#else
2034 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 2035 if (!efmt)
cda139a7
MD
2036 {
2037 if (exp < 0)
2038 {
2039 a[ch++] = '0';
2040 a[ch++] = '.';
2041 dpt = exp;
f872b822
MD
2042 while (++dpt)
2043 a[ch++] = '0';
cda139a7
MD
2044 }
2045 else
f872b822 2046 dpt = exp + 1;
cda139a7 2047 }
0f2d19dd
JB
2048 else
2049 dpt = 1;
f872b822
MD
2050#endif
2051
2052 do
2053 {
2054 d = f;
2055 f -= d;
2056 a[ch++] = d + '0';
2057 if (f < fx[wp])
2058 break;
2059 if (f + fx[wp] >= 1.0)
2060 {
2061 a[ch - 1]++;
2062 break;
2063 }
2064 f *= 10.0;
2065 if (!(--dpt))
2066 a[ch++] = '.';
0f2d19dd 2067 }
f872b822 2068 while (wp--);
0f2d19dd
JB
2069
2070 if (dpt > 0)
cda139a7 2071 {
f872b822 2072#ifndef ENGNOT
cda139a7
MD
2073 if ((dpt > 4) && (exp > 6))
2074 {
f872b822 2075 d = (a[0] == '-' ? 2 : 1);
cda139a7 2076 for (i = ch++; i > d; i--)
f872b822 2077 a[i] = a[i - 1];
cda139a7
MD
2078 a[d] = '.';
2079 efmt = 1;
2080 }
2081 else
f872b822 2082#endif
cda139a7 2083 {
f872b822
MD
2084 while (--dpt)
2085 a[ch++] = '0';
cda139a7
MD
2086 a[ch++] = '.';
2087 }
2088 }
f872b822
MD
2089 if (a[ch - 1] == '.')
2090 a[ch++] = '0'; /* trailing zero */
2091 if (efmt && exp)
2092 {
2093 a[ch++] = 'e';
2094 if (exp < 0)
2095 {
2096 exp = -exp;
2097 a[ch++] = '-';
2098 }
2099 for (i = 10; i <= exp; i *= 10);
2100 for (i /= 10; i; i /= 10)
2101 {
2102 a[ch++] = exp / i + '0';
2103 exp %= i;
2104 }
0f2d19dd 2105 }
0f2d19dd
JB
2106 return ch;
2107}
2108
1cc91f1b 2109
0f2d19dd 2110static scm_sizet
1bbd0b84 2111iflo2str (SCM flt, char *str)
0f2d19dd
JB
2112{
2113 scm_sizet i;
f3ae5d60
MD
2114 if (SCM_SLOPPY_REALP (flt))
2115 i = idbl2str (SCM_REAL_VALUE (flt), str);
0f2d19dd 2116 else
f872b822 2117 {
f3ae5d60
MD
2118 i = idbl2str (SCM_COMPLEX_REAL (flt), str);
2119 if (SCM_COMPLEX_IMAG (flt) != 0.0)
2120 {
2121 if (0 <= SCM_COMPLEX_IMAG (flt))
2122 str[i++] = '+';
2123 i += idbl2str (SCM_COMPLEX_IMAG (flt), &str[i]);
2124 str[i++] = 'i';
2125 }
f872b822 2126 }
0f2d19dd
JB
2127 return i;
2128}
0f2d19dd 2129
5c11cc9d 2130/* convert a long to a string (unterminated). returns the number of
1bbd0b84
GB
2131 characters in the result.
2132 rad is output base
2133 p is destination: worst case (base 2) is SCM_INTBUFLEN */
0f2d19dd 2134scm_sizet
1bbd0b84 2135scm_iint2str (long num, int rad, char *p)
0f2d19dd 2136{
5c11cc9d
GH
2137 scm_sizet j = 1;
2138 scm_sizet i;
2139 unsigned long n = (num < 0) ? -num : num;
2140
f872b822 2141 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2142 j++;
2143
2144 i = j;
2145 if (num < 0)
f872b822 2146 {
f872b822 2147 *p++ = '-';
5c11cc9d
GH
2148 j++;
2149 n = -num;
f872b822 2150 }
5c11cc9d
GH
2151 else
2152 n = num;
f872b822
MD
2153 while (i--)
2154 {
5c11cc9d
GH
2155 int d = n % rad;
2156
f872b822
MD
2157 n /= rad;
2158 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2159 }
0f2d19dd
JB
2160 return j;
2161}
2162
2163
2164#ifdef SCM_BIGDIG
1cc91f1b 2165
0f2d19dd 2166static SCM
1bbd0b84 2167big2str (SCM b, unsigned int radix)
0f2d19dd 2168{
f872b822
MD
2169 SCM t = scm_copybig (b, 0); /* sign of temp doesn't matter */
2170 register SCM_BIGDIG *ds = SCM_BDIGITS (t);
2171 scm_sizet i = SCM_NUMDIGS (t);
2172 scm_sizet j = radix == 16 ? (SCM_BITSPERDIG * i) / 4 + 2
2173 : radix >= 10 ? (SCM_BITSPERDIG * i * 241L) / 800 + 2
2174 : (SCM_BITSPERDIG * i) + 2;
0f2d19dd
JB
2175 scm_sizet k = 0;
2176 scm_sizet radct = 0;
0f2d19dd 2177 SCM_BIGDIG radpow = 1, radmod = 0;
f872b822 2178 SCM ss = scm_makstr ((long) j, 0);
9eb364fc 2179 char *s = SCM_STRING_CHARS (ss), c;
f872b822
MD
2180 while ((long) radpow * radix < SCM_BIGRAD)
2181 {
2182 radpow *= radix;
2183 radct++;
2184 }
f872b822
MD
2185 while ((i || radmod) && j)
2186 {
2187 if (k == 0)
2188 {
2189 radmod = (SCM_BIGDIG) scm_divbigdig (ds, i, radpow);
2190 k = radct;
2191 if (!ds[i - 1])
2192 i--;
2193 }
2194 c = radmod % radix;
2195 radmod /= radix;
2196 k--;
2197 s[--j] = c < 10 ? c + '0' : c + 'a' - 10;
2198 }
aa3188a7
DH
2199
2200 if (SCM_BIGSIGN (b))
2201 s[--j] = '-';
2202
2203 if (j > 0)
2204 {
2205 /* The pre-reserved string length was too large. */
2206 unsigned long int length = SCM_STRING_LENGTH (ss);
2207 ss = scm_substring (ss, SCM_MAKINUM (j), SCM_MAKINUM (length));
f872b822 2208 }
b098016b
JB
2209
2210 return scm_return_first (ss, t);
0f2d19dd
JB
2211}
2212#endif
2213
2214
a1ec6916 2215SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
2216 (SCM n, SCM radix),
2217 "Return a string holding the external representation of the\n"
2218 "number N in the given RADIX. If N is inexact, a radix of 10\n"
2219 "will be used.")
1bbd0b84 2220#define FUNC_NAME s_scm_number_to_string
0f2d19dd 2221{
1bbd0b84 2222 int base;
98cb6e75
DH
2223
2224 if (SCM_UNBNDP (radix)) {
2225 base = 10;
2226 } else {
2227 SCM_VALIDATE_INUM (2, radix);
2228 base = SCM_INUM (radix);
2229 SCM_ASSERT_RANGE (2, radix, base >= 2);
2230 }
2231
bb628794 2232 if (SCM_INUMP (n)) {
98cb6e75 2233 char num_buf [SCM_INTBUFLEN];
bb628794 2234 scm_sizet length = scm_iint2str (SCM_INUM (n), base, num_buf);
98cb6e75 2235 return scm_makfromstr (num_buf, length, 0);
bb628794
DH
2236 } else if (SCM_BIGP (n)) {
2237 return big2str (n, (unsigned int) base);
2238 } else if (SCM_INEXACTP (n)) {
98cb6e75 2239 char num_buf [SCM_FLOBUFLEN];
bb628794 2240 return scm_makfromstr (num_buf, iflo2str (n, num_buf), 0);
98cb6e75 2241 } else {
bb628794 2242 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd
JB
2243 }
2244}
1bbd0b84 2245#undef FUNC_NAME
0f2d19dd
JB
2246
2247
2248/* These print routines are stubbed here so that scm_repl.c doesn't need
f3ae5d60 2249 SCM_BIGDIG conditionals */
1cc91f1b 2250
0f2d19dd 2251int
f3ae5d60 2252scm_print_real (SCM sexp, SCM port, scm_print_state *pstate)
0f2d19dd 2253{
0f2d19dd 2254 char num_buf[SCM_FLOBUFLEN];
f872b822 2255 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
0f2d19dd
JB
2256 return !0;
2257}
2258
f3ae5d60
MD
2259int
2260scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate)
2261{
2262 char num_buf[SCM_FLOBUFLEN];
2263 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
2264 return !0;
2265}
1cc91f1b 2266
0f2d19dd 2267int
1bbd0b84 2268scm_bigprint (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd
JB
2269{
2270#ifdef SCM_BIGDIG
f872b822 2271 exp = big2str (exp, (unsigned int) 10);
aa3188a7 2272 scm_lfwrite (SCM_STRING_CHARS (exp), (scm_sizet) SCM_STRING_LENGTH (exp), port);
0f2d19dd 2273#else
f872b822 2274 scm_ipruk ("bignum", exp, port);
0f2d19dd
JB
2275#endif
2276 return !0;
2277}
2278/*** END nums->strs ***/
2279
2280/*** STRINGS -> NUMBERS ***/
2a8fecee
JB
2281
2282static SCM
1bbd0b84 2283scm_small_istr2int (char *str, long len, long radix)
2a8fecee
JB
2284{
2285 register long n = 0, ln;
2286 register int c;
2287 register int i = 0;
2288 int lead_neg = 0;
f872b822
MD
2289 if (0 >= len)
2290 return SCM_BOOL_F; /* zero scm_length */
2291 switch (*str)
2292 { /* leading sign */
2293 case '-':
2294 lead_neg = 1;
2295 case '+':
2296 if (++i == len)
2297 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2298 }
2a8fecee 2299
f872b822
MD
2300 do
2301 {
2302 switch (c = str[i++])
2303 {
2304 case DIGITS:
2305 c = c - '0';
2306 goto accumulate;
2307 case 'A':
2308 case 'B':
2309 case 'C':
2310 case 'D':
2311 case 'E':
2312 case 'F':
2313 c = c - 'A' + 10;
2314 goto accumulate;
2315 case 'a':
2316 case 'b':
2317 case 'c':
2318 case 'd':
2319 case 'e':
2320 case 'f':
2321 c = c - 'a' + 10;
2322 accumulate:
2323 if (c >= radix)
2324 return SCM_BOOL_F; /* bad digit for radix */
2325 ln = n;
2326 n = n * radix - c;
2327 /* Negation is a workaround for HP700 cc bug */
2328 if (n > ln || (-n > -SCM_MOST_NEGATIVE_FIXNUM))
2329 goto ovfl;
2330 break;
2331 default:
2332 return SCM_BOOL_F; /* not a digit */
2333 }
2a8fecee 2334 }
f872b822
MD
2335 while (i < len);
2336 if (!lead_neg)
2337 if ((n = -n) > SCM_MOST_POSITIVE_FIXNUM)
2338 goto ovfl;
2339 return SCM_MAKINUM (n);
2a8fecee
JB
2340 ovfl: /* overflow scheme integer */
2341 return SCM_BOOL_F;
2342}
2343
2344
1cc91f1b 2345
0f2d19dd 2346SCM
1bbd0b84 2347scm_istr2int (char *str, long len, long radix)
0f2d19dd
JB
2348{
2349 scm_sizet j;
2350 register scm_sizet k, blen = 1;
2351 scm_sizet i = 0;
2352 int c;
2353 SCM res;
2354 register SCM_BIGDIG *ds;
2355 register unsigned long t2;
2356
f872b822
MD
2357 if (0 >= len)
2358 return SCM_BOOL_F; /* zero scm_length */
2a8fecee
JB
2359
2360 /* Short numbers we parse directly into an int, to avoid the overhead
2361 of creating a bignum. */
2362 if (len < 6)
2363 return scm_small_istr2int (str, len, radix);
2364
f872b822
MD
2365 if (16 == radix)
2366 j = 1 + (4 * len * sizeof (char)) / (SCM_BITSPERDIG);
0f2d19dd 2367 else if (10 <= radix)
f872b822
MD
2368 j = 1 + (84 * len * sizeof (char)) / (SCM_BITSPERDIG * 25);
2369 else
2370 j = 1 + (len * sizeof (char)) / (SCM_BITSPERDIG);
2371 switch (str[0])
2372 { /* leading sign */
2373 case '-':
2374 case '+':
2375 if (++i == (unsigned) len)
2376 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2377 }
2378 res = scm_mkbig (j, '-' == str[0]);
2379 ds = SCM_BDIGITS (res);
2380 for (k = j; k--;)
2381 ds[k] = 0;
2382 do
2383 {
2384 switch (c = str[i++])
2385 {
2386 case DIGITS:
2387 c = c - '0';
2388 goto accumulate;
2389 case 'A':
2390 case 'B':
2391 case 'C':
2392 case 'D':
2393 case 'E':
2394 case 'F':
2395 c = c - 'A' + 10;
2396 goto accumulate;
2397 case 'a':
2398 case 'b':
2399 case 'c':
2400 case 'd':
2401 case 'e':
2402 case 'f':
2403 c = c - 'a' + 10;
2404 accumulate:
2405 if (c >= radix)
2406 return SCM_BOOL_F; /* bad digit for radix */
2407 k = 0;
2408 t2 = c;
2409 moretodo:
2410 while (k < blen)
2411 {
2412/* printf ("k = %d, blen = %d, t2 = %ld, ds[k] = %d\n", k, blen, t2, ds[k]); */
2413 t2 += ds[k] * radix;
2414 ds[k++] = SCM_BIGLO (t2);
2415 t2 = SCM_BIGDN (t2);
2416 }
2417 if (blen > j)
2418 scm_num_overflow ("bignum");
2419 if (t2)
2420 {
2421 blen++;
2422 goto moretodo;
2423 }
2424 break;
2425 default:
2426 return SCM_BOOL_F; /* not a digit */
2427 }
0f2d19dd 2428 }
f872b822
MD
2429 while (i < (unsigned) len);
2430 if (blen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
2431 if (SCM_INUMP (res = scm_big2inum (res, blen)))
2432 return res;
2433 if (j == blen)
2434 return res;
2435 return scm_adjbig (res, blen);
0f2d19dd 2436}
0f2d19dd 2437
0f2d19dd 2438SCM
1bbd0b84 2439scm_istr2flo (char *str, long len, long radix)
0f2d19dd
JB
2440{
2441 register int c, i = 0;
2442 double lead_sgn;
2443 double res = 0.0, tmp = 0.0;
2444 int flg = 0;
2445 int point = 0;
2446 SCM second;
2447
f872b822
MD
2448 if (i >= len)
2449 return SCM_BOOL_F; /* zero scm_length */
0f2d19dd 2450
f872b822
MD
2451 switch (*str)
2452 { /* leading sign */
2453 case '-':
2454 lead_sgn = -1.0;
2455 i++;
2456 break;
2457 case '+':
2458 lead_sgn = 1.0;
2459 i++;
0f2d19dd
JB
2460 break;
2461 default:
f872b822 2462 lead_sgn = 0.0;
0f2d19dd 2463 }
f872b822
MD
2464 if (i == len)
2465 return SCM_BOOL_F; /* bad if lone `+' or `-' */
2466
2467 if (str[i] == 'i' || str[i] == 'I')
2468 { /* handle `+i' and `-i' */
2469 if (lead_sgn == 0.0)
2470 return SCM_BOOL_F; /* must have leading sign */
2471 if (++i < len)
2472 return SCM_BOOL_F; /* `i' not last character */
f8de44c1 2473 return scm_make_complex (0.0, lead_sgn);
f872b822
MD
2474 }
2475 do
2476 { /* check initial digits */
2477 switch (c = str[i])
2478 {
2479 case DIGITS:
2480 c = c - '0';
2481 goto accum1;
2482 case 'D':
2483 case 'E':
2484 case 'F':
2485 if (radix == 10)
2486 goto out1; /* must be exponent */
2487 case 'A':
2488 case 'B':
2489 case 'C':
2490 c = c - 'A' + 10;
2491 goto accum1;
2492 case 'd':
2493 case 'e':
2494 case 'f':
2495 if (radix == 10)
2496 goto out1;
2497 case 'a':
2498 case 'b':
2499 case 'c':
2500 c = c - 'a' + 10;
2501 accum1:
2502 if (c >= radix)
2503 return SCM_BOOL_F; /* bad digit for radix */
2504 res = res * radix + c;
2505 flg = 1; /* res is valid */
2506 break;
2507 default:
2508 goto out1;
2509 }
2510 }
2511 while (++i < len);
0f2d19dd
JB
2512 out1:
2513
2514 /* if true, then we did see a digit above, and res is valid */
f872b822
MD
2515 if (i == len)
2516 goto done;
0f2d19dd
JB
2517
2518 /* By here, must have seen a digit,
2519 or must have next char be a `.' with radix==10 */
2520 if (!flg)
f872b822 2521 if (!(str[i] == '.' && radix == 10))
0f2d19dd
JB
2522 return SCM_BOOL_F;
2523
f872b822
MD
2524 while (str[i] == '#')
2525 { /* optional sharps */
2526 res *= radix;
2527 if (++i == len)
2528 goto done;
0f2d19dd 2529 }
0f2d19dd 2530
f872b822
MD
2531 if (str[i] == '/')
2532 {
2533 while (++i < len)
2534 {
2535 switch (c = str[i])
2536 {
2537 case DIGITS:
2538 c = c - '0';
2539 goto accum2;
2540 case 'A':
2541 case 'B':
2542 case 'C':
2543 case 'D':
2544 case 'E':
2545 case 'F':
2546 c = c - 'A' + 10;
2547 goto accum2;
2548 case 'a':
2549 case 'b':
2550 case 'c':
2551 case 'd':
2552 case 'e':
2553 case 'f':
2554 c = c - 'a' + 10;
2555 accum2:
2556 if (c >= radix)
2557 return SCM_BOOL_F;
2558 tmp = tmp * radix + c;
2559 break;
2560 default:
2561 goto out2;
2562 }
2563 }
2564 out2:
2565 if (tmp == 0.0)
2566 return SCM_BOOL_F; /* `slash zero' not allowed */
2567 if (i < len)
2568 while (str[i] == '#')
2569 { /* optional sharps */
2570 tmp *= radix;
2571 if (++i == len)
2572 break;
2573 }
2574 res /= tmp;
2575 goto done;
0f2d19dd 2576 }
f872b822
MD
2577
2578 if (str[i] == '.')
2579 { /* decimal point notation */
2580 if (radix != 10)
2581 return SCM_BOOL_F; /* must be radix 10 */
2582 while (++i < len)
2583 {
2584 switch (c = str[i])
2585 {
2586 case DIGITS:
2587 point--;
2588 res = res * 10.0 + c - '0';
2589 flg = 1;
2590 break;
2591 default:
2592 goto out3;
2593 }
2594 }
2595 out3:
2596 if (!flg)
2597 return SCM_BOOL_F; /* no digits before or after decimal point */
2598 if (i == len)
2599 goto adjust;
2600 while (str[i] == '#')
2601 { /* ignore remaining sharps */
2602 if (++i == len)
2603 goto adjust;
2604 }
0f2d19dd 2605 }
0f2d19dd 2606
f872b822
MD
2607 switch (str[i])
2608 { /* exponent */
2609 case 'd':
2610 case 'D':
2611 case 'e':
2612 case 'E':
2613 case 'f':
2614 case 'F':
2615 case 'l':
2616 case 'L':
2617 case 's':
2618 case 'S':
2619 {
2620 int expsgn = 1, expon = 0;
2621 if (radix != 10)
2622 return SCM_BOOL_F; /* only in radix 10 */
2623 if (++i == len)
2624 return SCM_BOOL_F; /* bad exponent */
2625 switch (str[i])
2626 {
2627 case '-':
2628 expsgn = (-1);
2629 case '+':
2630 if (++i == len)
2631 return SCM_BOOL_F; /* bad exponent */
2632 }
2633 if (str[i] < '0' || str[i] > '9')
2634 return SCM_BOOL_F; /* bad exponent */
2635 do
2636 {
2637 switch (c = str[i])
2638 {
2639 case DIGITS:
2640 expon = expon * 10 + c - '0';
f3ae5d60 2641 if (expon > SCM_MAXEXP)
dd47565a 2642 scm_out_of_range ("string->number", SCM_MAKINUM (expon));
f872b822
MD
2643 break;
2644 default:
2645 goto out4;
2646 }
2647 }
2648 while (++i < len);
2649 out4:
2650 point += expsgn * expon;
0f2d19dd 2651 }
f872b822 2652 }
0f2d19dd
JB
2653
2654 adjust:
2655 if (point >= 0)
f872b822
MD
2656 while (point--)
2657 res *= 10.0;
0f2d19dd 2658 else
f872b822
MD
2659#ifdef _UNICOS
2660 while (point++)
2661 res *= 0.1;
2662#else
2663 while (point++)
2664 res /= 10.0;
2665#endif
0f2d19dd
JB
2666
2667 done:
2668 /* at this point, we have a legitimate floating point result */
f872b822
MD
2669 if (lead_sgn == -1.0)
2670 res = -res;
2671 if (i == len)
f8de44c1 2672 return scm_make_real (res);
f872b822
MD
2673
2674 if (str[i] == 'i' || str[i] == 'I')
2675 { /* pure imaginary number */
2676 if (lead_sgn == 0.0)
2677 return SCM_BOOL_F; /* must have leading sign */
2678 if (++i < len)
2679 return SCM_BOOL_F; /* `i' not last character */
f8de44c1 2680 return scm_make_complex (0.0, res);
f872b822 2681 }
0f2d19dd 2682
f872b822
MD
2683 switch (str[i++])
2684 {
2685 case '-':
2686 lead_sgn = -1.0;
2687 break;
2688 case '+':
2689 lead_sgn = 1.0;
2690 break;
2691 case '@':
2692 { /* polar input for complex number */
2693 /* get a `real' for scm_angle */
2694 second = scm_istr2flo (&str[i], (long) (len - i), radix);
f3ae5d60 2695 if (!SCM_SLOPPY_INEXACTP (second))
f872b822 2696 return SCM_BOOL_F; /* not `real' */
f3ae5d60 2697 if (SCM_SLOPPY_COMPLEXP (second))
f872b822 2698 return SCM_BOOL_F; /* not `real' */
5986c47d 2699 tmp = SCM_REAL_VALUE (second);
f8de44c1 2700 return scm_make_complex (res * cos (tmp), res * sin (tmp));
f872b822
MD
2701 }
2702 default:
2703 return SCM_BOOL_F;
2704 }
0f2d19dd
JB
2705
2706 /* at this point, last char must be `i' */
f872b822
MD
2707 if (str[len - 1] != 'i' && str[len - 1] != 'I')
2708 return SCM_BOOL_F;
0f2d19dd 2709 /* handles `x+i' and `x-i' */
f872b822 2710 if (i == (len - 1))
f8de44c1 2711 return scm_make_complex (res, lead_sgn);
0f2d19dd 2712 /* get a `ureal' for complex part */
f872b822 2713 second = scm_istr2flo (&str[i], (long) ((len - i) - 1), radix);
f3ae5d60 2714 if (!SCM_INEXACTP (second))
f872b822 2715 return SCM_BOOL_F; /* not `ureal' */
f3ae5d60 2716 if (SCM_SLOPPY_COMPLEXP (second))
f872b822 2717 return SCM_BOOL_F; /* not `ureal' */
5986c47d 2718 tmp = SCM_REAL_VALUE (second);
f872b822
MD
2719 if (tmp < 0.0)
2720 return SCM_BOOL_F; /* not `ureal' */
f8de44c1 2721 return scm_make_complex (res, (lead_sgn * tmp));
0f2d19dd 2722}
0f2d19dd
JB
2723
2724
1cc91f1b 2725
0f2d19dd 2726SCM
1bbd0b84 2727scm_istring2number (char *str, long len, long radix)
0f2d19dd
JB
2728{
2729 int i = 0;
2730 char ex = 0;
2731 char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */
2732 SCM res;
f872b822
MD
2733 if (len == 1)
2734 if (*str == '+' || *str == '-') /* Catches lone `+' and `-' for speed */
0f2d19dd
JB
2735 return SCM_BOOL_F;
2736
f872b822
MD
2737 while ((len - i) >= 2 && str[i] == '#' && ++i)
2738 switch (str[i++])
2739 {
2740 case 'b':
2741 case 'B':
2742 if (rx_p++)
2743 return SCM_BOOL_F;
2744 radix = 2;
2745 break;
2746 case 'o':
2747 case 'O':
2748 if (rx_p++)
2749 return SCM_BOOL_F;
2750 radix = 8;
2751 break;
2752 case 'd':
2753 case 'D':
2754 if (rx_p++)
2755 return SCM_BOOL_F;
2756 radix = 10;
2757 break;
2758 case 'x':
2759 case 'X':
2760 if (rx_p++)
2761 return SCM_BOOL_F;
2762 radix = 16;
2763 break;
2764 case 'i':
2765 case 'I':
2766 if (ex_p++)
2767 return SCM_BOOL_F;
2768 ex = 2;
2769 break;
2770 case 'e':
2771 case 'E':
2772 if (ex_p++)
2773 return SCM_BOOL_F;
2774 ex = 1;
2775 break;
2776 default:
2777 return SCM_BOOL_F;
2778 }
2779
2780 switch (ex)
2781 {
2782 case 1:
2783 return scm_istr2int (&str[i], len - i, radix);
2784 case 0:
2785 res = scm_istr2int (&str[i], len - i, radix);
2786 if (SCM_NFALSEP (res))
2787 return res;
f872b822
MD
2788 case 2:
2789 return scm_istr2flo (&str[i], len - i, radix);
f872b822 2790 }
0f2d19dd
JB
2791 return SCM_BOOL_F;
2792}
2793
2794
a1ec6916 2795SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794
DH
2796 (SCM string, SCM radix),
2797 "Returns a number of the maximally precise representation\n"
2798 "expressed by the given STRING. RADIX must be an exact integer,\n"
2799 "either 2, 8, 10, or 16. If supplied, RADIX is a default radix\n"
2800 "that may be overridden by an explicit radix prefix in STRING\n"
2801 "(e.g. \"#o177\"). If RADIX is not supplied, then the default\n"
2802 "radix is 10. If string is not a syntactically valid notation\n"
2803 "for a number, then `string->number' returns #f. (r5rs)")
1bbd0b84 2804#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2805{
2806 SCM answer;
1bbd0b84 2807 int base;
a6d9e5ab 2808 SCM_VALIDATE_STRING (1, string);
3b3b36dd 2809 SCM_VALIDATE_INUM_MIN_DEF_COPY (2,radix,2,10,base);
34f0f2b8 2810 answer = scm_istring2number (SCM_STRING_CHARS (string),
a6d9e5ab 2811 SCM_STRING_LENGTH (string),
1bbd0b84 2812 base);
bb628794 2813 return scm_return_first (answer, string);
0f2d19dd 2814}
1bbd0b84 2815#undef FUNC_NAME
0f2d19dd
JB
2816/*** END strs->nums ***/
2817
5986c47d 2818
0f2d19dd 2819SCM
f3ae5d60 2820scm_make_real (double x)
0f2d19dd
JB
2821{
2822 SCM z;
3a9809df
DH
2823 SCM_NEWCELL2 (z);
2824 SCM_SET_CELL_TYPE (z, scm_tc16_real);
2825 SCM_REAL_VALUE (z) = x;
0f2d19dd
JB
2826 return z;
2827}
0f2d19dd 2828
5986c47d 2829
f3ae5d60
MD
2830SCM
2831scm_make_complex (double x, double y)
2832{
3a9809df
DH
2833 if (y == 0.0) {
2834 return scm_make_real (x);
2835 } else {
2836 SCM z;
2837 SCM_NEWSMOB (z, scm_tc16_complex, scm_must_malloc (2L * sizeof (double), "complex"));
2838 SCM_COMPLEX_REAL (z) = x;
2839 SCM_COMPLEX_IMAG (z) = y;
2840 return z;
2841 }
f3ae5d60 2842}
1cc91f1b 2843
5986c47d 2844
0f2d19dd 2845SCM
1bbd0b84 2846scm_bigequal (SCM x, SCM y)
0f2d19dd
JB
2847{
2848#ifdef SCM_BIGDIG
f872b822
MD
2849 if (0 == scm_bigcomp (x, y))
2850 return SCM_BOOL_T;
0f2d19dd
JB
2851#endif
2852 return SCM_BOOL_F;
2853}
2854
0f2d19dd 2855SCM
f3ae5d60 2856scm_real_equalp (SCM x, SCM y)
0f2d19dd 2857{
f3ae5d60 2858 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
2859}
2860
f3ae5d60
MD
2861SCM
2862scm_complex_equalp (SCM x, SCM y)
2863{
2864 return SCM_BOOL (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
2865 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
2866}
0f2d19dd
JB
2867
2868
2869
1bbd0b84 2870SCM_REGISTER_PROC (s_number_p, "number?", 1, 0, 0, scm_number_p);
1cc91f1b 2871
a1ec6916 2872SCM_DEFINE (scm_number_p, "complex?", 1, 0, 0,
1bbd0b84 2873 (SCM x),
bb628794
DH
2874 "Return #t if X is a complex number, #f else. Note that the\n"
2875 "sets of real, rational and integer values form subsets of the\n"
2876 "set of complex numbers, i. e. the predicate will also be\n"
2877 "fulfilled if X is a real, rational or integer number.")
1bbd0b84 2878#define FUNC_NAME s_scm_number_p
0f2d19dd 2879{
bb628794 2880 return SCM_BOOL (SCM_NUMBERP (x));
0f2d19dd 2881}
1bbd0b84 2882#undef FUNC_NAME
0f2d19dd
JB
2883
2884
1bbd0b84 2885SCM_REGISTER_PROC (s_real_p, "real?", 1, 0, 0, scm_real_p);
1cc91f1b 2886
a1ec6916 2887SCM_DEFINE (scm_real_p, "rational?", 1, 0, 0,
1bbd0b84 2888 (SCM x),
bb628794
DH
2889 "Return #t if X is a rational number, #f else. Note that the\n"
2890 "set of integer values forms a subset of the set of rational\n"
2891 "numbers, i. e. the predicate will also be fulfilled if X is an\n"
2892 "integer number.")
1bbd0b84 2893#define FUNC_NAME s_scm_real_p
0f2d19dd 2894{
bb628794 2895 if (SCM_INUMP (x)) {
0f2d19dd 2896 return SCM_BOOL_T;
bb628794 2897 } else if (SCM_IMP (x)) {
0f2d19dd 2898 return SCM_BOOL_F;
bb628794 2899 } else if (SCM_SLOPPY_REALP (x)) {
0f2d19dd 2900 return SCM_BOOL_T;
bb628794 2901 } else if (SCM_BIGP (x)) {
0f2d19dd 2902 return SCM_BOOL_T;
bb628794
DH
2903 } else {
2904 return SCM_BOOL_F;
2905 }
0f2d19dd 2906}
1bbd0b84 2907#undef FUNC_NAME
0f2d19dd
JB
2908
2909
a1ec6916 2910SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 2911 (SCM x),
bb628794 2912 "Return #t if X is an integer number, #f else.")
1bbd0b84 2913#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
2914{
2915 double r;
f872b822
MD
2916 if (SCM_INUMP (x))
2917 return SCM_BOOL_T;
2918 if (SCM_IMP (x))
2919 return SCM_BOOL_F;
f872b822
MD
2920 if (SCM_BIGP (x))
2921 return SCM_BOOL_T;
f3ae5d60 2922 if (!SCM_SLOPPY_INEXACTP (x))
f872b822 2923 return SCM_BOOL_F;
f3ae5d60 2924 if (SCM_SLOPPY_COMPLEXP (x))
f872b822 2925 return SCM_BOOL_F;
5986c47d 2926 r = SCM_REAL_VALUE (x);
f872b822
MD
2927 if (r == floor (r))
2928 return SCM_BOOL_T;
0f2d19dd
JB
2929 return SCM_BOOL_F;
2930}
1bbd0b84 2931#undef FUNC_NAME
0f2d19dd
JB
2932
2933
a1ec6916 2934SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 2935 (SCM x),
bb628794 2936 "Return #t if X is an inexact number, #f else.")
1bbd0b84 2937#define FUNC_NAME s_scm_inexact_p
0f2d19dd 2938{
f4c627b3 2939 return SCM_BOOL (SCM_INEXACTP (x));
0f2d19dd 2940}
1bbd0b84 2941#undef FUNC_NAME
0f2d19dd
JB
2942
2943
152f82bf 2944SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
1cc91f1b 2945
0f2d19dd 2946SCM
6e8d25a6 2947scm_num_eq_p (SCM x, SCM y)
0f2d19dd 2948{
f4c627b3
DH
2949 if (SCM_INUMP (x)) {
2950 long xx = SCM_INUM (x);
2951 if (SCM_INUMP (y)) {
2952 long yy = SCM_INUM (y);
2953 return SCM_BOOL (xx == yy);
2954 } else if (SCM_BIGP (y)) {
2955 return SCM_BOOL_F;
2956 } else if (SCM_REALP (y)) {
2957 return SCM_BOOL ((double) xx == SCM_REAL_VALUE (y));
2958 } else if (SCM_COMPLEXP (y)) {
2959 return SCM_BOOL (((double) xx == SCM_COMPLEX_REAL (y))
2960 && (0.0 == SCM_COMPLEX_IMAG (y)));
2961 } else {
2962 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2963 }
f4c627b3
DH
2964 } else if (SCM_BIGP (x)) {
2965 if (SCM_INUMP (y)) {
2966 return SCM_BOOL_F;
2967 } else if (SCM_BIGP (y)) {
2968 return SCM_BOOL (0 == scm_bigcomp (x, y));
2969 } else if (SCM_REALP (y)) {
2970 return SCM_BOOL (scm_big2dbl (x) == SCM_REAL_VALUE (y));
2971 } else if (SCM_COMPLEXP (y)) {
2972 return SCM_BOOL ((scm_big2dbl (x) == SCM_COMPLEX_REAL (y))
2973 && (0.0 == SCM_COMPLEX_IMAG (y)));
2974 } else {
2975 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
2976 }
2977 } else if (SCM_REALP (x)) {
2978 if (SCM_INUMP (y)) {
2979 return SCM_BOOL (SCM_REAL_VALUE (x) == (double) SCM_INUM (y));
2980 } else if (SCM_BIGP (y)) {
2981 return SCM_BOOL (SCM_REAL_VALUE (x) == scm_big2dbl (y));
2982 } else if (SCM_REALP (y)) {
2983 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
2984 } else if (SCM_COMPLEXP (y)) {
2985 return SCM_BOOL ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
2986 && (0.0 == SCM_COMPLEX_IMAG (y)));
2987 } else {
2988 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2989 }
f4c627b3
DH
2990 } else if (SCM_COMPLEXP (x)) {
2991 if (SCM_INUMP (y)) {
2992 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == (double) SCM_INUM (y))
2993 && (SCM_COMPLEX_IMAG (x) == 0.0));
2994 } else if (SCM_BIGP (y)) {
2995 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == scm_big2dbl (y))
2996 && (SCM_COMPLEX_IMAG (x) == 0.0));
2997 } else if (SCM_REALP (y)) {
2998 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
2999 && (SCM_COMPLEX_IMAG (x) == 0.0));
3000 } else if (SCM_COMPLEXP (y)) {
3001 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
3002 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
3003 } else {
3004 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3005 }
3006 } else {
3007 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
3008 }
0f2d19dd
JB
3009}
3010
3011
152f82bf 3012SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
1cc91f1b 3013
0f2d19dd 3014SCM
6e8d25a6 3015scm_less_p (SCM x, SCM y)
0f2d19dd 3016{
f4c627b3
DH
3017 if (SCM_INUMP (x)) {
3018 long xx = SCM_INUM (x);
3019 if (SCM_INUMP (y)) {
3020 long yy = SCM_INUM (y);
3021 return SCM_BOOL (xx < yy);
3022 } else if (SCM_BIGP (y)) {
3023 return SCM_BOOL (!SCM_BIGSIGN (y));
3024 } else if (SCM_REALP (y)) {
3025 return SCM_BOOL ((double) xx < SCM_REAL_VALUE (y));
3026 } else {
3027 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3028 }
f4c627b3
DH
3029 } else if (SCM_BIGP (x)) {
3030 if (SCM_INUMP (y)) {
3031 return SCM_BOOL (SCM_BIGSIGN (x));
3032 } else if (SCM_BIGP (y)) {
3033 return SCM_BOOL (1 == scm_bigcomp (x, y));
3034 } else if (SCM_REALP (y)) {
3035 return SCM_BOOL (scm_big2dbl (x) < SCM_REAL_VALUE (y));
3036 } else {
3037 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3038 }
3039 } else if (SCM_REALP (x)) {
3040 if (SCM_INUMP (y)) {
3041 return SCM_BOOL (SCM_REAL_VALUE (x) < (double) SCM_INUM (y));
3042 } else if (SCM_BIGP (y)) {
3043 return SCM_BOOL (SCM_REAL_VALUE (x) < scm_big2dbl (y));
3044 } else if (SCM_REALP (y)) {
3045 return SCM_BOOL (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
3046 } else {
3047 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3048 }
f4c627b3
DH
3049 } else {
3050 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
3051 }
0f2d19dd
JB
3052}
3053
3054
c76b1eaf
MD
3055SCM_GPROC1 (s_scm_gr_p, ">", scm_tc7_rpsubr, scm_gr_p, g_gr_p);
3056/* "Return #t if the list of parameters is monotonically\n"
3057 * "increasing."
3058 */
1bbd0b84 3059#define FUNC_NAME s_scm_gr_p
c76b1eaf
MD
3060SCM
3061scm_gr_p (SCM x, SCM y)
0f2d19dd 3062{
c76b1eaf
MD
3063 if (!SCM_NUMBERP (x))
3064 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG1, FUNC_NAME);
3065 else if (!SCM_NUMBERP (y))
3066 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG2, FUNC_NAME);
3067 else
3068 return scm_less_p (y, x);
0f2d19dd 3069}
1bbd0b84 3070#undef FUNC_NAME
0f2d19dd
JB
3071
3072
c76b1eaf
MD
3073SCM_GPROC1 (s_scm_leq_p, "<=", scm_tc7_rpsubr, scm_leq_p, g_leq_p);
3074/* "Return #t if the list of parameters is monotonically\n"
3075 * "non-decreasing."
3076 */
1bbd0b84 3077#define FUNC_NAME s_scm_leq_p
c76b1eaf
MD
3078SCM
3079scm_leq_p (SCM x, SCM y)
0f2d19dd 3080{
c76b1eaf
MD
3081 if (!SCM_NUMBERP (x))
3082 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG1, FUNC_NAME);
3083 else if (!SCM_NUMBERP (y))
3084 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG2, FUNC_NAME);
3085 else
3086 return SCM_BOOL_NOT (scm_less_p (y, x));
0f2d19dd 3087}
1bbd0b84 3088#undef FUNC_NAME
0f2d19dd
JB
3089
3090
c76b1eaf
MD
3091SCM_GPROC1 (s_scm_geq_p, ">=", scm_tc7_rpsubr, scm_geq_p, g_geq_p);
3092/* "Return #t if the list of parameters is monotonically\n"
3093 * "non-increasing."
3094 */
1bbd0b84 3095#define FUNC_NAME s_scm_geq_p
c76b1eaf
MD
3096SCM
3097scm_geq_p (SCM x, SCM y)
0f2d19dd 3098{
c76b1eaf
MD
3099 if (!SCM_NUMBERP (x))
3100 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG1, FUNC_NAME);
3101 else if (!SCM_NUMBERP (y))
3102 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG2, FUNC_NAME);
3103 else
f872b822 3104 return SCM_BOOL_NOT (scm_less_p (x, y));
0f2d19dd 3105}
1bbd0b84 3106#undef FUNC_NAME
0f2d19dd
JB
3107
3108
152f82bf 3109SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
1cc91f1b 3110
0f2d19dd 3111SCM
6e8d25a6 3112scm_zero_p (SCM z)
0f2d19dd 3113{
c2ff8ab0
DH
3114 if (SCM_INUMP (z)) {
3115 return SCM_BOOL (SCM_EQ_P (z, SCM_INUM0));
3116 } else if (SCM_BIGP (z)) {
3117 return SCM_BOOL_F;
3118 } else if (SCM_REALP (z)) {
3119 return SCM_BOOL (SCM_REAL_VALUE (z) == 0.0);
3120 } else if (SCM_COMPLEXP (z)) {
3121 return SCM_BOOL (SCM_COMPLEX_REAL (z) == 0.0
3122 && SCM_COMPLEX_IMAG (z) == 0.0);
3123 } else {
3124 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
3125 }
0f2d19dd
JB
3126}
3127
3128
152f82bf 3129SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
1cc91f1b 3130
0f2d19dd 3131SCM
6e8d25a6 3132scm_positive_p (SCM x)
0f2d19dd 3133{
c2ff8ab0
DH
3134 if (SCM_INUMP (x)) {
3135 return SCM_BOOL (SCM_INUM (x) > 0);
3136 } else if (SCM_BIGP (x)) {
3137 return SCM_BOOL (!SCM_BIGSIGN (x));
3138 } else if (SCM_REALP (x)) {
3139 return SCM_BOOL(SCM_REAL_VALUE (x) > 0.0);
3140 } else {
3141 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
3142 }
0f2d19dd
JB
3143}
3144
3145
152f82bf 3146SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
1cc91f1b 3147
0f2d19dd 3148SCM
6e8d25a6 3149scm_negative_p (SCM x)
0f2d19dd 3150{
c2ff8ab0
DH
3151 if (SCM_INUMP (x)) {
3152 return SCM_BOOL (SCM_INUM (x) < 0);
3153 } else if (SCM_BIGP (x)) {
3154 return SCM_BOOL (SCM_BIGSIGN (x));
3155 } else if (SCM_REALP (x)) {
3156 return SCM_BOOL(SCM_REAL_VALUE (x) < 0.0);
3157 } else {
3158 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
3159 }
0f2d19dd
JB
3160}
3161
3162
9de33deb 3163SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
1cc91f1b 3164
0f2d19dd 3165SCM
6e8d25a6 3166scm_max (SCM x, SCM y)
0f2d19dd 3167{
f4c627b3
DH
3168 if (SCM_UNBNDP (y)) {
3169 if (SCM_UNBNDP (x)) {
3170 SCM_WTA_DISPATCH_0 (g_max, x, SCM_ARG1, s_max);
3171 } else if (SCM_NUMBERP (x)) {
f872b822 3172 return x;
f4c627b3
DH
3173 } else {
3174 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3175 }
f4c627b3
DH
3176 }
3177
3178 if (SCM_INUMP (x)) {
3179 long xx = SCM_INUM (x);
3180 if (SCM_INUMP (y)) {
3181 long yy = SCM_INUM (y);
3182 return (xx < yy) ? y : x;
3183 } else if (SCM_BIGP (y)) {
3184 return SCM_BIGSIGN (y) ? x : y;
3185 } else if (SCM_REALP (y)) {
3186 double z = xx;
3187 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3188 } else {
3189 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3190 }
f4c627b3
DH
3191 } else if (SCM_BIGP (x)) {
3192 if (SCM_INUMP (y)) {
3193 return SCM_BIGSIGN (x) ? y : x;
3194 } else if (SCM_BIGP (y)) {
3195 return (1 == scm_bigcomp (x, y)) ? y : x;
3196 } else if (SCM_REALP (y)) {
3197 double z = scm_big2dbl (x);
3198 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3199 } else {
3200 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3201 }
3202 } else if (SCM_REALP (x)) {
3203 if (SCM_INUMP (y)) {
3204 double z = SCM_INUM (y);
3205 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3206 } else if (SCM_BIGP (y)) {
3207 double z = scm_big2dbl (y);
3208 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3209 } else if (SCM_REALP (y)) {
3210 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? y : x;
3211 } else {
3212 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3213 }
f4c627b3
DH
3214 } else {
3215 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
3216 }
0f2d19dd
JB
3217}
3218
3219
9de33deb 3220SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
1cc91f1b 3221
0f2d19dd 3222SCM
6e8d25a6 3223scm_min (SCM x, SCM y)
0f2d19dd 3224{
f4c627b3
DH
3225 if (SCM_UNBNDP (y)) {
3226 if (SCM_UNBNDP (x)) {
3227 SCM_WTA_DISPATCH_0 (g_min, x, SCM_ARG1, s_min);
3228 } else if (SCM_NUMBERP (x)) {
f872b822 3229 return x;
f4c627b3
DH
3230 } else {
3231 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3232 }
f4c627b3
DH
3233 }
3234
3235 if (SCM_INUMP (x)) {
3236 long xx = SCM_INUM (x);
3237 if (SCM_INUMP (y)) {
3238 long yy = SCM_INUM (y);
3239 return (xx < yy) ? x : y;
3240 } else if (SCM_BIGP (y)) {
3241 return SCM_BIGSIGN (y) ? y : x;
3242 } else if (SCM_REALP (y)) {
3243 double z = xx;
3244 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3245 } else {
3246 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3247 }
f4c627b3
DH
3248 } else if (SCM_BIGP (x)) {
3249 if (SCM_INUMP (y)) {
3250 return SCM_BIGSIGN (x) ? x : y;
3251 } else if (SCM_BIGP (y)) {
3252 return (-1 == scm_bigcomp (x, y)) ? y : x;
3253 } else if (SCM_REALP (y)) {
3254 double z = scm_big2dbl (x);
3255 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3256 } else {
3257 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
3258 }
3259 } else if (SCM_REALP (x)) {
3260 if (SCM_INUMP (y)) {
3261 double z = SCM_INUM (y);
3262 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3263 } else if (SCM_BIGP (y)) {
3264 double z = scm_big2dbl (y);
3265 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3266 } else if (SCM_REALP (y)) {
3267 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? x : y;
3268 } else {
3269 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3270 }
f4c627b3
DH
3271 } else {
3272 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
3273 }
0f2d19dd
JB
3274}
3275
3276
9de33deb 3277SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
1cc91f1b 3278
0f2d19dd 3279SCM
6e8d25a6 3280scm_sum (SCM x, SCM y)
0f2d19dd 3281{
98cb6e75
DH
3282 if (SCM_UNBNDP (y)) {
3283 if (SCM_UNBNDP (x)) {
3284 return SCM_INUM0;
3285 } else if (SCM_NUMBERP (x)) {
f872b822 3286 return x;
98cb6e75
DH
3287 } else {
3288 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3289 }
98cb6e75 3290 }
c209c88e 3291
98cb6e75
DH
3292 if (SCM_INUMP (x)) {
3293 long int xx = SCM_INUM (x);
3294 if (SCM_INUMP (y)) {
3295 long int yy = SCM_INUM (y);
3296 long int z = xx + yy;
3297 if (SCM_FIXABLE (z)) {
3298 return SCM_MAKINUM (z);
3299 } else {
3300#ifdef SCM_BIGDIG
3301 return scm_long2big (z);
3302#else /* SCM_BIGDIG */
3303 return scm_make_real ((double) z);
3304#endif /* SCM_BIGDIG */
3305 }
3306 } else if (SCM_BIGP (y)) {
3307 intbig:
f872b822 3308 {
98cb6e75
DH
3309 long int xx = SCM_INUM (x);
3310#ifndef SCM_DIGSTOOBIG
3311 long z = scm_pseudolong (xx);
3312 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3313 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3314#else /* SCM_DIGSTOOBIG */
3315 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3316 scm_longdigs (xx, zdigs);
3317 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3318 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3319#endif /* SCM_DIGSTOOBIG */
0f2d19dd 3320 }
98cb6e75
DH
3321 } else if (SCM_REALP (y)) {
3322 return scm_make_real (xx + SCM_REAL_VALUE (y));
3323 } else if (SCM_COMPLEXP (y)) {
3324 return scm_make_complex (xx + SCM_COMPLEX_REAL (y),
3325 SCM_COMPLEX_IMAG (y));
3326 } else {
3327 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3328 }
98cb6e75
DH
3329 } else if (SCM_BIGP (x)) {
3330 if (SCM_INUMP (y)) {
3331 SCM_SWAP (x, y);
3332 goto intbig;
3333 } else if (SCM_BIGP (y)) {
3334 if (SCM_NUMDIGS (x) > SCM_NUMDIGS (y)) {
3335 SCM_SWAP (x, y);
3336 }
3337 return scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3338 SCM_BIGSIGN (x), y, 0);
3339 } else if (SCM_REALP (y)) {
3340 return scm_make_real (scm_big2dbl (x) + SCM_REAL_VALUE (y));
3341 } else if (SCM_COMPLEXP (y)) {
3342 return scm_make_complex (scm_big2dbl (x) + SCM_COMPLEX_REAL (y),
3343 SCM_COMPLEX_IMAG (y));
3344 } else {
3345 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3346 }
98cb6e75
DH
3347 } else if (SCM_REALP (x)) {
3348 if (SCM_INUMP (y)) {
3349 return scm_make_real (SCM_REAL_VALUE (x) + SCM_INUM (y));
3350 } else if (SCM_BIGP (y)) {
3351 return scm_make_real (SCM_REAL_VALUE (x) + scm_big2dbl (y));
3352 } else if (SCM_REALP (y)) {
3353 return scm_make_real (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
3354 } else if (SCM_COMPLEXP (y)) {
3355 return scm_make_complex (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
3356 SCM_COMPLEX_IMAG (y));
3357 } else {
3358 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3359 }
3360 } else if (SCM_COMPLEXP (x)) {
3361 if (SCM_INUMP (y)) {
3362 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_INUM (y),
3363 SCM_COMPLEX_IMAG (x));
3364 } else if (SCM_BIGP (y)) {
3365 return scm_make_complex (SCM_COMPLEX_REAL (x) + scm_big2dbl (y),
3366 SCM_COMPLEX_IMAG (x));
3367 } else if (SCM_REALP (y)) {
3368 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
3369 SCM_COMPLEX_IMAG (x));
3370 } else if (SCM_COMPLEXP (y)) {
3371 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
3372 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
3373 } else {
3374 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3375 }
3376 } else {
3377 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
3378 }
0f2d19dd
JB
3379}
3380
3381
9de33deb 3382SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
1cc91f1b 3383
0f2d19dd 3384SCM
6e8d25a6 3385scm_difference (SCM x, SCM y)
0f2d19dd 3386{
98cb6e75
DH
3387 if (SCM_UNBNDP (y)) {
3388 if (SCM_INUMP (x)) {
3389 long xx = -SCM_INUM (x);
3390 if (SCM_FIXABLE (xx)) {
3391 return SCM_MAKINUM (xx);
3392 } else {
f872b822 3393#ifdef SCM_BIGDIG
98cb6e75 3394 return scm_long2big (xx);
f3ae5d60 3395#else
98cb6e75 3396 return scm_make_real ((double) xx);
f3ae5d60 3397#endif
f3ae5d60 3398 }
98cb6e75
DH
3399 } else if (SCM_BIGP (x)) {
3400 SCM z = scm_copybig (x, !SCM_BIGSIGN (x));
3401 unsigned int digs = SCM_NUMDIGS (z);
3402 unsigned int size = digs * SCM_BITSPERDIG / SCM_CHAR_BIT;
3403 return size <= sizeof (SCM) ? scm_big2inum (z, digs) : z;
3404 } else if (SCM_REALP (x)) {
3405 return scm_make_real (-SCM_REAL_VALUE (x));
3406 } else if (SCM_COMPLEXP (x)) {
3407 return scm_make_complex (-SCM_COMPLEX_REAL (x), -SCM_COMPLEX_IMAG (x));
3408 } else {
3409 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 3410 }
98cb6e75
DH
3411 }
3412
3413 if (SCM_INUMP (x)) {
3414 long int xx = SCM_INUM (x);
3415 if (SCM_INUMP (y)) {
3416 long int yy = SCM_INUM (y);
3417 long int z = xx - yy;
3418 if (SCM_FIXABLE (z)) {
3419 return SCM_MAKINUM (z);
3420 } else {
f872b822 3421#ifdef SCM_BIGDIG
98cb6e75 3422 return scm_long2big (z);
f872b822 3423#else
98cb6e75 3424 return scm_make_real ((double) z);
f872b822 3425#endif
98cb6e75
DH
3426 }
3427 } else if (SCM_BIGP (y)) {
3428#ifndef SCM_DIGSTOOBIG
3429 long z = scm_pseudolong (xx);
3430 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3431 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3432#else
98cb6e75
DH
3433 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3434 scm_longdigs (xx, zdigs);
3435 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3436 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3437#endif
98cb6e75
DH
3438 } else if (SCM_REALP (y)) {
3439 return scm_make_real (xx - SCM_REAL_VALUE (y));
3440 } else if (SCM_COMPLEXP (y)) {
3441 return scm_make_complex (xx - SCM_COMPLEX_REAL (y),
3442 -SCM_COMPLEX_IMAG (y));
3443 } else {
3444 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 3445 }
98cb6e75
DH
3446 } else if (SCM_BIGP (x)) {
3447 if (SCM_INUMP (y)) {
3448 long int yy = SCM_INUM (y);
3449#ifndef SCM_DIGSTOOBIG
3450 long z = scm_pseudolong (yy);
3451 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3452 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
f872b822 3453#else
98cb6e75
DH
3454 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3455 scm_longdigs (yy, zdigs);
3456 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3457 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
0f2d19dd 3458#endif
98cb6e75
DH
3459 } else if (SCM_BIGP (y)) {
3460 return (SCM_NUMDIGS (x) < SCM_NUMDIGS (y))
3461 ? scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3462 SCM_BIGSIGN (x), y, SCM_BIGSIGNFLAG)
3463 : scm_addbig (SCM_BDIGITS (y), SCM_NUMDIGS (y),
3464 SCM_BIGSIGN (y) ^ SCM_BIGSIGNFLAG, x, 0);
3465 } else if (SCM_REALP (y)) {
3466 return scm_make_real (scm_big2dbl (x) - SCM_REAL_VALUE (y));
3467 } else if (SCM_COMPLEXP (y)) {
3468 return scm_make_complex (scm_big2dbl (x) - SCM_COMPLEX_REAL (y),
3469 - SCM_COMPLEX_IMAG (y));
3470 } else {
3471 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3472 }
3473 } else if (SCM_REALP (x)) {
3474 if (SCM_INUMP (y)) {
3475 return scm_make_real (SCM_REAL_VALUE (x) - SCM_INUM (y));
3476 } else if (SCM_BIGP (y)) {
3477 return scm_make_real (SCM_REAL_VALUE (x) - scm_big2dbl (y));
3478 } else if (SCM_REALP (y)) {
3479 return scm_make_real (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
3480 } else if (SCM_COMPLEXP (y)) {
3481 return scm_make_complex (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
3482 -SCM_COMPLEX_IMAG (y));
3483 } else {
3484 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3485 }
3486 } else if (SCM_COMPLEXP (x)) {
3487 if (SCM_INUMP (y)) {
3488 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_INUM (y),
3489 SCM_COMPLEX_IMAG (x));
3490 } else if (SCM_BIGP (y)) {
3491 return scm_make_complex (SCM_COMPLEX_REAL (x) - scm_big2dbl (y),
3492 SCM_COMPLEX_IMAG (x));
3493 } else if (SCM_REALP (y)) {
3494 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
3495 SCM_COMPLEX_IMAG (x));
3496 } else if (SCM_COMPLEXP (y)) {
3497 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
3498 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
3499 } else {
3500 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3501 }
3502 } else {
3503 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
3504 }
0f2d19dd
JB
3505}
3506
3507
9de33deb 3508SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
1cc91f1b 3509
0f2d19dd 3510SCM
6e8d25a6 3511scm_product (SCM x, SCM y)
0f2d19dd 3512{
f4c627b3
DH
3513 if (SCM_UNBNDP (y)) {
3514 if (SCM_UNBNDP (x)) {
3515 return SCM_MAKINUM (1L);
3516 } else if (SCM_NUMBERP (x)) {
f872b822 3517 return x;
f4c627b3
DH
3518 } else {
3519 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 3520 }
f4c627b3
DH
3521 }
3522
3523 if (SCM_INUMP (x)) {
3524 long xx;
3525
3526 intbig:
3527 xx = SCM_INUM (x);
3528
3529 if (xx == 0) {
f872b822 3530 return x;
f4c627b3
DH
3531 } else if (xx == 1) {
3532 return y;
3533 }
3534
3535 if (SCM_INUMP (y)) {
3536 long yy = SCM_INUM (y);
3537 long kk = xx * yy;
3538 SCM k = SCM_MAKINUM (kk);
3539 if (kk != SCM_INUM (k) || kk / xx != yy) {
f872b822 3540#ifdef SCM_BIGDIG
f4c627b3 3541 int sgn = (xx < 0) ^ (yy < 0);
f872b822 3542#ifndef SCM_DIGSTOOBIG
f4c627b3
DH
3543 long i = scm_pseudolong (xx);
3544 long j = scm_pseudolong (yy);
f872b822
MD
3545 return scm_mulbig ((SCM_BIGDIG *) & i, SCM_DIGSPERLONG,
3546 (SCM_BIGDIG *) & j, SCM_DIGSPERLONG, sgn);
3547#else /* SCM_DIGSTOOBIG */
f4c627b3
DH
3548 SCM_BIGDIG xdigs [SCM_DIGSPERLONG];
3549 SCM_BIGDIG ydigs [SCM_DIGSPERLONG];
3550 scm_longdigs (xx, xdigs);
3551 scm_longdigs (yy, ydigs);
3552 return scm_mulbig (xdigs, SCM_DIGSPERLONG,
3553 ydigs, SCM_DIGSPERLONG,
f872b822
MD
3554 sgn);
3555#endif
f4c627b3
DH
3556#else
3557 return scm_make_real (((double) xx) * ((double) yy));
3558#endif
3559 } else {
3560 return k;
0f2d19dd 3561 }
f4c627b3
DH
3562 } else if (SCM_BIGP (y)) {
3563#ifndef SCM_DIGSTOOBIG
3564 long z = scm_pseudolong (xx);
3565 return scm_mulbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3566 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3567 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3568#else
f4c627b3
DH
3569 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3570 scm_longdigs (xx, zdigs);
3571 return scm_mulbig (zdigs, SCM_DIGSPERLONG,
3572 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3573 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3574#endif
f4c627b3
DH
3575 } else if (SCM_REALP (y)) {
3576 return scm_make_real (xx * SCM_REAL_VALUE (y));
3577 } else if (SCM_COMPLEXP (y)) {
3578 return scm_make_complex (xx * SCM_COMPLEX_REAL (y),
3579 xx * SCM_COMPLEX_IMAG (y));
3580 } else {
3581 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3582 }
3583 } else if (SCM_BIGP (x)) {
3584 if (SCM_INUMP (y)) {
3585 SCM_SWAP (x, y);
3586 goto intbig;
3587 } else if (SCM_BIGP (y)) {
3588 return scm_mulbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3589 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3590 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y));
3591 } else if (SCM_REALP (y)) {
3592 return scm_make_real (scm_big2dbl (x) * SCM_REAL_VALUE (y));
3593 } else if (SCM_COMPLEXP (y)) {
3594 double z = scm_big2dbl (x);
3595 return scm_make_complex (z * SCM_COMPLEX_REAL (y),
3596 z * SCM_COMPLEX_IMAG (y));
3597 } else {
3598 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3599 }
3600 } else if (SCM_REALP (x)) {
3601 if (SCM_INUMP (y)) {
3602 return scm_make_real (SCM_INUM (y) * SCM_REAL_VALUE (x));
3603 } else if (SCM_BIGP (y)) {
3604 return scm_make_real (scm_big2dbl (y) * SCM_REAL_VALUE (x));
3605 } else if (SCM_REALP (y)) {
3606 return scm_make_real (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
3607 } else if (SCM_COMPLEXP (y)) {
3608 return scm_make_complex (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
3609 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
3610 } else {
3611 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3612 }
3613 } else if (SCM_COMPLEXP (x)) {
3614 if (SCM_INUMP (y)) {
3615 return scm_make_complex (SCM_INUM (y) * SCM_COMPLEX_REAL (x),
3616 SCM_INUM (y) * SCM_COMPLEX_IMAG (x));
3617 } else if (SCM_BIGP (y)) {
3618 double z = scm_big2dbl (y);
3619 return scm_make_complex (z * SCM_COMPLEX_REAL (x),
3620 z * SCM_COMPLEX_IMAG (x));
3621 } else if (SCM_REALP (y)) {
3622 return scm_make_complex (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
3623 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
3624 } else if (SCM_COMPLEXP (y)) {
3625 return scm_make_complex (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
3626 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
3627 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
3628 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
3629 } else {
3630 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3631 }
3632 } else {
3633 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
3634 }
3635}
3636
3637
0f2d19dd 3638double
6e8d25a6 3639scm_num2dbl (SCM a, const char *why)
f4c627b3 3640#define FUNC_NAME why
0f2d19dd 3641{
f4c627b3 3642 if (SCM_INUMP (a)) {
0f2d19dd 3643 return (double) SCM_INUM (a);
f4c627b3
DH
3644 } else if (SCM_BIGP (a)) {
3645 return scm_big2dbl (a);
3646 } else if (SCM_REALP (a)) {
3647 return (SCM_REAL_VALUE (a));
3648 } else {
3649 SCM_WRONG_TYPE_ARG (SCM_ARGn, a);
3650 }
0f2d19dd 3651}
f4c627b3 3652#undef FUNC_NAME
0f2d19dd
JB
3653
3654
9de33deb 3655SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
1cc91f1b 3656
0f2d19dd 3657SCM
6e8d25a6 3658scm_divide (SCM x, SCM y)
0f2d19dd 3659{
f8de44c1
DH
3660 double a;
3661
3662 if (SCM_UNBNDP (y)) {
3663 if (SCM_UNBNDP (x)) {
3664 SCM_WTA_DISPATCH_0 (g_divide, x, SCM_ARG1, s_divide);
3665 } else if (SCM_INUMP (x)) {
3666 if (SCM_EQ_P (x, SCM_MAKINUM (1L)) || SCM_EQ_P (x, SCM_MAKINUM (-1L))) {
3667 return x;
3668 } else {
3669 return scm_make_real (1.0 / (double) SCM_INUM (x));
3670 }
f8de44c1
DH
3671 } else if (SCM_BIGP (x)) {
3672 return scm_make_real (1.0 / scm_big2dbl (x));
f8de44c1
DH
3673 } else if (SCM_REALP (x)) {
3674 return scm_make_real (1.0 / SCM_REAL_VALUE (x));
3675 } else if (SCM_COMPLEXP (x)) {
3676 double r = SCM_COMPLEX_REAL (x);
3677 double i = SCM_COMPLEX_IMAG (x);
3678 double d = r * r + i * i;
3679 return scm_make_complex (r / d, -i / d);
3680 } else {
3681 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
3682 }
3683 }
3684
3685 if (SCM_INUMP (x)) {
3686 long xx = SCM_INUM (x);
3687 if (SCM_INUMP (y)) {
3688 long yy = SCM_INUM (y);
3689 if (yy == 0) {
f4c627b3 3690 scm_num_overflow (s_divide);
f8de44c1
DH
3691 } else if (xx % yy != 0) {
3692 return scm_make_real ((double) xx / (double) yy);
3693 } else {
3694 long z = xx / yy;
3695 if (SCM_FIXABLE (z)) {
3696 return SCM_MAKINUM (z);
3697 } else {
f872b822 3698#ifdef SCM_BIGDIG
f8de44c1 3699 return scm_long2big (z);
f872b822 3700#else
f8de44c1 3701 return scm_make_real ((double) xx / (double) yy);
f872b822 3702#endif
f872b822 3703 }
f8de44c1 3704 }
f8de44c1
DH
3705 } else if (SCM_BIGP (y)) {
3706 return scm_make_real ((double) xx / scm_big2dbl (y));
f8de44c1
DH
3707 } else if (SCM_REALP (y)) {
3708 return scm_make_real ((double) xx / SCM_REAL_VALUE (y));
3709 } else if (SCM_COMPLEXP (y)) {
3710 a = xx;
3711 complex_div: /* y _must_ be a complex number */
3712 {
3713 double r = SCM_COMPLEX_REAL (y);
3714 double i = SCM_COMPLEX_IMAG (y);
3715 double d = r * r + i * i;
3716 return scm_make_complex ((a * r) / d, (-a * i) / d);
3717 }
3718 } else {
3719 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
3720 }
f8de44c1
DH
3721 } else if (SCM_BIGP (x)) {
3722 if (SCM_INUMP (y)) {
3723 long int yy = SCM_INUM (y);
3724 if (yy == 0) {
3725 scm_num_overflow (s_divide);
3726 } else if (yy == 1) {
3727 return x;
3728 } else {
3729 long z = yy < 0 ? -yy : yy;
3730 if (z < SCM_BIGRAD) {
3731 SCM w = scm_copybig (x, SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0));
3732 return scm_divbigdig (SCM_BDIGITS (w), SCM_NUMDIGS (w),
3733 (SCM_BIGDIG) z)
3734 ? scm_make_real (scm_big2dbl (x) / (double) yy)
3735 : scm_normbig (w);
3736 } else {
3737 SCM w;
3738#ifndef SCM_DIGSTOOBIG
3739 z = scm_pseudolong (z);
3740 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3741 (SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3742 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 3743#else
f8de44c1
DH
3744 SCM_BIGDIG zdigs[SCM_DIGSPERLONG];
3745 scm_longdigs (z, zdigs);
3746 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3747 zdigs, SCM_DIGSPERLONG,
3748 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 3749#endif
f4c627b3
DH
3750 return (!SCM_UNBNDP (w))
3751 ? w
3752 : scm_make_real (scm_big2dbl (x) / (double) yy);
f872b822 3753 }
f8de44c1
DH
3754 }
3755 } else if (SCM_BIGP (y)) {
3756 SCM w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3757 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3758 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y), 3);
f4c627b3
DH
3759 return (!SCM_UNBNDP (w))
3760 ? w
3761 : scm_make_real (scm_big2dbl (x) / scm_big2dbl (y));
f8de44c1
DH
3762 } else if (SCM_REALP (y)) {
3763 return scm_make_real (scm_big2dbl (x) / SCM_REAL_VALUE (y));
3764 } else if (SCM_COMPLEXP (y)) {
3765 a = scm_big2dbl (x);
3766 goto complex_div;
3767 } else {
3768 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 3769 }
f8de44c1
DH
3770 } else if (SCM_REALP (x)) {
3771 double rx = SCM_REAL_VALUE (x);
3772 if (SCM_INUMP (y)) {
3773 return scm_make_real (rx / (double) SCM_INUM (y));
f8de44c1
DH
3774 } else if (SCM_BIGP (y)) {
3775 return scm_make_real (rx / scm_big2dbl (y));
f8de44c1
DH
3776 } else if (SCM_REALP (y)) {
3777 return scm_make_real (rx / SCM_REAL_VALUE (y));
3778 } else if (SCM_COMPLEXP (y)) {
3779 a = rx;
3780 goto complex_div;
3781 } else {
3782 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 3783 }
f8de44c1
DH
3784 } else if (SCM_COMPLEXP (x)) {
3785 double rx = SCM_COMPLEX_REAL (x);
3786 double ix = SCM_COMPLEX_IMAG (x);
3787 if (SCM_INUMP (y)) {
3788 double d = SCM_INUM (y);
3789 return scm_make_complex (rx / d, ix / d);
f8de44c1
DH
3790 } else if (SCM_BIGP (y)) {
3791 double d = scm_big2dbl (y);
3792 return scm_make_complex (rx / d, ix / d);
f8de44c1
DH
3793 } else if (SCM_REALP (y)) {
3794 double d = SCM_REAL_VALUE (y);
3795 return scm_make_complex (rx / d, ix / d);
3796 } else if (SCM_COMPLEXP (y)) {
3797 double ry = SCM_COMPLEX_REAL (y);
3798 double iy = SCM_COMPLEX_IMAG (y);
3799 double d = ry * ry + iy * iy;
3800 return scm_make_complex ((rx * ry + ix * iy) / d,
3801 (ix * ry - rx * iy) / d);
3802 } else {
3803 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
3804 }
3805 } else {
3806 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd
JB
3807 }
3808}
3809
3810
9de33deb 3811SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_cxr, (SCM (*)()) scm_asinh, g_asinh);
1cc91f1b 3812
0f2d19dd 3813double
6e8d25a6 3814scm_asinh (double x)
0f2d19dd 3815{
f872b822 3816 return log (x + sqrt (x * x + 1));
0f2d19dd
JB
3817}
3818
3819
3820
3821
9de33deb 3822SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_cxr, (SCM (*)()) scm_acosh, g_acosh);
1cc91f1b 3823
0f2d19dd 3824double
6e8d25a6 3825scm_acosh (double x)
0f2d19dd 3826{
f872b822 3827 return log (x + sqrt (x * x - 1));
0f2d19dd
JB
3828}
3829
3830
3831
3832
9de33deb 3833SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_cxr, (SCM (*)()) scm_atanh, g_atanh);
1cc91f1b 3834
0f2d19dd 3835double
6e8d25a6 3836scm_atanh (double x)
0f2d19dd 3837{
f872b822 3838 return 0.5 * log ((1 + x) / (1 - x));
0f2d19dd
JB
3839}
3840
3841
3842
3843
9de33deb 3844SCM_GPROC1 (s_truncate, "truncate", scm_tc7_cxr, (SCM (*)()) scm_truncate, g_truncate);
1cc91f1b 3845
0f2d19dd 3846double
6e8d25a6 3847scm_truncate (double x)
0f2d19dd 3848{
f872b822
MD
3849 if (x < 0.0)
3850 return -floor (-x);
3851 return floor (x);
0f2d19dd
JB
3852}
3853
3854
3855
9de33deb 3856SCM_GPROC1 (s_round, "round", scm_tc7_cxr, (SCM (*)()) scm_round, g_round);
1cc91f1b 3857
0f2d19dd 3858double
6e8d25a6 3859scm_round (double x)
0f2d19dd
JB
3860{
3861 double plus_half = x + 0.5;
f872b822 3862 double result = floor (plus_half);
0f2d19dd 3863 /* Adjust so that the scm_round is towards even. */
f872b822 3864 return (plus_half == result && plus_half / 2 != floor (plus_half / 2))
0f2d19dd
JB
3865 ? result - 1 : result;
3866}
3867
3868
3869
9de33deb 3870SCM_GPROC1 (s_exact_to_inexact, "exact->inexact", scm_tc7_cxr, (SCM (*)()) scm_exact_to_inexact, g_exact_to_inexact);
1cc91f1b 3871
0f2d19dd 3872double
6e8d25a6 3873scm_exact_to_inexact (double z)
0f2d19dd
JB
3874{
3875 return z;
3876}
3877
3878
9de33deb
MD
3879SCM_GPROC1 (s_i_floor, "floor", scm_tc7_cxr, (SCM (*)()) floor, g_i_floor);
3880SCM_GPROC1 (s_i_ceil, "ceiling", scm_tc7_cxr, (SCM (*)()) ceil, g_i_ceil);
3881SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_cxr, (SCM (*)()) sqrt, g_i_sqrt);
3882SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_cxr, (SCM (*)()) fabs, g_i_abs);
3883SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_cxr, (SCM (*)()) exp, g_i_exp);
3884SCM_GPROC1 (s_i_log, "$log", scm_tc7_cxr, (SCM (*)()) log, g_i_log);
3885SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_cxr, (SCM (*)()) sin, g_i_sin);
3886SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_cxr, (SCM (*)()) cos, g_i_cos);
3887SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_cxr, (SCM (*)()) tan, g_i_tan);
3888SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_cxr, (SCM (*)()) asin, g_i_asin);
3889SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_cxr, (SCM (*)()) acos, g_i_acos);
3890SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_cxr, (SCM (*)()) atan, g_i_atan);
3891SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_cxr, (SCM (*)()) sinh, g_i_sinh);
3892SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_cxr, (SCM (*)()) cosh, g_i_cosh);
3893SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_cxr, (SCM (*)()) tanh, g_i_tanh);
f872b822
MD
3894
3895struct dpair
3896{
3897 double x, y;
3898};
3899
3eeba8d4
JB
3900static void scm_two_doubles (SCM z1,
3901 SCM z2,
3902 const char *sstring,
3903 struct dpair * xy);
f872b822
MD
3904
3905static void
6e8d25a6 3906scm_two_doubles (SCM z1, SCM z2, const char *sstring, struct dpair *xy)
0f2d19dd 3907{
98cb6e75 3908 if (SCM_INUMP (z1)) {
f872b822 3909 xy->x = SCM_INUM (z1);
98cb6e75
DH
3910 } else if (SCM_BIGP (z1)) {
3911 xy->x = scm_big2dbl (z1);
3912 } else if (SCM_REALP (z1)) {
3913 xy->x = SCM_REAL_VALUE (z1);
3914 } else {
3915 scm_wrong_type_arg (sstring, SCM_ARG1, z1);
3916 }
3917
3918 if (SCM_INUMP (z2)) {
f872b822 3919 xy->y = SCM_INUM (z2);
98cb6e75
DH
3920 } else if (SCM_BIGP (z2)) {
3921 xy->y = scm_big2dbl (z2);
3922 } else if (SCM_REALP (z2)) {
3923 xy->y = SCM_REAL_VALUE (z2);
3924 } else {
3925 scm_wrong_type_arg (sstring, SCM_ARG2, z2);
3926 }
0f2d19dd
JB
3927}
3928
3929
a1ec6916 3930SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
1bbd0b84 3931 (SCM z1, SCM z2),
bb628794 3932 "")
1bbd0b84 3933#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
3934{
3935 struct dpair xy;
1bbd0b84 3936 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3937 return scm_make_real (pow (xy.x, xy.y));
0f2d19dd 3938}
1bbd0b84 3939#undef FUNC_NAME
0f2d19dd
JB
3940
3941
a1ec6916 3942SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
1bbd0b84 3943 (SCM z1, SCM z2),
b380b885 3944 "")
1bbd0b84 3945#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
3946{
3947 struct dpair xy;
1bbd0b84 3948 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3949 return scm_make_real (atan2 (xy.x, xy.y));
0f2d19dd 3950}
1bbd0b84 3951#undef FUNC_NAME
0f2d19dd
JB
3952
3953
a1ec6916 3954SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794
DH
3955 (SCM real, SCM imaginary),
3956 "Return a complex number constructed of the given REAL and\n"
3957 "IMAGINARY parts.")
1bbd0b84 3958#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
3959{
3960 struct dpair xy;
bb628794 3961 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
f8de44c1 3962 return scm_make_complex (xy.x, xy.y);
0f2d19dd 3963}
1bbd0b84 3964#undef FUNC_NAME
0f2d19dd
JB
3965
3966
3967
a1ec6916 3968SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
1bbd0b84 3969 (SCM z1, SCM z2),
bb628794 3970 "Return the complex number Z1 * e^(i * Z2).")
1bbd0b84 3971#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
3972{
3973 struct dpair xy;
1bbd0b84 3974 scm_two_doubles (z1, z2, FUNC_NAME, &xy);
f8de44c1 3975 return scm_make_complex (xy.x * cos (xy.y), xy.x * sin (xy.y));
0f2d19dd 3976}
1bbd0b84 3977#undef FUNC_NAME
0f2d19dd
JB
3978
3979
152f82bf 3980SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
1cc91f1b 3981
0f2d19dd 3982SCM
6e8d25a6 3983scm_real_part (SCM z)
0f2d19dd 3984{
c2ff8ab0
DH
3985 if (SCM_INUMP (z)) {
3986 return z;
3987 } else if (SCM_BIGP (z)) {
3988 return z;
3989 } else if (SCM_REALP (z)) {
3990 return z;
3991 } else if (SCM_COMPLEXP (z)) {
3992 return scm_make_real (SCM_COMPLEX_REAL (z));
3993 } else {
3994 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
3995 }
0f2d19dd
JB
3996}
3997
3998
152f82bf 3999SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
1cc91f1b 4000
0f2d19dd 4001SCM
6e8d25a6 4002scm_imag_part (SCM z)
0f2d19dd 4003{
c2ff8ab0 4004 if (SCM_INUMP (z)) {
f872b822 4005 return SCM_INUM0;
c2ff8ab0 4006 } else if (SCM_BIGP (z)) {
f872b822 4007 return SCM_INUM0;
c2ff8ab0
DH
4008 } else if (SCM_REALP (z)) {
4009 return scm_flo0;
4010 } else if (SCM_COMPLEXP (z)) {
4011 return scm_make_real (SCM_COMPLEX_IMAG (z));
4012 } else {
4013 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
4014 }
0f2d19dd
JB
4015}
4016
4017
9de33deb 4018SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
1cc91f1b 4019
0f2d19dd 4020SCM
6e8d25a6 4021scm_magnitude (SCM z)
0f2d19dd 4022{
c2ff8ab0 4023 if (SCM_INUMP (z)) {
5986c47d
DH
4024 long int zz = SCM_INUM (z);
4025 if (zz >= 0) {
4026 return z;
4027 } else if (SCM_POSFIXABLE (-zz)) {
4028 return SCM_MAKINUM (-zz);
4029 } else {
4030#ifdef SCM_BIGDIG
4031 return scm_long2big (-zz);
4032#else
4033 scm_num_overflow (s_magnitude);
4034#endif
4035 }
c2ff8ab0 4036 } else if (SCM_BIGP (z)) {
5986c47d
DH
4037 if (!SCM_BIGSIGN (z)) {
4038 return z;
4039 } else {
4040 return scm_copybig (z, 0);
4041 }
c2ff8ab0
DH
4042 } else if (SCM_REALP (z)) {
4043 return scm_make_real (fabs (SCM_REAL_VALUE (z)));
4044 } else if (SCM_COMPLEXP (z)) {
4045 double r = SCM_COMPLEX_REAL (z);
4046 double i = SCM_COMPLEX_IMAG (z);
4047 return scm_make_real (sqrt (i * i + r * r));
4048 } else {
4049 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
4050 }
0f2d19dd
JB
4051}
4052
4053
9de33deb 4054SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
1cc91f1b 4055
0f2d19dd 4056SCM
6e8d25a6 4057scm_angle (SCM z)
0f2d19dd 4058{
f4c627b3
DH
4059 if (SCM_INUMP (z)) {
4060 if (SCM_INUM (z) >= 0) {
4061 return scm_make_real (atan2 (0.0, 1.0));
4062 } else {
4063 return scm_make_real (atan2 (0.0, -1.0));
f872b822 4064 }
f4c627b3
DH
4065 } else if (SCM_BIGP (z)) {
4066 if (SCM_BIGSIGN (z)) {
4067 return scm_make_real (atan2 (0.0, -1.0));
4068 } else {
4069 return scm_make_real (atan2 (0.0, 1.0));
0f2d19dd 4070 }
f4c627b3
DH
4071 } else if (SCM_REALP (z)) {
4072 return scm_make_real (atan2 (0.0, SCM_REAL_VALUE (z)));
4073 } else if (SCM_COMPLEXP (z)) {
4074 return scm_make_real (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
4075 } else {
4076 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
4077 }
0f2d19dd
JB
4078}
4079
4080
a1ec6916 4081SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 4082 (SCM z),
bb628794 4083 "Returns an exact number that is numerically closest to Z.")
1bbd0b84 4084#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 4085{
c2ff8ab0 4086 if (SCM_INUMP (z)) {
f872b822 4087 return z;
c2ff8ab0 4088 } else if (SCM_BIGP (z)) {
f872b822 4089 return z;
c2ff8ab0
DH
4090 } else if (SCM_REALP (z)) {
4091 double u = floor (SCM_REAL_VALUE (z) + 0.5);
4092 long lu = (long) u;
4093 if (SCM_FIXABLE (lu)) {
4094 return SCM_MAKINUM (lu);
f872b822 4095#ifdef SCM_BIGDIG
c2ff8ab0
DH
4096 } else if (isfinite (u)) {
4097 return scm_dbl2big (u);
f872b822 4098#endif
c2ff8ab0
DH
4099 } else {
4100 scm_num_overflow (s_scm_inexact_to_exact);
4101 }
4102 } else {
4103 SCM_WRONG_TYPE_ARG (1, z);
4104 }
0f2d19dd 4105}
1bbd0b84 4106#undef FUNC_NAME
0f2d19dd
JB
4107
4108
0f2d19dd 4109#ifdef SCM_BIGDIG
0f2d19dd 4110/* d must be integer */
1cc91f1b 4111
0f2d19dd 4112SCM
6e8d25a6 4113scm_dbl2big (double d)
0f2d19dd
JB
4114{
4115 scm_sizet i = 0;
4116 long c;
4117 SCM_BIGDIG *digits;
4118 SCM ans;
f872b822
MD
4119 double u = (d < 0) ? -d : d;
4120 while (0 != floor (u))
4121 {
4122 u /= SCM_BIGRAD;
4123 i++;
4124 }
4125 ans = scm_mkbig (i, d < 0);
4126 digits = SCM_BDIGITS (ans);
4127 while (i--)
4128 {
4129 u *= SCM_BIGRAD;
4130 c = floor (u);
4131 u -= c;
4132 digits[i] = c;
4133 }
cf7c17e9 4134#ifndef SCM_RECKLESS
e1724d20 4135 if (u != 0)
52859adf 4136 scm_num_overflow ("dbl2big");
e1724d20 4137#endif
0f2d19dd
JB
4138 return ans;
4139}
4140
4141
4142
0f2d19dd 4143double
6e8d25a6 4144scm_big2dbl (SCM b)
0f2d19dd
JB
4145{
4146 double ans = 0.0;
f872b822
MD
4147 scm_sizet i = SCM_NUMDIGS (b);
4148 SCM_BIGDIG *digits = SCM_BDIGITS (b);
4149 while (i--)
4150 ans = digits[i] + SCM_BIGRAD * ans;
f3ae5d60
MD
4151 if (SCM_BIGSIGN (b))
4152 return - ans;
0f2d19dd
JB
4153 return ans;
4154}
f872b822 4155#endif
0f2d19dd 4156
1cc91f1b 4157
0f2d19dd 4158SCM
6e8d25a6 4159scm_long2num (long sl)
0f2d19dd 4160{
f872b822
MD
4161 if (!SCM_FIXABLE (sl))
4162 {
0f2d19dd 4163#ifdef SCM_BIGDIG
f872b822 4164 return scm_long2big (sl);
0f2d19dd 4165#else
f8de44c1 4166 return scm_make_real ((double) sl);
f872b822
MD
4167#endif
4168 }
4169 return SCM_MAKINUM (sl);
0f2d19dd
JB
4170}
4171
4172
5c11cc9d 4173#ifdef HAVE_LONG_LONGS
1cc91f1b 4174
0f2d19dd 4175SCM
6e8d25a6 4176scm_long_long2num (long_long sl)
0f2d19dd 4177{
f872b822
MD
4178 if (!SCM_FIXABLE (sl))
4179 {
0f2d19dd 4180#ifdef SCM_BIGDIG
f872b822 4181 return scm_long_long2big (sl);
0f2d19dd 4182#else
f8de44c1 4183 return scm_make_real ((double) sl);
f872b822
MD
4184#endif
4185 }
f2961ccd
DH
4186 else
4187 {
4188 /* we know that sl fits into an inum */
4189 return SCM_MAKINUM ((scm_bits_t) sl);
4190 }
0f2d19dd 4191}
0f2d19dd 4192
f69a01b2 4193#endif /* HAVE_LONG_LONGS */
0f2d19dd 4194
1cc91f1b 4195
0f2d19dd 4196SCM
6e8d25a6 4197scm_ulong2num (unsigned long sl)
0f2d19dd 4198{
f872b822
MD
4199 if (!SCM_POSFIXABLE (sl))
4200 {
0f2d19dd 4201#ifdef SCM_BIGDIG
f872b822 4202 return scm_ulong2big (sl);
0f2d19dd 4203#else
f8de44c1 4204 return scm_make_real ((double) sl);
f872b822
MD
4205#endif
4206 }
4207 return SCM_MAKINUM (sl);
0f2d19dd
JB
4208}
4209
1cc91f1b 4210
0f2d19dd 4211long
6e8d25a6 4212scm_num2long (SCM num, char *pos, const char *s_caller)
0f2d19dd 4213{
98cb6e75
DH
4214 if (SCM_INUMP (num)) {
4215 return SCM_INUM (num);
4216 } else if (SCM_BIGP (num)) {
4217 long int res;
4218 /* can't use res directly in case num is -2^31. */
4219 unsigned long int pos_res = 0;
4220 unsigned long int old_res = 0;
4221 scm_sizet l;
4222
4223 for (l = SCM_NUMDIGS (num); l--;) {
4224 pos_res = SCM_BIGUP (pos_res) + SCM_BDIGITS (num)[l];
4225 if (pos_res >= old_res) {
4226 old_res = pos_res;
4227 } else {
4228 /* overflow. */
4229 scm_out_of_range (s_caller, num);
4230 }
0f2d19dd 4231 }
98cb6e75
DH
4232 if (SCM_BIGSIGN (num)) {
4233 res = -pos_res;
4234 if (res <= 0) {
4235 return res;
4236 } else {
4237 scm_out_of_range (s_caller, num);
4238 }
4239 } else {
4240 res = pos_res;
4241 if (res >= 0) {
4242 return res;
4243 } else {
4244 scm_out_of_range (s_caller, num);
4245 }
0f2d19dd 4246 }
98cb6e75
DH
4247 } else if (SCM_REALP (num)) {
4248 double u = SCM_REAL_VALUE (num);
4249 long int res = u;
4250 if ((double) res == u) {
5c11cc9d 4251 return res;
98cb6e75
DH
4252 } else {
4253 scm_out_of_range (s_caller, num);
f872b822 4254 }
98cb6e75
DH
4255 } else {
4256 scm_wrong_type_arg (s_caller, (int) pos, num);
4257 }
0f2d19dd
JB
4258}
4259
4260
5c11cc9d 4261#ifdef HAVE_LONG_LONGS
1cc91f1b 4262
0f2d19dd 4263long_long
6e8d25a6 4264scm_num2long_long (SCM num, char *pos, const char *s_caller)
0f2d19dd 4265{
98cb6e75
DH
4266 if (SCM_INUMP (num)) {
4267 return SCM_INUM (num);
4268 } else if (SCM_BIGP (num)) {
4269 long long res;
4270 /* can't use res directly in case num is -2^63. */
4271 unsigned long long int pos_res = 0;
4272 unsigned long long int old_res = 0;
4273 scm_sizet l;
4274
4275 for (l = SCM_NUMDIGS (num); l--;) {
4276 pos_res = SCM_LONGLONGBIGUP (pos_res) + SCM_BDIGITS (num)[l];
4277 if (pos_res >= old_res) {
4278 old_res = pos_res;
4279 } else {
4280 /* overflow. */
4281 scm_out_of_range (s_caller, num);
4282 }
0f2d19dd 4283 }
98cb6e75
DH
4284 if (SCM_BIGSIGN (num)) {
4285 res = -pos_res;
4286 if (res <= 0) {
4287 return res;
4288 } else {
4289 scm_out_of_range (s_caller, num);
4290 }
4291 } else {
4292 res = pos_res;
4293 if (res >= 0) {
4294 return res;
4295 } else {
4296 scm_out_of_range (s_caller, num);
4297 }
f872b822 4298 }
98cb6e75
DH
4299 } else if (SCM_REALP (num)) {
4300 double u = SCM_REAL_VALUE (num);
4301 long long int res = u;
4302 if ((double) res == u) {
f872b822 4303 return res;
98cb6e75
DH
4304 } else {
4305 scm_out_of_range (s_caller, num);
f872b822 4306 }
98cb6e75
DH
4307 } else {
4308 scm_wrong_type_arg (s_caller, (int) pos, num);
4309 }
0f2d19dd 4310}
0f2d19dd 4311
f69a01b2 4312#endif /* HAVE_LONG_LONGS */
0f2d19dd 4313
1cc91f1b 4314
0f2d19dd 4315unsigned long
6e8d25a6 4316scm_num2ulong (SCM num, char *pos, const char *s_caller)
0f2d19dd 4317{
98cb6e75
DH
4318 if (SCM_INUMP (num)) {
4319 long nnum = SCM_INUM (num);
4320 if (nnum >= 0) {
4321 return nnum;
4322 } else {
4323 scm_out_of_range (s_caller, num);
4324 }
4325 } else if (SCM_BIGP (num)) {
4326 unsigned long int res = 0;
4327 unsigned long int old_res = 0;
4328 scm_sizet l;
4329
4330 for (l = SCM_NUMDIGS (num); l--;) {
4331 res = SCM_BIGUP (res) + SCM_BDIGITS (num)[l];
4332 if (res >= old_res) {
4333 old_res = res;
4334 } else {
4335 scm_out_of_range (s_caller, num);
4336 }
0f2d19dd 4337 }
98cb6e75
DH
4338 return res;
4339 } else if (SCM_REALP (num)) {
4340 double u = SCM_REAL_VALUE (num);
4341 unsigned long int res = u;
4342 if ((double) res == u) {
f872b822 4343 return res;
98cb6e75
DH
4344 } else {
4345 scm_out_of_range (s_caller, num);
f872b822 4346 }
98cb6e75
DH
4347 } else {
4348 scm_wrong_type_arg (s_caller, (int) pos, num);
4349 }
0f2d19dd
JB
4350}
4351
4352
0f2d19dd
JB
4353void
4354scm_init_numbers ()
0f2d19dd 4355{
f3ae5d60
MD
4356 scm_add_feature ("complex");
4357 scm_add_feature ("inexact");
5986c47d 4358 scm_flo0 = scm_make_real (0.0);
f872b822 4359#ifdef DBL_DIG
0f2d19dd 4360 scm_dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
f872b822 4361#else
0f2d19dd
JB
4362 { /* determine floating point precision */
4363 double f = 0.1;
f872b822 4364 double fsum = 1.0 + f;
bb628794
DH
4365 while (fsum != 1.0) {
4366 if (++scm_dblprec > 20) {
4367 fsum = 1.0;
4368 } else {
f872b822 4369 f /= 10.0;
bb628794 4370 fsum = f + 1.0;
f872b822 4371 }
bb628794 4372 }
f872b822 4373 scm_dblprec = scm_dblprec - 1;
0f2d19dd 4374 }
f872b822 4375#endif /* DBL_DIG */
8dc9439f 4376#ifndef SCM_MAGIC_SNARFER
a0599745 4377#include "libguile/numbers.x"
8dc9439f 4378#endif
0f2d19dd 4379}
89e00824
ML
4380
4381/*
4382 Local Variables:
4383 c-file-style: "gnu"
4384 End:
4385*/