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