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