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