(AC_CHECK_FUNCS): Check for copysign.
[bpt/guile.git] / libguile / numbers.c
CommitLineData
be54b15d 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001 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
09fb7599
DH
68#define SCM_SWAP(x,y) do { SCM __t = x; x = y; y = __t; } while (0)
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);
8a525303 901#ifndef SCM_RECKLESS
09fb7599 902 } else if (SCM_NUMBERP (n1)) {
d28da049 903 return n1;
09fb7599
DH
904 } else {
905 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
906#else
907 } else {
908 return n1;
909#endif
d28da049 910 }
8a525303 911 }
09fb7599
DH
912
913 if (SCM_INUMP (n1)) {
9a00c9fc 914 nn1 = SCM_INUM (n1);
09fb7599
DH
915 if (SCM_INUMP (n2)) {
916 long nn2 = SCM_INUM (n2);
917 return SCM_MAKINUM (nn1 & nn2);
09fb7599
DH
918 } else if SCM_BIGP (n2) {
919 intbig:
920 {
8a525303 921# ifndef SCM_DIGSTOOBIG
09fb7599
DH
922 long z = scm_pseudolong (nn1);
923 if ((nn1 < 0) && SCM_BIGSIGN (n2)) {
924 return scm_big_ior ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
925 SCM_BIGSIGNFLAG, n2);
926 } else {
927 return scm_big_and ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
928 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, 0);
929 }
8a525303 930# else
09fb7599
DH
931 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
932 scm_longdigs (nn1, zdigs);
933 if ((nn1 < 0) && SCM_BIGSIGN (n2)) {
934 return scm_big_ior (zdigs, SCM_DIGSPERLONG, SCM_BIGSIGNFLAG, n2);
935 } else {
936 return scm_big_and (zdigs, SCM_DIGSPERLONG,
937 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, 0);
938 }
8a525303 939# endif
09fb7599 940 }
09fb7599
DH
941 } else {
942 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
943 }
09fb7599
DH
944 } else if (SCM_BIGP (n1)) {
945 if (SCM_INUMP (n2)) {
946 SCM_SWAP (n1, n2);
9a00c9fc 947 nn1 = SCM_INUM (n1);
09fb7599
DH
948 goto intbig;
949 } else if (SCM_BIGP (n2)) {
950 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
951 SCM_SWAP (n1, n2);
952 };
953 if ((SCM_BIGSIGN (n1)) && SCM_BIGSIGN (n2)) {
954 return scm_big_ior (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
955 SCM_BIGSIGNFLAG, n2);
956 } else {
957 return scm_big_and (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
958 SCM_BIGSIGN (n1), n2, 0);
959 }
960 } else {
961 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
962 }
09fb7599
DH
963 } else {
964 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
965 }
0f2d19dd 966}
1bbd0b84 967#undef FUNC_NAME
0f2d19dd 968
09fb7599 969
c3ee7520 970SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
1bbd0b84 971 (SCM n1, SCM n2),
3c3db128
GH
972 "Return the bitwise OR of the integer arguments.\n\n"
973 "@lisp\n"
974 "(logior) @result{} 0\n"
975 "(logior 7) @result{} 7\n"
976 "(logior #b000 #b001 #b011) @result{} 3\n"
1e6808ea 977 "@end lisp")
1bbd0b84 978#define FUNC_NAME s_scm_logior
0f2d19dd 979{
9a00c9fc
DH
980 long int nn1;
981
09fb7599
DH
982 if (SCM_UNBNDP (n2)) {
983 if (SCM_UNBNDP (n1)) {
984 return SCM_INUM0;
8a525303 985#ifndef SCM_RECKLESS
09fb7599 986 } else if (SCM_NUMBERP (n1)) {
d28da049 987 return n1;
09fb7599
DH
988 } else {
989 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
990#else
991 } else {
992 return n1;
993#endif
d28da049 994 }
8a525303 995 }
09fb7599
DH
996
997 if (SCM_INUMP (n1)) {
9a00c9fc 998 nn1 = SCM_INUM (n1);
09fb7599
DH
999 if (SCM_INUMP (n2)) {
1000 long nn2 = SCM_INUM (n2);
1001 return SCM_MAKINUM (nn1 | nn2);
09fb7599
DH
1002 } else if (SCM_BIGP (n2)) {
1003 intbig:
1004 {
8a525303 1005# ifndef SCM_DIGSTOOBIG
09fb7599
DH
1006 long z = scm_pseudolong (nn1);
1007 if ((!(nn1 < 0)) && !SCM_BIGSIGN (n2)) {
1008 return scm_big_ior ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
1009 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
1010 } else {
1011 return scm_big_and ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
1012 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, SCM_BIGSIGNFLAG);
1013 }
8a525303 1014# else
5fa20751 1015 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
09fb7599
DH
1016 scm_longdigs (nn1, zdigs);
1017 if ((!(nn1 < 0)) && !SCM_BIGSIGN (n2)) {
1018 return scm_big_ior (zdigs, SCM_DIGSPERLONG,
1019 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
1020 } else {
1021 return scm_big_and (zdigs, SCM_DIGSPERLONG,
1022 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2, SCM_BIGSIGNFLAG);
1023 }
8a525303 1024# endif
09fb7599 1025 }
09fb7599
DH
1026 } else {
1027 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1028 }
09fb7599
DH
1029 } else if (SCM_BIGP (n1)) {
1030 if (SCM_INUMP (n2)) {
1031 SCM_SWAP (n1, n2);
9a00c9fc 1032 nn1 = SCM_INUM (n1);
09fb7599
DH
1033 goto intbig;
1034 } else if (SCM_BIGP (n2)) {
1035 if (SCM_NUMDIGS (n1) > SCM_NUMDIGS (n2)) {
1036 SCM_SWAP (n1, n2);
1037 };
1038 if ((!SCM_BIGSIGN (n1)) && !SCM_BIGSIGN (n2)) {
1039 return scm_big_ior (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
1040 SCM_BIGSIGN (n1), n2);
1041 } else {
1042 return scm_big_and (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
1043 SCM_BIGSIGN (n1), n2, SCM_BIGSIGNFLAG);
1044 }
1045 } else {
1046 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1047 }
09fb7599
DH
1048 } else {
1049 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
1050 }
0f2d19dd 1051}
1bbd0b84 1052#undef FUNC_NAME
0f2d19dd 1053
09fb7599 1054
c3ee7520 1055SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
1bbd0b84 1056 (SCM n1, SCM n2),
3c3db128
GH
1057 "Return the bitwise XOR of the integer arguments. A bit is\n"
1058 "set in the result if it is set in an odd number of arguments.\n"
1059 "@lisp\n"
1060 "(logxor) @result{} 0\n"
1061 "(logxor 7) @result{} 7\n"
1062 "(logxor #b000 #b001 #b011) @result{} 2\n"
1063 "(logxor #b000 #b001 #b011 #b011) @result{} 1\n"
1e6808ea 1064 "@end lisp")
1bbd0b84 1065#define FUNC_NAME s_scm_logxor
0f2d19dd 1066{
9a00c9fc
DH
1067 long int nn1;
1068
09fb7599
DH
1069 if (SCM_UNBNDP (n2)) {
1070 if (SCM_UNBNDP (n1)) {
1071 return SCM_INUM0;
8a525303 1072#ifndef SCM_RECKLESS
09fb7599
DH
1073 } else if (SCM_NUMBERP (n1)) {
1074 return n1;
1075 } else {
1076 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
1077#else
1078 } else {
d28da049 1079 return n1;
09fb7599 1080#endif
d28da049 1081 }
8a525303 1082 }
09fb7599
DH
1083
1084 if (SCM_INUMP (n1)) {
9a00c9fc 1085 nn1 = SCM_INUM (n1);
09fb7599
DH
1086 if (SCM_INUMP (n2)) {
1087 long nn2 = SCM_INUM (n2);
1088 return SCM_MAKINUM (nn1 ^ nn2);
09fb7599
DH
1089 } else if (SCM_BIGP (n2)) {
1090 intbig:
8a525303
GB
1091 {
1092# ifndef SCM_DIGSTOOBIG
09fb7599
DH
1093 long z = scm_pseudolong (nn1);
1094 return scm_big_xor ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
1095 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303 1096# else
09fb7599
DH
1097 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
1098 scm_longdigs (nn1, zdigs);
1099 return scm_big_xor (zdigs, SCM_DIGSPERLONG,
1100 (nn1 < 0) ? SCM_BIGSIGNFLAG : 0, n2);
8a525303
GB
1101# endif
1102 }
09fb7599
DH
1103 } else {
1104 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1105 }
09fb7599
DH
1106 } else if (SCM_BIGP (n1)) {
1107 if (SCM_INUMP (n2)) {
1108 SCM_SWAP (n1, n2);
9a00c9fc 1109 nn1 = SCM_INUM (n1);
09fb7599
DH
1110 goto intbig;
1111 } else if (SCM_BIGP (n2)) {
1112 if (SCM_NUMDIGS(n1) > SCM_NUMDIGS(n2)) {
1113 SCM_SWAP (n1, n2);
1114 }
1115 return scm_big_xor (SCM_BDIGITS (n1), SCM_NUMDIGS (n1),
1116 SCM_BIGSIGN (n1), n2);
1117 } else {
1118 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1119 }
09fb7599
DH
1120 } else {
1121 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
1122 }
0f2d19dd 1123}
1bbd0b84 1124#undef FUNC_NAME
0f2d19dd 1125
09fb7599 1126
a1ec6916 1127SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1e6808ea
MG
1128 (SCM j, SCM k),
1129 "@lisp\n"
b380b885
MD
1130 "(logtest j k) @equiv{} (not (zero? (logand j k)))\n\n"
1131 "(logtest #b0100 #b1011) @result{} #f\n"
1132 "(logtest #b0100 #b0111) @result{} #t\n"
1e6808ea 1133 "@end lisp")
1bbd0b84 1134#define FUNC_NAME s_scm_logtest
0f2d19dd 1135{
1e6808ea 1136 long int nj;
9a00c9fc 1137
1e6808ea
MG
1138 if (SCM_INUMP (j)) {
1139 nj = SCM_INUM (j);
1140 if (SCM_INUMP (k)) {
1141 long nk = SCM_INUM (k);
1142 return SCM_BOOL (nj & nk);
1143 } else if (SCM_BIGP (k)) {
f8de44c1
DH
1144 intbig:
1145 {
8a525303 1146# ifndef SCM_DIGSTOOBIG
1e6808ea 1147 long z = scm_pseudolong (nj);
f8de44c1 1148 return scm_big_test ((SCM_BIGDIG *)&z, SCM_DIGSPERLONG,
1e6808ea 1149 (nj < 0) ? SCM_BIGSIGNFLAG : 0, k);
8a525303 1150# else
f8de44c1 1151 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
1e6808ea 1152 scm_longdigs (nj, zdigs);
f8de44c1 1153 return scm_big_test (zdigs, SCM_DIGSPERLONG,
1e6808ea 1154 (nj < 0) ? SCM_BIGSIGNFLAG : 0, k);
8a525303 1155# endif
f8de44c1 1156 }
f8de44c1 1157 } else {
1e6808ea 1158 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
f8de44c1 1159 }
1e6808ea
MG
1160 } else if (SCM_BIGP (j)) {
1161 if (SCM_INUMP (k)) {
1162 SCM_SWAP (j, k);
1163 nj = SCM_INUM (j);
f8de44c1 1164 goto intbig;
1e6808ea
MG
1165 } else if (SCM_BIGP (k)) {
1166 if (SCM_NUMDIGS (j) > SCM_NUMDIGS (k)) {
1167 SCM_SWAP (j, k);
f8de44c1 1168 }
1e6808ea
MG
1169 return scm_big_test (SCM_BDIGITS (j), SCM_NUMDIGS (j),
1170 SCM_BIGSIGN (j), k);
f8de44c1 1171 } else {
1e6808ea 1172 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
f8de44c1 1173 }
f8de44c1 1174 } else {
1e6808ea 1175 SCM_WRONG_TYPE_ARG (SCM_ARG1, j);
f8de44c1 1176 }
0f2d19dd 1177}
1bbd0b84 1178#undef FUNC_NAME
0f2d19dd 1179
c1bfcf60 1180
a1ec6916 1181SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 1182 (SCM index, SCM j),
1e6808ea 1183 "@lisp\n"
b380b885
MD
1184 "(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j)\n\n"
1185 "(logbit? 0 #b1101) @result{} #t\n"
1186 "(logbit? 1 #b1101) @result{} #f\n"
1187 "(logbit? 2 #b1101) @result{} #t\n"
1188 "(logbit? 3 #b1101) @result{} #t\n"
1189 "(logbit? 4 #b1101) @result{} #f\n"
1e6808ea 1190 "@end lisp")
1bbd0b84 1191#define FUNC_NAME s_scm_logbit_p
0f2d19dd 1192{
78166ad5
DH
1193 unsigned long int iindex;
1194
1195 SCM_VALIDATE_INUM_MIN (SCM_ARG1, index, 0);
1196 iindex = (unsigned long int) SCM_INUM (index);
1197
1198 if (SCM_INUMP (j)) {
1199 return SCM_BOOL ((1L << iindex) & SCM_INUM (j));
1200 } else if (SCM_BIGP (j)) {
1201 if (SCM_NUMDIGS (j) * SCM_BITSPERDIG < iindex) {
1202 return SCM_BOOL_F;
1203 } else if (SCM_BIGSIGN (j)) {
8a525303 1204 long num = -1;
1be6b49c 1205 size_t i = 0;
78166ad5 1206 SCM_BIGDIG * x = SCM_BDIGITS (j);
1be6b49c 1207 size_t nx = iindex / SCM_BITSPERDIG;
78166ad5 1208 while (1) {
8a525303 1209 num += x[i];
78166ad5
DH
1210 if (nx == i++) {
1211 return SCM_BOOL (((1L << (iindex % SCM_BITSPERDIG)) & num) == 0);
1212 } else if (num < 0) {
1213 num = -1;
1214 } else {
1215 num = 0;
1216 }
8a525303 1217 }
78166ad5
DH
1218 } else {
1219 return SCM_BOOL (SCM_BDIGITS (j) [iindex / SCM_BITSPERDIG]
1220 & (1L << (iindex % SCM_BITSPERDIG)));
8a525303 1221 }
78166ad5
DH
1222 } else {
1223 SCM_WRONG_TYPE_ARG (SCM_ARG2, j);
8a525303 1224 }
0f2d19dd 1225}
1bbd0b84 1226#undef FUNC_NAME
0f2d19dd 1227
78166ad5 1228
a1ec6916 1229SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 1230 (SCM n),
1e6808ea
MG
1231 "Return the integer which is the 2s-complement of the integer\n"
1232 "argument.\n"
1233 "\n"
b380b885
MD
1234 "@lisp\n"
1235 "(number->string (lognot #b10000000) 2)\n"
1236 " @result{} \"-10000001\"\n"
1237 "(number->string (lognot #b0) 2)\n"
1238 " @result{} \"-1\"\n"
1e6808ea 1239 "@end lisp")
1bbd0b84 1240#define FUNC_NAME s_scm_lognot
0f2d19dd 1241{
f872b822 1242 return scm_difference (SCM_MAKINUM (-1L), n);
0f2d19dd 1243}
1bbd0b84 1244#undef FUNC_NAME
0f2d19dd 1245
a1ec6916 1246SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 1247 (SCM n, SCM k),
1e6808ea
MG
1248 "Return @var{n} raised to the non-negative integer exponent\n"
1249 "@var{k}.\n"
1250 "\n"
b380b885
MD
1251 "@lisp\n"
1252 "(integer-expt 2 5)\n"
1253 " @result{} 32\n"
1254 "(integer-expt -3 3)\n"
1255 " @result{} -27\n"
1256 "@end lisp")
1bbd0b84 1257#define FUNC_NAME s_scm_integer_expt
0f2d19dd 1258{
f872b822 1259 SCM acc = SCM_MAKINUM (1L);
1bbd0b84 1260 int i2;
0f2d19dd 1261#ifdef SCM_BIGDIG
4260a7fc 1262 if (SCM_EQ_P (n, SCM_INUM0) || SCM_EQ_P (n, acc))
2cd04b42 1263 return n;
4260a7fc
DH
1264 else if (SCM_EQ_P (n, SCM_MAKINUM (-1L)))
1265 return SCM_FALSEP (scm_even_p (k)) ? n : acc;
0f2d19dd 1266#endif
2830fd91
MD
1267 if (SCM_REALP (k))
1268 {
1269 double r = SCM_REAL_VALUE (k);
1270 i2 = r;
1271 if (i2 != r)
1272 SCM_WRONG_TYPE_ARG (2, k);
1273 }
1274 else
1275 SCM_VALIDATE_ULONG_COPY (2,k,i2);
1bbd0b84 1276 if (i2 < 0)
f872b822 1277 {
1bbd0b84 1278 i2 = -i2;
2cd04b42 1279 n = scm_divide (n, SCM_UNDEFINED);
f872b822
MD
1280 }
1281 while (1)
1282 {
1bbd0b84 1283 if (0 == i2)
f872b822 1284 return acc;
1bbd0b84 1285 if (1 == i2)
2cd04b42 1286 return scm_product (acc, n);
1bbd0b84 1287 if (i2 & 1)
2cd04b42
GB
1288 acc = scm_product (acc, n);
1289 n = scm_product (n, n);
1bbd0b84 1290 i2 >>= 1;
f872b822 1291 }
0f2d19dd 1292}
1bbd0b84 1293#undef FUNC_NAME
0f2d19dd 1294
a1ec6916 1295SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 1296 (SCM n, SCM cnt),
1e6808ea
MG
1297 "The function ash performs an arithmetic shift left by @var{cnt}\n"
1298 "bits (or shift right, if @var{cnt} is negative). 'Arithmetic'\n"
1299 "means, that the function does not guarantee to keep the bit\n"
1300 "structure of @var{n}, but rather guarantees that the result\n"
1301 "will always be rounded towards minus infinity. Therefore, the\n"
1302 "results of ash and a corresponding bitwise shift will differ if\n"
1303 "@var{n} is negative.\n"
1304 "\n"
3ab9f56e 1305 "Formally, the function returns an integer equivalent to\n"
1e6808ea
MG
1306 "@code{(inexact->exact (floor (* @var{n} (expt 2 @var{cnt}))))}.\n"
1307 "\n"
b380b885 1308 "@lisp\n"
1e6808ea
MG
1309 "(number->string (ash #b1 3) 2) @result{} \"1000\"\n"
1310 "(number->string (ash #b1010 -1) 2) @result{} \"101\"\n"
a3c8b9fc 1311 "@end lisp")
1bbd0b84 1312#define FUNC_NAME s_scm_ash
0f2d19dd 1313{
3ab9f56e
DH
1314 long bits_to_shift;
1315
1316#ifndef SCM_BIGDIG
1317 SCM_VALIDATE_INUM (1, n)
1318#endif
1319 SCM_VALIDATE_INUM (2, cnt);
1320
1321 bits_to_shift = SCM_INUM (cnt);
0f2d19dd 1322#ifdef SCM_BIGDIG
3ab9f56e
DH
1323 if (bits_to_shift < 0) {
1324 /* Shift right by abs(cnt) bits. This is realized as a division by
1325 div:=2^abs(cnt). However, to guarantee the floor rounding, negative
1326 values require some special treatment.
1327 */
1328 SCM div = scm_integer_expt (SCM_MAKINUM (2), SCM_MAKINUM (-bits_to_shift));
1329 if (SCM_FALSEP (scm_negative_p (n)))
1330 return scm_quotient (n, div);
1331 else
1332 return scm_sum (SCM_MAKINUM (-1L),
1333 scm_quotient (scm_sum (SCM_MAKINUM (1L), n), div));
1334 } else
1335 /* Shift left is done by multiplication with 2^CNT */
f872b822 1336 return scm_product (n, scm_integer_expt (SCM_MAKINUM (2), cnt));
0f2d19dd 1337#else
3ab9f56e
DH
1338 if (bits_to_shift < 0)
1339 /* Signed right shift (SCM_SRS does it right) by abs(cnt) bits. */
1340 return SCM_MAKINUM (SCM_SRS (SCM_INUM (n), -bits_to_shift));
1341 else {
1342 /* Shift left, but make sure not to leave the range of inums */
1343 SCM res = SCM_MAKINUM (SCM_INUM (n) << cnt);
1344 if (SCM_INUM (res) >> cnt != SCM_INUM (n))
1345 scm_num_overflow (FUNC_NAME);
1346 return res;
1347 }
0f2d19dd
JB
1348#endif
1349}
1bbd0b84 1350#undef FUNC_NAME
0f2d19dd 1351
3c9f20f8 1352
a1ec6916 1353SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 1354 (SCM n, SCM start, SCM end),
1e6808ea
MG
1355 "Return the integer composed of the @var{start} (inclusive)\n"
1356 "through @var{end} (exclusive) bits of @var{n}. The\n"
1357 "@var{start}th bit becomes the 0-th bit in the result.\n"
1358 "\n"
b380b885
MD
1359 "@lisp\n"
1360 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
1361 " @result{} \"1010\"\n"
1362 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
1363 " @result{} \"10110\"\n"
1364 "@end lisp")
1bbd0b84 1365#define FUNC_NAME s_scm_bit_extract
0f2d19dd 1366{
ac0c002c 1367 unsigned long int istart, iend;
c1bfcf60
GB
1368 SCM_VALIDATE_INUM_MIN_COPY (2,start,0,istart);
1369 SCM_VALIDATE_INUM_MIN_COPY (3, end, 0, iend);
1370 SCM_ASSERT_RANGE (3, end, (iend >= istart));
78166ad5
DH
1371
1372 if (SCM_INUMP (n)) {
ac0c002c
DH
1373 long int in = SCM_INUM (n);
1374 unsigned long int bits = iend - istart;
1375
1be6b49c 1376 if (in < 0 && bits >= SCM_I_FIXNUM_BIT)
ac0c002c
DH
1377 {
1378 /* Since we emulate two's complement encoded numbers, this special
1379 * case requires us to produce a result that has more bits than can be
1380 * stored in a fixnum. Thus, we fall back to the more general
1381 * algorithm that is used for bignums.
1382 */
1383 goto generalcase;
1384 }
1385
1be6b49c 1386 if (istart < SCM_I_FIXNUM_BIT)
ac0c002c
DH
1387 {
1388 in = in >> istart;
1be6b49c 1389 if (bits < SCM_I_FIXNUM_BIT)
ac0c002c
DH
1390 return SCM_MAKINUM (in & ((1L << bits) - 1));
1391 else /* we know: in >= 0 */
1392 return SCM_MAKINUM (in);
1393 }
1394 else if (in < 0)
1395 {
1396 return SCM_MAKINUM (-1L & ((1L << bits) - 1));
1397 }
1398 else
1399 {
1400 return SCM_MAKINUM (0);
1401 }
78166ad5 1402 } else if (SCM_BIGP (n)) {
ac0c002c
DH
1403 generalcase:
1404 {
1405 SCM num1 = SCM_MAKINUM (1L);
1406 SCM num2 = SCM_MAKINUM (2L);
1407 SCM bits = SCM_MAKINUM (iend - istart);
1408 SCM mask = scm_difference (scm_integer_expt (num2, bits), num1);
1409 return scm_logand (mask, scm_ash (n, SCM_MAKINUM (-istart)));
1410 }
78166ad5
DH
1411 } else {
1412 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1413 }
0f2d19dd 1414}
1bbd0b84 1415#undef FUNC_NAME
0f2d19dd 1416
3c9f20f8 1417
e4755e5c
JB
1418static const char scm_logtab[] = {
1419 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
1420};
1cc91f1b 1421
a1ec6916 1422SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 1423 (SCM n),
1e6808ea
MG
1424 "Return the number of bits in integer @var{n}. If integer is\n"
1425 "positive, the 1-bits in its binary representation are counted.\n"
1426 "If negative, the 0-bits in its two's-complement binary\n"
1427 "representation are counted. If 0, 0 is returned.\n"
1428 "\n"
b380b885
MD
1429 "@lisp\n"
1430 "(logcount #b10101010)\n"
1431 " @result{} 4\n"
1432 "(logcount 0)\n"
1433 " @result{} 0\n"
1434 "(logcount -2)\n"
1435 " @result{} 1\n"
1436 "@end lisp")
1bbd0b84 1437#define FUNC_NAME s_scm_logcount
0f2d19dd 1438{
3c9f20f8
DH
1439 if (SCM_INUMP (n)) {
1440 unsigned long int c = 0;
1441 long int nn = SCM_INUM (n);
1442 if (nn < 0) {
1443 nn = -1 - nn;
1444 };
1445 while (nn) {
1446 c += scm_logtab[15 & nn];
1447 nn >>= 4;
1448 };
1449 return SCM_MAKINUM (c);
1450 } else if (SCM_BIGP (n)) {
1451 if (SCM_BIGSIGN (n)) {
1452 return scm_logcount (scm_difference (SCM_MAKINUM (-1L), n));
1453 } else {
1454 unsigned long int c = 0;
1be6b49c 1455 size_t i = SCM_NUMDIGS (n);
3c9f20f8
DH
1456 SCM_BIGDIG * ds = SCM_BDIGITS (n);
1457 while (i--) {
1458 SCM_BIGDIG d;
1459 for (d = ds[i]; d; d >>= 4) {
f872b822 1460 c += scm_logtab[15 & d];
3c9f20f8
DH
1461 }
1462 }
f872b822
MD
1463 return SCM_MAKINUM (c);
1464 }
3c9f20f8
DH
1465 } else {
1466 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1467 }
0f2d19dd 1468}
1bbd0b84
GB
1469#undef FUNC_NAME
1470
0f2d19dd 1471
e4755e5c
JB
1472static const char scm_ilentab[] = {
1473 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
1474};
1cc91f1b 1475
a1ec6916 1476SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
1bbd0b84 1477 (SCM n),
bb2c02f2 1478 "Return the number of bits necessary to represent @var{n}.\n"
1e6808ea 1479 "\n"
b380b885
MD
1480 "@lisp\n"
1481 "(integer-length #b10101010)\n"
1482 " @result{} 8\n"
1483 "(integer-length 0)\n"
1484 " @result{} 0\n"
1485 "(integer-length #b1111)\n"
1486 " @result{} 4\n"
1487 "@end lisp")
1bbd0b84 1488#define FUNC_NAME s_scm_integer_length
0f2d19dd 1489{
3c9f20f8
DH
1490 if (SCM_INUMP (n)) {
1491 unsigned long int c = 0;
1492 unsigned int l = 4;
1493 long int nn = SCM_INUM (n);
1494 if (nn < 0) {
1495 nn = -1 - nn;
1496 };
1497 while (nn) {
f872b822 1498 c += 4;
3c9f20f8
DH
1499 l = scm_ilentab [15 & nn];
1500 nn >>= 4;
1501 };
1502 return SCM_MAKINUM (c - 4 + l);
1503 } else if (SCM_BIGP (n)) {
1504 if (SCM_BIGSIGN (n)) {
1505 return scm_integer_length (scm_difference (SCM_MAKINUM (-1L), n));
1506 } else {
1507 unsigned long int digs = SCM_NUMDIGS (n) - 1;
1508 unsigned long int c = digs * SCM_BITSPERDIG;
1509 unsigned int l = 4;
1510 SCM_BIGDIG * ds = SCM_BDIGITS (n);
1511 SCM_BIGDIG d = ds [digs];
1512 while (d) {
1513 c += 4;
1514 l = scm_ilentab [15 & d];
1515 d >>= 4;
1516 };
1517 return SCM_MAKINUM (c - 4 + l);
f872b822 1518 }
3c9f20f8
DH
1519 } else {
1520 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1521 }
0f2d19dd 1522}
1bbd0b84 1523#undef FUNC_NAME
0f2d19dd
JB
1524
1525
1526#ifdef SCM_BIGDIG
e4755e5c 1527static const char s_bignum[] = "bignum";
1cc91f1b 1528
0f2d19dd 1529SCM
1be6b49c 1530scm_i_mkbig (size_t nlen, int sign)
0f2d19dd 1531{
c209c88e 1532 SCM v;
5843e5c9
DH
1533 SCM_BIGDIG *base;
1534
1535 if (((nlen << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD) != nlen)
2500356c 1536 scm_memory_error (s_bignum);
5843e5c9 1537
4c9419ac 1538 base = scm_gc_malloc (nlen * sizeof (SCM_BIGDIG), s_bignum);
5843e5c9 1539
228a24ef 1540 v = scm_cell (SCM_MAKE_BIGNUM_TAG (nlen, sign), (scm_t_bits) base);
0f2d19dd
JB
1541 return v;
1542}
1543
0f2d19dd 1544SCM
1be6b49c 1545scm_i_big2inum (SCM b, size_t l)
0f2d19dd
JB
1546{
1547 unsigned long num = 0;
f872b822
MD
1548 SCM_BIGDIG *tmp = SCM_BDIGITS (b);
1549 while (l--)
1550 num = SCM_BIGUP (num) + tmp[l];
f3ae5d60 1551 if (!SCM_BIGSIGN (b))
f872b822
MD
1552 {
1553 if (SCM_POSFIXABLE (num))
1554 return SCM_MAKINUM (num);
1555 }
894a712b 1556 else if (num <= -SCM_MOST_NEGATIVE_FIXNUM)
f872b822 1557 return SCM_MAKINUM (-num);
0f2d19dd
JB
1558 return b;
1559}
1560
1be6b49c 1561static const char s_adjbig[] = "scm_i_adjbig";
1cc91f1b 1562
0f2d19dd 1563SCM
1be6b49c 1564scm_i_adjbig (SCM b, size_t nlen)
0f2d19dd 1565{
1be6b49c 1566 size_t nsiz = nlen;
f3ae5d60 1567 if (((nsiz << SCM_BIGSIZEFIELD) >> SCM_BIGSIZEFIELD) != nlen)
2500356c 1568 scm_memory_error (s_adjbig);
2bf746cc 1569
0f2d19dd 1570 SCM_DEFER_INTS;
2bf746cc
JB
1571 {
1572 SCM_BIGDIG *digits
1573 = ((SCM_BIGDIG *)
4c9419ac
MV
1574 scm_gc_realloc (SCM_BDIGITS (b),
1575 SCM_NUMDIGS (b) * sizeof (SCM_BIGDIG),
1576 nsiz * sizeof (SCM_BIGDIG), s_bignum));
2bf746cc 1577
6a0476fd 1578 SCM_SET_BIGNUM_BASE (b, digits);
f3ae5d60 1579 SCM_SETNUMDIGS (b, nsiz, SCM_BIGSIGN (b));
2bf746cc 1580 }
0f2d19dd
JB
1581 SCM_ALLOW_INTS;
1582 return b;
1583}
1584
0f2d19dd 1585SCM
1be6b49c 1586scm_i_normbig (SCM b)
0f2d19dd 1587{
f872b822 1588#ifndef _UNICOS
1be6b49c 1589 size_t nlen = SCM_NUMDIGS (b);
0f2d19dd 1590#else
f872b822 1591 int nlen = SCM_NUMDIGS (b); /* unsigned nlen breaks on Cray when nlen => 0 */
0f2d19dd 1592#endif
f872b822
MD
1593 SCM_BIGDIG *zds = SCM_BDIGITS (b);
1594 while (nlen-- && !zds[nlen]);
1595 nlen++;
1596 if (nlen * SCM_BITSPERDIG / SCM_CHAR_BIT <= sizeof (SCM))
1be6b49c 1597 if (SCM_INUMP (b = scm_i_big2inum (b, (size_t) nlen)))
f872b822
MD
1598 return b;
1599 if (SCM_NUMDIGS (b) == nlen)
1600 return b;
1be6b49c 1601 return scm_i_adjbig (b, (size_t) nlen);
0f2d19dd
JB
1602}
1603
0f2d19dd 1604SCM
1be6b49c 1605scm_i_copybig (SCM b, int sign)
0f2d19dd 1606{
1be6b49c
ML
1607 size_t i = SCM_NUMDIGS (b);
1608 SCM ans = scm_i_mkbig (i, sign);
f872b822
MD
1609 SCM_BIGDIG *src = SCM_BDIGITS (b), *dst = SCM_BDIGITS (ans);
1610 while (i--)
1611 dst[i] = src[i];
0f2d19dd
JB
1612 return ans;
1613}
1614
0f2d19dd 1615int
1bbd0b84 1616scm_bigcomp (SCM x, SCM y)
0f2d19dd 1617{
f872b822
MD
1618 int xsign = SCM_BIGSIGN (x);
1619 int ysign = SCM_BIGSIGN (y);
1be6b49c 1620 size_t xlen, ylen;
2bf746cc
JB
1621
1622 /* Look at the signs, first. */
f872b822
MD
1623 if (ysign < xsign)
1624 return 1;
1625 if (ysign > xsign)
1626 return -1;
2bf746cc
JB
1627
1628 /* They're the same sign, so see which one has more digits. Note
1629 that, if they are negative, the longer number is the lesser. */
f872b822
MD
1630 ylen = SCM_NUMDIGS (y);
1631 xlen = SCM_NUMDIGS (x);
2bf746cc
JB
1632 if (ylen > xlen)
1633 return (xsign) ? -1 : 1;
f872b822
MD
1634 if (ylen < xlen)
1635 return (xsign) ? 1 : -1;
2bf746cc
JB
1636
1637 /* They have the same number of digits, so find the most significant
1638 digit where they differ. */
1639 while (xlen)
1640 {
1641 --xlen;
1642 if (SCM_BDIGITS (y)[xlen] != SCM_BDIGITS (x)[xlen])
1643 /* Make the discrimination based on the digit that differs. */
f872b822
MD
1644 return ((SCM_BDIGITS (y)[xlen] > SCM_BDIGITS (x)[xlen])
1645 ? (xsign ? -1 : 1)
1646 : (xsign ? 1 : -1));
2bf746cc
JB
1647 }
1648
1649 /* The numbers are identical. */
1650 return 0;
0f2d19dd
JB
1651}
1652
1653#ifndef SCM_DIGSTOOBIG
1654
1cc91f1b 1655
0f2d19dd 1656long
1bbd0b84 1657scm_pseudolong (long x)
0f2d19dd 1658{
f872b822
MD
1659 union
1660 {
0f2d19dd
JB
1661 long l;
1662 SCM_BIGDIG bd[SCM_DIGSPERLONG];
f872b822
MD
1663 }
1664 p;
1be6b49c 1665 size_t i = 0;
f872b822
MD
1666 if (x < 0)
1667 x = -x;
1668 while (i < SCM_DIGSPERLONG)
1669 {
1670 p.bd[i++] = SCM_BIGLO (x);
1671 x = SCM_BIGDN (x);
1672 }
0f2d19dd
JB
1673 /* p.bd[0] = SCM_BIGLO(x); p.bd[1] = SCM_BIGDN(x); */
1674 return p.l;
1675}
1676
1677#else
1678
1cc91f1b 1679
0f2d19dd 1680void
1bbd0b84 1681scm_longdigs (long x, SCM_BIGDIG digs[])
0f2d19dd 1682{
1be6b49c 1683 size_t i = 0;
f872b822
MD
1684 if (x < 0)
1685 x = -x;
1686 while (i < SCM_DIGSPERLONG)
1687 {
1688 digs[i++] = SCM_BIGLO (x);
1689 x = SCM_BIGDN (x);
1690 }
0f2d19dd
JB
1691}
1692#endif
1693
1694
1cc91f1b 1695
0f2d19dd 1696SCM
1be6b49c 1697scm_addbig (SCM_BIGDIG *x, size_t nx, int xsgn, SCM bigy, int sgny)
0f2d19dd
JB
1698{
1699 /* Assumes nx <= SCM_NUMDIGS(bigy) */
f3ae5d60 1700 /* Assumes xsgn and sgny scm_equal either 0 or SCM_BIGSIGNFLAG */
0f2d19dd 1701 long num = 0;
1be6b49c
ML
1702 size_t i = 0, ny = SCM_NUMDIGS (bigy);
1703 SCM z = scm_i_copybig (bigy, SCM_BIGSIGN (bigy) ^ sgny);
f872b822
MD
1704 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1705 if (xsgn ^ SCM_BIGSIGN (z))
1706 {
1707 do
1708 {
1709 num += (long) zds[i] - x[i];
1710 if (num < 0)
1711 {
1712 zds[i] = num + SCM_BIGRAD;
1713 num = -1;
1714 }
1715 else
1716 {
1717 zds[i] = SCM_BIGLO (num);
1718 num = 0;
1719 }
1720 }
1721 while (++i < nx);
1722 if (num && nx == ny)
1723 {
1724 num = 1;
1725 i = 0;
4260a7fc 1726 SCM_SET_CELL_WORD_0 (z, SCM_CELL_WORD_0 (z) ^ SCM_BIGSIGNFLAG);
f872b822
MD
1727 do
1728 {
1729 num += (SCM_BIGRAD - 1) - zds[i];
1730 zds[i++] = SCM_BIGLO (num);
1731 num = SCM_BIGDN (num);
1732 }
1733 while (i < ny);
1734 }
1735 else
1736 while (i < ny)
1737 {
1738 num += zds[i];
1739 if (num < 0)
1740 {
1741 zds[i++] = num + SCM_BIGRAD;
1742 num = -1;
1743 }
1744 else
1745 {
1746 zds[i++] = SCM_BIGLO (num);
1747 num = 0;
1748 }
1749 }
1750 }
1751 else
1752 {
1753 do
1754 {
1755 num += (long) zds[i] + x[i];
1756 zds[i++] = SCM_BIGLO (num);
1757 num = SCM_BIGDN (num);
1758 }
1759 while (i < nx);
1760 if (!num)
1761 return z;
1762 while (i < ny)
1763 {
1764 num += zds[i];
1765 zds[i++] = SCM_BIGLO (num);
1766 num = SCM_BIGDN (num);
1767 if (!num)
1768 return z;
1769 }
1770 if (num)
1771 {
1be6b49c 1772 z = scm_i_adjbig (z, ny + 1);
f872b822
MD
1773 SCM_BDIGITS (z)[ny] = num;
1774 return z;
1775 }
1776 }
1be6b49c 1777 return scm_i_normbig (z);
0f2d19dd
JB
1778}
1779
1cc91f1b 1780
0f2d19dd 1781SCM
1be6b49c 1782scm_mulbig (SCM_BIGDIG *x, size_t nx, SCM_BIGDIG *y, size_t ny, int sgn)
0f2d19dd 1783{
1be6b49c 1784 size_t i = 0, j = nx + ny;
0f2d19dd 1785 unsigned long n = 0;
1be6b49c 1786 SCM z = scm_i_mkbig (j, sgn);
f872b822
MD
1787 SCM_BIGDIG *zds = SCM_BDIGITS (z);
1788 while (j--)
1789 zds[j] = 0;
1790 do
1791 {
1792 j = 0;
1793 if (x[i])
1794 {
1795 do
1796 {
1797 n += zds[i + j] + ((unsigned long) x[i] * y[j]);
1798 zds[i + j++] = SCM_BIGLO (n);
1799 n = SCM_BIGDN (n);
1800 }
1801 while (j < ny);
1802 if (n)
1803 {
1804 zds[i + j] = n;
1805 n = 0;
1806 }
1807 }
0f2d19dd 1808 }
f872b822 1809 while (++i < nx);
1be6b49c 1810 return scm_i_normbig (z);
0f2d19dd
JB
1811}
1812
1cc91f1b 1813
0f2d19dd 1814unsigned int
1be6b49c 1815scm_divbigdig (SCM_BIGDIG * ds, size_t h, SCM_BIGDIG div)
0f2d19dd
JB
1816{
1817 register unsigned long t2 = 0;
f872b822
MD
1818 while (h--)
1819 {
1820 t2 = SCM_BIGUP (t2) + ds[h];
1821 ds[h] = t2 / div;
1822 t2 %= div;
1823 }
0f2d19dd
JB
1824 return t2;
1825}
1826
1827
1cc91f1b 1828
f4c627b3 1829static SCM
1bbd0b84 1830scm_divbigint (SCM x, long z, int sgn, int mode)
0f2d19dd 1831{
f872b822
MD
1832 if (z < 0)
1833 z = -z;
1834 if (z < SCM_BIGRAD)
1835 {
1836 register unsigned long t2 = 0;
1837 register SCM_BIGDIG *ds = SCM_BDIGITS (x);
1be6b49c 1838 size_t nd = SCM_NUMDIGS (x);
f872b822
MD
1839 while (nd--)
1840 t2 = (SCM_BIGUP (t2) + ds[nd]) % z;
1841 if (mode && t2)
1842 t2 = z - t2;
1843 return SCM_MAKINUM (sgn ? -t2 : t2);
1844 }
0f2d19dd
JB
1845 {
1846#ifndef SCM_DIGSTOOBIG
f872b822
MD
1847 unsigned long t2 = scm_pseudolong (z);
1848 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1849 (SCM_BIGDIG *) & t2, SCM_DIGSPERLONG,
1850 sgn, mode);
0f2d19dd
JB
1851#else
1852 SCM_BIGDIG t2[SCM_DIGSPERLONG];
f872b822
MD
1853 scm_longdigs (z, t2);
1854 return scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
1855 t2, SCM_DIGSPERLONG,
1856 sgn, mode);
0f2d19dd
JB
1857#endif
1858 }
1859}
1860
1cc91f1b 1861
f4c627b3 1862static SCM
1be6b49c 1863scm_divbigbig (SCM_BIGDIG *x, size_t nx, SCM_BIGDIG *y, size_t ny, int sgn, int modes)
0f2d19dd
JB
1864{
1865 /* modes description
f872b822
MD
1866 0 remainder
1867 1 scm_modulo
1868 2 quotient
f4c627b3 1869 3 quotient but returns SCM_UNDEFINED if division is not exact. */
1be6b49c 1870 size_t i = 0, j = 0;
0f2d19dd
JB
1871 long num = 0;
1872 unsigned long t2 = 0;
1873 SCM z, newy;
f872b822 1874 SCM_BIGDIG d = 0, qhat, *zds, *yds;
0f2d19dd
JB
1875 /* algorithm requires nx >= ny */
1876 if (nx < ny)
f872b822
MD
1877 switch (modes)
1878 {
1879 case 0: /* remainder -- just return x */
1be6b49c 1880 z = scm_i_mkbig (nx, sgn);
f872b822
MD
1881 zds = SCM_BDIGITS (z);
1882 do
1883 {
1884 zds[i] = x[i];
1885 }
1886 while (++i < nx);
1887 return z;
1888 case 1: /* scm_modulo -- return y-x */
1be6b49c 1889 z = scm_i_mkbig (ny, sgn);
f872b822
MD
1890 zds = SCM_BDIGITS (z);
1891 do
1892 {
1893 num += (long) y[i] - x[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 while (++i < nx);
1906 while (i < ny)
1907 {
1908 num += y[i];
1909 if (num < 0)
1910 {
1911 zds[i++] = num + SCM_BIGRAD;
1912 num = -1;
1913 }
1914 else
1915 {
1916 zds[i++] = num;
1917 num = 0;
1918 }
1919 }
1920 goto doadj;
1921 case 2:
1922 return SCM_INUM0; /* quotient is zero */
1923 case 3:
f4c627b3 1924 return SCM_UNDEFINED; /* the division is not exact */
0f2d19dd 1925 }
f872b822 1926
1be6b49c 1927 z = scm_i_mkbig (nx == ny ? nx + 2 : nx + 1, sgn);
f872b822
MD
1928 zds = SCM_BDIGITS (z);
1929 if (nx == ny)
1930 zds[nx + 1] = 0;
1931 while (!y[ny - 1])
1932 ny--; /* in case y came in as a psuedolong */
1933 if (y[ny - 1] < (SCM_BIGRAD >> 1))
1934 { /* normalize operands */
1935 d = SCM_BIGRAD / (y[ny - 1] + 1);
1be6b49c 1936 newy = scm_i_mkbig (ny, 0);
f872b822
MD
1937 yds = SCM_BDIGITS (newy);
1938 while (j < ny)
1939 {
1940 t2 += (unsigned long) y[j] * d;
1941 yds[j++] = SCM_BIGLO (t2);
1942 t2 = SCM_BIGDN (t2);
1943 }
1944 y = yds;
1945 j = 0;
1946 t2 = 0;
1947 while (j < nx)
1948 {
1949 t2 += (unsigned long) x[j] * d;
1950 zds[j++] = SCM_BIGLO (t2);
1951 t2 = SCM_BIGDN (t2);
1952 }
1953 zds[j] = t2;
1954 }
1955 else
1956 {
1957 zds[j = nx] = 0;
1958 while (j--)
1959 zds[j] = x[j];
1960 }
1961 j = nx == ny ? nx + 1 : nx; /* dividend needs more digits than divisor */
1962 do
1963 { /* loop over digits of quotient */
1964 if (zds[j] == y[ny - 1])
1965 qhat = SCM_BIGRAD - 1;
1966 else
1967 qhat = (SCM_BIGUP (zds[j]) + zds[j - 1]) / y[ny - 1];
1968 if (!qhat)
1969 continue;
1970 i = 0;
1971 num = 0;
1972 t2 = 0;
1973 do
1974 { /* multiply and subtract */
1975 t2 += (unsigned long) y[i] * qhat;
1976 num += zds[j - ny + i] - SCM_BIGLO (t2);
1977 if (num < 0)
1978 {
1979 zds[j - ny + i] = num + SCM_BIGRAD;
1980 num = -1;
1981 }
1982 else
1983 {
1984 zds[j - ny + i] = num;
1985 num = 0;
1986 }
1987 t2 = SCM_BIGDN (t2);
1988 }
1989 while (++i < ny);
1990 num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
1991 while (num)
1992 { /* "add back" required */
1993 i = 0;
1994 num = 0;
1995 qhat--;
1996 do
1997 {
1998 num += (long) zds[j - ny + i] + y[i];
1999 zds[j - ny + i] = SCM_BIGLO (num);
2000 num = SCM_BIGDN (num);
2001 }
2002 while (++i < ny);
2003 num--;
2004 }
2005 if (modes & 2)
2006 zds[j] = qhat;
2007 }
2008 while (--j >= ny);
2009 switch (modes)
2010 {
2011 case 3: /* check that remainder==0 */
2012 for (j = ny; j && !zds[j - 1]; --j);
2013 if (j)
f4c627b3 2014 return SCM_UNDEFINED;
f872b822
MD
2015 case 2: /* move quotient down in z */
2016 j = (nx == ny ? nx + 2 : nx + 1) - ny;
2017 for (i = 0; i < j; i++)
2018 zds[i] = zds[i + ny];
2019 ny = i;
2020 break;
2021 case 1: /* subtract for scm_modulo */
2022 i = 0;
2023 num = 0;
2024 j = 0;
2025 do
2026 {
2027 num += y[i] - zds[i];
2028 j = j | zds[i];
2029 if (num < 0)
2030 {
2031 zds[i] = num + SCM_BIGRAD;
2032 num = -1;
2033 }
2034 else
2035 {
2036 zds[i] = num;
2037 num = 0;
2038 }
2039 }
2040 while (++i < ny);
2041 if (!j)
2042 return SCM_INUM0;
2043 case 0: /* just normalize remainder */
2044 if (d)
2045 scm_divbigdig (zds, ny, d);
2046 }
0f2d19dd 2047 doadj:
f872b822
MD
2048 for (j = ny; j && !zds[j - 1]; --j);
2049 if (j * SCM_BITSPERDIG <= sizeof (SCM) * SCM_CHAR_BIT)
1be6b49c 2050 if (SCM_INUMP (z = scm_i_big2inum (z, j)))
f872b822 2051 return z;
1be6b49c 2052 return scm_i_adjbig (z, j);
0f2d19dd
JB
2053}
2054#endif
f872b822 2055\f
0f2d19dd
JB
2056
2057
2058
0f2d19dd
JB
2059
2060/*** NUMBERS -> STRINGS ***/
0f2d19dd 2061int scm_dblprec;
e4755e5c 2062static const double fx[] =
f872b822
MD
2063{ 0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5,
2064 5e-6, 5e-7, 5e-8, 5e-9, 5e-10,
2065 5e-11, 5e-12, 5e-13, 5e-14, 5e-15,
2066 5e-16, 5e-17, 5e-18, 5e-19, 5e-20};
0f2d19dd
JB
2067
2068
2069
1cc91f1b 2070
1be6b49c 2071static size_t
1bbd0b84 2072idbl2str (double f, char *a)
0f2d19dd
JB
2073{
2074 int efmt, dpt, d, i, wp = scm_dblprec;
1be6b49c 2075 size_t ch = 0;
0f2d19dd
JB
2076 int exp = 0;
2077
f872b822
MD
2078 if (f == 0.0)
2079 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
7351e207
MV
2080
2081 if (xisinf (f))
2082 {
2083 if (f < 0)
2084 strcpy (a, "-inf.0");
2085 else
2086 strcpy (a, "+inf.0");
2087 return ch+6;
2088 }
2089 else if (xisnan (f))
2090 {
2091 strcpy (a, "+nan.0");
2092 return ch+6;
2093 }
2094
f872b822
MD
2095 if (f < 0.0)
2096 {
2097 f = -f;
2098 a[ch++] = '-';
2099 }
7351e207 2100
f872b822
MD
2101#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
2102 make-uniform-vector, from causing infinite loops. */
2103 while (f < 1.0)
2104 {
2105 f *= 10.0;
2106 if (exp-- < DBL_MIN_10_EXP)
7351e207
MV
2107 {
2108 a[ch++] = '#';
2109 a[ch++] = '.';
2110 a[ch++] = '#';
2111 return ch;
2112 }
f872b822
MD
2113 }
2114 while (f > 10.0)
2115 {
2116 f *= 0.10;
2117 if (exp++ > DBL_MAX_10_EXP)
7351e207
MV
2118 {
2119 a[ch++] = '#';
2120 a[ch++] = '.';
2121 a[ch++] = '#';
2122 return ch;
2123 }
f872b822
MD
2124 }
2125#else
2126 while (f < 1.0)
2127 {
2128 f *= 10.0;
2129 exp--;
2130 }
2131 while (f > 10.0)
2132 {
2133 f /= 10.0;
2134 exp++;
2135 }
2136#endif
2137 if (f + fx[wp] >= 10.0)
2138 {
2139 f = 1.0;
2140 exp++;
2141 }
0f2d19dd 2142 zero:
f872b822
MD
2143#ifdef ENGNOT
2144 dpt = (exp + 9999) % 3;
0f2d19dd
JB
2145 exp -= dpt++;
2146 efmt = 1;
f872b822
MD
2147#else
2148 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 2149 if (!efmt)
cda139a7
MD
2150 {
2151 if (exp < 0)
2152 {
2153 a[ch++] = '0';
2154 a[ch++] = '.';
2155 dpt = exp;
f872b822
MD
2156 while (++dpt)
2157 a[ch++] = '0';
cda139a7
MD
2158 }
2159 else
f872b822 2160 dpt = exp + 1;
cda139a7 2161 }
0f2d19dd
JB
2162 else
2163 dpt = 1;
f872b822
MD
2164#endif
2165
2166 do
2167 {
2168 d = f;
2169 f -= d;
2170 a[ch++] = d + '0';
2171 if (f < fx[wp])
2172 break;
2173 if (f + fx[wp] >= 1.0)
2174 {
2175 a[ch - 1]++;
2176 break;
2177 }
2178 f *= 10.0;
2179 if (!(--dpt))
2180 a[ch++] = '.';
0f2d19dd 2181 }
f872b822 2182 while (wp--);
0f2d19dd
JB
2183
2184 if (dpt > 0)
cda139a7 2185 {
f872b822 2186#ifndef ENGNOT
cda139a7
MD
2187 if ((dpt > 4) && (exp > 6))
2188 {
f872b822 2189 d = (a[0] == '-' ? 2 : 1);
cda139a7 2190 for (i = ch++; i > d; i--)
f872b822 2191 a[i] = a[i - 1];
cda139a7
MD
2192 a[d] = '.';
2193 efmt = 1;
2194 }
2195 else
f872b822 2196#endif
cda139a7 2197 {
f872b822
MD
2198 while (--dpt)
2199 a[ch++] = '0';
cda139a7
MD
2200 a[ch++] = '.';
2201 }
2202 }
f872b822
MD
2203 if (a[ch - 1] == '.')
2204 a[ch++] = '0'; /* trailing zero */
2205 if (efmt && exp)
2206 {
2207 a[ch++] = 'e';
2208 if (exp < 0)
2209 {
2210 exp = -exp;
2211 a[ch++] = '-';
2212 }
2213 for (i = 10; i <= exp; i *= 10);
2214 for (i /= 10; i; i /= 10)
2215 {
2216 a[ch++] = exp / i + '0';
2217 exp %= i;
2218 }
0f2d19dd 2219 }
0f2d19dd
JB
2220 return ch;
2221}
2222
1cc91f1b 2223
1be6b49c 2224static size_t
1bbd0b84 2225iflo2str (SCM flt, char *str)
0f2d19dd 2226{
1be6b49c 2227 size_t i;
3c9a524f 2228 if (SCM_REALP (flt))
f3ae5d60 2229 i = idbl2str (SCM_REAL_VALUE (flt), str);
0f2d19dd 2230 else
f872b822 2231 {
f3ae5d60
MD
2232 i = idbl2str (SCM_COMPLEX_REAL (flt), str);
2233 if (SCM_COMPLEX_IMAG (flt) != 0.0)
2234 {
7351e207
MV
2235 double imag = SCM_COMPLEX_IMAG (flt);
2236 /* Don't output a '+' for negative numbers or for Inf and
2237 NaN. They will provide their own sign. */
2238 if (0 <= imag && !xisinf (imag) && !xisnan (imag))
f3ae5d60 2239 str[i++] = '+';
7351e207 2240 i += idbl2str (imag, &str[i]);
f3ae5d60
MD
2241 str[i++] = 'i';
2242 }
f872b822 2243 }
0f2d19dd
JB
2244 return i;
2245}
0f2d19dd 2246
5c11cc9d 2247/* convert a long to a string (unterminated). returns the number of
1bbd0b84
GB
2248 characters in the result.
2249 rad is output base
2250 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 2251size_t
1bbd0b84 2252scm_iint2str (long num, int rad, char *p)
0f2d19dd 2253{
1be6b49c
ML
2254 size_t j = 1;
2255 size_t i;
5c11cc9d
GH
2256 unsigned long n = (num < 0) ? -num : num;
2257
f872b822 2258 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2259 j++;
2260
2261 i = j;
2262 if (num < 0)
f872b822 2263 {
f872b822 2264 *p++ = '-';
5c11cc9d
GH
2265 j++;
2266 n = -num;
f872b822 2267 }
5c11cc9d
GH
2268 else
2269 n = num;
f872b822
MD
2270 while (i--)
2271 {
5c11cc9d
GH
2272 int d = n % rad;
2273
f872b822
MD
2274 n /= rad;
2275 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2276 }
0f2d19dd
JB
2277 return j;
2278}
2279
2280
2281#ifdef SCM_BIGDIG
1cc91f1b 2282
0f2d19dd 2283static SCM
1bbd0b84 2284big2str (SCM b, unsigned int radix)
0f2d19dd 2285{
1be6b49c 2286 SCM t = scm_i_copybig (b, 0); /* sign of temp doesn't matter */
f872b822 2287 register SCM_BIGDIG *ds = SCM_BDIGITS (t);
1be6b49c
ML
2288 size_t i = SCM_NUMDIGS (t);
2289 size_t j = radix == 16 ? (SCM_BITSPERDIG * i) / 4 + 2
f872b822
MD
2290 : radix >= 10 ? (SCM_BITSPERDIG * i * 241L) / 800 + 2
2291 : (SCM_BITSPERDIG * i) + 2;
1be6b49c
ML
2292 size_t k = 0;
2293 size_t radct = 0;
0f2d19dd 2294 SCM_BIGDIG radpow = 1, radmod = 0;
be54b15d 2295 SCM ss = scm_allocate_string (j);
9eb364fc 2296 char *s = SCM_STRING_CHARS (ss), c;
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
DH
2671 unsigned int idx = *p_idx;
2672
2673 if (idx == len)
2674 return SCM_BOOL_F;
2675
7351e207
MV
2676 if (idx+5 <= len && !strncmp (mem+idx, "inf.0", 5))
2677 {
2678 *p_idx = idx+5;
2679 return scm_inf ();
2680 }
2681
2682 if (idx+4 < len && !strncmp (mem+idx, "nan.", 4))
2683 {
2684 enum t_exactness x = EXACT;
2685
2686 /* Cobble up the fraction. We might want to set the NaN's
2687 mantissa from it. */
2688 idx += 4;
2689 mem2uinteger (mem, len, &idx, 10, &x);
2690 *p_idx = idx;
2691 return scm_nan ();
2692 }
2693
3c9a524f
DH
2694 if (mem[idx] == '.')
2695 {
2696 if (radix != 10)
2697 return SCM_BOOL_F;
2698 else if (idx + 1 == len)
2699 return SCM_BOOL_F;
2700 else if (!isdigit (mem[idx + 1]))
2701 return SCM_BOOL_F;
2702 else
2703 return mem2decimal_from_point (SCM_MAKINUM (0), mem, len,
2704 p_idx, p_exactness);
f872b822 2705 }
3c9a524f
DH
2706 else
2707 {
2708 enum t_exactness x = EXACT;
2709 SCM uinteger;
2710 SCM result;
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;
2742
2743 return result;
f872b822 2744 }
3c9a524f 2745}
0f2d19dd 2746
0f2d19dd 2747
3c9a524f 2748/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 2749
3c9a524f
DH
2750static SCM
2751mem2complex (const char* mem, size_t len, unsigned int idx,
2752 unsigned int radix, enum t_exactness *p_exactness)
2753{
2754 char c;
2755 int sign = 0;
2756 SCM ureal;
2757
2758 if (idx == len)
2759 return SCM_BOOL_F;
2760
2761 c = mem[idx];
2762 if (c == '+')
2763 {
2764 idx++;
2765 sign = 1;
2766 }
2767 else if (c == '-')
2768 {
2769 idx++;
2770 sign = -1;
0f2d19dd 2771 }
0f2d19dd 2772
3c9a524f
DH
2773 if (idx == len)
2774 return SCM_BOOL_F;
2775
2776 ureal = mem2ureal (mem, len, &idx, radix, p_exactness);
2777 if (SCM_FALSEP (ureal))
f872b822 2778 {
3c9a524f
DH
2779 /* input must be either +i or -i */
2780
2781 if (sign == 0)
2782 return SCM_BOOL_F;
2783
2784 if (mem[idx] == 'i' || mem[idx] == 'I')
f872b822 2785 {
3c9a524f
DH
2786 idx++;
2787 if (idx != len)
2788 return SCM_BOOL_F;
2789
2790 return scm_make_rectangular (SCM_MAKINUM (0), SCM_MAKINUM (sign));
f872b822 2791 }
3c9a524f
DH
2792 else
2793 return SCM_BOOL_F;
0f2d19dd 2794 }
3c9a524f
DH
2795 else
2796 {
fc194577 2797 if (sign == -1 && SCM_FALSEP (scm_nan_p (ureal)))
3c9a524f 2798 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 2799
3c9a524f
DH
2800 if (idx == len)
2801 return ureal;
2802
2803 c = mem[idx];
2804 switch (c)
f872b822 2805 {
3c9a524f
DH
2806 case 'i': case 'I':
2807 /* either +<ureal>i or -<ureal>i */
2808
2809 idx++;
2810 if (sign == 0)
2811 return SCM_BOOL_F;
2812 if (idx != len)
2813 return SCM_BOOL_F;
2814 return scm_make_rectangular (SCM_MAKINUM (0), ureal);
2815
2816 case '@':
2817 /* polar input: <real>@<real>. */
2818
2819 idx++;
2820 if (idx == len)
2821 return SCM_BOOL_F;
2822 else
f872b822 2823 {
3c9a524f
DH
2824 int sign;
2825 SCM angle;
2826 SCM result;
2827
2828 c = mem[idx];
2829 if (c == '+')
2830 {
2831 idx++;
2832 sign = 1;
2833 }
2834 else if (c == '-')
2835 {
2836 idx++;
2837 sign = -1;
2838 }
2839 else
2840 sign = 1;
2841
2842 angle = mem2ureal (mem, len, &idx, radix, p_exactness);
2843 if (SCM_FALSEP (angle))
2844 return SCM_BOOL_F;
2845 if (idx != len)
2846 return SCM_BOOL_F;
2847
fc194577 2848 if (sign == -1 && SCM_FALSEP (scm_nan_p (ureal)))
3c9a524f
DH
2849 angle = scm_difference (angle, SCM_UNDEFINED);
2850
2851 result = scm_make_polar (ureal, angle);
2852 return result;
f872b822 2853 }
3c9a524f
DH
2854 case '+':
2855 case '-':
2856 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 2857
3c9a524f
DH
2858 idx++;
2859 if (idx == len)
2860 return SCM_BOOL_F;
2861 else
2862 {
2863 int sign = (c == '+') ? 1 : -1;
2864 SCM imag = mem2ureal (mem, len, &idx, radix, p_exactness);
0f2d19dd 2865
3c9a524f
DH
2866 if (SCM_FALSEP (imag))
2867 imag = SCM_MAKINUM (sign);
fc194577 2868 else if (sign == -1 && SCM_FALSEP (scm_nan_p (ureal)))
1fe5e088 2869 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 2870
3c9a524f
DH
2871 if (idx == len)
2872 return SCM_BOOL_F;
2873 if (mem[idx] != 'i' && mem[idx] != 'I')
2874 return SCM_BOOL_F;
0f2d19dd 2875
3c9a524f
DH
2876 idx++;
2877 if (idx != len)
2878 return SCM_BOOL_F;
0f2d19dd 2879
1fe5e088 2880 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
2881 }
2882 default:
2883 return SCM_BOOL_F;
2884 }
2885 }
0f2d19dd 2886}
0f2d19dd
JB
2887
2888
3c9a524f
DH
2889/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
2890
2891enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 2892
0f2d19dd 2893SCM
3c9a524f 2894scm_i_mem2number (const char* mem, size_t len, unsigned int default_radix)
0f2d19dd 2895{
3c9a524f
DH
2896 unsigned int idx = 0;
2897 unsigned int radix = NO_RADIX;
2898 enum t_exactness forced_x = NO_EXACTNESS;
2899 enum t_exactness implicit_x = EXACT;
2900 SCM result;
2901
2902 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
2903 while (idx + 2 < len && mem[idx] == '#')
2904 {
2905 switch (mem[idx + 1])
2906 {
2907 case 'b': case 'B':
2908 if (radix != NO_RADIX)
2909 return SCM_BOOL_F;
2910 radix = DUAL;
2911 break;
2912 case 'd': case 'D':
2913 if (radix != NO_RADIX)
2914 return SCM_BOOL_F;
2915 radix = DEC;
2916 break;
2917 case 'i': case 'I':
2918 if (forced_x != NO_EXACTNESS)
2919 return SCM_BOOL_F;
2920 forced_x = INEXACT;
2921 break;
2922 case 'e': case 'E':
2923 if (forced_x != NO_EXACTNESS)
2924 return SCM_BOOL_F;
2925 forced_x = EXACT;
2926 break;
2927 case 'o': case 'O':
2928 if (radix != NO_RADIX)
2929 return SCM_BOOL_F;
2930 radix = OCT;
2931 break;
2932 case 'x': case 'X':
2933 if (radix != NO_RADIX)
2934 return SCM_BOOL_F;
2935 radix = HEX;
2936 break;
2937 default:
f872b822 2938 return SCM_BOOL_F;
3c9a524f
DH
2939 }
2940 idx += 2;
2941 }
2942
2943 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
2944 if (radix == NO_RADIX)
2945 result = mem2complex (mem, len, idx, default_radix, &implicit_x);
2946 else
2947 result = mem2complex (mem, len, idx, (unsigned int) radix, &implicit_x);
2948
2949 if (SCM_FALSEP (result))
2950 return SCM_BOOL_F;
f872b822 2951
3c9a524f 2952 switch (forced_x)
f872b822 2953 {
3c9a524f
DH
2954 case EXACT:
2955 if (SCM_INEXACTP (result))
2956 /* FIXME: This may change the value. */
2957 return scm_inexact_to_exact (result);
2958 else
2959 return result;
2960 case INEXACT:
2961 if (SCM_INEXACTP (result))
2962 return result;
2963 else
2964 return scm_exact_to_inexact (result);
2965 case NO_EXACTNESS:
2966 default:
2967 if (implicit_x == INEXACT)
2968 {
2969 if (SCM_INEXACTP (result))
2970 return result;
2971 else
2972 return scm_exact_to_inexact (result);
2973 }
2974 else
2975 return result;
f872b822 2976 }
0f2d19dd
JB
2977}
2978
2979
a1ec6916 2980SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 2981 (SCM string, SCM radix),
1e6808ea 2982 "Return a number of the maximally precise representation\n"
942e5b91 2983 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
2984 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
2985 "is a default radix that may be overridden by an explicit radix\n"
2986 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
2987 "supplied, then the default radix is 10. If string is not a\n"
2988 "syntactically valid notation for a number, then\n"
2989 "@code{string->number} returns @code{#f}.")
1bbd0b84 2990#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2991{
2992 SCM answer;
1bbd0b84 2993 int base;
a6d9e5ab 2994 SCM_VALIDATE_STRING (1, string);
3b3b36dd 2995 SCM_VALIDATE_INUM_MIN_DEF_COPY (2,radix,2,10,base);
3c9a524f
DH
2996 answer = scm_i_mem2number (SCM_STRING_CHARS (string),
2997 SCM_STRING_LENGTH (string),
2998 base);
bb628794 2999 return scm_return_first (answer, string);
0f2d19dd 3000}
1bbd0b84 3001#undef FUNC_NAME
3c9a524f
DH
3002
3003
0f2d19dd
JB
3004/*** END strs->nums ***/
3005
5986c47d 3006
0f2d19dd 3007SCM
f3ae5d60 3008scm_make_real (double x)
0f2d19dd
JB
3009{
3010 SCM z;
228a24ef 3011 z = scm_double_cell (scm_tc16_real, 0, 0, 0);
3a9809df 3012 SCM_REAL_VALUE (z) = x;
0f2d19dd
JB
3013 return z;
3014}
0f2d19dd 3015
5986c47d 3016
f3ae5d60
MD
3017SCM
3018scm_make_complex (double x, double y)
3019{
3a9809df
DH
3020 if (y == 0.0) {
3021 return scm_make_real (x);
3022 } else {
3023 SCM z;
4c9419ac
MV
3024 SCM_NEWSMOB (z, scm_tc16_complex, scm_gc_malloc (2*sizeof (double),
3025 "complex"));
3a9809df
DH
3026 SCM_COMPLEX_REAL (z) = x;
3027 SCM_COMPLEX_IMAG (z) = y;
3028 return z;
3029 }
f3ae5d60 3030}
1cc91f1b 3031
5986c47d 3032
0f2d19dd 3033SCM
1bbd0b84 3034scm_bigequal (SCM x, SCM y)
0f2d19dd
JB
3035{
3036#ifdef SCM_BIGDIG
f872b822
MD
3037 if (0 == scm_bigcomp (x, y))
3038 return SCM_BOOL_T;
0f2d19dd
JB
3039#endif
3040 return SCM_BOOL_F;
3041}
3042
0f2d19dd 3043SCM
f3ae5d60 3044scm_real_equalp (SCM x, SCM y)
0f2d19dd 3045{
f3ae5d60 3046 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
3047}
3048
f3ae5d60
MD
3049SCM
3050scm_complex_equalp (SCM x, SCM y)
3051{
3052 return SCM_BOOL (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
3053 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
3054}
0f2d19dd
JB
3055
3056
3057
1bbd0b84 3058SCM_REGISTER_PROC (s_number_p, "number?", 1, 0, 0, scm_number_p);
942e5b91
MG
3059/* "Return @code{#t} if @var{x} is a number, @code{#f}\n"
3060 * "else. Note that the sets of complex, real, rational and\n"
3061 * "integer values form subsets of the set of numbers, i. e. the\n"
3062 * "predicate will be fulfilled for any number."
3063 */
a1ec6916 3064SCM_DEFINE (scm_number_p, "complex?", 1, 0, 0,
1bbd0b84 3065 (SCM x),
942e5b91 3066 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 3067 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
3068 "values form subsets of the set of complex numbers, i. e. the\n"
3069 "predicate will also be fulfilled if @var{x} is a real,\n"
3070 "rational or integer number.")
1bbd0b84 3071#define FUNC_NAME s_scm_number_p
0f2d19dd 3072{
bb628794 3073 return SCM_BOOL (SCM_NUMBERP (x));
0f2d19dd 3074}
1bbd0b84 3075#undef FUNC_NAME
0f2d19dd
JB
3076
3077
1bbd0b84 3078SCM_REGISTER_PROC (s_real_p, "real?", 1, 0, 0, scm_real_p);
942e5b91
MG
3079/* "Return @code{#t} if @var{x} is a real number, @code{#f} else.\n"
3080 * "Note that the sets of integer and rational values form a subset\n"
3081 * "of the set of real numbers, i. e. the predicate will also\n"
3082 * "be fulfilled if @var{x} is an integer or a rational number."
3083 */
a1ec6916 3084SCM_DEFINE (scm_real_p, "rational?", 1, 0, 0,
1bbd0b84 3085 (SCM x),
942e5b91 3086 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 3087 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91
MG
3088 "the set of rational numbers, i. e. the predicate will also be\n"
3089 "fulfilled if @var{x} is an integer number. Real numbers\n"
3090 "will also satisfy this predicate, because of their limited\n"
3091 "precision.")
1bbd0b84 3092#define FUNC_NAME s_scm_real_p
0f2d19dd 3093{
bb628794 3094 if (SCM_INUMP (x)) {
0f2d19dd 3095 return SCM_BOOL_T;
bb628794 3096 } else if (SCM_IMP (x)) {
0f2d19dd 3097 return SCM_BOOL_F;
3c9a524f 3098 } else if (SCM_REALP (x)) {
0f2d19dd 3099 return SCM_BOOL_T;
bb628794 3100 } else if (SCM_BIGP (x)) {
0f2d19dd 3101 return SCM_BOOL_T;
bb628794
DH
3102 } else {
3103 return SCM_BOOL_F;
3104 }
0f2d19dd 3105}
1bbd0b84 3106#undef FUNC_NAME
0f2d19dd
JB
3107
3108
a1ec6916 3109SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 3110 (SCM x),
942e5b91
MG
3111 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
3112 "else.")
1bbd0b84 3113#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
3114{
3115 double r;
f872b822
MD
3116 if (SCM_INUMP (x))
3117 return SCM_BOOL_T;
3118 if (SCM_IMP (x))
3119 return SCM_BOOL_F;
f872b822
MD
3120 if (SCM_BIGP (x))
3121 return SCM_BOOL_T;
3c9a524f 3122 if (!SCM_INEXACTP (x))
f872b822 3123 return SCM_BOOL_F;
3c9a524f 3124 if (SCM_COMPLEXP (x))
f872b822 3125 return SCM_BOOL_F;
5986c47d 3126 r = SCM_REAL_VALUE (x);
f872b822
MD
3127 if (r == floor (r))
3128 return SCM_BOOL_T;
0f2d19dd
JB
3129 return SCM_BOOL_F;
3130}
1bbd0b84 3131#undef FUNC_NAME
0f2d19dd
JB
3132
3133
a1ec6916 3134SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 3135 (SCM x),
942e5b91
MG
3136 "Return @code{#t} if @var{x} is an inexact number, @code{#f}\n"
3137 "else.")
1bbd0b84 3138#define FUNC_NAME s_scm_inexact_p
0f2d19dd 3139{
f4c627b3 3140 return SCM_BOOL (SCM_INEXACTP (x));
0f2d19dd 3141}
1bbd0b84 3142#undef FUNC_NAME
0f2d19dd
JB
3143
3144
152f82bf 3145SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
942e5b91 3146/* "Return @code{#t} if all parameters are numerically equal." */
0f2d19dd 3147SCM
6e8d25a6 3148scm_num_eq_p (SCM x, SCM y)
0f2d19dd 3149{
f4c627b3
DH
3150 if (SCM_INUMP (x)) {
3151 long xx = SCM_INUM (x);
3152 if (SCM_INUMP (y)) {
3153 long yy = SCM_INUM (y);
3154 return SCM_BOOL (xx == yy);
3155 } else if (SCM_BIGP (y)) {
3156 return SCM_BOOL_F;
3157 } else if (SCM_REALP (y)) {
3158 return SCM_BOOL ((double) xx == SCM_REAL_VALUE (y));
3159 } else if (SCM_COMPLEXP (y)) {
3160 return SCM_BOOL (((double) xx == SCM_COMPLEX_REAL (y))
3161 && (0.0 == SCM_COMPLEX_IMAG (y)));
3162 } else {
3163 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3164 }
f4c627b3
DH
3165 } else if (SCM_BIGP (x)) {
3166 if (SCM_INUMP (y)) {
3167 return SCM_BOOL_F;
3168 } else if (SCM_BIGP (y)) {
3169 return SCM_BOOL (0 == scm_bigcomp (x, y));
3170 } else if (SCM_REALP (y)) {
1be6b49c 3171 return SCM_BOOL (scm_i_big2dbl (x) == SCM_REAL_VALUE (y));
f4c627b3 3172 } else if (SCM_COMPLEXP (y)) {
1be6b49c 3173 return SCM_BOOL ((scm_i_big2dbl (x) == SCM_COMPLEX_REAL (y))
f4c627b3
DH
3174 && (0.0 == SCM_COMPLEX_IMAG (y)));
3175 } else {
3176 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3177 }
3178 } else if (SCM_REALP (x)) {
3179 if (SCM_INUMP (y)) {
3180 return SCM_BOOL (SCM_REAL_VALUE (x) == (double) SCM_INUM (y));
3181 } else if (SCM_BIGP (y)) {
1be6b49c 3182 return SCM_BOOL (SCM_REAL_VALUE (x) == scm_i_big2dbl (y));
f4c627b3
DH
3183 } else if (SCM_REALP (y)) {
3184 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
3185 } else if (SCM_COMPLEXP (y)) {
3186 return SCM_BOOL ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
3187 && (0.0 == SCM_COMPLEX_IMAG (y)));
3188 } else {
3189 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3190 }
f4c627b3
DH
3191 } else if (SCM_COMPLEXP (x)) {
3192 if (SCM_INUMP (y)) {
3193 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == (double) SCM_INUM (y))
3194 && (SCM_COMPLEX_IMAG (x) == 0.0));
3195 } else if (SCM_BIGP (y)) {
1be6b49c 3196 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == scm_i_big2dbl (y))
f4c627b3
DH
3197 && (SCM_COMPLEX_IMAG (x) == 0.0));
3198 } else if (SCM_REALP (y)) {
3199 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
3200 && (SCM_COMPLEX_IMAG (x) == 0.0));
3201 } else if (SCM_COMPLEXP (y)) {
3202 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
3203 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
3204 } else {
3205 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3206 }
3207 } else {
3208 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
3209 }
0f2d19dd
JB
3210}
3211
3212
152f82bf 3213SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
942e5b91
MG
3214/* "Return @code{#t} if the list of parameters is monotonically\n"
3215 * "increasing."
3216 */
0f2d19dd 3217SCM
6e8d25a6 3218scm_less_p (SCM x, SCM y)
0f2d19dd 3219{
f4c627b3
DH
3220 if (SCM_INUMP (x)) {
3221 long xx = SCM_INUM (x);
3222 if (SCM_INUMP (y)) {
3223 long yy = SCM_INUM (y);
3224 return SCM_BOOL (xx < yy);
3225 } else if (SCM_BIGP (y)) {
3226 return SCM_BOOL (!SCM_BIGSIGN (y));
3227 } else if (SCM_REALP (y)) {
3228 return SCM_BOOL ((double) xx < SCM_REAL_VALUE (y));
3229 } else {
3230 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3231 }
f4c627b3
DH
3232 } else if (SCM_BIGP (x)) {
3233 if (SCM_INUMP (y)) {
3234 return SCM_BOOL (SCM_BIGSIGN (x));
3235 } else if (SCM_BIGP (y)) {
3236 return SCM_BOOL (1 == scm_bigcomp (x, y));
3237 } else if (SCM_REALP (y)) {
1be6b49c 3238 return SCM_BOOL (scm_i_big2dbl (x) < SCM_REAL_VALUE (y));
f4c627b3
DH
3239 } else {
3240 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3241 }
3242 } else if (SCM_REALP (x)) {
3243 if (SCM_INUMP (y)) {
3244 return SCM_BOOL (SCM_REAL_VALUE (x) < (double) SCM_INUM (y));
3245 } else if (SCM_BIGP (y)) {
1be6b49c 3246 return SCM_BOOL (SCM_REAL_VALUE (x) < scm_i_big2dbl (y));
f4c627b3
DH
3247 } else if (SCM_REALP (y)) {
3248 return SCM_BOOL (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
3249 } else {
3250 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3251 }
f4c627b3
DH
3252 } else {
3253 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
3254 }
0f2d19dd
JB
3255}
3256
3257
c76b1eaf 3258SCM_GPROC1 (s_scm_gr_p, ">", scm_tc7_rpsubr, scm_gr_p, g_gr_p);
942e5b91
MG
3259/* "Return @code{#t} if the list of parameters is monotonically\n"
3260 * "decreasing."
c76b1eaf 3261 */
1bbd0b84 3262#define FUNC_NAME s_scm_gr_p
c76b1eaf
MD
3263SCM
3264scm_gr_p (SCM x, SCM y)
0f2d19dd 3265{
c76b1eaf
MD
3266 if (!SCM_NUMBERP (x))
3267 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG1, FUNC_NAME);
3268 else if (!SCM_NUMBERP (y))
3269 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG2, FUNC_NAME);
3270 else
3271 return scm_less_p (y, x);
0f2d19dd 3272}
1bbd0b84 3273#undef FUNC_NAME
0f2d19dd
JB
3274
3275
c76b1eaf 3276SCM_GPROC1 (s_scm_leq_p, "<=", scm_tc7_rpsubr, scm_leq_p, g_leq_p);
942e5b91 3277/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3278 * "non-decreasing."
3279 */
1bbd0b84 3280#define FUNC_NAME s_scm_leq_p
c76b1eaf
MD
3281SCM
3282scm_leq_p (SCM x, SCM y)
0f2d19dd 3283{
c76b1eaf
MD
3284 if (!SCM_NUMBERP (x))
3285 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG1, FUNC_NAME);
3286 else if (!SCM_NUMBERP (y))
3287 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG2, FUNC_NAME);
fc194577
MV
3288 else if (SCM_NFALSEP (scm_nan_p (x)) || SCM_NFALSEP (scm_nan_p (y)))
3289 return SCM_BOOL_F;
c76b1eaf
MD
3290 else
3291 return SCM_BOOL_NOT (scm_less_p (y, x));
0f2d19dd 3292}
1bbd0b84 3293#undef FUNC_NAME
0f2d19dd
JB
3294
3295
c76b1eaf 3296SCM_GPROC1 (s_scm_geq_p, ">=", scm_tc7_rpsubr, scm_geq_p, g_geq_p);
942e5b91 3297/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3298 * "non-increasing."
3299 */
1bbd0b84 3300#define FUNC_NAME s_scm_geq_p
c76b1eaf
MD
3301SCM
3302scm_geq_p (SCM x, SCM y)
0f2d19dd 3303{
c76b1eaf
MD
3304 if (!SCM_NUMBERP (x))
3305 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG1, FUNC_NAME);
3306 else if (!SCM_NUMBERP (y))
3307 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG2, FUNC_NAME);
fc194577
MV
3308 else if (SCM_NFALSEP (scm_nan_p (x)) || SCM_NFALSEP (scm_nan_p (y)))
3309 return SCM_BOOL_F;
c76b1eaf 3310 else
fc194577 3311 return SCM_BOOL_NOT (scm_less_p (x, y));
0f2d19dd 3312}
1bbd0b84 3313#undef FUNC_NAME
0f2d19dd
JB
3314
3315
152f82bf 3316SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
942e5b91
MG
3317/* "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
3318 * "zero."
3319 */
0f2d19dd 3320SCM
6e8d25a6 3321scm_zero_p (SCM z)
0f2d19dd 3322{
c2ff8ab0
DH
3323 if (SCM_INUMP (z)) {
3324 return SCM_BOOL (SCM_EQ_P (z, SCM_INUM0));
3325 } else if (SCM_BIGP (z)) {
3326 return SCM_BOOL_F;
3327 } else if (SCM_REALP (z)) {
3328 return SCM_BOOL (SCM_REAL_VALUE (z) == 0.0);
3329 } else if (SCM_COMPLEXP (z)) {
3330 return SCM_BOOL (SCM_COMPLEX_REAL (z) == 0.0
3331 && SCM_COMPLEX_IMAG (z) == 0.0);
3332 } else {
3333 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
3334 }
0f2d19dd
JB
3335}
3336
3337
152f82bf 3338SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
942e5b91
MG
3339/* "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
3340 * "zero."
3341 */
0f2d19dd 3342SCM
6e8d25a6 3343scm_positive_p (SCM x)
0f2d19dd 3344{
c2ff8ab0
DH
3345 if (SCM_INUMP (x)) {
3346 return SCM_BOOL (SCM_INUM (x) > 0);
3347 } else if (SCM_BIGP (x)) {
3348 return SCM_BOOL (!SCM_BIGSIGN (x));
3349 } else if (SCM_REALP (x)) {
3350 return SCM_BOOL(SCM_REAL_VALUE (x) > 0.0);
3351 } else {
3352 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
3353 }
0f2d19dd
JB
3354}
3355
3356
152f82bf 3357SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
942e5b91
MG
3358/* "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
3359 * "zero."
3360 */
0f2d19dd 3361SCM
6e8d25a6 3362scm_negative_p (SCM x)
0f2d19dd 3363{
c2ff8ab0
DH
3364 if (SCM_INUMP (x)) {
3365 return SCM_BOOL (SCM_INUM (x) < 0);
3366 } else if (SCM_BIGP (x)) {
3367 return SCM_BOOL (SCM_BIGSIGN (x));
3368 } else if (SCM_REALP (x)) {
3369 return SCM_BOOL(SCM_REAL_VALUE (x) < 0.0);
3370 } else {
3371 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
3372 }
0f2d19dd
JB
3373}
3374
3375
9de33deb 3376SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
942e5b91
MG
3377/* "Return the maximum of all parameter values."
3378 */
0f2d19dd 3379SCM
6e8d25a6 3380scm_max (SCM x, SCM y)
0f2d19dd 3381{
f4c627b3
DH
3382 if (SCM_UNBNDP (y)) {
3383 if (SCM_UNBNDP (x)) {
c05e97b7 3384 SCM_WTA_DISPATCH_0 (g_max, s_max);
f4c627b3 3385 } else if (SCM_NUMBERP (x)) {
f872b822 3386 return x;
f4c627b3
DH
3387 } else {
3388 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3389 }
f4c627b3
DH
3390 }
3391
3392 if (SCM_INUMP (x)) {
3393 long xx = SCM_INUM (x);
3394 if (SCM_INUMP (y)) {
3395 long yy = SCM_INUM (y);
3396 return (xx < yy) ? y : x;
3397 } else if (SCM_BIGP (y)) {
3398 return SCM_BIGSIGN (y) ? x : y;
3399 } else if (SCM_REALP (y)) {
3400 double z = xx;
3401 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3402 } else {
3403 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3404 }
f4c627b3
DH
3405 } else if (SCM_BIGP (x)) {
3406 if (SCM_INUMP (y)) {
3407 return SCM_BIGSIGN (x) ? y : x;
3408 } else if (SCM_BIGP (y)) {
3409 return (1 == scm_bigcomp (x, y)) ? y : x;
3410 } else if (SCM_REALP (y)) {
1be6b49c 3411 double z = scm_i_big2dbl (x);
f4c627b3
DH
3412 return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
3413 } else {
3414 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3415 }
3416 } else if (SCM_REALP (x)) {
3417 if (SCM_INUMP (y)) {
3418 double z = SCM_INUM (y);
3419 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3420 } else if (SCM_BIGP (y)) {
1be6b49c 3421 double z = scm_i_big2dbl (y);
f4c627b3
DH
3422 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3423 } else if (SCM_REALP (y)) {
3424 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? y : x;
3425 } else {
3426 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3427 }
f4c627b3
DH
3428 } else {
3429 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
3430 }
0f2d19dd
JB
3431}
3432
3433
9de33deb 3434SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
942e5b91
MG
3435/* "Return the minium of all parameter values."
3436 */
0f2d19dd 3437SCM
6e8d25a6 3438scm_min (SCM x, SCM y)
0f2d19dd 3439{
f4c627b3
DH
3440 if (SCM_UNBNDP (y)) {
3441 if (SCM_UNBNDP (x)) {
c05e97b7 3442 SCM_WTA_DISPATCH_0 (g_min, s_min);
f4c627b3 3443 } else if (SCM_NUMBERP (x)) {
f872b822 3444 return x;
f4c627b3
DH
3445 } else {
3446 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3447 }
f4c627b3
DH
3448 }
3449
3450 if (SCM_INUMP (x)) {
3451 long xx = SCM_INUM (x);
3452 if (SCM_INUMP (y)) {
3453 long yy = SCM_INUM (y);
3454 return (xx < yy) ? x : y;
3455 } else if (SCM_BIGP (y)) {
3456 return SCM_BIGSIGN (y) ? y : x;
3457 } else if (SCM_REALP (y)) {
3458 double z = xx;
3459 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3460 } else {
3461 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3462 }
f4c627b3
DH
3463 } else if (SCM_BIGP (x)) {
3464 if (SCM_INUMP (y)) {
3465 return SCM_BIGSIGN (x) ? x : y;
3466 } else if (SCM_BIGP (y)) {
3467 return (-1 == scm_bigcomp (x, y)) ? y : x;
3468 } else if (SCM_REALP (y)) {
1be6b49c 3469 double z = scm_i_big2dbl (x);
f4c627b3
DH
3470 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3471 } else {
3472 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
3473 }
3474 } else if (SCM_REALP (x)) {
3475 if (SCM_INUMP (y)) {
3476 double z = SCM_INUM (y);
3477 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3478 } else if (SCM_BIGP (y)) {
1be6b49c 3479 double z = scm_i_big2dbl (y);
f4c627b3
DH
3480 return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
3481 } else if (SCM_REALP (y)) {
3482 return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? x : y;
3483 } else {
3484 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3485 }
f4c627b3
DH
3486 } else {
3487 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
3488 }
0f2d19dd
JB
3489}
3490
3491
9de33deb 3492SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
942e5b91
MG
3493/* "Return the sum of all parameter values. Return 0 if called without\n"
3494 * "any parameters."
3495 */
0f2d19dd 3496SCM
6e8d25a6 3497scm_sum (SCM x, SCM y)
0f2d19dd 3498{
98cb6e75
DH
3499 if (SCM_UNBNDP (y)) {
3500 if (SCM_UNBNDP (x)) {
3501 return SCM_INUM0;
3502 } else if (SCM_NUMBERP (x)) {
f872b822 3503 return x;
98cb6e75
DH
3504 } else {
3505 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3506 }
98cb6e75 3507 }
c209c88e 3508
98cb6e75
DH
3509 if (SCM_INUMP (x)) {
3510 long int xx = SCM_INUM (x);
3511 if (SCM_INUMP (y)) {
3512 long int yy = SCM_INUM (y);
3513 long int z = xx + yy;
3514 if (SCM_FIXABLE (z)) {
3515 return SCM_MAKINUM (z);
3516 } else {
3517#ifdef SCM_BIGDIG
1be6b49c 3518 return scm_i_long2big (z);
98cb6e75
DH
3519#else /* SCM_BIGDIG */
3520 return scm_make_real ((double) z);
3521#endif /* SCM_BIGDIG */
3522 }
3523 } else if (SCM_BIGP (y)) {
3524 intbig:
f872b822 3525 {
98cb6e75
DH
3526 long int xx = SCM_INUM (x);
3527#ifndef SCM_DIGSTOOBIG
3528 long z = scm_pseudolong (xx);
3529 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3530 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3531#else /* SCM_DIGSTOOBIG */
3532 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3533 scm_longdigs (xx, zdigs);
3534 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3535 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, 0);
3536#endif /* SCM_DIGSTOOBIG */
0f2d19dd 3537 }
98cb6e75
DH
3538 } else if (SCM_REALP (y)) {
3539 return scm_make_real (xx + SCM_REAL_VALUE (y));
3540 } else if (SCM_COMPLEXP (y)) {
3541 return scm_make_complex (xx + SCM_COMPLEX_REAL (y),
3542 SCM_COMPLEX_IMAG (y));
3543 } else {
3544 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3545 }
98cb6e75
DH
3546 } else if (SCM_BIGP (x)) {
3547 if (SCM_INUMP (y)) {
3548 SCM_SWAP (x, y);
3549 goto intbig;
3550 } else if (SCM_BIGP (y)) {
3551 if (SCM_NUMDIGS (x) > SCM_NUMDIGS (y)) {
3552 SCM_SWAP (x, y);
3553 }
3554 return scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3555 SCM_BIGSIGN (x), y, 0);
3556 } else if (SCM_REALP (y)) {
1be6b49c 3557 return scm_make_real (scm_i_big2dbl (x) + SCM_REAL_VALUE (y));
98cb6e75 3558 } else if (SCM_COMPLEXP (y)) {
1be6b49c 3559 return scm_make_complex (scm_i_big2dbl (x) + SCM_COMPLEX_REAL (y),
98cb6e75
DH
3560 SCM_COMPLEX_IMAG (y));
3561 } else {
3562 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3563 }
98cb6e75
DH
3564 } else if (SCM_REALP (x)) {
3565 if (SCM_INUMP (y)) {
3566 return scm_make_real (SCM_REAL_VALUE (x) + SCM_INUM (y));
3567 } else if (SCM_BIGP (y)) {
1be6b49c 3568 return scm_make_real (SCM_REAL_VALUE (x) + scm_i_big2dbl (y));
98cb6e75
DH
3569 } else if (SCM_REALP (y)) {
3570 return scm_make_real (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
3571 } else if (SCM_COMPLEXP (y)) {
3572 return scm_make_complex (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
3573 SCM_COMPLEX_IMAG (y));
3574 } else {
3575 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3576 }
3577 } else if (SCM_COMPLEXP (x)) {
3578 if (SCM_INUMP (y)) {
3579 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_INUM (y),
3580 SCM_COMPLEX_IMAG (x));
3581 } else if (SCM_BIGP (y)) {
1be6b49c 3582 return scm_make_complex (SCM_COMPLEX_REAL (x) + scm_i_big2dbl (y),
98cb6e75
DH
3583 SCM_COMPLEX_IMAG (x));
3584 } else if (SCM_REALP (y)) {
3585 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
3586 SCM_COMPLEX_IMAG (x));
3587 } else if (SCM_COMPLEXP (y)) {
3588 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
3589 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
3590 } else {
3591 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3592 }
3593 } else {
3594 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
3595 }
0f2d19dd
JB
3596}
3597
3598
9de33deb 3599SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
609c3d30
MG
3600/* If called with one argument @var{z1}, -@var{z1} returned. Otherwise
3601 * the sum of all but the first argument are subtracted from the first
3602 * argument. */
c05e97b7 3603#define FUNC_NAME s_difference
0f2d19dd 3604SCM
6e8d25a6 3605scm_difference (SCM x, SCM y)
0f2d19dd 3606{
98cb6e75 3607 if (SCM_UNBNDP (y)) {
c05e97b7
MV
3608 if (SCM_UNBNDP (x)) {
3609 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
3610 } else if (SCM_INUMP (x)) {
98cb6e75
DH
3611 long xx = -SCM_INUM (x);
3612 if (SCM_FIXABLE (xx)) {
3613 return SCM_MAKINUM (xx);
3614 } else {
f872b822 3615#ifdef SCM_BIGDIG
1be6b49c 3616 return scm_i_long2big (xx);
f3ae5d60 3617#else
98cb6e75 3618 return scm_make_real ((double) xx);
f3ae5d60 3619#endif
f3ae5d60 3620 }
98cb6e75 3621 } else if (SCM_BIGP (x)) {
1be6b49c 3622 SCM z = scm_i_copybig (x, !SCM_BIGSIGN (x));
98cb6e75
DH
3623 unsigned int digs = SCM_NUMDIGS (z);
3624 unsigned int size = digs * SCM_BITSPERDIG / SCM_CHAR_BIT;
1be6b49c 3625 return size <= sizeof (SCM) ? scm_i_big2inum (z, digs) : z;
98cb6e75
DH
3626 } else if (SCM_REALP (x)) {
3627 return scm_make_real (-SCM_REAL_VALUE (x));
3628 } else if (SCM_COMPLEXP (x)) {
3629 return scm_make_complex (-SCM_COMPLEX_REAL (x), -SCM_COMPLEX_IMAG (x));
3630 } else {
3631 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 3632 }
98cb6e75
DH
3633 }
3634
3635 if (SCM_INUMP (x)) {
3636 long int xx = SCM_INUM (x);
3637 if (SCM_INUMP (y)) {
3638 long int yy = SCM_INUM (y);
3639 long int z = xx - yy;
3640 if (SCM_FIXABLE (z)) {
3641 return SCM_MAKINUM (z);
3642 } else {
f872b822 3643#ifdef SCM_BIGDIG
1be6b49c 3644 return scm_i_long2big (z);
f872b822 3645#else
98cb6e75 3646 return scm_make_real ((double) z);
f872b822 3647#endif
98cb6e75
DH
3648 }
3649 } else if (SCM_BIGP (y)) {
3650#ifndef SCM_DIGSTOOBIG
3651 long z = scm_pseudolong (xx);
3652 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3653 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3654#else
98cb6e75
DH
3655 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3656 scm_longdigs (xx, zdigs);
3657 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3658 (xx < 0) ? SCM_BIGSIGNFLAG : 0, y, SCM_BIGSIGNFLAG);
f872b822 3659#endif
98cb6e75
DH
3660 } else if (SCM_REALP (y)) {
3661 return scm_make_real (xx - SCM_REAL_VALUE (y));
3662 } else if (SCM_COMPLEXP (y)) {
3663 return scm_make_complex (xx - SCM_COMPLEX_REAL (y),
3664 -SCM_COMPLEX_IMAG (y));
3665 } else {
3666 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 3667 }
98cb6e75
DH
3668 } else if (SCM_BIGP (x)) {
3669 if (SCM_INUMP (y)) {
3670 long int yy = SCM_INUM (y);
3671#ifndef SCM_DIGSTOOBIG
3672 long z = scm_pseudolong (yy);
3673 return scm_addbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3674 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
f872b822 3675#else
98cb6e75
DH
3676 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3677 scm_longdigs (yy, zdigs);
3678 return scm_addbig (zdigs, SCM_DIGSPERLONG,
3679 (yy < 0) ? 0 : SCM_BIGSIGNFLAG, x, 0);
0f2d19dd 3680#endif
98cb6e75
DH
3681 } else if (SCM_BIGP (y)) {
3682 return (SCM_NUMDIGS (x) < SCM_NUMDIGS (y))
3683 ? scm_addbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3684 SCM_BIGSIGN (x), y, SCM_BIGSIGNFLAG)
3685 : scm_addbig (SCM_BDIGITS (y), SCM_NUMDIGS (y),
3686 SCM_BIGSIGN (y) ^ SCM_BIGSIGNFLAG, x, 0);
3687 } else if (SCM_REALP (y)) {
1be6b49c 3688 return scm_make_real (scm_i_big2dbl (x) - SCM_REAL_VALUE (y));
98cb6e75 3689 } else if (SCM_COMPLEXP (y)) {
1be6b49c 3690 return scm_make_complex (scm_i_big2dbl (x) - SCM_COMPLEX_REAL (y),
98cb6e75
DH
3691 - SCM_COMPLEX_IMAG (y));
3692 } else {
3693 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3694 }
3695 } else if (SCM_REALP (x)) {
3696 if (SCM_INUMP (y)) {
3697 return scm_make_real (SCM_REAL_VALUE (x) - SCM_INUM (y));
3698 } else if (SCM_BIGP (y)) {
1be6b49c 3699 return scm_make_real (SCM_REAL_VALUE (x) - scm_i_big2dbl (y));
98cb6e75
DH
3700 } else if (SCM_REALP (y)) {
3701 return scm_make_real (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
3702 } else if (SCM_COMPLEXP (y)) {
3703 return scm_make_complex (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
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_COMPLEXP (x)) {
3709 if (SCM_INUMP (y)) {
3710 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_INUM (y),
3711 SCM_COMPLEX_IMAG (x));
3712 } else if (SCM_BIGP (y)) {
1be6b49c 3713 return scm_make_complex (SCM_COMPLEX_REAL (x) - scm_i_big2dbl (y),
98cb6e75
DH
3714 SCM_COMPLEX_IMAG (x));
3715 } else if (SCM_REALP (y)) {
3716 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
3717 SCM_COMPLEX_IMAG (x));
3718 } else if (SCM_COMPLEXP (y)) {
3719 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
3720 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
3721 } else {
3722 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
3723 }
3724 } else {
3725 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
3726 }
0f2d19dd 3727}
c05e97b7 3728#undef FUNC_NAME
0f2d19dd 3729
9de33deb 3730SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
942e5b91
MG
3731/* "Return the product of all arguments. If called without arguments,\n"
3732 * "1 is returned."
3733 */
0f2d19dd 3734SCM
6e8d25a6 3735scm_product (SCM x, SCM y)
0f2d19dd 3736{
f4c627b3
DH
3737 if (SCM_UNBNDP (y)) {
3738 if (SCM_UNBNDP (x)) {
3739 return SCM_MAKINUM (1L);
3740 } else if (SCM_NUMBERP (x)) {
f872b822 3741 return x;
f4c627b3
DH
3742 } else {
3743 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 3744 }
f4c627b3
DH
3745 }
3746
3747 if (SCM_INUMP (x)) {
3748 long xx;
3749
3750 intbig:
3751 xx = SCM_INUM (x);
3752
3753 if (xx == 0) {
f872b822 3754 return x;
f4c627b3
DH
3755 } else if (xx == 1) {
3756 return y;
3757 }
3758
3759 if (SCM_INUMP (y)) {
3760 long yy = SCM_INUM (y);
3761 long kk = xx * yy;
3762 SCM k = SCM_MAKINUM (kk);
3763 if (kk != SCM_INUM (k) || kk / xx != yy) {
f872b822 3764#ifdef SCM_BIGDIG
f4c627b3 3765 int sgn = (xx < 0) ^ (yy < 0);
f872b822 3766#ifndef SCM_DIGSTOOBIG
f4c627b3
DH
3767 long i = scm_pseudolong (xx);
3768 long j = scm_pseudolong (yy);
f872b822
MD
3769 return scm_mulbig ((SCM_BIGDIG *) & i, SCM_DIGSPERLONG,
3770 (SCM_BIGDIG *) & j, SCM_DIGSPERLONG, sgn);
3771#else /* SCM_DIGSTOOBIG */
f4c627b3
DH
3772 SCM_BIGDIG xdigs [SCM_DIGSPERLONG];
3773 SCM_BIGDIG ydigs [SCM_DIGSPERLONG];
3774 scm_longdigs (xx, xdigs);
3775 scm_longdigs (yy, ydigs);
3776 return scm_mulbig (xdigs, SCM_DIGSPERLONG,
3777 ydigs, SCM_DIGSPERLONG,
f872b822
MD
3778 sgn);
3779#endif
f4c627b3
DH
3780#else
3781 return scm_make_real (((double) xx) * ((double) yy));
3782#endif
3783 } else {
3784 return k;
0f2d19dd 3785 }
f4c627b3
DH
3786 } else if (SCM_BIGP (y)) {
3787#ifndef SCM_DIGSTOOBIG
3788 long z = scm_pseudolong (xx);
3789 return scm_mulbig ((SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
3790 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3791 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3792#else
f4c627b3
DH
3793 SCM_BIGDIG zdigs [SCM_DIGSPERLONG];
3794 scm_longdigs (xx, zdigs);
3795 return scm_mulbig (zdigs, SCM_DIGSPERLONG,
3796 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3797 SCM_BIGSIGN (y) ? (xx > 0) : (xx < 0));
0f2d19dd 3798#endif
f4c627b3
DH
3799 } else if (SCM_REALP (y)) {
3800 return scm_make_real (xx * SCM_REAL_VALUE (y));
3801 } else if (SCM_COMPLEXP (y)) {
3802 return scm_make_complex (xx * SCM_COMPLEX_REAL (y),
3803 xx * SCM_COMPLEX_IMAG (y));
3804 } else {
3805 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3806 }
3807 } else if (SCM_BIGP (x)) {
3808 if (SCM_INUMP (y)) {
3809 SCM_SWAP (x, y);
3810 goto intbig;
3811 } else if (SCM_BIGP (y)) {
3812 return scm_mulbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
3813 SCM_BDIGITS (y), SCM_NUMDIGS (y),
3814 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y));
3815 } else if (SCM_REALP (y)) {
1be6b49c 3816 return scm_make_real (scm_i_big2dbl (x) * SCM_REAL_VALUE (y));
f4c627b3 3817 } else if (SCM_COMPLEXP (y)) {
1be6b49c 3818 double z = scm_i_big2dbl (x);
f4c627b3
DH
3819 return scm_make_complex (z * SCM_COMPLEX_REAL (y),
3820 z * SCM_COMPLEX_IMAG (y));
3821 } else {
3822 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3823 }
3824 } else if (SCM_REALP (x)) {
3825 if (SCM_INUMP (y)) {
3826 return scm_make_real (SCM_INUM (y) * SCM_REAL_VALUE (x));
3827 } else if (SCM_BIGP (y)) {
1be6b49c 3828 return scm_make_real (scm_i_big2dbl (y) * SCM_REAL_VALUE (x));
f4c627b3
DH
3829 } else if (SCM_REALP (y)) {
3830 return scm_make_real (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
3831 } else if (SCM_COMPLEXP (y)) {
3832 return scm_make_complex (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
3833 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
3834 } else {
3835 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3836 }
3837 } else if (SCM_COMPLEXP (x)) {
3838 if (SCM_INUMP (y)) {
3839 return scm_make_complex (SCM_INUM (y) * SCM_COMPLEX_REAL (x),
3840 SCM_INUM (y) * SCM_COMPLEX_IMAG (x));
3841 } else if (SCM_BIGP (y)) {
1be6b49c 3842 double z = scm_i_big2dbl (y);
f4c627b3
DH
3843 return scm_make_complex (z * SCM_COMPLEX_REAL (x),
3844 z * SCM_COMPLEX_IMAG (x));
3845 } else if (SCM_REALP (y)) {
3846 return scm_make_complex (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
3847 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
3848 } else if (SCM_COMPLEXP (y)) {
3849 return scm_make_complex (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
3850 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
3851 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
3852 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
3853 } else {
3854 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
3855 }
3856 } else {
3857 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
3858 }
3859}
3860
3861
0f2d19dd 3862double
6e8d25a6 3863scm_num2dbl (SCM a, const char *why)
f4c627b3 3864#define FUNC_NAME why
0f2d19dd 3865{
f4c627b3 3866 if (SCM_INUMP (a)) {
0f2d19dd 3867 return (double) SCM_INUM (a);
f4c627b3 3868 } else if (SCM_BIGP (a)) {
1be6b49c 3869 return scm_i_big2dbl (a);
f4c627b3
DH
3870 } else if (SCM_REALP (a)) {
3871 return (SCM_REAL_VALUE (a));
3872 } else {
3873 SCM_WRONG_TYPE_ARG (SCM_ARGn, a);
3874 }
0f2d19dd 3875}
f4c627b3 3876#undef FUNC_NAME
0f2d19dd 3877
7351e207
MV
3878#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
3879 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
3880#define ALLOW_DIVIDE_BY_ZERO
3881/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
3882#endif
0f2d19dd 3883
ba74ef4e
MV
3884/* The code below for complex division is adapted from the GNU
3885 libstdc++, which adapted it from f2c's libF77, and is subject to
3886 this copyright: */
3887
3888/****************************************************************
3889Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
3890
3891Permission to use, copy, modify, and distribute this software
3892and its documentation for any purpose and without fee is hereby
3893granted, provided that the above copyright notice appear in all
3894copies and that both that the copyright notice and this
3895permission notice and warranty disclaimer appear in supporting
3896documentation, and that the names of AT&T Bell Laboratories or
3897Bellcore or any of their entities not be used in advertising or
3898publicity pertaining to distribution of the software without
3899specific, written prior permission.
3900
3901AT&T and Bellcore disclaim all warranties with regard to this
3902software, including all implied warranties of merchantability
3903and fitness. In no event shall AT&T or Bellcore be liable for
3904any special, indirect or consequential damages or any damages
3905whatsoever resulting from loss of use, data or profits, whether
3906in an action of contract, negligence or other tortious action,
3907arising out of or in connection with the use or performance of
3908this software.
3909****************************************************************/
3910
9de33deb 3911SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
609c3d30
MG
3912/* Divide the first argument by the product of the remaining
3913 arguments. If called with one argument @var{z1}, 1/@var{z1} is
3914 returned. */
c05e97b7 3915#define FUNC_NAME s_divide
0f2d19dd 3916SCM
6e8d25a6 3917scm_divide (SCM x, SCM y)
0f2d19dd 3918{
f8de44c1
DH
3919 double a;
3920
3921 if (SCM_UNBNDP (y)) {
3922 if (SCM_UNBNDP (x)) {
c05e97b7 3923 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
f8de44c1 3924 } else if (SCM_INUMP (x)) {
164826d3
DH
3925 long xx = SCM_INUM (x);
3926 if (xx == 1 || xx == -1) {
f8de44c1 3927 return x;
7351e207 3928#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
164826d3
DH
3929 } else if (xx == 0) {
3930 scm_num_overflow (s_divide);
7351e207 3931#endif
f8de44c1 3932 } else {
164826d3 3933 return scm_make_real (1.0 / (double) xx);
f8de44c1 3934 }
f8de44c1 3935 } else if (SCM_BIGP (x)) {
1be6b49c 3936 return scm_make_real (1.0 / scm_i_big2dbl (x));
f8de44c1 3937 } else if (SCM_REALP (x)) {
5eec27e9 3938 double xx = SCM_REAL_VALUE (x);
7351e207 3939#ifndef ALLOW_DIVIDE_BY_ZERO
5eec27e9
DH
3940 if (xx == 0.0)
3941 scm_num_overflow (s_divide);
3942 else
7351e207 3943#endif
5eec27e9 3944 return scm_make_real (1.0 / xx);
f8de44c1
DH
3945 } else if (SCM_COMPLEXP (x)) {
3946 double r = SCM_COMPLEX_REAL (x);
3947 double i = SCM_COMPLEX_IMAG (x);
ba74ef4e
MV
3948 if (r <= i) {
3949 double t = r / i;
3950 double d = i * (1.0 + t * t);
3951 return scm_make_complex (t / d, -1.0 / d);
3952 } else {
3953 double t = i / r;
3954 double d = r * (1.0 + t * t);
3955 return scm_make_complex (1.0 / d, -t / d);
3956 }
f8de44c1
DH
3957 } else {
3958 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
3959 }
3960 }
3961
3962 if (SCM_INUMP (x)) {
3963 long xx = SCM_INUM (x);
3964 if (SCM_INUMP (y)) {
3965 long yy = SCM_INUM (y);
3966 if (yy == 0) {
7351e207 3967#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
f4c627b3 3968 scm_num_overflow (s_divide);
7351e207
MV
3969#else
3970 return scm_make_real ((double) xx / (double) yy);
3971#endif
f8de44c1
DH
3972 } else if (xx % yy != 0) {
3973 return scm_make_real ((double) xx / (double) yy);
3974 } else {
3975 long z = xx / yy;
3976 if (SCM_FIXABLE (z)) {
3977 return SCM_MAKINUM (z);
3978 } else {
f872b822 3979#ifdef SCM_BIGDIG
1be6b49c 3980 return scm_i_long2big (z);
f872b822 3981#else
f8de44c1 3982 return scm_make_real ((double) xx / (double) yy);
f872b822 3983#endif
f872b822 3984 }
f8de44c1 3985 }
f8de44c1 3986 } else if (SCM_BIGP (y)) {
1be6b49c 3987 return scm_make_real ((double) xx / scm_i_big2dbl (y));
f8de44c1 3988 } else if (SCM_REALP (y)) {
5eec27e9 3989 double yy = SCM_REAL_VALUE (y);
7351e207 3990#ifndef ALLOW_DIVIDE_BY_ZERO
5eec27e9
DH
3991 if (yy == 0.0)
3992 scm_num_overflow (s_divide);
3993 else
7351e207 3994#endif
5eec27e9 3995 return scm_make_real ((double) xx / yy);
f8de44c1
DH
3996 } else if (SCM_COMPLEXP (y)) {
3997 a = xx;
3998 complex_div: /* y _must_ be a complex number */
3999 {
4000 double r = SCM_COMPLEX_REAL (y);
4001 double i = SCM_COMPLEX_IMAG (y);
ba74ef4e
MV
4002 if (r <= i) {
4003 double t = r / i;
4004 double d = i * (1.0 + t * t);
4005 return scm_make_complex ((a * t) / d, -a / d);
4006 } else {
4007 double t = i / r;
4008 double d = r * (1.0 + t * t);
4009 return scm_make_complex (a / d, -(a * t) / d);
4010 }
f8de44c1
DH
4011 }
4012 } else {
4013 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
4014 }
f8de44c1
DH
4015 } else if (SCM_BIGP (x)) {
4016 if (SCM_INUMP (y)) {
4017 long int yy = SCM_INUM (y);
4018 if (yy == 0) {
7351e207 4019#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
f8de44c1 4020 scm_num_overflow (s_divide);
7351e207
MV
4021#else
4022 if (scm_bigcomp (x, scm_i_int2big (0)) == 0)
4023 return scm_nan ();
4024 else
4025 return scm_inf ();
4026#endif
f8de44c1
DH
4027 } else if (yy == 1) {
4028 return x;
4029 } else {
4030 long z = yy < 0 ? -yy : yy;
4031 if (z < SCM_BIGRAD) {
1be6b49c 4032 SCM w = scm_i_copybig (x, SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0));
f8de44c1
DH
4033 return scm_divbigdig (SCM_BDIGITS (w), SCM_NUMDIGS (w),
4034 (SCM_BIGDIG) z)
1be6b49c
ML
4035 ? scm_make_real (scm_i_big2dbl (x) / (double) yy)
4036 : scm_i_normbig (w);
f8de44c1
DH
4037 } else {
4038 SCM w;
4039#ifndef SCM_DIGSTOOBIG
4040 z = scm_pseudolong (z);
4041 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
4042 (SCM_BIGDIG *) & z, SCM_DIGSPERLONG,
4043 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 4044#else
f8de44c1
DH
4045 SCM_BIGDIG zdigs[SCM_DIGSPERLONG];
4046 scm_longdigs (z, zdigs);
4047 w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
4048 zdigs, SCM_DIGSPERLONG,
4049 SCM_BIGSIGN (x) ? (yy > 0) : (yy < 0), 3);
f872b822 4050#endif
f4c627b3
DH
4051 return (!SCM_UNBNDP (w))
4052 ? w
1be6b49c 4053 : scm_make_real (scm_i_big2dbl (x) / (double) yy);
f872b822 4054 }
f8de44c1
DH
4055 }
4056 } else if (SCM_BIGP (y)) {
4057 SCM w = scm_divbigbig (SCM_BDIGITS (x), SCM_NUMDIGS (x),
4058 SCM_BDIGITS (y), SCM_NUMDIGS (y),
4059 SCM_BIGSIGN (x) ^ SCM_BIGSIGN (y), 3);
f4c627b3
DH
4060 return (!SCM_UNBNDP (w))
4061 ? w
1be6b49c 4062 : scm_make_real (scm_i_big2dbl (x) / scm_i_big2dbl (y));
f8de44c1 4063 } else if (SCM_REALP (y)) {
5eec27e9 4064 double yy = SCM_REAL_VALUE (y);
7351e207 4065#ifndef ALLOW_DIVIDE_BY_ZERO
5eec27e9
DH
4066 if (yy == 0.0)
4067 scm_num_overflow (s_divide);
4068 else
7351e207 4069#endif
5eec27e9 4070 return scm_make_real (scm_i_big2dbl (x) / yy);
f8de44c1 4071 } else if (SCM_COMPLEXP (y)) {
1be6b49c 4072 a = scm_i_big2dbl (x);
f8de44c1
DH
4073 goto complex_div;
4074 } else {
4075 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4076 }
f8de44c1
DH
4077 } else if (SCM_REALP (x)) {
4078 double rx = SCM_REAL_VALUE (x);
4079 if (SCM_INUMP (y)) {
5eec27e9 4080 long int yy = SCM_INUM (y);
7351e207
MV
4081#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
4082 if (yy == 0)
5eec27e9 4083 scm_num_overflow (s_divide);
7351e207
MV
4084 else
4085#endif
5eec27e9 4086 return scm_make_real (rx / (double) yy);
f8de44c1 4087 } else if (SCM_BIGP (y)) {
1be6b49c 4088 return scm_make_real (rx / scm_i_big2dbl (y));
f8de44c1 4089 } else if (SCM_REALP (y)) {
5eec27e9 4090 double yy = SCM_REAL_VALUE (y);
7351e207 4091#ifndef ALLOW_DIVIDE_BY_ZERO
5eec27e9
DH
4092 if (yy == 0.0)
4093 scm_num_overflow (s_divide);
4094 else
7351e207 4095#endif
5eec27e9 4096 return scm_make_real (rx / yy);
f8de44c1
DH
4097 } else if (SCM_COMPLEXP (y)) {
4098 a = rx;
4099 goto complex_div;
4100 } else {
4101 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4102 }
f8de44c1
DH
4103 } else if (SCM_COMPLEXP (x)) {
4104 double rx = SCM_COMPLEX_REAL (x);
4105 double ix = SCM_COMPLEX_IMAG (x);
4106 if (SCM_INUMP (y)) {
5eec27e9 4107 long int yy = SCM_INUM (y);
7351e207
MV
4108#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
4109 if (yy == 0)
5eec27e9 4110 scm_num_overflow (s_divide);
7351e207
MV
4111 else
4112#endif
4113 {
5eec27e9
DH
4114 double d = yy;
4115 return scm_make_complex (rx / d, ix / d);
4116 }
f8de44c1 4117 } else if (SCM_BIGP (y)) {
1be6b49c 4118 double d = scm_i_big2dbl (y);
f8de44c1 4119 return scm_make_complex (rx / d, ix / d);
f8de44c1 4120 } else if (SCM_REALP (y)) {
5eec27e9 4121 double yy = SCM_REAL_VALUE (y);
7351e207 4122#ifndef ALLOW_DIVIDE_BY_ZERO
5eec27e9
DH
4123 if (yy == 0.0)
4124 scm_num_overflow (s_divide);
4125 else
7351e207 4126#endif
5eec27e9 4127 return scm_make_complex (rx / yy, ix / yy);
f8de44c1
DH
4128 } else if (SCM_COMPLEXP (y)) {
4129 double ry = SCM_COMPLEX_REAL (y);
4130 double iy = SCM_COMPLEX_IMAG (y);
ba74ef4e
MV
4131 if (ry <= iy) {
4132 double t = ry / iy;
4133 double d = iy * (1.0 + t * t);
4134 return scm_make_complex ((rx * t + ix) / d, (ix * t - rx) / d);
4135 } else {
4136 double t = iy / ry;
4137 double d = ry * (1.0 + t * t);
4138 return scm_make_complex ((rx + ix * t) / d, (ix - rx * t) / d);
4139 }
f8de44c1
DH
4140 } else {
4141 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
4142 }
4143 } else {
4144 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd
JB
4145 }
4146}
c05e97b7 4147#undef FUNC_NAME
0f2d19dd 4148
9de33deb 4149SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_cxr, (SCM (*)()) scm_asinh, g_asinh);
942e5b91
MG
4150/* "Return the inverse hyperbolic sine of @var{x}."
4151 */
0f2d19dd 4152double
6e8d25a6 4153scm_asinh (double x)
0f2d19dd 4154{
f872b822 4155 return log (x + sqrt (x * x + 1));
0f2d19dd
JB
4156}
4157
4158
4159
4160
9de33deb 4161SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_cxr, (SCM (*)()) scm_acosh, g_acosh);
942e5b91
MG
4162/* "Return the inverse hyperbolic cosine of @var{x}."
4163 */
0f2d19dd 4164double
6e8d25a6 4165scm_acosh (double x)
0f2d19dd 4166{
f872b822 4167 return log (x + sqrt (x * x - 1));
0f2d19dd
JB
4168}
4169
4170
4171
4172
9de33deb 4173SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_cxr, (SCM (*)()) scm_atanh, g_atanh);
942e5b91
MG
4174/* "Return the inverse hyperbolic tangent of @var{x}."
4175 */
0f2d19dd 4176double
6e8d25a6 4177scm_atanh (double x)
0f2d19dd 4178{
f872b822 4179 return 0.5 * log ((1 + x) / (1 - x));
0f2d19dd
JB
4180}
4181
4182
4183
4184
9de33deb 4185SCM_GPROC1 (s_truncate, "truncate", scm_tc7_cxr, (SCM (*)()) scm_truncate, g_truncate);
942e5b91
MG
4186/* "Round the inexact number @var{x} towards zero."
4187 */
0f2d19dd 4188double
6e8d25a6 4189scm_truncate (double x)
0f2d19dd 4190{
f872b822
MD
4191 if (x < 0.0)
4192 return -floor (-x);
4193 return floor (x);
0f2d19dd
JB
4194}
4195
4196
4197
9de33deb 4198SCM_GPROC1 (s_round, "round", scm_tc7_cxr, (SCM (*)()) scm_round, g_round);
942e5b91
MG
4199/* "Round the inexact number @var{x}. If @var{x} is halfway between two\n"
4200 * "numbers, round towards even."
4201 */
0f2d19dd 4202double
6e8d25a6 4203scm_round (double x)
0f2d19dd
JB
4204{
4205 double plus_half = x + 0.5;
f872b822 4206 double result = floor (plus_half);
0f2d19dd 4207 /* Adjust so that the scm_round is towards even. */
f872b822 4208 return (plus_half == result && plus_half / 2 != floor (plus_half / 2))
0f2d19dd
JB
4209 ? result - 1 : result;
4210}
4211
4212
9de33deb 4213SCM_GPROC1 (s_i_floor, "floor", scm_tc7_cxr, (SCM (*)()) floor, g_i_floor);
942e5b91
MG
4214/* "Round the number @var{x} towards minus infinity."
4215 */
9de33deb 4216SCM_GPROC1 (s_i_ceil, "ceiling", scm_tc7_cxr, (SCM (*)()) ceil, g_i_ceil);
942e5b91
MG
4217/* "Round the number @var{x} towards infinity."
4218 */
9de33deb 4219SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_cxr, (SCM (*)()) sqrt, g_i_sqrt);
942e5b91
MG
4220/* "Return the square root of the real number @var{x}."
4221 */
9de33deb 4222SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_cxr, (SCM (*)()) fabs, g_i_abs);
942e5b91
MG
4223/* "Return the absolute value of the real number @var{x}."
4224 */
9de33deb 4225SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_cxr, (SCM (*)()) exp, g_i_exp);
942e5b91
MG
4226/* "Return the @var{x}th power of e."
4227 */
9de33deb 4228SCM_GPROC1 (s_i_log, "$log", scm_tc7_cxr, (SCM (*)()) log, g_i_log);
b3fcac34 4229/* "Return the natural logarithm of the real number @var{x}."
942e5b91 4230 */
9de33deb 4231SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_cxr, (SCM (*)()) sin, g_i_sin);
942e5b91
MG
4232/* "Return the sine of the real number @var{x}."
4233 */
9de33deb 4234SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_cxr, (SCM (*)()) cos, g_i_cos);
942e5b91
MG
4235/* "Return the cosine of the real number @var{x}."
4236 */
9de33deb 4237SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_cxr, (SCM (*)()) tan, g_i_tan);
942e5b91
MG
4238/* "Return the tangent of the real number @var{x}."
4239 */
9de33deb 4240SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_cxr, (SCM (*)()) asin, g_i_asin);
942e5b91
MG
4241/* "Return the arc sine of the real number @var{x}."
4242 */
9de33deb 4243SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_cxr, (SCM (*)()) acos, g_i_acos);
942e5b91
MG
4244/* "Return the arc cosine of the real number @var{x}."
4245 */
9de33deb 4246SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_cxr, (SCM (*)()) atan, g_i_atan);
942e5b91
MG
4247/* "Return the arc tangent of the real number @var{x}."
4248 */
9de33deb 4249SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_cxr, (SCM (*)()) sinh, g_i_sinh);
942e5b91
MG
4250/* "Return the hyperbolic sine of the real number @var{x}."
4251 */
9de33deb 4252SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_cxr, (SCM (*)()) cosh, g_i_cosh);
942e5b91
MG
4253/* "Return the hyperbolic cosine of the real number @var{x}."
4254 */
9de33deb 4255SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_cxr, (SCM (*)()) tanh, g_i_tanh);
942e5b91
MG
4256/* "Return the hyperbolic tangent of the real number @var{x}."
4257 */
f872b822
MD
4258
4259struct dpair
4260{
4261 double x, y;
4262};
4263
27c37006
NJ
4264static void scm_two_doubles (SCM x,
4265 SCM y,
3eeba8d4
JB
4266 const char *sstring,
4267 struct dpair * xy);
f872b822
MD
4268
4269static void
27c37006
NJ
4270scm_two_doubles (SCM x, SCM y, const char *sstring, struct dpair *xy)
4271{
4272 if (SCM_INUMP (x)) {
4273 xy->x = SCM_INUM (x);
4274 } else if (SCM_BIGP (x)) {
1be6b49c 4275 xy->x = scm_i_big2dbl (x);
27c37006
NJ
4276 } else if (SCM_REALP (x)) {
4277 xy->x = SCM_REAL_VALUE (x);
98cb6e75 4278 } else {
27c37006 4279 scm_wrong_type_arg (sstring, SCM_ARG1, x);
98cb6e75
DH
4280 }
4281
27c37006
NJ
4282 if (SCM_INUMP (y)) {
4283 xy->y = SCM_INUM (y);
4284 } else if (SCM_BIGP (y)) {
1be6b49c 4285 xy->y = scm_i_big2dbl (y);
27c37006
NJ
4286 } else if (SCM_REALP (y)) {
4287 xy->y = SCM_REAL_VALUE (y);
98cb6e75 4288 } else {
27c37006 4289 scm_wrong_type_arg (sstring, SCM_ARG2, y);
98cb6e75 4290 }
0f2d19dd
JB
4291}
4292
4293
a1ec6916 4294SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
27c37006
NJ
4295 (SCM x, SCM y),
4296 "Return @var{x} raised to the power of @var{y}. This\n"
0137a31b 4297 "procedure does not accept complex arguments.")
1bbd0b84 4298#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
4299{
4300 struct dpair xy;
27c37006 4301 scm_two_doubles (x, y, FUNC_NAME, &xy);
f8de44c1 4302 return scm_make_real (pow (xy.x, xy.y));
0f2d19dd 4303}
1bbd0b84 4304#undef FUNC_NAME
0f2d19dd
JB
4305
4306
a1ec6916 4307SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
27c37006
NJ
4308 (SCM x, SCM y),
4309 "Return the arc tangent of the two arguments @var{x} and\n"
4310 "@var{y}. This is similar to calculating the arc tangent of\n"
4311 "@var{x} / @var{y}, except that the signs of both arguments\n"
0137a31b
MG
4312 "are used to determine the quadrant of the result. This\n"
4313 "procedure does not accept complex arguments.")
1bbd0b84 4314#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
4315{
4316 struct dpair xy;
27c37006 4317 scm_two_doubles (x, y, FUNC_NAME, &xy);
f8de44c1 4318 return scm_make_real (atan2 (xy.x, xy.y));
0f2d19dd 4319}
1bbd0b84 4320#undef FUNC_NAME
0f2d19dd
JB
4321
4322
a1ec6916 4323SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794 4324 (SCM real, SCM imaginary),
942e5b91
MG
4325 "Return a complex number constructed of the given @var{real} and\n"
4326 "@var{imaginary} parts.")
1bbd0b84 4327#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
4328{
4329 struct dpair xy;
bb628794 4330 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
f8de44c1 4331 return scm_make_complex (xy.x, xy.y);
0f2d19dd 4332}
1bbd0b84 4333#undef FUNC_NAME
0f2d19dd
JB
4334
4335
4336
a1ec6916 4337SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
27c37006 4338 (SCM x, SCM y),
942e5b91 4339 "Return the complex number @var{x} * e^(i * @var{y}).")
1bbd0b84 4340#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
4341{
4342 struct dpair xy;
27c37006 4343 scm_two_doubles (x, y, FUNC_NAME, &xy);
f8de44c1 4344 return scm_make_complex (xy.x * cos (xy.y), xy.x * sin (xy.y));
0f2d19dd 4345}
1bbd0b84 4346#undef FUNC_NAME
0f2d19dd
JB
4347
4348
152f82bf 4349SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
942e5b91
MG
4350/* "Return the real part of the number @var{z}."
4351 */
0f2d19dd 4352SCM
6e8d25a6 4353scm_real_part (SCM z)
0f2d19dd 4354{
c2ff8ab0
DH
4355 if (SCM_INUMP (z)) {
4356 return z;
4357 } else if (SCM_BIGP (z)) {
4358 return z;
4359 } else if (SCM_REALP (z)) {
4360 return z;
4361 } else if (SCM_COMPLEXP (z)) {
4362 return scm_make_real (SCM_COMPLEX_REAL (z));
4363 } else {
4364 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
4365 }
0f2d19dd
JB
4366}
4367
4368
152f82bf 4369SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
942e5b91
MG
4370/* "Return the imaginary part of the number @var{z}."
4371 */
0f2d19dd 4372SCM
6e8d25a6 4373scm_imag_part (SCM z)
0f2d19dd 4374{
c2ff8ab0 4375 if (SCM_INUMP (z)) {
f872b822 4376 return SCM_INUM0;
c2ff8ab0 4377 } else if (SCM_BIGP (z)) {
f872b822 4378 return SCM_INUM0;
c2ff8ab0
DH
4379 } else if (SCM_REALP (z)) {
4380 return scm_flo0;
4381 } else if (SCM_COMPLEXP (z)) {
4382 return scm_make_real (SCM_COMPLEX_IMAG (z));
4383 } else {
4384 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
4385 }
0f2d19dd
JB
4386}
4387
4388
9de33deb 4389SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
942e5b91
MG
4390/* "Return the magnitude of the number @var{z}. This is the same as\n"
4391 * "@code{abs} for real arguments, but also allows complex numbers."
4392 */
0f2d19dd 4393SCM
6e8d25a6 4394scm_magnitude (SCM z)
0f2d19dd 4395{
c2ff8ab0 4396 if (SCM_INUMP (z)) {
5986c47d
DH
4397 long int zz = SCM_INUM (z);
4398 if (zz >= 0) {
4399 return z;
4400 } else if (SCM_POSFIXABLE (-zz)) {
4401 return SCM_MAKINUM (-zz);
4402 } else {
4403#ifdef SCM_BIGDIG
1be6b49c 4404 return scm_i_long2big (-zz);
5986c47d
DH
4405#else
4406 scm_num_overflow (s_magnitude);
4407#endif
4408 }
c2ff8ab0 4409 } else if (SCM_BIGP (z)) {
5986c47d
DH
4410 if (!SCM_BIGSIGN (z)) {
4411 return z;
4412 } else {
1be6b49c 4413 return scm_i_copybig (z, 0);
5986c47d 4414 }
c2ff8ab0
DH
4415 } else if (SCM_REALP (z)) {
4416 return scm_make_real (fabs (SCM_REAL_VALUE (z)));
4417 } else if (SCM_COMPLEXP (z)) {
4418 double r = SCM_COMPLEX_REAL (z);
4419 double i = SCM_COMPLEX_IMAG (z);
4420 return scm_make_real (sqrt (i * i + r * r));
4421 } else {
4422 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
4423 }
0f2d19dd
JB
4424}
4425
4426
9de33deb 4427SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
942e5b91
MG
4428/* "Return the angle of the complex number @var{z}."
4429 */
0f2d19dd 4430SCM
6e8d25a6 4431scm_angle (SCM z)
0f2d19dd 4432{
f4c627b3
DH
4433 if (SCM_INUMP (z)) {
4434 if (SCM_INUM (z) >= 0) {
4435 return scm_make_real (atan2 (0.0, 1.0));
4436 } else {
4437 return scm_make_real (atan2 (0.0, -1.0));
f872b822 4438 }
f4c627b3
DH
4439 } else if (SCM_BIGP (z)) {
4440 if (SCM_BIGSIGN (z)) {
4441 return scm_make_real (atan2 (0.0, -1.0));
4442 } else {
4443 return scm_make_real (atan2 (0.0, 1.0));
0f2d19dd 4444 }
f4c627b3
DH
4445 } else if (SCM_REALP (z)) {
4446 return scm_make_real (atan2 (0.0, SCM_REAL_VALUE (z)));
4447 } else if (SCM_COMPLEXP (z)) {
4448 return scm_make_real (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
4449 } else {
4450 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
4451 }
0f2d19dd
JB
4452}
4453
4454
3c9a524f
DH
4455SCM_GPROC (s_exact_to_inexact, "exact->inexact", 1, 0, 0, scm_exact_to_inexact, g_exact_to_inexact);
4456/* Convert the number @var{x} to its inexact representation.\n"
4457 */
4458SCM
4459scm_exact_to_inexact (SCM z)
4460{
4461 if (SCM_INUMP (z))
4462 return scm_make_real ((double) SCM_INUM (z));
4463 else if (SCM_BIGP (z))
4464 return scm_make_real (scm_i_big2dbl (z));
4465 else if (SCM_INEXACTP (z))
4466 return z;
4467 else
4468 SCM_WTA_DISPATCH_1 (g_exact_to_inexact, z, 1, s_exact_to_inexact);
4469}
4470
4471
a1ec6916 4472SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 4473 (SCM z),
1e6808ea 4474 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 4475#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 4476{
c2ff8ab0 4477 if (SCM_INUMP (z)) {
f872b822 4478 return z;
c2ff8ab0 4479 } else if (SCM_BIGP (z)) {
f872b822 4480 return z;
c2ff8ab0
DH
4481 } else if (SCM_REALP (z)) {
4482 double u = floor (SCM_REAL_VALUE (z) + 0.5);
4483 long lu = (long) u;
4484 if (SCM_FIXABLE (lu)) {
4485 return SCM_MAKINUM (lu);
f872b822 4486#ifdef SCM_BIGDIG
fc194577 4487 } else if (isfinite (u) && !xisnan (u)) {
1be6b49c 4488 return scm_i_dbl2big (u);
f872b822 4489#endif
c2ff8ab0
DH
4490 } else {
4491 scm_num_overflow (s_scm_inexact_to_exact);
4492 }
4493 } else {
4494 SCM_WRONG_TYPE_ARG (1, z);
4495 }
0f2d19dd 4496}
1bbd0b84 4497#undef FUNC_NAME
0f2d19dd
JB
4498
4499
0f2d19dd 4500#ifdef SCM_BIGDIG
0f2d19dd 4501/* d must be integer */
1cc91f1b 4502
0f2d19dd 4503SCM
1be6b49c 4504scm_i_dbl2big (double d)
0f2d19dd 4505{
1be6b49c 4506 size_t i = 0;
0f2d19dd
JB
4507 long c;
4508 SCM_BIGDIG *digits;
4509 SCM ans;
f872b822
MD
4510 double u = (d < 0) ? -d : d;
4511 while (0 != floor (u))
4512 {
4513 u /= SCM_BIGRAD;
4514 i++;
4515 }
1be6b49c 4516 ans = scm_i_mkbig (i, d < 0);
f872b822
MD
4517 digits = SCM_BDIGITS (ans);
4518 while (i--)
4519 {
4520 u *= SCM_BIGRAD;
4521 c = floor (u);
4522 u -= c;
4523 digits[i] = c;
4524 }
cf7c17e9 4525#ifndef SCM_RECKLESS
e1724d20 4526 if (u != 0)
52859adf 4527 scm_num_overflow ("dbl2big");
e1724d20 4528#endif
0f2d19dd
JB
4529 return ans;
4530}
4531
0f2d19dd 4532double
1be6b49c 4533scm_i_big2dbl (SCM b)
0f2d19dd
JB
4534{
4535 double ans = 0.0;
1be6b49c 4536 size_t i = SCM_NUMDIGS (b);
f872b822
MD
4537 SCM_BIGDIG *digits = SCM_BDIGITS (b);
4538 while (i--)
4539 ans = digits[i] + SCM_BIGRAD * ans;
f3ae5d60
MD
4540 if (SCM_BIGSIGN (b))
4541 return - ans;
0f2d19dd
JB
4542 return ans;
4543}
1cc91f1b 4544
f872b822 4545#endif
0f2d19dd 4546
5c11cc9d 4547#ifdef HAVE_LONG_LONGS
1be6b49c
ML
4548# ifndef LLONG_MAX
4549# define ULLONG_MAX ((unsigned long long) (-1))
4550# define LLONG_MAX ((long long) (ULLONG_MAX >> 1))
4551# define LLONG_MIN (~LLONG_MAX)
4552# endif
f872b822 4553#endif
0f2d19dd 4554
3d2e8ceb
MV
4555/* Parameters for creating integer conversion routines.
4556
4557 Define the following preprocessor macros before including
4558 "libguile/num2integral.i.c":
4559
4560 NUM2INTEGRAL - the name of the function for converting from a
4561 Scheme object to the integral type. This function
4562 will be defined when including "num2integral.i.c".
4563
4564 INTEGRAL2NUM - the name of the function for converting from the
4565 integral type to a Scheme object. This function
4566 will be defined.
4567
4568 INTEGRAL2BIG - the name of an internal function that createas a
4569 bignum from the integral type. This function will
4570 be defined. The name should start with "scm_i_".
4571
4572 ITYPE - the name of the integral type.
4573
4574 UNSIGNED - Define this when ITYPE is an unsigned type. Do not
4575 define it otherwise.
4576
4577 UNSIGNED_ITYPE
4578 - the name of the the unsigned variant of the
4579 integral type. If you don't define this, it defaults
4580 to "unsigned ITYPE" for signed types and simply "ITYPE"
4581 for unsigned ones.
4582
4583 SIZEOF_ITYPE - an expression giving the size of the integral type in
4584 bytes. This expression must be computable by the
4585 preprocessor. If you don't know a value for this,
4586 don't define it. The purpose of this parameter is
4587 mainly to suppress some warnings. The generated
4588 code will work correctly without it.
4589*/
4590
1be6b49c
ML
4591#define NUM2INTEGRAL scm_num2short
4592#define INTEGRAL2NUM scm_short2num
4593#define INTEGRAL2BIG scm_i_short2big
4594#define ITYPE short
3d2e8ceb 4595#define SIZEOF_ITYPE SIZEOF_SHORT
1be6b49c
ML
4596#include "libguile/num2integral.i.c"
4597
4598#define NUM2INTEGRAL scm_num2ushort
4599#define INTEGRAL2NUM scm_ushort2num
4600#define INTEGRAL2BIG scm_i_ushort2big
4601#define UNSIGNED
4602#define ITYPE unsigned short
3d2e8ceb 4603#define SIZEOF_ITYPE SIZEOF_SHORT
1be6b49c
ML
4604#include "libguile/num2integral.i.c"
4605
4606#define NUM2INTEGRAL scm_num2int
4607#define INTEGRAL2NUM scm_int2num
4608#define INTEGRAL2BIG scm_i_int2big
4609#define ITYPE int
3d2e8ceb 4610#define SIZEOF_ITYPE SIZEOF_INT
1be6b49c
ML
4611#include "libguile/num2integral.i.c"
4612
4613#define NUM2INTEGRAL scm_num2uint
4614#define INTEGRAL2NUM scm_uint2num
4615#define INTEGRAL2BIG scm_i_uint2big
4616#define UNSIGNED
4617#define ITYPE unsigned int
3d2e8ceb 4618#define SIZEOF_ITYPE SIZEOF_INT
1be6b49c
ML
4619#include "libguile/num2integral.i.c"
4620
4621#define NUM2INTEGRAL scm_num2long
4622#define INTEGRAL2NUM scm_long2num
4623#define INTEGRAL2BIG scm_i_long2big
4624#define ITYPE long
3d2e8ceb 4625#define SIZEOF_ITYPE SIZEOF_LONG
1be6b49c
ML
4626#include "libguile/num2integral.i.c"
4627
4628#define NUM2INTEGRAL scm_num2ulong
4629#define INTEGRAL2NUM scm_ulong2num
4630#define INTEGRAL2BIG scm_i_ulong2big
4631#define UNSIGNED
4632#define ITYPE unsigned long
3d2e8ceb 4633#define SIZEOF_ITYPE SIZEOF_LONG
1be6b49c
ML
4634#include "libguile/num2integral.i.c"
4635
1be6b49c
ML
4636#define NUM2INTEGRAL scm_num2ptrdiff
4637#define INTEGRAL2NUM scm_ptrdiff2num
4638#define INTEGRAL2BIG scm_i_ptrdiff2big
4639#define ITYPE ptrdiff_t
3d2e8ceb
MV
4640#define UNSIGNED_ITYPE size_t
4641#define SIZEOF_ITYPE SIZEOF_PTRDIFF_T
1be6b49c
ML
4642#include "libguile/num2integral.i.c"
4643
4644#define NUM2INTEGRAL scm_num2size
4645#define INTEGRAL2NUM scm_size2num
4646#define INTEGRAL2BIG scm_i_size2big
4647#define UNSIGNED
4648#define ITYPE size_t
3d2e8ceb 4649#define SIZEOF_ITYPE SIZEOF_SIZE_T
1be6b49c 4650#include "libguile/num2integral.i.c"
0f2d19dd 4651
5c11cc9d 4652#ifdef HAVE_LONG_LONGS
1cc91f1b 4653
caf08e65
MV
4654#ifndef ULONG_LONG_MAX
4655#define ULONG_LONG_MAX (~0ULL)
4656#endif
4657
1be6b49c
ML
4658#define NUM2INTEGRAL scm_num2long_long
4659#define INTEGRAL2NUM scm_long_long2num
4660#define INTEGRAL2BIG scm_i_long_long2big
4661#define ITYPE long long
3d2e8ceb 4662#define SIZEOF_ITYPE SIZEOF_LONG_LONG
1be6b49c
ML
4663#include "libguile/num2integral.i.c"
4664
4665#define NUM2INTEGRAL scm_num2ulong_long
4666#define INTEGRAL2NUM scm_ulong_long2num
4667#define INTEGRAL2BIG scm_i_ulong_long2big
4668#define UNSIGNED
4669#define ITYPE unsigned long long
3d2e8ceb 4670#define SIZEOF_ITYPE SIZEOF_LONG_LONG
1be6b49c 4671#include "libguile/num2integral.i.c"
0f2d19dd 4672
1be6b49c 4673#endif /* HAVE_LONG_LONGS */
caf08e65 4674
5437598b
MD
4675#define NUM2FLOAT scm_num2float
4676#define FLOAT2NUM scm_float2num
4677#define FTYPE float
4678#include "libguile/num2float.i.c"
4679
4680#define NUM2FLOAT scm_num2double
4681#define FLOAT2NUM scm_double2num
4682#define FTYPE double
4683#include "libguile/num2float.i.c"
4684
1be6b49c 4685#ifdef GUILE_DEBUG
caf08e65 4686
6063dc1d
SJ
4687#ifndef SIZE_MAX
4688#define SIZE_MAX ((size_t) (-1))
4689#endif
4690#ifndef PTRDIFF_MIN
4691#define PTRDIFF_MIN \
4692 ((ptrdiff_t) ((ptrdiff_t) 1 << (sizeof (ptrdiff_t) * 8 - 1)))
4693#endif
4694#ifndef PTRDIFF_MAX
4695#define PTRDIFF_MAX (~ PTRDIFF_MIN)
4696#endif
4697
1be6b49c
ML
4698#define CHECK(type, v) \
4699 do { \
4700 if ((v) != scm_num2##type (scm_##type##2num (v), 1, "check_sanity")) \
4701 abort (); \
4702 } while (0);
caf08e65 4703
1be6b49c
ML
4704static void
4705check_sanity ()
4706{
4707 CHECK (short, 0);
4708 CHECK (ushort, 0U);
4709 CHECK (int, 0);
4710 CHECK (uint, 0U);
4711 CHECK (long, 0L);
4712 CHECK (ulong, 0UL);
4713 CHECK (size, 0);
4714 CHECK (ptrdiff, 0);
4715
4716 CHECK (short, -1);
4717 CHECK (int, -1);
4718 CHECK (long, -1L);
4719 CHECK (ptrdiff, -1);
4720
4721 CHECK (short, SHRT_MAX);
4722 CHECK (short, SHRT_MIN);
4723 CHECK (ushort, USHRT_MAX);
4724 CHECK (int, INT_MAX);
4725 CHECK (int, INT_MIN);
4726 CHECK (uint, UINT_MAX);
4727 CHECK (long, LONG_MAX);
4728 CHECK (long, LONG_MIN);
4729 CHECK (ulong, ULONG_MAX);
4730 CHECK (size, SIZE_MAX);
4731 CHECK (ptrdiff, PTRDIFF_MAX);
4732 CHECK (ptrdiff, PTRDIFF_MIN);
0f2d19dd 4733
1be6b49c
ML
4734#ifdef HAVE_LONG_LONGS
4735 CHECK (long_long, 0LL);
4736 CHECK (ulong_long, 0ULL);
1be6b49c 4737 CHECK (long_long, -1LL);
1be6b49c
ML
4738 CHECK (long_long, LLONG_MAX);
4739 CHECK (long_long, LLONG_MIN);
4740 CHECK (ulong_long, ULLONG_MAX);
4741#endif
0f2d19dd
JB
4742}
4743
b10586f0
ML
4744#undef CHECK
4745
4746#define CHECK \
4747 scm_internal_catch (SCM_BOOL_T, check_body, &data, check_handler, &data); \
4748 if (!SCM_FALSEP (data)) abort();
4749
4750static SCM
4751check_body (void *data)
4752{
4753 SCM num = *(SCM *) data;
4754 scm_num2ulong (num, 1, NULL);
4755
4756 return SCM_UNSPECIFIED;
4757}
4758
4759static SCM
4760check_handler (void *data, SCM tag, SCM throw_args)
4761{
4762 SCM *num = (SCM *) data;
4763 *num = SCM_BOOL_F;
4764
4765 return SCM_UNSPECIFIED;
4766}
4767
4768SCM_DEFINE (scm_sys_check_number_conversions, "%check-number-conversions", 0, 0, 0,
b4e15479 4769 (void),
b10586f0
ML
4770 "Number conversion sanity checking.")
4771#define FUNC_NAME s_scm_sys_check_number_conversions
4772{
4773 SCM data = SCM_MAKINUM (-1);
4774 CHECK;
4775 data = scm_int2num (INT_MIN);
4776 CHECK;
4777 data = scm_ulong2num (ULONG_MAX);
4778 data = scm_difference (SCM_INUM0, data);
4779 CHECK;
4780 data = scm_ulong2num (ULONG_MAX);
4781 data = scm_sum (SCM_MAKINUM (1), data); data = scm_difference (SCM_INUM0, data);
4782 CHECK;
4783 data = scm_int2num (-10000); data = scm_product (data, data); data = scm_product (data, data);
4784 CHECK;
4785
4786 return SCM_UNSPECIFIED;
4787}
4788#undef FUNC_NAME
4789
1be6b49c 4790#endif
0f2d19dd 4791
0f2d19dd
JB
4792void
4793scm_init_numbers ()
0f2d19dd 4794{
1be6b49c 4795 abs_most_negative_fixnum = scm_i_long2big (- SCM_MOST_NEGATIVE_FIXNUM);
ac0c002c
DH
4796 scm_permanent_object (abs_most_negative_fixnum);
4797
a261c0e9
DH
4798 /* It may be possible to tune the performance of some algorithms by using
4799 * the following constants to avoid the creation of bignums. Please, before
4800 * using these values, remember the two rules of program optimization:
4801 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe
MV
4802 scm_c_define ("most-positive-fixnum",
4803 SCM_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
4804 scm_c_define ("most-negative-fixnum",
4805 SCM_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 4806
f3ae5d60
MD
4807 scm_add_feature ("complex");
4808 scm_add_feature ("inexact");
5986c47d 4809 scm_flo0 = scm_make_real (0.0);
f872b822 4810#ifdef DBL_DIG
0f2d19dd 4811 scm_dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
f872b822 4812#else
0f2d19dd
JB
4813 { /* determine floating point precision */
4814 double f = 0.1;
f872b822 4815 double fsum = 1.0 + f;
bb628794
DH
4816 while (fsum != 1.0) {
4817 if (++scm_dblprec > 20) {
4818 fsum = 1.0;
4819 } else {
f872b822 4820 f /= 10.0;
bb628794 4821 fsum = f + 1.0;
f872b822 4822 }
bb628794 4823 }
f872b822 4824 scm_dblprec = scm_dblprec - 1;
0f2d19dd 4825 }
f872b822 4826#endif /* DBL_DIG */
1be6b49c
ML
4827
4828#ifdef GUILE_DEBUG
4829 check_sanity ();
4830#endif
4831
a0599745 4832#include "libguile/numbers.x"
0f2d19dd 4833}
89e00824
ML
4834
4835/*
4836 Local Variables:
4837 c-file-style: "gnu"
4838 End:
4839*/