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