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