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