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