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