*** empty log message ***
[bpt/guile.git] / libguile / numbers.c
CommitLineData
238ebcef 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
ba74ef4e
MV
2 *
3 * Portions Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories
4 * and Bellcore. See scm_divide.
5 *
f81e080b 6 *
73be1d9e
MV
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 11 *
73be1d9e
MV
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
0f2d19dd 16 *
73be1d9e
MV
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
1bbd0b84 21
0f2d19dd 22\f
ca46fb90
RB
23/* General assumptions:
24 * All objects satisfying SCM_COMPLEXP() have a non-zero complex component.
25 * All objects satisfying SCM_BIGP() are too large to fit in a fixnum.
26 * If an object satisfies integer?, it's either an inum, a bignum, or a real.
27 * If floor (r) == r, r is an int, and mpz_set_d will DTRT.
f92e85f7 28 * All objects satisfying SCM_FRACTIONP are never an integer.
ca46fb90
RB
29 */
30
31/* TODO:
32
33 - see if special casing bignums and reals in integer-exponent when
34 possible (to use mpz_pow and mpf_pow_ui) is faster.
35
36 - look in to better short-circuiting of common cases in
37 integer-expt and elsewhere.
38
39 - see if direct mpz operations can help in ash and elsewhere.
40
41 */
0f2d19dd 42
fa605590
KR
43/* tell glibc (2.3) to give prototype for C99 trunc() */
44#define _GNU_SOURCE
45
ee33d62a
RB
46#if HAVE_CONFIG_H
47# include <config.h>
48#endif
49
0f2d19dd 50#include <math.h>
3c9a524f 51#include <ctype.h>
fc194577 52#include <string.h>
f92e85f7 53
a0599745 54#include "libguile/_scm.h"
a0599745
MD
55#include "libguile/feature.h"
56#include "libguile/ports.h"
57#include "libguile/root.h"
58#include "libguile/smob.h"
59#include "libguile/strings.h"
a0599745
MD
60
61#include "libguile/validate.h"
62#include "libguile/numbers.h"
1be6b49c 63#include "libguile/deprecation.h"
f4c627b3 64
f92e85f7
MV
65#include "libguile/eq.h"
66
55f26379
MV
67#include "libguile/discouraged.h"
68
0f2d19dd 69\f
f4c627b3 70
ca46fb90
RB
71/*
72 Wonder if this might be faster for some of our code? A switch on
73 the numtag would jump directly to the right case, and the
74 SCM_I_NUMTAG code might be faster than repeated SCM_FOOP tests...
75
76 #define SCM_I_NUMTAG_NOTNUM 0
77 #define SCM_I_NUMTAG_INUM 1
78 #define SCM_I_NUMTAG_BIG scm_tc16_big
79 #define SCM_I_NUMTAG_REAL scm_tc16_real
80 #define SCM_I_NUMTAG_COMPLEX scm_tc16_complex
81 #define SCM_I_NUMTAG(x) \
e11e83f3 82 (SCM_I_INUMP(x) ? SCM_I_NUMTAG_INUM \
ca46fb90 83 : (SCM_IMP(x) ? SCM_I_NUMTAG_NOTNUM \
534c55a9 84 : (((0xfcff & SCM_CELL_TYPE (x)) == scm_tc7_number) ? SCM_TYP16(x) \
ca46fb90
RB
85 : SCM_I_NUMTAG_NOTNUM)))
86*/
f92e85f7 87/* the macro above will not work as is with fractions */
f4c627b3
DH
88
89
34d19ef6 90#define SCM_SWAP(x, y) do { SCM __t = x; x = y; y = __t; } while (0)
09fb7599 91
56e55ac7 92/* FLOBUFLEN is the maximum number of characters neccessary for the
3a9809df
DH
93 * printed or scm_string representation of an inexact number.
94 */
0b799eea 95#define FLOBUFLEN (40+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
3a9809df 96
7351e207
MV
97#if defined (SCO)
98#if ! defined (HAVE_ISNAN)
99#define HAVE_ISNAN
100static int
101isnan (double x)
102{
103 return (IsNANorINF (x) && NaN (x) && ! IsINF (x)) ? 1 : 0;
104}
0f2d19dd 105#endif
7351e207
MV
106#if ! defined (HAVE_ISINF)
107#define HAVE_ISINF
108static int
109isinf (double x)
110{
111 return (IsNANorINF (x) && IsINF (x)) ? 1 : 0;
112}
0f2d19dd 113
7351e207 114#endif
e6f3ef58
MD
115#endif
116
b127c712 117
f8a8200b
KR
118/* mpz_cmp_d in gmp 4.1.3 doesn't recognise infinities, so xmpz_cmp_d uses
119 an explicit check. In some future gmp (don't know what version number),
120 mpz_cmp_d is supposed to do this itself. */
121#if 1
b127c712
KR
122#define xmpz_cmp_d(z, d) \
123 (xisinf (d) ? (d < 0.0 ? 1 : -1) : mpz_cmp_d (z, d))
124#else
125#define xmpz_cmp_d(z, d) mpz_cmp_d (z, d)
126#endif
127
a98ce907
KR
128/* For reference, sparc solaris 7 has infinities (IEEE) but doesn't have
129 isinf. It does have finite and isnan though, hence the use of those.
130 fpclass would be a possibility on that system too. */
f92e85f7
MV
131static int
132xisinf (double x)
133{
134#if defined (HAVE_ISINF)
135 return isinf (x);
136#elif defined (HAVE_FINITE) && defined (HAVE_ISNAN)
137 return (! (finite (x) || isnan (x)));
138#else
139 return 0;
140#endif
141}
142
143static int
144xisnan (double x)
145{
146#if defined (HAVE_ISNAN)
147 return isnan (x);
148#else
149 return 0;
150#endif
151}
152
0f2d19dd
JB
153\f
154
713a4259 155static mpz_t z_negative_one;
ac0c002c
DH
156
157\f
158
570b6821 159SCM_C_INLINE_KEYWORD SCM
ca46fb90
RB
160scm_i_mkbig ()
161{
162 /* Return a newly created bignum. */
163 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
164 mpz_init (SCM_I_BIG_MPZ (z));
165 return z;
166}
167
c71b0706
MV
168SCM_C_INLINE_KEYWORD SCM
169scm_i_long2big (long x)
170{
171 /* Return a newly created bignum initialized to X. */
172 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
173 mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
174 return z;
175}
176
177SCM_C_INLINE_KEYWORD SCM
178scm_i_ulong2big (unsigned long x)
179{
180 /* Return a newly created bignum initialized to X. */
181 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
182 mpz_init_set_ui (SCM_I_BIG_MPZ (z), x);
183 return z;
184}
185
570b6821 186SCM_C_INLINE_KEYWORD static SCM
ca46fb90
RB
187scm_i_clonebig (SCM src_big, int same_sign_p)
188{
189 /* Copy src_big's value, negate it if same_sign_p is false, and return. */
190 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
191 mpz_init_set (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (src_big));
0aacf84e
MD
192 if (!same_sign_p)
193 mpz_neg (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (z));
ca46fb90
RB
194 return z;
195}
196
570b6821 197SCM_C_INLINE_KEYWORD int
ca46fb90
RB
198scm_i_bigcmp (SCM x, SCM y)
199{
200 /* Return neg if x < y, pos if x > y, and 0 if x == y */
201 /* presume we already know x and y are bignums */
202 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
203 scm_remember_upto_here_2 (x, y);
204 return result;
205}
206
570b6821 207SCM_C_INLINE_KEYWORD SCM
ca46fb90
RB
208scm_i_dbl2big (double d)
209{
210 /* results are only defined if d is an integer */
211 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
212 mpz_init_set_d (SCM_I_BIG_MPZ (z), d);
213 return z;
214}
215
f92e85f7
MV
216/* Convert a integer in double representation to a SCM number. */
217
218SCM_C_INLINE_KEYWORD SCM
219scm_i_dbl2num (double u)
220{
221 /* SCM_MOST_POSITIVE_FIXNUM+1 and SCM_MOST_NEGATIVE_FIXNUM are both
222 powers of 2, so there's no rounding when making "double" values
223 from them. If plain SCM_MOST_POSITIVE_FIXNUM was used it could
224 get rounded on a 64-bit machine, hence the "+1".
225
226 The use of floor() to force to an integer value ensures we get a
227 "numerically closest" value without depending on how a
228 double->long cast or how mpz_set_d will round. For reference,
229 double->long probably follows the hardware rounding mode,
230 mpz_set_d truncates towards zero. */
231
232 /* XXX - what happens when SCM_MOST_POSITIVE_FIXNUM etc is not
233 representable as a double? */
234
235 if (u < (double) (SCM_MOST_POSITIVE_FIXNUM+1)
236 && u >= (double) SCM_MOST_NEGATIVE_FIXNUM)
d956fa6f 237 return SCM_I_MAKINUM ((long) u);
f92e85f7
MV
238 else
239 return scm_i_dbl2big (u);
240}
241
089c9a59
KR
242/* scm_i_big2dbl() rounds to the closest representable double, in accordance
243 with R5RS exact->inexact.
244
245 The approach is to use mpz_get_d to pick out the high DBL_MANT_DIG bits
f8a8200b
KR
246 (ie. truncate towards zero), then adjust to get the closest double by
247 examining the next lower bit and adding 1 (to the absolute value) if
248 necessary.
249
250 Bignums exactly half way between representable doubles are rounded to the
251 next higher absolute value (ie. away from zero). This seems like an
252 adequate interpretation of R5RS "numerically closest", and it's easier
253 and faster than a full "nearest-even" style.
254
255 The bit test must be done on the absolute value of the mpz_t, which means
256 we need to use mpz_getlimbn. mpz_tstbit is not right, it treats
257 negatives as twos complement.
258
259 In current gmp 4.1.3, mpz_get_d rounding is unspecified. It ends up
260 following the hardware rounding mode, but applied to the absolute value
261 of the mpz_t operand. This is not what we want so we put the high
262 DBL_MANT_DIG bits into a temporary. In some future gmp, don't know when,
263 mpz_get_d is supposed to always truncate towards zero.
264
265 ENHANCE-ME: The temporary init+clear to force the rounding in gmp 4.1.3
266 is a slowdown. It'd be faster to pick out the relevant high bits with
267 mpz_getlimbn if we could be bothered coding that, and if the new
268 truncating gmp doesn't come out. */
089c9a59
KR
269
270double
ca46fb90
RB
271scm_i_big2dbl (SCM b)
272{
089c9a59
KR
273 double result;
274 size_t bits;
275
276 bits = mpz_sizeinbase (SCM_I_BIG_MPZ (b), 2);
277
f8a8200b 278#if 1
089c9a59 279 {
f8a8200b 280 /* Current GMP, eg. 4.1.3, force truncation towards zero */
089c9a59
KR
281 mpz_t tmp;
282 if (bits > DBL_MANT_DIG)
283 {
284 size_t shift = bits - DBL_MANT_DIG;
285 mpz_init2 (tmp, DBL_MANT_DIG);
286 mpz_tdiv_q_2exp (tmp, SCM_I_BIG_MPZ (b), shift);
287 result = ldexp (mpz_get_d (tmp), shift);
288 mpz_clear (tmp);
289 }
290 else
291 {
292 result = mpz_get_d (SCM_I_BIG_MPZ (b));
293 }
294 }
295#else
f8a8200b 296 /* Future GMP */
089c9a59
KR
297 result = mpz_get_d (SCM_I_BIG_MPZ (b));
298#endif
299
300 if (bits > DBL_MANT_DIG)
301 {
302 unsigned long pos = bits - DBL_MANT_DIG - 1;
303 /* test bit number "pos" in absolute value */
304 if (mpz_getlimbn (SCM_I_BIG_MPZ (b), pos / GMP_NUMB_BITS)
305 & ((mp_limb_t) 1 << (pos % GMP_NUMB_BITS)))
306 {
307 result += ldexp ((double) mpz_sgn (SCM_I_BIG_MPZ (b)), pos + 1);
308 }
309 }
310
ca46fb90
RB
311 scm_remember_upto_here_1 (b);
312 return result;
313}
314
570b6821 315SCM_C_INLINE_KEYWORD SCM
ca46fb90
RB
316scm_i_normbig (SCM b)
317{
318 /* convert a big back to a fixnum if it'll fit */
319 /* presume b is a bignum */
320 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (b)))
321 {
322 long val = mpz_get_si (SCM_I_BIG_MPZ (b));
323 if (SCM_FIXABLE (val))
d956fa6f 324 b = SCM_I_MAKINUM (val);
ca46fb90
RB
325 }
326 return b;
327}
f872b822 328
f92e85f7
MV
329static SCM_C_INLINE_KEYWORD SCM
330scm_i_mpz2num (mpz_t b)
331{
332 /* convert a mpz number to a SCM number. */
333 if (mpz_fits_slong_p (b))
334 {
335 long val = mpz_get_si (b);
336 if (SCM_FIXABLE (val))
d956fa6f 337 return SCM_I_MAKINUM (val);
f92e85f7
MV
338 }
339
340 {
341 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
342 mpz_init_set (SCM_I_BIG_MPZ (z), b);
343 return z;
344 }
345}
346
347/* this is needed when we want scm_divide to make a float, not a ratio, even if passed two ints */
348static SCM scm_divide2real (SCM x, SCM y);
349
cba42c93
MV
350static SCM
351scm_i_make_ratio (SCM numerator, SCM denominator)
c60e130c 352#define FUNC_NAME "make-ratio"
f92e85f7 353{
c60e130c
MV
354 /* First make sure the arguments are proper.
355 */
e11e83f3 356 if (SCM_I_INUMP (denominator))
f92e85f7 357 {
bc36d050 358 if (scm_is_eq (denominator, SCM_INUM0))
f92e85f7 359 scm_num_overflow ("make-ratio");
bc36d050 360 if (scm_is_eq (denominator, SCM_I_MAKINUM(1)))
f92e85f7
MV
361 return numerator;
362 }
363 else
364 {
365 if (!(SCM_BIGP(denominator)))
366 SCM_WRONG_TYPE_ARG (2, denominator);
367 }
e11e83f3 368 if (!SCM_I_INUMP (numerator) && !SCM_BIGP (numerator))
c60e130c
MV
369 SCM_WRONG_TYPE_ARG (1, numerator);
370
371 /* Then flip signs so that the denominator is positive.
372 */
73e4de09 373 if (scm_is_true (scm_negative_p (denominator)))
c60e130c
MV
374 {
375 numerator = scm_difference (numerator, SCM_UNDEFINED);
376 denominator = scm_difference (denominator, SCM_UNDEFINED);
377 }
378
379 /* Now consider for each of the four fixnum/bignum combinations
380 whether the rational number is really an integer.
381 */
e11e83f3 382 if (SCM_I_INUMP (numerator))
f92e85f7 383 {
e11e83f3 384 long x = SCM_I_INUM (numerator);
bc36d050 385 if (scm_is_eq (numerator, SCM_INUM0))
f92e85f7 386 return SCM_INUM0;
e11e83f3 387 if (SCM_I_INUMP (denominator))
f92e85f7 388 {
dd5130ca 389 long y;
e11e83f3 390 y = SCM_I_INUM (denominator);
f92e85f7 391 if (x == y)
d956fa6f 392 return SCM_I_MAKINUM(1);
f92e85f7 393 if ((x % y) == 0)
d956fa6f 394 return SCM_I_MAKINUM (x / y);
f92e85f7 395 }
dd5130ca
KR
396 else
397 {
398 /* When x == SCM_MOST_NEGATIVE_FIXNUM we could have the negative
3271a325
KR
399 of that value for the denominator, as a bignum. Apart from
400 that case, abs(bignum) > abs(inum) so inum/bignum is not an
401 integer. */
402 if (x == SCM_MOST_NEGATIVE_FIXNUM
403 && mpz_cmp_ui (SCM_I_BIG_MPZ (denominator),
404 - SCM_MOST_NEGATIVE_FIXNUM) == 0)
d956fa6f 405 return SCM_I_MAKINUM(-1);
dd5130ca 406 }
f92e85f7 407 }
c60e130c 408 else if (SCM_BIGP (numerator))
f92e85f7 409 {
e11e83f3 410 if (SCM_I_INUMP (denominator))
c60e130c 411 {
e11e83f3 412 long yy = SCM_I_INUM (denominator);
c60e130c
MV
413 if (mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), yy))
414 return scm_divide (numerator, denominator);
415 }
416 else
f92e85f7 417 {
bc36d050 418 if (scm_is_eq (numerator, denominator))
d956fa6f 419 return SCM_I_MAKINUM(1);
c60e130c
MV
420 if (mpz_divisible_p (SCM_I_BIG_MPZ (numerator),
421 SCM_I_BIG_MPZ (denominator)))
422 return scm_divide(numerator, denominator);
f92e85f7 423 }
f92e85f7 424 }
c60e130c
MV
425
426 /* No, it's a proper fraction.
427 */
428 return scm_double_cell (scm_tc16_fraction,
429 SCM_UNPACK (numerator),
430 SCM_UNPACK (denominator), 0);
f92e85f7 431}
c60e130c 432#undef FUNC_NAME
f92e85f7
MV
433
434static void scm_i_fraction_reduce (SCM z)
435{
436 if (!(SCM_FRACTION_REDUCED (z)))
437 {
438 SCM divisor;
439 divisor = scm_gcd (SCM_FRACTION_NUMERATOR (z), SCM_FRACTION_DENOMINATOR (z));
bc36d050 440 if (!(scm_is_eq (divisor, SCM_I_MAKINUM(1))))
f92e85f7
MV
441 {
442 /* is this safe? */
443 SCM_FRACTION_SET_NUMERATOR (z, scm_divide (SCM_FRACTION_NUMERATOR (z), divisor));
444 SCM_FRACTION_SET_DENOMINATOR (z, scm_divide (SCM_FRACTION_DENOMINATOR (z), divisor));
445 }
446 SCM_FRACTION_REDUCED_SET (z);
447 }
448}
449
450double
451scm_i_fraction2double (SCM z)
452{
55f26379
MV
453 return scm_to_double (scm_divide2real (SCM_FRACTION_NUMERATOR (z),
454 SCM_FRACTION_DENOMINATOR (z)));
f92e85f7
MV
455}
456
a1ec6916 457SCM_DEFINE (scm_exact_p, "exact?", 1, 0, 0,
1bbd0b84 458 (SCM x),
942e5b91
MG
459 "Return @code{#t} if @var{x} is an exact number, @code{#f}\n"
460 "otherwise.")
1bbd0b84 461#define FUNC_NAME s_scm_exact_p
0f2d19dd 462{
e11e83f3 463 if (SCM_I_INUMP (x))
0aacf84e
MD
464 return SCM_BOOL_T;
465 if (SCM_BIGP (x))
466 return SCM_BOOL_T;
f92e85f7
MV
467 if (SCM_FRACTIONP (x))
468 return SCM_BOOL_T;
eb927cb9
MV
469 if (SCM_NUMBERP (x))
470 return SCM_BOOL_F;
471 SCM_WRONG_TYPE_ARG (1, x);
0f2d19dd 472}
1bbd0b84 473#undef FUNC_NAME
0f2d19dd 474
4219f20d 475
a1ec6916 476SCM_DEFINE (scm_odd_p, "odd?", 1, 0, 0,
1bbd0b84 477 (SCM n),
942e5b91
MG
478 "Return @code{#t} if @var{n} is an odd number, @code{#f}\n"
479 "otherwise.")
1bbd0b84 480#define FUNC_NAME s_scm_odd_p
0f2d19dd 481{
e11e83f3 482 if (SCM_I_INUMP (n))
0aacf84e 483 {
e11e83f3 484 long val = SCM_I_INUM (n);
73e4de09 485 return scm_from_bool ((val & 1L) != 0);
0aacf84e
MD
486 }
487 else if (SCM_BIGP (n))
488 {
489 int odd_p = mpz_odd_p (SCM_I_BIG_MPZ (n));
490 scm_remember_upto_here_1 (n);
73e4de09 491 return scm_from_bool (odd_p);
0aacf84e 492 }
73e4de09 493 else if (scm_is_true (scm_inf_p (n)))
7351e207 494 return SCM_BOOL_T;
f92e85f7
MV
495 else if (SCM_REALP (n))
496 {
497 double rem = fabs (fmod (SCM_REAL_VALUE(n), 2.0));
498 if (rem == 1.0)
499 return SCM_BOOL_T;
500 else if (rem == 0.0)
501 return SCM_BOOL_F;
502 else
503 SCM_WRONG_TYPE_ARG (1, n);
504 }
0aacf84e 505 else
a1a33b0f 506 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 507}
1bbd0b84 508#undef FUNC_NAME
0f2d19dd 509
4219f20d 510
a1ec6916 511SCM_DEFINE (scm_even_p, "even?", 1, 0, 0,
1bbd0b84 512 (SCM n),
942e5b91
MG
513 "Return @code{#t} if @var{n} is an even number, @code{#f}\n"
514 "otherwise.")
1bbd0b84 515#define FUNC_NAME s_scm_even_p
0f2d19dd 516{
e11e83f3 517 if (SCM_I_INUMP (n))
0aacf84e 518 {
e11e83f3 519 long val = SCM_I_INUM (n);
73e4de09 520 return scm_from_bool ((val & 1L) == 0);
0aacf84e
MD
521 }
522 else if (SCM_BIGP (n))
523 {
524 int even_p = mpz_even_p (SCM_I_BIG_MPZ (n));
525 scm_remember_upto_here_1 (n);
73e4de09 526 return scm_from_bool (even_p);
0aacf84e 527 }
73e4de09 528 else if (scm_is_true (scm_inf_p (n)))
7351e207 529 return SCM_BOOL_T;
f92e85f7
MV
530 else if (SCM_REALP (n))
531 {
532 double rem = fabs (fmod (SCM_REAL_VALUE(n), 2.0));
533 if (rem == 1.0)
534 return SCM_BOOL_F;
535 else if (rem == 0.0)
536 return SCM_BOOL_T;
537 else
538 SCM_WRONG_TYPE_ARG (1, n);
539 }
0aacf84e 540 else
a1a33b0f 541 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 542}
1bbd0b84 543#undef FUNC_NAME
0f2d19dd 544
7351e207 545SCM_DEFINE (scm_inf_p, "inf?", 1, 0, 0,
b1092b3a
MV
546 (SCM x),
547 "Return @code{#t} if @var{x} is either @samp{+inf.0}\n"
548 "or @samp{-inf.0}, @code{#f} otherwise.")
7351e207
MV
549#define FUNC_NAME s_scm_inf_p
550{
b1092b3a
MV
551 if (SCM_REALP (x))
552 return scm_from_bool (xisinf (SCM_REAL_VALUE (x)));
553 else if (SCM_COMPLEXP (x))
554 return scm_from_bool (xisinf (SCM_COMPLEX_REAL (x))
555 || xisinf (SCM_COMPLEX_IMAG (x)));
0aacf84e 556 else
7351e207 557 return SCM_BOOL_F;
7351e207
MV
558}
559#undef FUNC_NAME
560
561SCM_DEFINE (scm_nan_p, "nan?", 1, 0, 0,
562 (SCM n),
563 "Return @code{#t} if @var{n} is a NaN, @code{#f}\n"
564 "otherwise.")
565#define FUNC_NAME s_scm_nan_p
566{
0aacf84e 567 if (SCM_REALP (n))
73e4de09 568 return scm_from_bool (xisnan (SCM_REAL_VALUE (n)));
0aacf84e 569 else if (SCM_COMPLEXP (n))
73e4de09 570 return scm_from_bool (xisnan (SCM_COMPLEX_REAL (n))
7351e207 571 || xisnan (SCM_COMPLEX_IMAG (n)));
0aacf84e 572 else
7351e207 573 return SCM_BOOL_F;
7351e207
MV
574}
575#undef FUNC_NAME
576
577/* Guile's idea of infinity. */
578static double guile_Inf;
579
580/* Guile's idea of not a number. */
581static double guile_NaN;
582
583static void
584guile_ieee_init (void)
585{
586#if defined (HAVE_ISINF) || defined (HAVE_FINITE)
587
588/* Some version of gcc on some old version of Linux used to crash when
589 trying to make Inf and NaN. */
590
240a27d2
KR
591#ifdef INFINITY
592 /* C99 INFINITY, when available.
593 FIXME: The standard allows for INFINITY to be something that overflows
594 at compile time. We ought to have a configure test to check for that
595 before trying to use it. (But in practice we believe this is not a
596 problem on any system guile is likely to target.) */
597 guile_Inf = INFINITY;
598#elif HAVE_DINFINITY
599 /* OSF */
7351e207
MV
600 extern unsigned int DINFINITY[2];
601 guile_Inf = (*(X_CAST(double *, DINFINITY)));
602#else
603 double tmp = 1e+10;
604 guile_Inf = tmp;
605 for (;;)
606 {
607 guile_Inf *= 1e+10;
608 if (guile_Inf == tmp)
609 break;
610 tmp = guile_Inf;
611 }
612#endif
613
614#endif
615
616#if defined (HAVE_ISNAN)
617
240a27d2
KR
618#ifdef NAN
619 /* C99 NAN, when available */
620 guile_NaN = NAN;
621#elif HAVE_DQNAN
622 /* OSF */
7351e207
MV
623 extern unsigned int DQNAN[2];
624 guile_NaN = (*(X_CAST(double *, DQNAN)));
625#else
626 guile_NaN = guile_Inf / guile_Inf;
627#endif
628
629#endif
630}
631
632SCM_DEFINE (scm_inf, "inf", 0, 0, 0,
633 (void),
634 "Return Inf.")
635#define FUNC_NAME s_scm_inf
636{
637 static int initialized = 0;
638 if (! initialized)
639 {
640 guile_ieee_init ();
641 initialized = 1;
642 }
55f26379 643 return scm_from_double (guile_Inf);
7351e207
MV
644}
645#undef FUNC_NAME
646
647SCM_DEFINE (scm_nan, "nan", 0, 0, 0,
648 (void),
649 "Return NaN.")
650#define FUNC_NAME s_scm_nan
651{
652 static int initialized = 0;
0aacf84e 653 if (!initialized)
7351e207
MV
654 {
655 guile_ieee_init ();
656 initialized = 1;
657 }
55f26379 658 return scm_from_double (guile_NaN);
7351e207
MV
659}
660#undef FUNC_NAME
661
4219f20d 662
a48d60b1
MD
663SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
664 (SCM x),
665 "Return the absolute value of @var{x}.")
666#define FUNC_NAME
0f2d19dd 667{
e11e83f3 668 if (SCM_I_INUMP (x))
0aacf84e 669 {
e11e83f3 670 long int xx = SCM_I_INUM (x);
0aacf84e
MD
671 if (xx >= 0)
672 return x;
673 else if (SCM_POSFIXABLE (-xx))
d956fa6f 674 return SCM_I_MAKINUM (-xx);
0aacf84e
MD
675 else
676 return scm_i_long2big (-xx);
4219f20d 677 }
0aacf84e
MD
678 else if (SCM_BIGP (x))
679 {
680 const int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
681 if (sgn < 0)
682 return scm_i_clonebig (x, 0);
683 else
684 return x;
4219f20d 685 }
0aacf84e 686 else if (SCM_REALP (x))
ae38324d
KR
687 {
688 /* note that if x is a NaN then xx<0 is false so we return x unchanged */
689 double xx = SCM_REAL_VALUE (x);
690 if (xx < 0.0)
55f26379 691 return scm_from_double (-xx);
ae38324d
KR
692 else
693 return x;
694 }
f92e85f7
MV
695 else if (SCM_FRACTIONP (x))
696 {
73e4de09 697 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (x))))
f92e85f7 698 return x;
cba42c93 699 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7
MV
700 SCM_FRACTION_DENOMINATOR (x));
701 }
0aacf84e 702 else
a48d60b1 703 SCM_WTA_DISPATCH_1 (g_scm_abs, x, 1, s_scm_abs);
0f2d19dd 704}
a48d60b1 705#undef FUNC_NAME
0f2d19dd 706
4219f20d 707
9de33deb 708SCM_GPROC (s_quotient, "quotient", 2, 0, 0, scm_quotient, g_quotient);
942e5b91
MG
709/* "Return the quotient of the numbers @var{x} and @var{y}."
710 */
0f2d19dd 711SCM
6e8d25a6 712scm_quotient (SCM x, SCM y)
0f2d19dd 713{
e11e83f3 714 if (SCM_I_INUMP (x))
0aacf84e 715 {
e11e83f3
MV
716 long xx = SCM_I_INUM (x);
717 if (SCM_I_INUMP (y))
0aacf84e 718 {
e11e83f3 719 long yy = SCM_I_INUM (y);
0aacf84e
MD
720 if (yy == 0)
721 scm_num_overflow (s_quotient);
722 else
723 {
724 long z = xx / yy;
725 if (SCM_FIXABLE (z))
d956fa6f 726 return SCM_I_MAKINUM (z);
0aacf84e
MD
727 else
728 return scm_i_long2big (z);
729 }
828865c3 730 }
0aacf84e 731 else if (SCM_BIGP (y))
ac0c002c 732 {
e11e83f3 733 if ((SCM_I_INUM (x) == SCM_MOST_NEGATIVE_FIXNUM)
4dc09ee4
KR
734 && (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
735 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
736 {
737 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
738 scm_remember_upto_here_1 (y);
d956fa6f 739 return SCM_I_MAKINUM (-1);
4dc09ee4 740 }
0aacf84e 741 else
d956fa6f 742 return SCM_I_MAKINUM (0);
ac0c002c
DH
743 }
744 else
0aacf84e 745 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
828865c3 746 }
0aacf84e
MD
747 else if (SCM_BIGP (x))
748 {
e11e83f3 749 if (SCM_I_INUMP (y))
0aacf84e 750 {
e11e83f3 751 long yy = SCM_I_INUM (y);
0aacf84e
MD
752 if (yy == 0)
753 scm_num_overflow (s_quotient);
754 else if (yy == 1)
755 return x;
756 else
757 {
758 SCM result = scm_i_mkbig ();
759 if (yy < 0)
760 {
761 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (result),
762 SCM_I_BIG_MPZ (x),
763 - yy);
764 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
765 }
766 else
767 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
768 scm_remember_upto_here_1 (x);
769 return scm_i_normbig (result);
770 }
771 }
772 else if (SCM_BIGP (y))
773 {
774 SCM result = scm_i_mkbig ();
775 mpz_tdiv_q (SCM_I_BIG_MPZ (result),
776 SCM_I_BIG_MPZ (x),
777 SCM_I_BIG_MPZ (y));
778 scm_remember_upto_here_2 (x, y);
779 return scm_i_normbig (result);
780 }
781 else
782 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
f872b822 783 }
0aacf84e 784 else
89a7e495 785 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG1, s_quotient);
0f2d19dd
JB
786}
787
9de33deb 788SCM_GPROC (s_remainder, "remainder", 2, 0, 0, scm_remainder, g_remainder);
942e5b91
MG
789/* "Return the remainder of the numbers @var{x} and @var{y}.\n"
790 * "@lisp\n"
791 * "(remainder 13 4) @result{} 1\n"
792 * "(remainder -13 4) @result{} -1\n"
793 * "@end lisp"
794 */
0f2d19dd 795SCM
6e8d25a6 796scm_remainder (SCM x, SCM y)
0f2d19dd 797{
e11e83f3 798 if (SCM_I_INUMP (x))
0aacf84e 799 {
e11e83f3 800 if (SCM_I_INUMP (y))
0aacf84e 801 {
e11e83f3 802 long yy = SCM_I_INUM (y);
0aacf84e
MD
803 if (yy == 0)
804 scm_num_overflow (s_remainder);
805 else
806 {
e11e83f3 807 long z = SCM_I_INUM (x) % yy;
d956fa6f 808 return SCM_I_MAKINUM (z);
0aacf84e
MD
809 }
810 }
811 else if (SCM_BIGP (y))
ac0c002c 812 {
e11e83f3 813 if ((SCM_I_INUM (x) == SCM_MOST_NEGATIVE_FIXNUM)
4dc09ee4
KR
814 && (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
815 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
816 {
817 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
818 scm_remember_upto_here_1 (y);
d956fa6f 819 return SCM_I_MAKINUM (0);
4dc09ee4 820 }
0aacf84e
MD
821 else
822 return x;
ac0c002c
DH
823 }
824 else
0aacf84e 825 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
89a7e495 826 }
0aacf84e
MD
827 else if (SCM_BIGP (x))
828 {
e11e83f3 829 if (SCM_I_INUMP (y))
0aacf84e 830 {
e11e83f3 831 long yy = SCM_I_INUM (y);
0aacf84e
MD
832 if (yy == 0)
833 scm_num_overflow (s_remainder);
834 else
835 {
836 SCM result = scm_i_mkbig ();
837 if (yy < 0)
838 yy = - yy;
839 mpz_tdiv_r_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ(x), yy);
840 scm_remember_upto_here_1 (x);
841 return scm_i_normbig (result);
842 }
843 }
844 else if (SCM_BIGP (y))
845 {
846 SCM result = scm_i_mkbig ();
847 mpz_tdiv_r (SCM_I_BIG_MPZ (result),
848 SCM_I_BIG_MPZ (x),
849 SCM_I_BIG_MPZ (y));
850 scm_remember_upto_here_2 (x, y);
851 return scm_i_normbig (result);
852 }
853 else
854 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
f872b822 855 }
0aacf84e 856 else
89a7e495 857 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG1, s_remainder);
0f2d19dd
JB
858}
859
89a7e495 860
9de33deb 861SCM_GPROC (s_modulo, "modulo", 2, 0, 0, scm_modulo, g_modulo);
942e5b91
MG
862/* "Return the modulo of the numbers @var{x} and @var{y}.\n"
863 * "@lisp\n"
864 * "(modulo 13 4) @result{} 1\n"
865 * "(modulo -13 4) @result{} 3\n"
866 * "@end lisp"
867 */
0f2d19dd 868SCM
6e8d25a6 869scm_modulo (SCM x, SCM y)
0f2d19dd 870{
e11e83f3 871 if (SCM_I_INUMP (x))
0aacf84e 872 {
e11e83f3
MV
873 long xx = SCM_I_INUM (x);
874 if (SCM_I_INUMP (y))
0aacf84e 875 {
e11e83f3 876 long yy = SCM_I_INUM (y);
0aacf84e
MD
877 if (yy == 0)
878 scm_num_overflow (s_modulo);
879 else
880 {
66b1c775
KR
881 /* C99 specifies that "%" is the remainder corresponding to a
882 quotient rounded towards zero, and that's also traditional
883 for machine division, so z here should be well defined. */
0aacf84e
MD
884 long z = xx % yy;
885 long result;
886
887 if (yy < 0)
888 {
889 if (z > 0)
890 result = z + yy;
891 else
892 result = z;
893 }
894 else
895 {
896 if (z < 0)
897 result = z + yy;
898 else
899 result = z;
900 }
d956fa6f 901 return SCM_I_MAKINUM (result);
0aacf84e
MD
902 }
903 }
904 else if (SCM_BIGP (y))
905 {
906 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
0aacf84e
MD
907 {
908 mpz_t z_x;
909 SCM result;
910
911 if (sgn_y < 0)
912 {
913 SCM pos_y = scm_i_clonebig (y, 0);
914 /* do this after the last scm_op */
915 mpz_init_set_si (z_x, xx);
916 result = pos_y; /* re-use this bignum */
917 mpz_mod (SCM_I_BIG_MPZ (result),
918 z_x,
919 SCM_I_BIG_MPZ (pos_y));
920 scm_remember_upto_here_1 (pos_y);
921 }
922 else
923 {
924 result = scm_i_mkbig ();
925 /* do this after the last scm_op */
926 mpz_init_set_si (z_x, xx);
927 mpz_mod (SCM_I_BIG_MPZ (result),
928 z_x,
929 SCM_I_BIG_MPZ (y));
930 scm_remember_upto_here_1 (y);
931 }
ca46fb90 932
0aacf84e
MD
933 if ((sgn_y < 0) && mpz_sgn (SCM_I_BIG_MPZ (result)) != 0)
934 mpz_add (SCM_I_BIG_MPZ (result),
935 SCM_I_BIG_MPZ (y),
936 SCM_I_BIG_MPZ (result));
937 scm_remember_upto_here_1 (y);
938 /* and do this before the next one */
939 mpz_clear (z_x);
940 return scm_i_normbig (result);
941 }
942 }
943 else
944 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
f872b822 945 }
0aacf84e
MD
946 else if (SCM_BIGP (x))
947 {
e11e83f3 948 if (SCM_I_INUMP (y))
0aacf84e 949 {
e11e83f3 950 long yy = SCM_I_INUM (y);
0aacf84e
MD
951 if (yy == 0)
952 scm_num_overflow (s_modulo);
953 else
954 {
955 SCM result = scm_i_mkbig ();
956 mpz_mod_ui (SCM_I_BIG_MPZ (result),
957 SCM_I_BIG_MPZ (x),
958 (yy < 0) ? - yy : yy);
959 scm_remember_upto_here_1 (x);
960 if ((yy < 0) && (mpz_sgn (SCM_I_BIG_MPZ (result)) != 0))
961 mpz_sub_ui (SCM_I_BIG_MPZ (result),
962 SCM_I_BIG_MPZ (result),
963 - yy);
964 return scm_i_normbig (result);
965 }
966 }
967 else if (SCM_BIGP (y))
968 {
0aacf84e
MD
969 {
970 SCM result = scm_i_mkbig ();
971 int y_sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
972 SCM pos_y = scm_i_clonebig (y, y_sgn >= 0);
973 mpz_mod (SCM_I_BIG_MPZ (result),
974 SCM_I_BIG_MPZ (x),
975 SCM_I_BIG_MPZ (pos_y));
ca46fb90 976
0aacf84e
MD
977 scm_remember_upto_here_1 (x);
978 if ((y_sgn < 0) && (mpz_sgn (SCM_I_BIG_MPZ (result)) != 0))
979 mpz_add (SCM_I_BIG_MPZ (result),
980 SCM_I_BIG_MPZ (y),
981 SCM_I_BIG_MPZ (result));
982 scm_remember_upto_here_2 (y, pos_y);
983 return scm_i_normbig (result);
984 }
985 }
986 else
987 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
828865c3 988 }
0aacf84e 989 else
09fb7599 990 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG1, s_modulo);
0f2d19dd
JB
991}
992
9de33deb 993SCM_GPROC1 (s_gcd, "gcd", scm_tc7_asubr, scm_gcd, g_gcd);
942e5b91
MG
994/* "Return the greatest common divisor of all arguments.\n"
995 * "If called without arguments, 0 is returned."
996 */
0f2d19dd 997SCM
6e8d25a6 998scm_gcd (SCM x, SCM y)
0f2d19dd 999{
ca46fb90 1000 if (SCM_UNBNDP (y))
0aacf84e 1001 return SCM_UNBNDP (x) ? SCM_INUM0 : x;
ca46fb90 1002
e11e83f3 1003 if (SCM_I_INUMP (x))
ca46fb90 1004 {
e11e83f3 1005 if (SCM_I_INUMP (y))
ca46fb90 1006 {
e11e83f3
MV
1007 long xx = SCM_I_INUM (x);
1008 long yy = SCM_I_INUM (y);
ca46fb90
RB
1009 long u = xx < 0 ? -xx : xx;
1010 long v = yy < 0 ? -yy : yy;
1011 long result;
0aacf84e
MD
1012 if (xx == 0)
1013 result = v;
1014 else if (yy == 0)
1015 result = u;
1016 else
1017 {
1018 long k = 1;
1019 long t;
1020 /* Determine a common factor 2^k */
1021 while (!(1 & (u | v)))
1022 {
1023 k <<= 1;
1024 u >>= 1;
1025 v >>= 1;
1026 }
1027 /* Now, any factor 2^n can be eliminated */
1028 if (u & 1)
1029 t = -v;
1030 else
1031 {
1032 t = u;
1033 b3:
1034 t = SCM_SRS (t, 1);
1035 }
1036 if (!(1 & t))
1037 goto b3;
1038 if (t > 0)
1039 u = t;
1040 else
1041 v = -t;
1042 t = u - v;
1043 if (t != 0)
1044 goto b3;
1045 result = u * k;
1046 }
1047 return (SCM_POSFIXABLE (result)
d956fa6f 1048 ? SCM_I_MAKINUM (result)
0aacf84e 1049 : scm_i_long2big (result));
ca46fb90
RB
1050 }
1051 else if (SCM_BIGP (y))
1052 {
0bff4dce
KR
1053 SCM_SWAP (x, y);
1054 goto big_inum;
ca46fb90
RB
1055 }
1056 else
1057 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 1058 }
ca46fb90
RB
1059 else if (SCM_BIGP (x))
1060 {
e11e83f3 1061 if (SCM_I_INUMP (y))
ca46fb90
RB
1062 {
1063 unsigned long result;
0bff4dce
KR
1064 long yy;
1065 big_inum:
e11e83f3 1066 yy = SCM_I_INUM (y);
8c5b0afc
KR
1067 if (yy == 0)
1068 return scm_abs (x);
0aacf84e
MD
1069 if (yy < 0)
1070 yy = -yy;
ca46fb90
RB
1071 result = mpz_gcd_ui (NULL, SCM_I_BIG_MPZ (x), yy);
1072 scm_remember_upto_here_1 (x);
0aacf84e 1073 return (SCM_POSFIXABLE (result)
d956fa6f 1074 ? SCM_I_MAKINUM (result)
c71b0706 1075 : scm_from_ulong (result));
ca46fb90
RB
1076 }
1077 else if (SCM_BIGP (y))
1078 {
1079 SCM result = scm_i_mkbig ();
0aacf84e
MD
1080 mpz_gcd (SCM_I_BIG_MPZ (result),
1081 SCM_I_BIG_MPZ (x),
1082 SCM_I_BIG_MPZ (y));
1083 scm_remember_upto_here_2 (x, y);
ca46fb90
RB
1084 return scm_i_normbig (result);
1085 }
1086 else
1087 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
09fb7599 1088 }
ca46fb90 1089 else
09fb7599 1090 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
0f2d19dd
JB
1091}
1092
9de33deb 1093SCM_GPROC1 (s_lcm, "lcm", scm_tc7_asubr, scm_lcm, g_lcm);
942e5b91
MG
1094/* "Return the least common multiple of the arguments.\n"
1095 * "If called without arguments, 1 is returned."
1096 */
0f2d19dd 1097SCM
6e8d25a6 1098scm_lcm (SCM n1, SCM n2)
0f2d19dd 1099{
ca46fb90
RB
1100 if (SCM_UNBNDP (n2))
1101 {
1102 if (SCM_UNBNDP (n1))
d956fa6f
MV
1103 return SCM_I_MAKINUM (1L);
1104 n2 = SCM_I_MAKINUM (1L);
09fb7599 1105 }
09fb7599 1106
e11e83f3 1107 SCM_GASSERT2 (SCM_I_INUMP (n1) || SCM_BIGP (n1),
ca46fb90 1108 g_lcm, n1, n2, SCM_ARG1, s_lcm);
e11e83f3 1109 SCM_GASSERT2 (SCM_I_INUMP (n2) || SCM_BIGP (n2),
ca46fb90 1110 g_lcm, n1, n2, SCM_ARGn, s_lcm);
09fb7599 1111
e11e83f3 1112 if (SCM_I_INUMP (n1))
ca46fb90 1113 {
e11e83f3 1114 if (SCM_I_INUMP (n2))
ca46fb90
RB
1115 {
1116 SCM d = scm_gcd (n1, n2);
bc36d050 1117 if (scm_is_eq (d, SCM_INUM0))
ca46fb90
RB
1118 return d;
1119 else
1120 return scm_abs (scm_product (n1, scm_quotient (n2, d)));
1121 }
1122 else
1123 {
1124 /* inum n1, big n2 */
1125 inumbig:
1126 {
1127 SCM result = scm_i_mkbig ();
e11e83f3 1128 long nn1 = SCM_I_INUM (n1);
ca46fb90
RB
1129 if (nn1 == 0) return SCM_INUM0;
1130 if (nn1 < 0) nn1 = - nn1;
1131 mpz_lcm_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n2), nn1);
1132 scm_remember_upto_here_1 (n2);
1133 return result;
1134 }
1135 }
1136 }
1137 else
1138 {
1139 /* big n1 */
e11e83f3 1140 if (SCM_I_INUMP (n2))
ca46fb90
RB
1141 {
1142 SCM_SWAP (n1, n2);
1143 goto inumbig;
1144 }
1145 else
1146 {
1147 SCM result = scm_i_mkbig ();
1148 mpz_lcm(SCM_I_BIG_MPZ (result),
1149 SCM_I_BIG_MPZ (n1),
1150 SCM_I_BIG_MPZ (n2));
1151 scm_remember_upto_here_2(n1, n2);
1152 /* shouldn't need to normalize b/c lcm of 2 bigs should be big */
1153 return result;
1154 }
f872b822 1155 }
0f2d19dd
JB
1156}
1157
8a525303
GB
1158/* Emulating 2's complement bignums with sign magnitude arithmetic:
1159
1160 Logand:
1161 X Y Result Method:
1162 (len)
1163 + + + x (map digit:logand X Y)
1164 + - + x (map digit:logand X (lognot (+ -1 Y)))
1165 - + + y (map digit:logand (lognot (+ -1 X)) Y)
1166 - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y)))
1167
1168 Logior:
1169 X Y Result Method:
1170
1171 + + + (map digit:logior X Y)
1172 + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y)))
1173 - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y)))
1174 - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y)))
1175
1176 Logxor:
1177 X Y Result Method:
1178
1179 + + + (map digit:logxor X Y)
1180 + - - (+ 1 (map digit:logxor X (+ -1 Y)))
1181 - + - (+ 1 (map digit:logxor (+ -1 X) Y))
1182 - - + (map digit:logxor (+ -1 X) (+ -1 Y))
1183
1184 Logtest:
1185 X Y Result
1186
1187 + + (any digit:logand X Y)
1188 + - (any digit:logand X (lognot (+ -1 Y)))
1189 - + (any digit:logand (lognot (+ -1 X)) Y)
1190 - - #t
1191
1192*/
1193
c3ee7520 1194SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
1bbd0b84 1195 (SCM n1, SCM n2),
3c3db128
GH
1196 "Return the bitwise AND of the integer arguments.\n\n"
1197 "@lisp\n"
1198 "(logand) @result{} -1\n"
1199 "(logand 7) @result{} 7\n"
535f2a51 1200 "(logand #b111 #b011 #b001) @result{} 1\n"
3c3db128 1201 "@end lisp")
1bbd0b84 1202#define FUNC_NAME s_scm_logand
0f2d19dd 1203{
9a00c9fc
DH
1204 long int nn1;
1205
0aacf84e
MD
1206 if (SCM_UNBNDP (n2))
1207 {
1208 if (SCM_UNBNDP (n1))
d956fa6f 1209 return SCM_I_MAKINUM (-1);
0aacf84e
MD
1210 else if (!SCM_NUMBERP (n1))
1211 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
1212 else if (SCM_NUMBERP (n1))
1213 return n1;
1214 else
1215 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 1216 }
09fb7599 1217
e11e83f3 1218 if (SCM_I_INUMP (n1))
0aacf84e 1219 {
e11e83f3
MV
1220 nn1 = SCM_I_INUM (n1);
1221 if (SCM_I_INUMP (n2))
0aacf84e 1222 {
e11e83f3 1223 long nn2 = SCM_I_INUM (n2);
d956fa6f 1224 return SCM_I_MAKINUM (nn1 & nn2);
0aacf84e
MD
1225 }
1226 else if SCM_BIGP (n2)
1227 {
1228 intbig:
1229 if (n1 == 0)
1230 return SCM_INUM0;
1231 {
1232 SCM result_z = scm_i_mkbig ();
1233 mpz_t nn1_z;
1234 mpz_init_set_si (nn1_z, nn1);
1235 mpz_and (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
1236 scm_remember_upto_here_1 (n2);
1237 mpz_clear (nn1_z);
1238 return scm_i_normbig (result_z);
1239 }
1240 }
1241 else
1242 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1243 }
1244 else if (SCM_BIGP (n1))
1245 {
e11e83f3 1246 if (SCM_I_INUMP (n2))
0aacf84e
MD
1247 {
1248 SCM_SWAP (n1, n2);
e11e83f3 1249 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
1250 goto intbig;
1251 }
1252 else if (SCM_BIGP (n2))
1253 {
1254 SCM result_z = scm_i_mkbig ();
1255 mpz_and (SCM_I_BIG_MPZ (result_z),
1256 SCM_I_BIG_MPZ (n1),
1257 SCM_I_BIG_MPZ (n2));
1258 scm_remember_upto_here_2 (n1, n2);
1259 return scm_i_normbig (result_z);
1260 }
1261 else
1262 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 1263 }
0aacf84e 1264 else
09fb7599 1265 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 1266}
1bbd0b84 1267#undef FUNC_NAME
0f2d19dd 1268
09fb7599 1269
c3ee7520 1270SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
1bbd0b84 1271 (SCM n1, SCM n2),
3c3db128
GH
1272 "Return the bitwise OR of the integer arguments.\n\n"
1273 "@lisp\n"
1274 "(logior) @result{} 0\n"
1275 "(logior 7) @result{} 7\n"
1276 "(logior #b000 #b001 #b011) @result{} 3\n"
1e6808ea 1277 "@end lisp")
1bbd0b84 1278#define FUNC_NAME s_scm_logior
0f2d19dd 1279{
9a00c9fc
DH
1280 long int nn1;
1281
0aacf84e
MD
1282 if (SCM_UNBNDP (n2))
1283 {
1284 if (SCM_UNBNDP (n1))
1285 return SCM_INUM0;
1286 else if (SCM_NUMBERP (n1))
1287 return n1;
1288 else
1289 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 1290 }
09fb7599 1291
e11e83f3 1292 if (SCM_I_INUMP (n1))
0aacf84e 1293 {
e11e83f3
MV
1294 nn1 = SCM_I_INUM (n1);
1295 if (SCM_I_INUMP (n2))
0aacf84e 1296 {
e11e83f3 1297 long nn2 = SCM_I_INUM (n2);
d956fa6f 1298 return SCM_I_MAKINUM (nn1 | nn2);
0aacf84e
MD
1299 }
1300 else if (SCM_BIGP (n2))
1301 {
1302 intbig:
1303 if (nn1 == 0)
1304 return n2;
1305 {
1306 SCM result_z = scm_i_mkbig ();
1307 mpz_t nn1_z;
1308 mpz_init_set_si (nn1_z, nn1);
1309 mpz_ior (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
1310 scm_remember_upto_here_1 (n2);
1311 mpz_clear (nn1_z);
1312 return result_z;
1313 }
1314 }
1315 else
1316 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1317 }
1318 else if (SCM_BIGP (n1))
1319 {
e11e83f3 1320 if (SCM_I_INUMP (n2))
0aacf84e
MD
1321 {
1322 SCM_SWAP (n1, n2);
e11e83f3 1323 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
1324 goto intbig;
1325 }
1326 else if (SCM_BIGP (n2))
1327 {
1328 SCM result_z = scm_i_mkbig ();
1329 mpz_ior (SCM_I_BIG_MPZ (result_z),
1330 SCM_I_BIG_MPZ (n1),
1331 SCM_I_BIG_MPZ (n2));
1332 scm_remember_upto_here_2 (n1, n2);
1333 return result_z;
1334 }
1335 else
1336 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 1337 }
0aacf84e 1338 else
09fb7599 1339 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 1340}
1bbd0b84 1341#undef FUNC_NAME
0f2d19dd 1342
09fb7599 1343
c3ee7520 1344SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
1bbd0b84 1345 (SCM n1, SCM n2),
3c3db128
GH
1346 "Return the bitwise XOR of the integer arguments. A bit is\n"
1347 "set in the result if it is set in an odd number of arguments.\n"
1348 "@lisp\n"
1349 "(logxor) @result{} 0\n"
1350 "(logxor 7) @result{} 7\n"
1351 "(logxor #b000 #b001 #b011) @result{} 2\n"
1352 "(logxor #b000 #b001 #b011 #b011) @result{} 1\n"
1e6808ea 1353 "@end lisp")
1bbd0b84 1354#define FUNC_NAME s_scm_logxor
0f2d19dd 1355{
9a00c9fc
DH
1356 long int nn1;
1357
0aacf84e
MD
1358 if (SCM_UNBNDP (n2))
1359 {
1360 if (SCM_UNBNDP (n1))
1361 return SCM_INUM0;
1362 else if (SCM_NUMBERP (n1))
1363 return n1;
1364 else
1365 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 1366 }
09fb7599 1367
e11e83f3 1368 if (SCM_I_INUMP (n1))
0aacf84e 1369 {
e11e83f3
MV
1370 nn1 = SCM_I_INUM (n1);
1371 if (SCM_I_INUMP (n2))
0aacf84e 1372 {
e11e83f3 1373 long nn2 = SCM_I_INUM (n2);
d956fa6f 1374 return SCM_I_MAKINUM (nn1 ^ nn2);
0aacf84e
MD
1375 }
1376 else if (SCM_BIGP (n2))
1377 {
1378 intbig:
1379 {
1380 SCM result_z = scm_i_mkbig ();
1381 mpz_t nn1_z;
1382 mpz_init_set_si (nn1_z, nn1);
1383 mpz_xor (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
1384 scm_remember_upto_here_1 (n2);
1385 mpz_clear (nn1_z);
1386 return scm_i_normbig (result_z);
1387 }
1388 }
1389 else
1390 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1391 }
1392 else if (SCM_BIGP (n1))
1393 {
e11e83f3 1394 if (SCM_I_INUMP (n2))
0aacf84e
MD
1395 {
1396 SCM_SWAP (n1, n2);
e11e83f3 1397 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
1398 goto intbig;
1399 }
1400 else if (SCM_BIGP (n2))
1401 {
1402 SCM result_z = scm_i_mkbig ();
1403 mpz_xor (SCM_I_BIG_MPZ (result_z),
1404 SCM_I_BIG_MPZ (n1),
1405 SCM_I_BIG_MPZ (n2));
1406 scm_remember_upto_here_2 (n1, n2);
1407 return scm_i_normbig (result_z);
1408 }
1409 else
1410 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 1411 }
0aacf84e 1412 else
09fb7599 1413 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 1414}
1bbd0b84 1415#undef FUNC_NAME
0f2d19dd 1416
09fb7599 1417
a1ec6916 1418SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1e6808ea
MG
1419 (SCM j, SCM k),
1420 "@lisp\n"
b380b885
MD
1421 "(logtest j k) @equiv{} (not (zero? (logand j k)))\n\n"
1422 "(logtest #b0100 #b1011) @result{} #f\n"
1423 "(logtest #b0100 #b0111) @result{} #t\n"
1e6808ea 1424 "@end lisp")
1bbd0b84 1425#define FUNC_NAME s_scm_logtest
0f2d19dd 1426{
1e6808ea 1427 long int nj;
9a00c9fc 1428
e11e83f3 1429 if (SCM_I_INUMP (j))
0aacf84e 1430 {
e11e83f3
MV
1431 nj = SCM_I_INUM (j);
1432 if (SCM_I_INUMP (k))
0aacf84e 1433 {
e11e83f3 1434 long nk = SCM_I_INUM (k);
73e4de09 1435 return scm_from_bool (nj & nk);
0aacf84e
MD
1436 }
1437 else if (SCM_BIGP (k))
1438 {
1439 intbig:
1440 if (nj == 0)
1441 return SCM_BOOL_F;
1442 {
1443 SCM result;
1444 mpz_t nj_z;
1445 mpz_init_set_si (nj_z, nj);
1446 mpz_and (nj_z, nj_z, SCM_I_BIG_MPZ (k));
1447 scm_remember_upto_here_1 (k);
73e4de09 1448 result = scm_from_bool (mpz_sgn (nj_z) != 0);
0aacf84e
MD
1449 mpz_clear (nj_z);
1450 return result;
1451 }
1452 }
1453 else
1454 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
1455 }
1456 else if (SCM_BIGP (j))
1457 {
e11e83f3 1458 if (SCM_I_INUMP (k))
0aacf84e
MD
1459 {
1460 SCM_SWAP (j, k);
e11e83f3 1461 nj = SCM_I_INUM (j);
0aacf84e
MD
1462 goto intbig;
1463 }
1464 else if (SCM_BIGP (k))
1465 {
1466 SCM result;
1467 mpz_t result_z;
1468 mpz_init (result_z);
1469 mpz_and (result_z,
1470 SCM_I_BIG_MPZ (j),
1471 SCM_I_BIG_MPZ (k));
1472 scm_remember_upto_here_2 (j, k);
73e4de09 1473 result = scm_from_bool (mpz_sgn (result_z) != 0);
0aacf84e
MD
1474 mpz_clear (result_z);
1475 return result;
1476 }
1477 else
1478 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
1479 }
1480 else
1481 SCM_WRONG_TYPE_ARG (SCM_ARG1, j);
0f2d19dd 1482}
1bbd0b84 1483#undef FUNC_NAME
0f2d19dd 1484
c1bfcf60 1485
a1ec6916 1486SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 1487 (SCM index, SCM j),
1e6808ea 1488 "@lisp\n"
b380b885
MD
1489 "(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j)\n\n"
1490 "(logbit? 0 #b1101) @result{} #t\n"
1491 "(logbit? 1 #b1101) @result{} #f\n"
1492 "(logbit? 2 #b1101) @result{} #t\n"
1493 "(logbit? 3 #b1101) @result{} #t\n"
1494 "(logbit? 4 #b1101) @result{} #f\n"
1e6808ea 1495 "@end lisp")
1bbd0b84 1496#define FUNC_NAME s_scm_logbit_p
0f2d19dd 1497{
78166ad5 1498 unsigned long int iindex;
5efd3c7d 1499 iindex = scm_to_ulong (index);
78166ad5 1500
e11e83f3 1501 if (SCM_I_INUMP (j))
0d75f6d8
KR
1502 {
1503 /* bits above what's in an inum follow the sign bit */
20fcc8ed 1504 iindex = min (iindex, SCM_LONG_BIT - 1);
e11e83f3 1505 return scm_from_bool ((1L << iindex) & SCM_I_INUM (j));
0d75f6d8 1506 }
0aacf84e
MD
1507 else if (SCM_BIGP (j))
1508 {
1509 int val = mpz_tstbit (SCM_I_BIG_MPZ (j), iindex);
1510 scm_remember_upto_here_1 (j);
73e4de09 1511 return scm_from_bool (val);
0aacf84e
MD
1512 }
1513 else
78166ad5 1514 SCM_WRONG_TYPE_ARG (SCM_ARG2, j);
0f2d19dd 1515}
1bbd0b84 1516#undef FUNC_NAME
0f2d19dd 1517
78166ad5 1518
a1ec6916 1519SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 1520 (SCM n),
4d814788 1521 "Return the integer which is the ones-complement of the integer\n"
1e6808ea
MG
1522 "argument.\n"
1523 "\n"
b380b885
MD
1524 "@lisp\n"
1525 "(number->string (lognot #b10000000) 2)\n"
1526 " @result{} \"-10000001\"\n"
1527 "(number->string (lognot #b0) 2)\n"
1528 " @result{} \"-1\"\n"
1e6808ea 1529 "@end lisp")
1bbd0b84 1530#define FUNC_NAME s_scm_lognot
0f2d19dd 1531{
e11e83f3 1532 if (SCM_I_INUMP (n)) {
f9811f9f
KR
1533 /* No overflow here, just need to toggle all the bits making up the inum.
1534 Enhancement: No need to strip the tag and add it back, could just xor
1535 a block of 1 bits, if that worked with the various debug versions of
1536 the SCM typedef. */
e11e83f3 1537 return SCM_I_MAKINUM (~ SCM_I_INUM (n));
f9811f9f
KR
1538
1539 } else if (SCM_BIGP (n)) {
1540 SCM result = scm_i_mkbig ();
1541 mpz_com (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n));
1542 scm_remember_upto_here_1 (n);
1543 return result;
1544
1545 } else {
1546 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1547 }
0f2d19dd 1548}
1bbd0b84 1549#undef FUNC_NAME
0f2d19dd 1550
518b7508
KR
1551/* returns 0 if IN is not an integer. OUT must already be
1552 initialized. */
1553static int
1554coerce_to_big (SCM in, mpz_t out)
1555{
1556 if (SCM_BIGP (in))
1557 mpz_set (out, SCM_I_BIG_MPZ (in));
e11e83f3
MV
1558 else if (SCM_I_INUMP (in))
1559 mpz_set_si (out, SCM_I_INUM (in));
518b7508
KR
1560 else
1561 return 0;
1562
1563 return 1;
1564}
1565
d885e204 1566SCM_DEFINE (scm_modulo_expt, "modulo-expt", 3, 0, 0,
518b7508
KR
1567 (SCM n, SCM k, SCM m),
1568 "Return @var{n} raised to the integer exponent\n"
1569 "@var{k}, modulo @var{m}.\n"
1570 "\n"
1571 "@lisp\n"
1572 "(modulo-expt 2 3 5)\n"
1573 " @result{} 3\n"
1574 "@end lisp")
d885e204 1575#define FUNC_NAME s_scm_modulo_expt
518b7508
KR
1576{
1577 mpz_t n_tmp;
1578 mpz_t k_tmp;
1579 mpz_t m_tmp;
1580
1581 /* There are two classes of error we might encounter --
1582 1) Math errors, which we'll report by calling scm_num_overflow,
1583 and
1584 2) wrong-type errors, which of course we'll report by calling
1585 SCM_WRONG_TYPE_ARG.
1586 We don't report those errors immediately, however; instead we do
1587 some cleanup first. These variables tell us which error (if
1588 any) we should report after cleaning up.
1589 */
1590 int report_overflow = 0;
1591
1592 int position_of_wrong_type = 0;
1593 SCM value_of_wrong_type = SCM_INUM0;
1594
1595 SCM result = SCM_UNDEFINED;
1596
1597 mpz_init (n_tmp);
1598 mpz_init (k_tmp);
1599 mpz_init (m_tmp);
1600
bc36d050 1601 if (scm_is_eq (m, SCM_INUM0))
518b7508
KR
1602 {
1603 report_overflow = 1;
1604 goto cleanup;
1605 }
1606
1607 if (!coerce_to_big (n, n_tmp))
1608 {
1609 value_of_wrong_type = n;
1610 position_of_wrong_type = 1;
1611 goto cleanup;
1612 }
1613
1614 if (!coerce_to_big (k, k_tmp))
1615 {
1616 value_of_wrong_type = k;
1617 position_of_wrong_type = 2;
1618 goto cleanup;
1619 }
1620
1621 if (!coerce_to_big (m, m_tmp))
1622 {
1623 value_of_wrong_type = m;
1624 position_of_wrong_type = 3;
1625 goto cleanup;
1626 }
1627
1628 /* if the exponent K is negative, and we simply call mpz_powm, we
1629 will get a divide-by-zero exception when an inverse 1/n mod m
1630 doesn't exist (or is not unique). Since exceptions are hard to
1631 handle, we'll attempt the inversion "by hand" -- that way, we get
1632 a simple failure code, which is easy to handle. */
1633
1634 if (-1 == mpz_sgn (k_tmp))
1635 {
1636 if (!mpz_invert (n_tmp, n_tmp, m_tmp))
1637 {
1638 report_overflow = 1;
1639 goto cleanup;
1640 }
1641 mpz_neg (k_tmp, k_tmp);
1642 }
1643
1644 result = scm_i_mkbig ();
1645 mpz_powm (SCM_I_BIG_MPZ (result),
1646 n_tmp,
1647 k_tmp,
1648 m_tmp);
b7b8c575
KR
1649
1650 if (mpz_sgn (m_tmp) < 0 && mpz_sgn (SCM_I_BIG_MPZ (result)) != 0)
1651 mpz_add (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), m_tmp);
1652
518b7508
KR
1653 cleanup:
1654 mpz_clear (m_tmp);
1655 mpz_clear (k_tmp);
1656 mpz_clear (n_tmp);
1657
1658 if (report_overflow)
1659 scm_num_overflow (FUNC_NAME);
1660
1661 if (position_of_wrong_type)
1662 SCM_WRONG_TYPE_ARG (position_of_wrong_type,
1663 value_of_wrong_type);
1664
1665 return scm_i_normbig (result);
1666}
1667#undef FUNC_NAME
1668
a1ec6916 1669SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 1670 (SCM n, SCM k),
0bafe73b 1671 "Return @var{n} raised to the exact integer exponent\n"
1e6808ea
MG
1672 "@var{k}.\n"
1673 "\n"
b380b885
MD
1674 "@lisp\n"
1675 "(integer-expt 2 5)\n"
1676 " @result{} 32\n"
1677 "(integer-expt -3 3)\n"
1678 " @result{} -27\n"
1679 "@end lisp")
1bbd0b84 1680#define FUNC_NAME s_scm_integer_expt
0f2d19dd 1681{
1c35cb19
RB
1682 long i2 = 0;
1683 SCM z_i2 = SCM_BOOL_F;
1684 int i2_is_big = 0;
d956fa6f 1685 SCM acc = SCM_I_MAKINUM (1L);
ca46fb90 1686
d57ed702 1687 /* 0^0 == 1 according to R5RS */
bc36d050 1688 if (scm_is_eq (n, SCM_INUM0) || scm_is_eq (n, acc))
73e4de09 1689 return scm_is_false (scm_zero_p(k)) ? n : acc;
bc36d050 1690 else if (scm_is_eq (n, SCM_I_MAKINUM (-1L)))
73e4de09 1691 return scm_is_false (scm_even_p (k)) ? n : acc;
ca46fb90 1692
e11e83f3
MV
1693 if (SCM_I_INUMP (k))
1694 i2 = SCM_I_INUM (k);
ca46fb90
RB
1695 else if (SCM_BIGP (k))
1696 {
1697 z_i2 = scm_i_clonebig (k, 1);
ca46fb90
RB
1698 scm_remember_upto_here_1 (k);
1699 i2_is_big = 1;
1700 }
2830fd91 1701 else
ca46fb90
RB
1702 SCM_WRONG_TYPE_ARG (2, k);
1703
1704 if (i2_is_big)
f872b822 1705 {
ca46fb90
RB
1706 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == -1)
1707 {
1708 mpz_neg (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2));
1709 n = scm_divide (n, SCM_UNDEFINED);
1710 }
1711 while (1)
1712 {
1713 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == 0)
1714 {
ca46fb90
RB
1715 return acc;
1716 }
1717 if (mpz_cmp_ui(SCM_I_BIG_MPZ (z_i2), 1) == 0)
1718 {
ca46fb90
RB
1719 return scm_product (acc, n);
1720 }
1721 if (mpz_tstbit(SCM_I_BIG_MPZ (z_i2), 0))
1722 acc = scm_product (acc, n);
1723 n = scm_product (n, n);
1724 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2), 1);
1725 }
f872b822 1726 }
ca46fb90 1727 else
f872b822 1728 {
ca46fb90
RB
1729 if (i2 < 0)
1730 {
1731 i2 = -i2;
1732 n = scm_divide (n, SCM_UNDEFINED);
1733 }
1734 while (1)
1735 {
1736 if (0 == i2)
1737 return acc;
1738 if (1 == i2)
1739 return scm_product (acc, n);
1740 if (i2 & 1)
1741 acc = scm_product (acc, n);
1742 n = scm_product (n, n);
1743 i2 >>= 1;
1744 }
f872b822 1745 }
0f2d19dd 1746}
1bbd0b84 1747#undef FUNC_NAME
0f2d19dd 1748
a1ec6916 1749SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 1750 (SCM n, SCM cnt),
32f19569
KR
1751 "Return @var{n} shifted left by @var{cnt} bits, or shifted right\n"
1752 "if @var{cnt} is negative. This is an ``arithmetic'' shift.\n"
1e6808ea 1753 "\n"
e7644cb2 1754 "This is effectively a multiplication by 2^@var{cnt}, and when\n"
32f19569
KR
1755 "@var{cnt} is negative it's a division, rounded towards negative\n"
1756 "infinity. (Note that this is not the same rounding as\n"
1757 "@code{quotient} does.)\n"
1758 "\n"
1759 "With @var{n} viewed as an infinite precision twos complement,\n"
1760 "@code{ash} means a left shift introducing zero bits, or a right\n"
1761 "shift dropping bits.\n"
1e6808ea 1762 "\n"
b380b885 1763 "@lisp\n"
1e6808ea
MG
1764 "(number->string (ash #b1 3) 2) @result{} \"1000\"\n"
1765 "(number->string (ash #b1010 -1) 2) @result{} \"101\"\n"
32f19569
KR
1766 "\n"
1767 ";; -23 is bits ...11101001, -6 is bits ...111010\n"
1768 "(ash -23 -2) @result{} -6\n"
a3c8b9fc 1769 "@end lisp")
1bbd0b84 1770#define FUNC_NAME s_scm_ash
0f2d19dd 1771{
3ab9f56e 1772 long bits_to_shift;
5efd3c7d 1773 bits_to_shift = scm_to_long (cnt);
ca46fb90
RB
1774
1775 if (bits_to_shift < 0)
1776 {
1777 /* Shift right by abs(cnt) bits. This is realized as a division
1778 by div:=2^abs(cnt). However, to guarantee the floor
1779 rounding, negative values require some special treatment.
1780 */
d956fa6f 1781 SCM div = scm_integer_expt (SCM_I_MAKINUM (2),
5efd3c7d 1782 scm_from_long (-bits_to_shift));
f92e85f7
MV
1783
1784 /* scm_quotient assumes its arguments are integers, but it's legal to (ash 1/2 -1) */
73e4de09 1785 if (scm_is_false (scm_negative_p (n)))
ca46fb90
RB
1786 return scm_quotient (n, div);
1787 else
d956fa6f
MV
1788 return scm_sum (SCM_I_MAKINUM (-1L),
1789 scm_quotient (scm_sum (SCM_I_MAKINUM (1L), n), div));
ca46fb90
RB
1790 }
1791 else
3ab9f56e 1792 /* Shift left is done by multiplication with 2^CNT */
d956fa6f 1793 return scm_product (n, scm_integer_expt (SCM_I_MAKINUM (2), cnt));
0f2d19dd 1794}
1bbd0b84 1795#undef FUNC_NAME
0f2d19dd 1796
3c9f20f8 1797
a1ec6916 1798SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 1799 (SCM n, SCM start, SCM end),
1e6808ea
MG
1800 "Return the integer composed of the @var{start} (inclusive)\n"
1801 "through @var{end} (exclusive) bits of @var{n}. The\n"
1802 "@var{start}th bit becomes the 0-th bit in the result.\n"
1803 "\n"
b380b885
MD
1804 "@lisp\n"
1805 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
1806 " @result{} \"1010\"\n"
1807 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
1808 " @result{} \"10110\"\n"
1809 "@end lisp")
1bbd0b84 1810#define FUNC_NAME s_scm_bit_extract
0f2d19dd 1811{
7f848242 1812 unsigned long int istart, iend, bits;
5efd3c7d
MV
1813 istart = scm_to_ulong (start);
1814 iend = scm_to_ulong (end);
c1bfcf60 1815 SCM_ASSERT_RANGE (3, end, (iend >= istart));
78166ad5 1816
7f848242
KR
1817 /* how many bits to keep */
1818 bits = iend - istart;
1819
e11e83f3 1820 if (SCM_I_INUMP (n))
0aacf84e 1821 {
e11e83f3 1822 long int in = SCM_I_INUM (n);
7f848242
KR
1823
1824 /* When istart>=SCM_I_FIXNUM_BIT we can just limit the shift to
d77ad560 1825 SCM_I_FIXNUM_BIT-1 to get either 0 or -1 per the sign of "in". */
857ae6af 1826 in = SCM_SRS (in, min (istart, SCM_I_FIXNUM_BIT-1));
ac0c002c 1827
0aacf84e
MD
1828 if (in < 0 && bits >= SCM_I_FIXNUM_BIT)
1829 {
1830 /* Since we emulate two's complement encoded numbers, this
1831 * special case requires us to produce a result that has
7f848242 1832 * more bits than can be stored in a fixnum.
0aacf84e 1833 */
7f848242
KR
1834 SCM result = scm_i_long2big (in);
1835 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
1836 bits);
1837 return result;
0aacf84e 1838 }
ac0c002c 1839
7f848242 1840 /* mask down to requisite bits */
857ae6af 1841 bits = min (bits, SCM_I_FIXNUM_BIT);
d956fa6f 1842 return SCM_I_MAKINUM (in & ((1L << bits) - 1));
0aacf84e
MD
1843 }
1844 else if (SCM_BIGP (n))
ac0c002c 1845 {
7f848242
KR
1846 SCM result;
1847 if (bits == 1)
1848 {
d956fa6f 1849 result = SCM_I_MAKINUM (mpz_tstbit (SCM_I_BIG_MPZ (n), istart));
7f848242
KR
1850 }
1851 else
1852 {
1853 /* ENHANCE-ME: It'd be nice not to allocate a new bignum when
1854 bits<SCM_I_FIXNUM_BIT. Would want some help from GMP to get
1855 such bits into a ulong. */
1856 result = scm_i_mkbig ();
1857 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(n), istart);
1858 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(result), bits);
1859 result = scm_i_normbig (result);
1860 }
1861 scm_remember_upto_here_1 (n);
1862 return result;
ac0c002c 1863 }
0aacf84e 1864 else
78166ad5 1865 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 1866}
1bbd0b84 1867#undef FUNC_NAME
0f2d19dd 1868
7f848242 1869
e4755e5c
JB
1870static const char scm_logtab[] = {
1871 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
1872};
1cc91f1b 1873
a1ec6916 1874SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 1875 (SCM n),
1e6808ea
MG
1876 "Return the number of bits in integer @var{n}. If integer is\n"
1877 "positive, the 1-bits in its binary representation are counted.\n"
1878 "If negative, the 0-bits in its two's-complement binary\n"
1879 "representation are counted. If 0, 0 is returned.\n"
1880 "\n"
b380b885
MD
1881 "@lisp\n"
1882 "(logcount #b10101010)\n"
ca46fb90
RB
1883 " @result{} 4\n"
1884 "(logcount 0)\n"
1885 " @result{} 0\n"
1886 "(logcount -2)\n"
1887 " @result{} 1\n"
1888 "@end lisp")
1889#define FUNC_NAME s_scm_logcount
1890{
e11e83f3 1891 if (SCM_I_INUMP (n))
f872b822 1892 {
ca46fb90 1893 unsigned long int c = 0;
e11e83f3 1894 long int nn = SCM_I_INUM (n);
ca46fb90
RB
1895 if (nn < 0)
1896 nn = -1 - nn;
1897 while (nn)
1898 {
1899 c += scm_logtab[15 & nn];
1900 nn >>= 4;
1901 }
d956fa6f 1902 return SCM_I_MAKINUM (c);
f872b822 1903 }
ca46fb90 1904 else if (SCM_BIGP (n))
f872b822 1905 {
ca46fb90 1906 unsigned long count;
713a4259
KR
1907 if (mpz_sgn (SCM_I_BIG_MPZ (n)) >= 0)
1908 count = mpz_popcount (SCM_I_BIG_MPZ (n));
ca46fb90 1909 else
713a4259
KR
1910 count = mpz_hamdist (SCM_I_BIG_MPZ (n), z_negative_one);
1911 scm_remember_upto_here_1 (n);
d956fa6f 1912 return SCM_I_MAKINUM (count);
f872b822 1913 }
ca46fb90
RB
1914 else
1915 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 1916}
ca46fb90 1917#undef FUNC_NAME
0f2d19dd
JB
1918
1919
ca46fb90
RB
1920static const char scm_ilentab[] = {
1921 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
1922};
1923
0f2d19dd 1924
ca46fb90
RB
1925SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
1926 (SCM n),
1927 "Return the number of bits necessary to represent @var{n}.\n"
1928 "\n"
1929 "@lisp\n"
1930 "(integer-length #b10101010)\n"
1931 " @result{} 8\n"
1932 "(integer-length 0)\n"
1933 " @result{} 0\n"
1934 "(integer-length #b1111)\n"
1935 " @result{} 4\n"
1936 "@end lisp")
1937#define FUNC_NAME s_scm_integer_length
1938{
e11e83f3 1939 if (SCM_I_INUMP (n))
0aacf84e
MD
1940 {
1941 unsigned long int c = 0;
1942 unsigned int l = 4;
e11e83f3 1943 long int nn = SCM_I_INUM (n);
0aacf84e
MD
1944 if (nn < 0)
1945 nn = -1 - nn;
1946 while (nn)
1947 {
1948 c += 4;
1949 l = scm_ilentab [15 & nn];
1950 nn >>= 4;
1951 }
d956fa6f 1952 return SCM_I_MAKINUM (c - 4 + l);
0aacf84e
MD
1953 }
1954 else if (SCM_BIGP (n))
1955 {
1956 /* mpz_sizeinbase looks at the absolute value of negatives, whereas we
1957 want a ones-complement. If n is ...111100..00 then mpz_sizeinbase is
1958 1 too big, so check for that and adjust. */
1959 size_t size = mpz_sizeinbase (SCM_I_BIG_MPZ (n), 2);
1960 if (mpz_sgn (SCM_I_BIG_MPZ (n)) < 0
1961 && mpz_scan0 (SCM_I_BIG_MPZ (n), /* no 0 bits above the lowest 1 */
1962 mpz_scan1 (SCM_I_BIG_MPZ (n), 0)) == ULONG_MAX)
1963 size--;
1964 scm_remember_upto_here_1 (n);
d956fa6f 1965 return SCM_I_MAKINUM (size);
0aacf84e
MD
1966 }
1967 else
ca46fb90 1968 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
ca46fb90
RB
1969}
1970#undef FUNC_NAME
0f2d19dd
JB
1971
1972/*** NUMBERS -> STRINGS ***/
0b799eea
MV
1973#define SCM_MAX_DBL_PREC 60
1974#define SCM_MAX_DBL_RADIX 36
1975
1976/* this is an array starting with radix 2, and ending with radix SCM_MAX_DBL_RADIX */
1977static int scm_dblprec[SCM_MAX_DBL_RADIX - 1];
1978static double fx_per_radix[SCM_MAX_DBL_RADIX - 1][SCM_MAX_DBL_PREC];
1979
1980static
1981void init_dblprec(int *prec, int radix) {
1982 /* determine floating point precision by adding successively
1983 smaller increments to 1.0 until it is considered == 1.0 */
1984 double f = ((double)1.0)/radix;
1985 double fsum = 1.0 + f;
1986
1987 *prec = 0;
1988 while (fsum != 1.0)
1989 {
1990 if (++(*prec) > SCM_MAX_DBL_PREC)
1991 fsum = 1.0;
1992 else
1993 {
1994 f /= radix;
1995 fsum = f + 1.0;
1996 }
1997 }
1998 (*prec) -= 1;
1999}
2000
2001static
2002void init_fx_radix(double *fx_list, int radix)
2003{
2004 /* initialize a per-radix list of tolerances. When added
2005 to a number < 1.0, we can determine if we should raund
2006 up and quit converting a number to a string. */
2007 int i;
2008 fx_list[0] = 0.0;
2009 fx_list[1] = 0.5;
2010 for( i = 2 ; i < SCM_MAX_DBL_PREC; ++i )
2011 fx_list[i] = (fx_list[i-1] / radix);
2012}
2013
2014/* use this array as a way to generate a single digit */
2015static const char*number_chars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
0f2d19dd 2016
1be6b49c 2017static size_t
0b799eea 2018idbl2str (double f, char *a, int radix)
0f2d19dd 2019{
0b799eea
MV
2020 int efmt, dpt, d, i, wp;
2021 double *fx;
2022#ifdef DBL_MIN_10_EXP
2023 double f_cpy;
2024 int exp_cpy;
2025#endif /* DBL_MIN_10_EXP */
2026 size_t ch = 0;
2027 int exp = 0;
2028
2029 if(radix < 2 ||
2030 radix > SCM_MAX_DBL_RADIX)
2031 {
2032 /* revert to existing behavior */
2033 radix = 10;
2034 }
2035
2036 wp = scm_dblprec[radix-2];
2037 fx = fx_per_radix[radix-2];
0f2d19dd 2038
f872b822 2039 if (f == 0.0)
abb7e44d
MV
2040 {
2041#ifdef HAVE_COPYSIGN
2042 double sgn = copysign (1.0, f);
2043
2044 if (sgn < 0.0)
2045 a[ch++] = '-';
2046#endif
abb7e44d
MV
2047 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
2048 }
7351e207
MV
2049
2050 if (xisinf (f))
2051 {
2052 if (f < 0)
2053 strcpy (a, "-inf.0");
2054 else
2055 strcpy (a, "+inf.0");
2056 return ch+6;
2057 }
2058 else if (xisnan (f))
2059 {
2060 strcpy (a, "+nan.0");
2061 return ch+6;
2062 }
2063
f872b822
MD
2064 if (f < 0.0)
2065 {
2066 f = -f;
2067 a[ch++] = '-';
2068 }
7351e207 2069
f872b822
MD
2070#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
2071 make-uniform-vector, from causing infinite loops. */
0b799eea
MV
2072 /* just do the checking...if it passes, we do the conversion for our
2073 radix again below */
2074 f_cpy = f;
2075 exp_cpy = exp;
2076
2077 while (f_cpy < 1.0)
f872b822 2078 {
0b799eea
MV
2079 f_cpy *= 10.0;
2080 if (exp_cpy-- < DBL_MIN_10_EXP)
7351e207
MV
2081 {
2082 a[ch++] = '#';
2083 a[ch++] = '.';
2084 a[ch++] = '#';
2085 return ch;
2086 }
f872b822 2087 }
0b799eea 2088 while (f_cpy > 10.0)
f872b822 2089 {
0b799eea
MV
2090 f_cpy *= 0.10;
2091 if (exp_cpy++ > DBL_MAX_10_EXP)
7351e207
MV
2092 {
2093 a[ch++] = '#';
2094 a[ch++] = '.';
2095 a[ch++] = '#';
2096 return ch;
2097 }
f872b822 2098 }
0b799eea
MV
2099#endif
2100
f872b822
MD
2101 while (f < 1.0)
2102 {
0b799eea 2103 f *= radix;
f872b822
MD
2104 exp--;
2105 }
0b799eea 2106 while (f > radix)
f872b822 2107 {
0b799eea 2108 f /= radix;
f872b822
MD
2109 exp++;
2110 }
0b799eea
MV
2111
2112 if (f + fx[wp] >= radix)
f872b822
MD
2113 {
2114 f = 1.0;
2115 exp++;
2116 }
0f2d19dd 2117 zero:
0b799eea
MV
2118#ifdef ENGNOT
2119 /* adding 9999 makes this equivalent to abs(x) % 3 */
f872b822 2120 dpt = (exp + 9999) % 3;
0f2d19dd
JB
2121 exp -= dpt++;
2122 efmt = 1;
f872b822
MD
2123#else
2124 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 2125 if (!efmt)
cda139a7
MD
2126 {
2127 if (exp < 0)
2128 {
2129 a[ch++] = '0';
2130 a[ch++] = '.';
2131 dpt = exp;
f872b822
MD
2132 while (++dpt)
2133 a[ch++] = '0';
cda139a7
MD
2134 }
2135 else
f872b822 2136 dpt = exp + 1;
cda139a7 2137 }
0f2d19dd
JB
2138 else
2139 dpt = 1;
f872b822
MD
2140#endif
2141
2142 do
2143 {
2144 d = f;
2145 f -= d;
0b799eea 2146 a[ch++] = number_chars[d];
f872b822
MD
2147 if (f < fx[wp])
2148 break;
2149 if (f + fx[wp] >= 1.0)
2150 {
0b799eea 2151 a[ch - 1] = number_chars[d+1];
f872b822
MD
2152 break;
2153 }
0b799eea 2154 f *= radix;
f872b822
MD
2155 if (!(--dpt))
2156 a[ch++] = '.';
0f2d19dd 2157 }
f872b822 2158 while (wp--);
0f2d19dd
JB
2159
2160 if (dpt > 0)
cda139a7 2161 {
f872b822 2162#ifndef ENGNOT
cda139a7
MD
2163 if ((dpt > 4) && (exp > 6))
2164 {
f872b822 2165 d = (a[0] == '-' ? 2 : 1);
cda139a7 2166 for (i = ch++; i > d; i--)
f872b822 2167 a[i] = a[i - 1];
cda139a7
MD
2168 a[d] = '.';
2169 efmt = 1;
2170 }
2171 else
f872b822 2172#endif
cda139a7 2173 {
f872b822
MD
2174 while (--dpt)
2175 a[ch++] = '0';
cda139a7
MD
2176 a[ch++] = '.';
2177 }
2178 }
f872b822
MD
2179 if (a[ch - 1] == '.')
2180 a[ch++] = '0'; /* trailing zero */
2181 if (efmt && exp)
2182 {
2183 a[ch++] = 'e';
2184 if (exp < 0)
2185 {
2186 exp = -exp;
2187 a[ch++] = '-';
2188 }
0b799eea
MV
2189 for (i = radix; i <= exp; i *= radix);
2190 for (i /= radix; i; i /= radix)
f872b822 2191 {
0b799eea 2192 a[ch++] = number_chars[exp / i];
f872b822
MD
2193 exp %= i;
2194 }
0f2d19dd 2195 }
0f2d19dd
JB
2196 return ch;
2197}
2198
7a1aba42
MV
2199
2200static size_t
2201icmplx2str (double real, double imag, char *str, int radix)
2202{
2203 size_t i;
2204
2205 i = idbl2str (real, str, radix);
2206 if (imag != 0.0)
2207 {
2208 /* Don't output a '+' for negative numbers or for Inf and
2209 NaN. They will provide their own sign. */
2210 if (0 <= imag && !xisinf (imag) && !xisnan (imag))
2211 str[i++] = '+';
2212 i += idbl2str (imag, &str[i], radix);
2213 str[i++] = 'i';
2214 }
2215 return i;
2216}
2217
1be6b49c 2218static size_t
0b799eea 2219iflo2str (SCM flt, char *str, int radix)
0f2d19dd 2220{
1be6b49c 2221 size_t i;
3c9a524f 2222 if (SCM_REALP (flt))
0b799eea 2223 i = idbl2str (SCM_REAL_VALUE (flt), str, radix);
0f2d19dd 2224 else
7a1aba42
MV
2225 i = icmplx2str (SCM_COMPLEX_REAL (flt), SCM_COMPLEX_IMAG (flt),
2226 str, radix);
0f2d19dd
JB
2227 return i;
2228}
0f2d19dd 2229
2881e77b 2230/* convert a scm_t_intmax to a string (unterminated). returns the number of
1bbd0b84
GB
2231 characters in the result.
2232 rad is output base
2233 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 2234size_t
2881e77b
MV
2235scm_iint2str (scm_t_intmax num, int rad, char *p)
2236{
2237 if (num < 0)
2238 {
2239 *p++ = '-';
2240 return scm_iuint2str (-num, rad, p) + 1;
2241 }
2242 else
2243 return scm_iuint2str (num, rad, p);
2244}
2245
2246/* convert a scm_t_intmax to a string (unterminated). returns the number of
2247 characters in the result.
2248 rad is output base
2249 p is destination: worst case (base 2) is SCM_INTBUFLEN */
2250size_t
2251scm_iuint2str (scm_t_uintmax num, int rad, char *p)
0f2d19dd 2252{
1be6b49c
ML
2253 size_t j = 1;
2254 size_t i;
2881e77b 2255 scm_t_uintmax n = num;
5c11cc9d 2256
f872b822 2257 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2258 j++;
2259
2260 i = j;
2881e77b 2261 n = num;
f872b822
MD
2262 while (i--)
2263 {
5c11cc9d
GH
2264 int d = n % rad;
2265
f872b822
MD
2266 n /= rad;
2267 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2268 }
0f2d19dd
JB
2269 return j;
2270}
2271
a1ec6916 2272SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
2273 (SCM n, SCM radix),
2274 "Return a string holding the external representation of the\n"
942e5b91
MG
2275 "number @var{n} in the given @var{radix}. If @var{n} is\n"
2276 "inexact, a radix of 10 will be used.")
1bbd0b84 2277#define FUNC_NAME s_scm_number_to_string
0f2d19dd 2278{
1bbd0b84 2279 int base;
98cb6e75 2280
0aacf84e 2281 if (SCM_UNBNDP (radix))
98cb6e75 2282 base = 10;
0aacf84e 2283 else
5efd3c7d 2284 base = scm_to_signed_integer (radix, 2, 36);
98cb6e75 2285
e11e83f3 2286 if (SCM_I_INUMP (n))
0aacf84e
MD
2287 {
2288 char num_buf [SCM_INTBUFLEN];
e11e83f3 2289 size_t length = scm_iint2str (SCM_I_INUM (n), base, num_buf);
cc95e00a 2290 return scm_from_locale_stringn (num_buf, length);
0aacf84e
MD
2291 }
2292 else if (SCM_BIGP (n))
2293 {
2294 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
2295 scm_remember_upto_here_1 (n);
cc95e00a 2296 return scm_take_locale_string (str);
0aacf84e 2297 }
f92e85f7
MV
2298 else if (SCM_FRACTIONP (n))
2299 {
2300 scm_i_fraction_reduce (n);
2301 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
cc95e00a 2302 scm_from_locale_string ("/"),
f92e85f7
MV
2303 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
2304 }
0aacf84e
MD
2305 else if (SCM_INEXACTP (n))
2306 {
2307 char num_buf [FLOBUFLEN];
cc95e00a 2308 return scm_from_locale_stringn (num_buf, iflo2str (n, num_buf, base));
0aacf84e
MD
2309 }
2310 else
bb628794 2311 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 2312}
1bbd0b84 2313#undef FUNC_NAME
0f2d19dd
JB
2314
2315
ca46fb90
RB
2316/* These print routines used to be stubbed here so that scm_repl.c
2317 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 2318
0f2d19dd 2319int
e81d98ec 2320scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2321{
56e55ac7 2322 char num_buf[FLOBUFLEN];
0b799eea 2323 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
0f2d19dd
JB
2324 return !0;
2325}
2326
b479fe9a
MV
2327void
2328scm_i_print_double (double val, SCM port)
2329{
2330 char num_buf[FLOBUFLEN];
2331 scm_lfwrite (num_buf, idbl2str (val, num_buf, 10), port);
2332}
2333
f3ae5d60 2334int
e81d98ec 2335scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 2336
f3ae5d60 2337{
56e55ac7 2338 char num_buf[FLOBUFLEN];
0b799eea 2339 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
f3ae5d60
MD
2340 return !0;
2341}
1cc91f1b 2342
7a1aba42
MV
2343void
2344scm_i_print_complex (double real, double imag, SCM port)
2345{
2346 char num_buf[FLOBUFLEN];
2347 scm_lfwrite (num_buf, icmplx2str (real, imag, num_buf, 10), port);
2348}
2349
f92e85f7
MV
2350int
2351scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
2352{
2353 SCM str;
2354 scm_i_fraction_reduce (sexp);
2355 str = scm_number_to_string (sexp, SCM_UNDEFINED);
cc95e00a 2356 scm_lfwrite (scm_i_string_chars (str), scm_i_string_length (str), port);
f92e85f7
MV
2357 scm_remember_upto_here_1 (str);
2358 return !0;
2359}
2360
0f2d19dd 2361int
e81d98ec 2362scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2363{
ca46fb90
RB
2364 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
2365 scm_remember_upto_here_1 (exp);
2366 scm_lfwrite (str, (size_t) strlen (str), port);
2367 free (str);
0f2d19dd
JB
2368 return !0;
2369}
2370/*** END nums->strs ***/
2371
3c9a524f 2372
0f2d19dd 2373/*** STRINGS -> NUMBERS ***/
2a8fecee 2374
3c9a524f
DH
2375/* The following functions implement the conversion from strings to numbers.
2376 * The implementation somehow follows the grammar for numbers as it is given
2377 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
2378 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
2379 * points should be noted about the implementation:
2380 * * Each function keeps a local index variable 'idx' that points at the
2381 * current position within the parsed string. The global index is only
2382 * updated if the function could parse the corresponding syntactic unit
2383 * successfully.
2384 * * Similarly, the functions keep track of indicators of inexactness ('#',
2385 * '.' or exponents) using local variables ('hash_seen', 'x'). Again, the
2386 * global exactness information is only updated after each part has been
2387 * successfully parsed.
2388 * * Sequences of digits are parsed into temporary variables holding fixnums.
2389 * Only if these fixnums would overflow, the result variables are updated
2390 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
2391 * the temporary variables holding the fixnums are cleared, and the process
2392 * starts over again. If for example fixnums were able to store five decimal
2393 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
2394 * and the result was computed as 12345 * 100000 + 67890. In other words,
2395 * only every five digits two bignum operations were performed.
2396 */
2397
2398enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
2399
2400/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
2401
2402/* In non ASCII-style encodings the following macro might not work. */
71df73ac
KR
2403#define XDIGIT2UINT(d) \
2404 (isdigit ((int) (unsigned char) d) \
2405 ? (d) - '0' \
2406 : tolower ((int) (unsigned char) d) - 'a' + 10)
3c9a524f 2407
2a8fecee 2408static SCM
3c9a524f
DH
2409mem2uinteger (const char* mem, size_t len, unsigned int *p_idx,
2410 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 2411{
3c9a524f
DH
2412 unsigned int idx = *p_idx;
2413 unsigned int hash_seen = 0;
2414 scm_t_bits shift = 1;
2415 scm_t_bits add = 0;
2416 unsigned int digit_value;
2417 SCM result;
2418 char c;
2419
2420 if (idx == len)
2421 return SCM_BOOL_F;
2a8fecee 2422
3c9a524f 2423 c = mem[idx];
71df73ac 2424 if (!isxdigit ((int) (unsigned char) c))
3c9a524f
DH
2425 return SCM_BOOL_F;
2426 digit_value = XDIGIT2UINT (c);
2427 if (digit_value >= radix)
2428 return SCM_BOOL_F;
2429
2430 idx++;
d956fa6f 2431 result = SCM_I_MAKINUM (digit_value);
3c9a524f 2432 while (idx != len)
f872b822 2433 {
3c9a524f 2434 char c = mem[idx];
71df73ac 2435 if (isxdigit ((int) (unsigned char) c))
f872b822 2436 {
3c9a524f 2437 if (hash_seen)
1fe5e088 2438 break;
3c9a524f
DH
2439 digit_value = XDIGIT2UINT (c);
2440 if (digit_value >= radix)
1fe5e088 2441 break;
f872b822 2442 }
3c9a524f
DH
2443 else if (c == '#')
2444 {
2445 hash_seen = 1;
2446 digit_value = 0;
2447 }
2448 else
2449 break;
2450
2451 idx++;
2452 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
2453 {
d956fa6f 2454 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 2455 if (add > 0)
d956fa6f 2456 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2457
2458 shift = radix;
2459 add = digit_value;
2460 }
2461 else
2462 {
2463 shift = shift * radix;
2464 add = add * radix + digit_value;
2465 }
2466 };
2467
2468 if (shift > 1)
d956fa6f 2469 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 2470 if (add > 0)
d956fa6f 2471 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2472
2473 *p_idx = idx;
2474 if (hash_seen)
2475 *p_exactness = INEXACT;
2476
2477 return result;
2a8fecee
JB
2478}
2479
2480
3c9a524f
DH
2481/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
2482 * covers the parts of the rules that start at a potential point. The value
2483 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
2484 * in variable result. The content of *p_exactness indicates, whether a hash
2485 * has already been seen in the digits before the point.
3c9a524f 2486 */
1cc91f1b 2487
3c9a524f
DH
2488/* In non ASCII-style encodings the following macro might not work. */
2489#define DIGIT2UINT(d) ((d) - '0')
2490
2491static SCM
79d34f68 2492mem2decimal_from_point (SCM result, const char* mem, size_t len,
3c9a524f 2493 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 2494{
3c9a524f
DH
2495 unsigned int idx = *p_idx;
2496 enum t_exactness x = *p_exactness;
3c9a524f
DH
2497
2498 if (idx == len)
79d34f68 2499 return result;
3c9a524f
DH
2500
2501 if (mem[idx] == '.')
2502 {
2503 scm_t_bits shift = 1;
2504 scm_t_bits add = 0;
2505 unsigned int digit_value;
d956fa6f 2506 SCM big_shift = SCM_I_MAKINUM (1);
3c9a524f
DH
2507
2508 idx++;
2509 while (idx != len)
2510 {
2511 char c = mem[idx];
71df73ac 2512 if (isdigit ((int) (unsigned char) c))
3c9a524f
DH
2513 {
2514 if (x == INEXACT)
2515 return SCM_BOOL_F;
2516 else
2517 digit_value = DIGIT2UINT (c);
2518 }
2519 else if (c == '#')
2520 {
2521 x = INEXACT;
2522 digit_value = 0;
2523 }
2524 else
2525 break;
2526
2527 idx++;
2528 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
2529 {
d956fa6f
MV
2530 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
2531 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 2532 if (add > 0)
d956fa6f 2533 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2534
2535 shift = 10;
2536 add = digit_value;
2537 }
2538 else
2539 {
2540 shift = shift * 10;
2541 add = add * 10 + digit_value;
2542 }
2543 };
2544
2545 if (add > 0)
2546 {
d956fa6f
MV
2547 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
2548 result = scm_product (result, SCM_I_MAKINUM (shift));
2549 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2550 }
2551
d8592269 2552 result = scm_divide (result, big_shift);
79d34f68 2553
3c9a524f
DH
2554 /* We've seen a decimal point, thus the value is implicitly inexact. */
2555 x = INEXACT;
f872b822 2556 }
3c9a524f 2557
3c9a524f 2558 if (idx != len)
f872b822 2559 {
3c9a524f
DH
2560 int sign = 1;
2561 unsigned int start;
2562 char c;
2563 int exponent;
2564 SCM e;
2565
2566 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
2567
2568 switch (mem[idx])
f872b822 2569 {
3c9a524f
DH
2570 case 'd': case 'D':
2571 case 'e': case 'E':
2572 case 'f': case 'F':
2573 case 'l': case 'L':
2574 case 's': case 'S':
2575 idx++;
2576 start = idx;
2577 c = mem[idx];
2578 if (c == '-')
2579 {
2580 idx++;
2581 sign = -1;
2582 c = mem[idx];
2583 }
2584 else if (c == '+')
2585 {
2586 idx++;
2587 sign = 1;
2588 c = mem[idx];
2589 }
2590 else
2591 sign = 1;
2592
71df73ac 2593 if (!isdigit ((int) (unsigned char) c))
3c9a524f
DH
2594 return SCM_BOOL_F;
2595
2596 idx++;
2597 exponent = DIGIT2UINT (c);
2598 while (idx != len)
f872b822 2599 {
3c9a524f 2600 char c = mem[idx];
71df73ac 2601 if (isdigit ((int) (unsigned char) c))
3c9a524f
DH
2602 {
2603 idx++;
2604 if (exponent <= SCM_MAXEXP)
2605 exponent = exponent * 10 + DIGIT2UINT (c);
2606 }
2607 else
2608 break;
f872b822 2609 }
3c9a524f
DH
2610
2611 if (exponent > SCM_MAXEXP)
f872b822 2612 {
3c9a524f 2613 size_t exp_len = idx - start;
cc95e00a 2614 SCM exp_string = scm_from_locale_stringn (&mem[start], exp_len);
3c9a524f
DH
2615 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
2616 scm_out_of_range ("string->number", exp_num);
f872b822 2617 }
3c9a524f 2618
d956fa6f 2619 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
2620 if (sign == 1)
2621 result = scm_product (result, e);
2622 else
f92e85f7 2623 result = scm_divide2real (result, e);
3c9a524f
DH
2624
2625 /* We've seen an exponent, thus the value is implicitly inexact. */
2626 x = INEXACT;
2627
f872b822 2628 break;
3c9a524f 2629
f872b822 2630 default:
3c9a524f 2631 break;
f872b822 2632 }
0f2d19dd 2633 }
3c9a524f
DH
2634
2635 *p_idx = idx;
2636 if (x == INEXACT)
2637 *p_exactness = x;
2638
2639 return result;
0f2d19dd 2640}
0f2d19dd 2641
3c9a524f
DH
2642
2643/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
2644
2645static SCM
2646mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
2647 unsigned int radix, enum t_exactness *p_exactness)
0f2d19dd 2648{
3c9a524f 2649 unsigned int idx = *p_idx;
164d2481 2650 SCM result;
3c9a524f
DH
2651
2652 if (idx == len)
2653 return SCM_BOOL_F;
2654
7351e207
MV
2655 if (idx+5 <= len && !strncmp (mem+idx, "inf.0", 5))
2656 {
2657 *p_idx = idx+5;
2658 return scm_inf ();
2659 }
2660
2661 if (idx+4 < len && !strncmp (mem+idx, "nan.", 4))
2662 {
2663 enum t_exactness x = EXACT;
2664
d8592269
MV
2665 /* Cobble up the fractional part. We might want to set the
2666 NaN's mantissa from it. */
7351e207
MV
2667 idx += 4;
2668 mem2uinteger (mem, len, &idx, 10, &x);
2669 *p_idx = idx;
2670 return scm_nan ();
2671 }
2672
3c9a524f
DH
2673 if (mem[idx] == '.')
2674 {
2675 if (radix != 10)
2676 return SCM_BOOL_F;
2677 else if (idx + 1 == len)
2678 return SCM_BOOL_F;
71df73ac 2679 else if (!isdigit ((int) (unsigned char) mem[idx + 1]))
3c9a524f
DH
2680 return SCM_BOOL_F;
2681 else
d956fa6f 2682 result = mem2decimal_from_point (SCM_I_MAKINUM (0), mem, len,
164d2481 2683 p_idx, p_exactness);
f872b822 2684 }
3c9a524f
DH
2685 else
2686 {
2687 enum t_exactness x = EXACT;
2688 SCM uinteger;
3c9a524f
DH
2689
2690 uinteger = mem2uinteger (mem, len, &idx, radix, &x);
73e4de09 2691 if (scm_is_false (uinteger))
3c9a524f
DH
2692 return SCM_BOOL_F;
2693
2694 if (idx == len)
2695 result = uinteger;
2696 else if (mem[idx] == '/')
f872b822 2697 {
3c9a524f
DH
2698 SCM divisor;
2699
2700 idx++;
2701
2702 divisor = mem2uinteger (mem, len, &idx, radix, &x);
73e4de09 2703 if (scm_is_false (divisor))
3c9a524f
DH
2704 return SCM_BOOL_F;
2705
f92e85f7 2706 /* both are int/big here, I assume */
cba42c93 2707 result = scm_i_make_ratio (uinteger, divisor);
f872b822 2708 }
3c9a524f
DH
2709 else if (radix == 10)
2710 {
2711 result = mem2decimal_from_point (uinteger, mem, len, &idx, &x);
73e4de09 2712 if (scm_is_false (result))
3c9a524f
DH
2713 return SCM_BOOL_F;
2714 }
2715 else
2716 result = uinteger;
2717
2718 *p_idx = idx;
2719 if (x == INEXACT)
2720 *p_exactness = x;
f872b822 2721 }
164d2481
MV
2722
2723 /* When returning an inexact zero, make sure it is represented as a
2724 floating point value so that we can change its sign.
2725 */
bc36d050 2726 if (scm_is_eq (result, SCM_I_MAKINUM(0)) && *p_exactness == INEXACT)
55f26379 2727 result = scm_from_double (0.0);
164d2481
MV
2728
2729 return result;
3c9a524f 2730}
0f2d19dd 2731
0f2d19dd 2732
3c9a524f 2733/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 2734
3c9a524f
DH
2735static SCM
2736mem2complex (const char* mem, size_t len, unsigned int idx,
2737 unsigned int radix, enum t_exactness *p_exactness)
2738{
2739 char c;
2740 int sign = 0;
2741 SCM ureal;
2742
2743 if (idx == len)
2744 return SCM_BOOL_F;
2745
2746 c = mem[idx];
2747 if (c == '+')
2748 {
2749 idx++;
2750 sign = 1;
2751 }
2752 else if (c == '-')
2753 {
2754 idx++;
2755 sign = -1;
0f2d19dd 2756 }
0f2d19dd 2757
3c9a524f
DH
2758 if (idx == len)
2759 return SCM_BOOL_F;
2760
2761 ureal = mem2ureal (mem, len, &idx, radix, p_exactness);
73e4de09 2762 if (scm_is_false (ureal))
f872b822 2763 {
3c9a524f
DH
2764 /* input must be either +i or -i */
2765
2766 if (sign == 0)
2767 return SCM_BOOL_F;
2768
2769 if (mem[idx] == 'i' || mem[idx] == 'I')
f872b822 2770 {
3c9a524f
DH
2771 idx++;
2772 if (idx != len)
2773 return SCM_BOOL_F;
2774
d956fa6f 2775 return scm_make_rectangular (SCM_I_MAKINUM (0), SCM_I_MAKINUM (sign));
f872b822 2776 }
3c9a524f
DH
2777 else
2778 return SCM_BOOL_F;
0f2d19dd 2779 }
3c9a524f
DH
2780 else
2781 {
73e4de09 2782 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 2783 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 2784
3c9a524f
DH
2785 if (idx == len)
2786 return ureal;
2787
2788 c = mem[idx];
2789 switch (c)
f872b822 2790 {
3c9a524f
DH
2791 case 'i': case 'I':
2792 /* either +<ureal>i or -<ureal>i */
2793
2794 idx++;
2795 if (sign == 0)
2796 return SCM_BOOL_F;
2797 if (idx != len)
2798 return SCM_BOOL_F;
d956fa6f 2799 return scm_make_rectangular (SCM_I_MAKINUM (0), ureal);
3c9a524f
DH
2800
2801 case '@':
2802 /* polar input: <real>@<real>. */
2803
2804 idx++;
2805 if (idx == len)
2806 return SCM_BOOL_F;
2807 else
f872b822 2808 {
3c9a524f
DH
2809 int sign;
2810 SCM angle;
2811 SCM result;
2812
2813 c = mem[idx];
2814 if (c == '+')
2815 {
2816 idx++;
2817 sign = 1;
2818 }
2819 else if (c == '-')
2820 {
2821 idx++;
2822 sign = -1;
2823 }
2824 else
2825 sign = 1;
2826
2827 angle = mem2ureal (mem, len, &idx, radix, p_exactness);
73e4de09 2828 if (scm_is_false (angle))
3c9a524f
DH
2829 return SCM_BOOL_F;
2830 if (idx != len)
2831 return SCM_BOOL_F;
2832
73e4de09 2833 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
2834 angle = scm_difference (angle, SCM_UNDEFINED);
2835
2836 result = scm_make_polar (ureal, angle);
2837 return result;
f872b822 2838 }
3c9a524f
DH
2839 case '+':
2840 case '-':
2841 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 2842
3c9a524f
DH
2843 idx++;
2844 if (idx == len)
2845 return SCM_BOOL_F;
2846 else
2847 {
2848 int sign = (c == '+') ? 1 : -1;
2849 SCM imag = mem2ureal (mem, len, &idx, radix, p_exactness);
0f2d19dd 2850
73e4de09 2851 if (scm_is_false (imag))
d956fa6f 2852 imag = SCM_I_MAKINUM (sign);
73e4de09 2853 else if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
1fe5e088 2854 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 2855
3c9a524f
DH
2856 if (idx == len)
2857 return SCM_BOOL_F;
2858 if (mem[idx] != 'i' && mem[idx] != 'I')
2859 return SCM_BOOL_F;
0f2d19dd 2860
3c9a524f
DH
2861 idx++;
2862 if (idx != len)
2863 return SCM_BOOL_F;
0f2d19dd 2864
1fe5e088 2865 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
2866 }
2867 default:
2868 return SCM_BOOL_F;
2869 }
2870 }
0f2d19dd 2871}
0f2d19dd
JB
2872
2873
3c9a524f
DH
2874/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
2875
2876enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 2877
0f2d19dd 2878SCM
3c9a524f 2879scm_i_mem2number (const char* mem, size_t len, unsigned int default_radix)
0f2d19dd 2880{
3c9a524f
DH
2881 unsigned int idx = 0;
2882 unsigned int radix = NO_RADIX;
2883 enum t_exactness forced_x = NO_EXACTNESS;
2884 enum t_exactness implicit_x = EXACT;
2885 SCM result;
2886
2887 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
2888 while (idx + 2 < len && mem[idx] == '#')
2889 {
2890 switch (mem[idx + 1])
2891 {
2892 case 'b': case 'B':
2893 if (radix != NO_RADIX)
2894 return SCM_BOOL_F;
2895 radix = DUAL;
2896 break;
2897 case 'd': case 'D':
2898 if (radix != NO_RADIX)
2899 return SCM_BOOL_F;
2900 radix = DEC;
2901 break;
2902 case 'i': case 'I':
2903 if (forced_x != NO_EXACTNESS)
2904 return SCM_BOOL_F;
2905 forced_x = INEXACT;
2906 break;
2907 case 'e': case 'E':
2908 if (forced_x != NO_EXACTNESS)
2909 return SCM_BOOL_F;
2910 forced_x = EXACT;
2911 break;
2912 case 'o': case 'O':
2913 if (radix != NO_RADIX)
2914 return SCM_BOOL_F;
2915 radix = OCT;
2916 break;
2917 case 'x': case 'X':
2918 if (radix != NO_RADIX)
2919 return SCM_BOOL_F;
2920 radix = HEX;
2921 break;
2922 default:
f872b822 2923 return SCM_BOOL_F;
3c9a524f
DH
2924 }
2925 idx += 2;
2926 }
2927
2928 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
2929 if (radix == NO_RADIX)
2930 result = mem2complex (mem, len, idx, default_radix, &implicit_x);
2931 else
2932 result = mem2complex (mem, len, idx, (unsigned int) radix, &implicit_x);
2933
73e4de09 2934 if (scm_is_false (result))
3c9a524f 2935 return SCM_BOOL_F;
f872b822 2936
3c9a524f 2937 switch (forced_x)
f872b822 2938 {
3c9a524f
DH
2939 case EXACT:
2940 if (SCM_INEXACTP (result))
3c9a524f
DH
2941 return scm_inexact_to_exact (result);
2942 else
2943 return result;
2944 case INEXACT:
2945 if (SCM_INEXACTP (result))
2946 return result;
2947 else
2948 return scm_exact_to_inexact (result);
2949 case NO_EXACTNESS:
2950 default:
2951 if (implicit_x == INEXACT)
2952 {
2953 if (SCM_INEXACTP (result))
2954 return result;
2955 else
2956 return scm_exact_to_inexact (result);
2957 }
2958 else
2959 return result;
f872b822 2960 }
0f2d19dd
JB
2961}
2962
2963
a1ec6916 2964SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 2965 (SCM string, SCM radix),
1e6808ea 2966 "Return a number of the maximally precise representation\n"
942e5b91 2967 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
2968 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
2969 "is a default radix that may be overridden by an explicit radix\n"
2970 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
2971 "supplied, then the default radix is 10. If string is not a\n"
2972 "syntactically valid notation for a number, then\n"
2973 "@code{string->number} returns @code{#f}.")
1bbd0b84 2974#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2975{
2976 SCM answer;
5efd3c7d 2977 unsigned int base;
a6d9e5ab 2978 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
2979
2980 if (SCM_UNBNDP (radix))
2981 base = 10;
2982 else
2983 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
2984
cc95e00a
MV
2985 answer = scm_i_mem2number (scm_i_string_chars (string),
2986 scm_i_string_length (string),
d8592269 2987 base);
8824ac88
MV
2988 scm_remember_upto_here_1 (string);
2989 return answer;
0f2d19dd 2990}
1bbd0b84 2991#undef FUNC_NAME
3c9a524f
DH
2992
2993
0f2d19dd
JB
2994/*** END strs->nums ***/
2995
5986c47d 2996
0f2d19dd 2997SCM
1bbd0b84 2998scm_bigequal (SCM x, SCM y)
0f2d19dd 2999{
47ae1f0e 3000 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
ca46fb90 3001 scm_remember_upto_here_2 (x, y);
73e4de09 3002 return scm_from_bool (0 == result);
0f2d19dd
JB
3003}
3004
0f2d19dd 3005SCM
f3ae5d60 3006scm_real_equalp (SCM x, SCM y)
0f2d19dd 3007{
73e4de09 3008 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
3009}
3010
f3ae5d60
MD
3011SCM
3012scm_complex_equalp (SCM x, SCM y)
3013{
73e4de09 3014 return scm_from_bool (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
f3ae5d60
MD
3015 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
3016}
0f2d19dd 3017
f92e85f7
MV
3018SCM
3019scm_i_fraction_equalp (SCM x, SCM y)
3020{
3021 scm_i_fraction_reduce (x);
3022 scm_i_fraction_reduce (y);
73e4de09 3023 if (scm_is_false (scm_equal_p (SCM_FRACTION_NUMERATOR (x),
02164269 3024 SCM_FRACTION_NUMERATOR (y)))
73e4de09 3025 || scm_is_false (scm_equal_p (SCM_FRACTION_DENOMINATOR (x),
02164269
MV
3026 SCM_FRACTION_DENOMINATOR (y))))
3027 return SCM_BOOL_F;
3028 else
3029 return SCM_BOOL_T;
f92e85f7 3030}
0f2d19dd
JB
3031
3032
8507ec80
MV
3033SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
3034 (SCM x),
3035 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
3036 "otherwise.")
3037#define FUNC_NAME s_scm_number_p
3038{
3039 return scm_from_bool (SCM_NUMBERP (x));
3040}
3041#undef FUNC_NAME
3042
3043SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 3044 (SCM x),
942e5b91 3045 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 3046 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
3047 "values form subsets of the set of complex numbers, i. e. the\n"
3048 "predicate will also be fulfilled if @var{x} is a real,\n"
3049 "rational or integer number.")
8507ec80 3050#define FUNC_NAME s_scm_complex_p
0f2d19dd 3051{
8507ec80
MV
3052 /* all numbers are complex. */
3053 return scm_number_p (x);
0f2d19dd 3054}
1bbd0b84 3055#undef FUNC_NAME
0f2d19dd 3056
f92e85f7
MV
3057SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
3058 (SCM x),
3059 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
3060 "otherwise. Note that the set of integer values forms a subset of\n"
3061 "the set of real numbers, i. e. the predicate will also be\n"
3062 "fulfilled if @var{x} is an integer number.")
3063#define FUNC_NAME s_scm_real_p
3064{
3065 /* we can't represent irrational numbers. */
3066 return scm_rational_p (x);
3067}
3068#undef FUNC_NAME
3069
3070SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 3071 (SCM x),
942e5b91 3072 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 3073 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 3074 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
3075 "fulfilled if @var{x} is an integer number.")
3076#define FUNC_NAME s_scm_rational_p
0f2d19dd 3077{
e11e83f3 3078 if (SCM_I_INUMP (x))
0f2d19dd 3079 return SCM_BOOL_T;
0aacf84e 3080 else if (SCM_IMP (x))
0f2d19dd 3081 return SCM_BOOL_F;
0aacf84e 3082 else if (SCM_BIGP (x))
0f2d19dd 3083 return SCM_BOOL_T;
f92e85f7
MV
3084 else if (SCM_FRACTIONP (x))
3085 return SCM_BOOL_T;
3086 else if (SCM_REALP (x))
3087 /* due to their limited precision, all floating point numbers are
3088 rational as well. */
3089 return SCM_BOOL_T;
0aacf84e 3090 else
bb628794 3091 return SCM_BOOL_F;
0f2d19dd 3092}
1bbd0b84 3093#undef FUNC_NAME
0f2d19dd 3094
a1ec6916 3095SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 3096 (SCM x),
942e5b91
MG
3097 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
3098 "else.")
1bbd0b84 3099#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
3100{
3101 double r;
e11e83f3 3102 if (SCM_I_INUMP (x))
f872b822
MD
3103 return SCM_BOOL_T;
3104 if (SCM_IMP (x))
3105 return SCM_BOOL_F;
f872b822
MD
3106 if (SCM_BIGP (x))
3107 return SCM_BOOL_T;
3c9a524f 3108 if (!SCM_INEXACTP (x))
f872b822 3109 return SCM_BOOL_F;
3c9a524f 3110 if (SCM_COMPLEXP (x))
f872b822 3111 return SCM_BOOL_F;
5986c47d 3112 r = SCM_REAL_VALUE (x);
1e35a229 3113 /* +/-inf passes r==floor(r), making those #t */
f872b822
MD
3114 if (r == floor (r))
3115 return SCM_BOOL_T;
0f2d19dd
JB
3116 return SCM_BOOL_F;
3117}
1bbd0b84 3118#undef FUNC_NAME
0f2d19dd
JB
3119
3120
a1ec6916 3121SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 3122 (SCM x),
942e5b91
MG
3123 "Return @code{#t} if @var{x} is an inexact number, @code{#f}\n"
3124 "else.")
1bbd0b84 3125#define FUNC_NAME s_scm_inexact_p
0f2d19dd 3126{
eb927cb9
MV
3127 if (SCM_INEXACTP (x))
3128 return SCM_BOOL_T;
3129 if (SCM_NUMBERP (x))
3130 return SCM_BOOL_F;
3131 SCM_WRONG_TYPE_ARG (1, x);
0f2d19dd 3132}
1bbd0b84 3133#undef FUNC_NAME
0f2d19dd
JB
3134
3135
152f82bf 3136SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
942e5b91 3137/* "Return @code{#t} if all parameters are numerically equal." */
0f2d19dd 3138SCM
6e8d25a6 3139scm_num_eq_p (SCM x, SCM y)
0f2d19dd 3140{
d8b95e27 3141 again:
e11e83f3 3142 if (SCM_I_INUMP (x))
0aacf84e 3143 {
e11e83f3
MV
3144 long xx = SCM_I_INUM (x);
3145 if (SCM_I_INUMP (y))
0aacf84e 3146 {
e11e83f3 3147 long yy = SCM_I_INUM (y);
73e4de09 3148 return scm_from_bool (xx == yy);
0aacf84e
MD
3149 }
3150 else if (SCM_BIGP (y))
3151 return SCM_BOOL_F;
3152 else if (SCM_REALP (y))
73e4de09 3153 return scm_from_bool ((double) xx == SCM_REAL_VALUE (y));
0aacf84e 3154 else if (SCM_COMPLEXP (y))
73e4de09 3155 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 3156 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
3157 else if (SCM_FRACTIONP (y))
3158 return SCM_BOOL_F;
0aacf84e
MD
3159 else
3160 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3161 }
0aacf84e
MD
3162 else if (SCM_BIGP (x))
3163 {
e11e83f3 3164 if (SCM_I_INUMP (y))
0aacf84e
MD
3165 return SCM_BOOL_F;
3166 else if (SCM_BIGP (y))
3167 {
3168 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3169 scm_remember_upto_here_2 (x, y);
73e4de09 3170 return scm_from_bool (0 == cmp);
0aacf84e
MD
3171 }
3172 else if (SCM_REALP (y))
3173 {
3174 int cmp;
3175 if (xisnan (SCM_REAL_VALUE (y)))
3176 return SCM_BOOL_F;
3177 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
3178 scm_remember_upto_here_1 (x);
73e4de09 3179 return scm_from_bool (0 == cmp);
0aacf84e
MD
3180 }
3181 else if (SCM_COMPLEXP (y))
3182 {
3183 int cmp;
3184 if (0.0 != SCM_COMPLEX_IMAG (y))
3185 return SCM_BOOL_F;
3186 if (xisnan (SCM_COMPLEX_REAL (y)))
3187 return SCM_BOOL_F;
3188 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
3189 scm_remember_upto_here_1 (x);
73e4de09 3190 return scm_from_bool (0 == cmp);
0aacf84e 3191 }
f92e85f7
MV
3192 else if (SCM_FRACTIONP (y))
3193 return SCM_BOOL_F;
0aacf84e
MD
3194 else
3195 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f4c627b3 3196 }
0aacf84e
MD
3197 else if (SCM_REALP (x))
3198 {
e11e83f3
MV
3199 if (SCM_I_INUMP (y))
3200 return scm_from_bool (SCM_REAL_VALUE (x) == (double) SCM_I_INUM (y));
0aacf84e
MD
3201 else if (SCM_BIGP (y))
3202 {
3203 int cmp;
3204 if (xisnan (SCM_REAL_VALUE (x)))
3205 return SCM_BOOL_F;
3206 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
3207 scm_remember_upto_here_1 (y);
73e4de09 3208 return scm_from_bool (0 == cmp);
0aacf84e
MD
3209 }
3210 else if (SCM_REALP (y))
73e4de09 3211 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 3212 else if (SCM_COMPLEXP (y))
73e4de09 3213 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 3214 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 3215 else if (SCM_FRACTIONP (y))
d8b95e27
KR
3216 {
3217 double xx = SCM_REAL_VALUE (x);
3218 if (xisnan (xx))
3219 return SCM_BOOL_F;
3220 if (xisinf (xx))
73e4de09 3221 return scm_from_bool (xx < 0.0);
d8b95e27
KR
3222 x = scm_inexact_to_exact (x); /* with x as frac or int */
3223 goto again;
3224 }
0aacf84e
MD
3225 else
3226 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3227 }
0aacf84e
MD
3228 else if (SCM_COMPLEXP (x))
3229 {
e11e83f3
MV
3230 if (SCM_I_INUMP (y))
3231 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
3232 && (SCM_COMPLEX_IMAG (x) == 0.0));
3233 else if (SCM_BIGP (y))
3234 {
3235 int cmp;
3236 if (0.0 != SCM_COMPLEX_IMAG (x))
3237 return SCM_BOOL_F;
3238 if (xisnan (SCM_COMPLEX_REAL (x)))
3239 return SCM_BOOL_F;
3240 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
3241 scm_remember_upto_here_1 (y);
73e4de09 3242 return scm_from_bool (0 == cmp);
0aacf84e
MD
3243 }
3244 else if (SCM_REALP (y))
73e4de09 3245 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
3246 && (SCM_COMPLEX_IMAG (x) == 0.0));
3247 else if (SCM_COMPLEXP (y))
73e4de09 3248 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 3249 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 3250 else if (SCM_FRACTIONP (y))
d8b95e27
KR
3251 {
3252 double xx;
3253 if (SCM_COMPLEX_IMAG (x) != 0.0)
3254 return SCM_BOOL_F;
3255 xx = SCM_COMPLEX_REAL (x);
3256 if (xisnan (xx))
3257 return SCM_BOOL_F;
3258 if (xisinf (xx))
73e4de09 3259 return scm_from_bool (xx < 0.0);
d8b95e27
KR
3260 x = scm_inexact_to_exact (x); /* with x as frac or int */
3261 goto again;
3262 }
f92e85f7
MV
3263 else
3264 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3265 }
3266 else if (SCM_FRACTIONP (x))
3267 {
e11e83f3 3268 if (SCM_I_INUMP (y))
f92e85f7
MV
3269 return SCM_BOOL_F;
3270 else if (SCM_BIGP (y))
3271 return SCM_BOOL_F;
3272 else if (SCM_REALP (y))
d8b95e27
KR
3273 {
3274 double yy = SCM_REAL_VALUE (y);
3275 if (xisnan (yy))
3276 return SCM_BOOL_F;
3277 if (xisinf (yy))
73e4de09 3278 return scm_from_bool (0.0 < yy);
d8b95e27
KR
3279 y = scm_inexact_to_exact (y); /* with y as frac or int */
3280 goto again;
3281 }
f92e85f7 3282 else if (SCM_COMPLEXP (y))
d8b95e27
KR
3283 {
3284 double yy;
3285 if (SCM_COMPLEX_IMAG (y) != 0.0)
3286 return SCM_BOOL_F;
3287 yy = SCM_COMPLEX_REAL (y);
3288 if (xisnan (yy))
3289 return SCM_BOOL_F;
3290 if (xisinf (yy))
73e4de09 3291 return scm_from_bool (0.0 < yy);
d8b95e27
KR
3292 y = scm_inexact_to_exact (y); /* with y as frac or int */
3293 goto again;
3294 }
f92e85f7
MV
3295 else if (SCM_FRACTIONP (y))
3296 return scm_i_fraction_equalp (x, y);
0aacf84e
MD
3297 else
3298 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f4c627b3 3299 }
0aacf84e 3300 else
f4c627b3 3301 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
0f2d19dd
JB
3302}
3303
3304
a5f0b599
KR
3305/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
3306 done are good for inums, but for bignums an answer can almost always be
3307 had by just examining a few high bits of the operands, as done by GMP in
3308 mpq_cmp. flonum/frac compares likewise, but with the slight complication
3309 of the float exponent to take into account. */
3310
152f82bf 3311SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
942e5b91
MG
3312/* "Return @code{#t} if the list of parameters is monotonically\n"
3313 * "increasing."
3314 */
0f2d19dd 3315SCM
6e8d25a6 3316scm_less_p (SCM x, SCM y)
0f2d19dd 3317{
a5f0b599 3318 again:
e11e83f3 3319 if (SCM_I_INUMP (x))
0aacf84e 3320 {
e11e83f3
MV
3321 long xx = SCM_I_INUM (x);
3322 if (SCM_I_INUMP (y))
0aacf84e 3323 {
e11e83f3 3324 long yy = SCM_I_INUM (y);
73e4de09 3325 return scm_from_bool (xx < yy);
0aacf84e
MD
3326 }
3327 else if (SCM_BIGP (y))
3328 {
3329 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3330 scm_remember_upto_here_1 (y);
73e4de09 3331 return scm_from_bool (sgn > 0);
0aacf84e
MD
3332 }
3333 else if (SCM_REALP (y))
73e4de09 3334 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 3335 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3336 {
3337 /* "x < a/b" becomes "x*b < a" */
3338 int_frac:
3339 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
3340 y = SCM_FRACTION_NUMERATOR (y);
3341 goto again;
3342 }
0aacf84e
MD
3343 else
3344 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3345 }
0aacf84e
MD
3346 else if (SCM_BIGP (x))
3347 {
e11e83f3 3348 if (SCM_I_INUMP (y))
0aacf84e
MD
3349 {
3350 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3351 scm_remember_upto_here_1 (x);
73e4de09 3352 return scm_from_bool (sgn < 0);
0aacf84e
MD
3353 }
3354 else if (SCM_BIGP (y))
3355 {
3356 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3357 scm_remember_upto_here_2 (x, y);
73e4de09 3358 return scm_from_bool (cmp < 0);
0aacf84e
MD
3359 }
3360 else if (SCM_REALP (y))
3361 {
3362 int cmp;
3363 if (xisnan (SCM_REAL_VALUE (y)))
3364 return SCM_BOOL_F;
3365 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
3366 scm_remember_upto_here_1 (x);
73e4de09 3367 return scm_from_bool (cmp < 0);
0aacf84e 3368 }
f92e85f7 3369 else if (SCM_FRACTIONP (y))
a5f0b599 3370 goto int_frac;
0aacf84e
MD
3371 else
3372 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f4c627b3 3373 }
0aacf84e
MD
3374 else if (SCM_REALP (x))
3375 {
e11e83f3
MV
3376 if (SCM_I_INUMP (y))
3377 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
3378 else if (SCM_BIGP (y))
3379 {
3380 int cmp;
3381 if (xisnan (SCM_REAL_VALUE (x)))
3382 return SCM_BOOL_F;
3383 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
3384 scm_remember_upto_here_1 (y);
73e4de09 3385 return scm_from_bool (cmp > 0);
0aacf84e
MD
3386 }
3387 else if (SCM_REALP (y))
73e4de09 3388 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 3389 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3390 {
3391 double xx = SCM_REAL_VALUE (x);
3392 if (xisnan (xx))
3393 return SCM_BOOL_F;
3394 if (xisinf (xx))
73e4de09 3395 return scm_from_bool (xx < 0.0);
a5f0b599
KR
3396 x = scm_inexact_to_exact (x); /* with x as frac or int */
3397 goto again;
3398 }
f92e85f7
MV
3399 else
3400 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3401 }
3402 else if (SCM_FRACTIONP (x))
3403 {
e11e83f3 3404 if (SCM_I_INUMP (y) || SCM_BIGP (y))
a5f0b599
KR
3405 {
3406 /* "a/b < y" becomes "a < y*b" */
3407 y = scm_product (y, SCM_FRACTION_DENOMINATOR (x));
3408 x = SCM_FRACTION_NUMERATOR (x);
3409 goto again;
3410 }
f92e85f7 3411 else if (SCM_REALP (y))
a5f0b599
KR
3412 {
3413 double yy = SCM_REAL_VALUE (y);
3414 if (xisnan (yy))
3415 return SCM_BOOL_F;
3416 if (xisinf (yy))
73e4de09 3417 return scm_from_bool (0.0 < yy);
a5f0b599
KR
3418 y = scm_inexact_to_exact (y); /* with y as frac or int */
3419 goto again;
3420 }
f92e85f7 3421 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3422 {
3423 /* "a/b < c/d" becomes "a*d < c*b" */
3424 SCM new_x = scm_product (SCM_FRACTION_NUMERATOR (x),
3425 SCM_FRACTION_DENOMINATOR (y));
3426 SCM new_y = scm_product (SCM_FRACTION_NUMERATOR (y),
3427 SCM_FRACTION_DENOMINATOR (x));
3428 x = new_x;
3429 y = new_y;
3430 goto again;
3431 }
0aacf84e
MD
3432 else
3433 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3434 }
0aacf84e 3435 else
f4c627b3 3436 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
0f2d19dd
JB
3437}
3438
3439
c76b1eaf 3440SCM_GPROC1 (s_scm_gr_p, ">", scm_tc7_rpsubr, scm_gr_p, g_gr_p);
942e5b91
MG
3441/* "Return @code{#t} if the list of parameters is monotonically\n"
3442 * "decreasing."
c76b1eaf 3443 */
1bbd0b84 3444#define FUNC_NAME s_scm_gr_p
c76b1eaf
MD
3445SCM
3446scm_gr_p (SCM x, SCM y)
0f2d19dd 3447{
c76b1eaf
MD
3448 if (!SCM_NUMBERP (x))
3449 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG1, FUNC_NAME);
3450 else if (!SCM_NUMBERP (y))
3451 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG2, FUNC_NAME);
3452 else
3453 return scm_less_p (y, x);
0f2d19dd 3454}
1bbd0b84 3455#undef FUNC_NAME
0f2d19dd
JB
3456
3457
c76b1eaf 3458SCM_GPROC1 (s_scm_leq_p, "<=", scm_tc7_rpsubr, scm_leq_p, g_leq_p);
942e5b91 3459/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3460 * "non-decreasing."
3461 */
1bbd0b84 3462#define FUNC_NAME s_scm_leq_p
c76b1eaf
MD
3463SCM
3464scm_leq_p (SCM x, SCM y)
0f2d19dd 3465{
c76b1eaf
MD
3466 if (!SCM_NUMBERP (x))
3467 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG1, FUNC_NAME);
3468 else if (!SCM_NUMBERP (y))
3469 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 3470 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 3471 return SCM_BOOL_F;
c76b1eaf 3472 else
73e4de09 3473 return scm_not (scm_less_p (y, x));
0f2d19dd 3474}
1bbd0b84 3475#undef FUNC_NAME
0f2d19dd
JB
3476
3477
c76b1eaf 3478SCM_GPROC1 (s_scm_geq_p, ">=", scm_tc7_rpsubr, scm_geq_p, g_geq_p);
942e5b91 3479/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3480 * "non-increasing."
3481 */
1bbd0b84 3482#define FUNC_NAME s_scm_geq_p
c76b1eaf
MD
3483SCM
3484scm_geq_p (SCM x, SCM y)
0f2d19dd 3485{
c76b1eaf
MD
3486 if (!SCM_NUMBERP (x))
3487 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG1, FUNC_NAME);
3488 else if (!SCM_NUMBERP (y))
3489 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 3490 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 3491 return SCM_BOOL_F;
c76b1eaf 3492 else
73e4de09 3493 return scm_not (scm_less_p (x, y));
0f2d19dd 3494}
1bbd0b84 3495#undef FUNC_NAME
0f2d19dd
JB
3496
3497
152f82bf 3498SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
942e5b91
MG
3499/* "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
3500 * "zero."
3501 */
0f2d19dd 3502SCM
6e8d25a6 3503scm_zero_p (SCM z)
0f2d19dd 3504{
e11e83f3 3505 if (SCM_I_INUMP (z))
bc36d050 3506 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 3507 else if (SCM_BIGP (z))
c2ff8ab0 3508 return SCM_BOOL_F;
0aacf84e 3509 else if (SCM_REALP (z))
73e4de09 3510 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 3511 else if (SCM_COMPLEXP (z))
73e4de09 3512 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 3513 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
3514 else if (SCM_FRACTIONP (z))
3515 return SCM_BOOL_F;
0aacf84e 3516 else
c2ff8ab0 3517 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
0f2d19dd
JB
3518}
3519
3520
152f82bf 3521SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
942e5b91
MG
3522/* "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
3523 * "zero."
3524 */
0f2d19dd 3525SCM
6e8d25a6 3526scm_positive_p (SCM x)
0f2d19dd 3527{
e11e83f3
MV
3528 if (SCM_I_INUMP (x))
3529 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
3530 else if (SCM_BIGP (x))
3531 {
3532 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3533 scm_remember_upto_here_1 (x);
73e4de09 3534 return scm_from_bool (sgn > 0);
0aacf84e
MD
3535 }
3536 else if (SCM_REALP (x))
73e4de09 3537 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
3538 else if (SCM_FRACTIONP (x))
3539 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 3540 else
c2ff8ab0 3541 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
0f2d19dd
JB
3542}
3543
3544
152f82bf 3545SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
942e5b91
MG
3546/* "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
3547 * "zero."
3548 */
0f2d19dd 3549SCM
6e8d25a6 3550scm_negative_p (SCM x)
0f2d19dd 3551{
e11e83f3
MV
3552 if (SCM_I_INUMP (x))
3553 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
3554 else if (SCM_BIGP (x))
3555 {
3556 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3557 scm_remember_upto_here_1 (x);
73e4de09 3558 return scm_from_bool (sgn < 0);
0aacf84e
MD
3559 }
3560 else if (SCM_REALP (x))
73e4de09 3561 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
3562 else if (SCM_FRACTIONP (x))
3563 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 3564 else
c2ff8ab0 3565 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
0f2d19dd
JB
3566}
3567
3568
2a06f791
KR
3569/* scm_min and scm_max return an inexact when either argument is inexact, as
3570 required by r5rs. On that basis, for exact/inexact combinations the
3571 exact is converted to inexact to compare and possibly return. This is
3572 unlike scm_less_p above which takes some trouble to preserve all bits in
3573 its test, such trouble is not required for min and max. */
3574
9de33deb 3575SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
942e5b91
MG
3576/* "Return the maximum of all parameter values."
3577 */
0f2d19dd 3578SCM
6e8d25a6 3579scm_max (SCM x, SCM y)
0f2d19dd 3580{
0aacf84e
MD
3581 if (SCM_UNBNDP (y))
3582 {
3583 if (SCM_UNBNDP (x))
3584 SCM_WTA_DISPATCH_0 (g_max, s_max);
e11e83f3 3585 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
3586 return x;
3587 else
3588 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3589 }
f4c627b3 3590
e11e83f3 3591 if (SCM_I_INUMP (x))
0aacf84e 3592 {
e11e83f3
MV
3593 long xx = SCM_I_INUM (x);
3594 if (SCM_I_INUMP (y))
0aacf84e 3595 {
e11e83f3 3596 long yy = SCM_I_INUM (y);
0aacf84e
MD
3597 return (xx < yy) ? y : x;
3598 }
3599 else if (SCM_BIGP (y))
3600 {
3601 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3602 scm_remember_upto_here_1 (y);
3603 return (sgn < 0) ? x : y;
3604 }
3605 else if (SCM_REALP (y))
3606 {
3607 double z = xx;
3608 /* if y==NaN then ">" is false and we return NaN */
55f26379 3609 return (z > SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 3610 }
f92e85f7
MV
3611 else if (SCM_FRACTIONP (y))
3612 {
e4bc5d6c 3613 use_less:
73e4de09 3614 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 3615 }
0aacf84e
MD
3616 else
3617 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3618 }
0aacf84e
MD
3619 else if (SCM_BIGP (x))
3620 {
e11e83f3 3621 if (SCM_I_INUMP (y))
0aacf84e
MD
3622 {
3623 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3624 scm_remember_upto_here_1 (x);
3625 return (sgn < 0) ? y : x;
3626 }
3627 else if (SCM_BIGP (y))
3628 {
3629 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3630 scm_remember_upto_here_2 (x, y);
3631 return (cmp > 0) ? x : y;
3632 }
3633 else if (SCM_REALP (y))
3634 {
2a06f791
KR
3635 /* if y==NaN then xx>yy is false, so we return the NaN y */
3636 double xx, yy;
3637 big_real:
3638 xx = scm_i_big2dbl (x);
3639 yy = SCM_REAL_VALUE (y);
55f26379 3640 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 3641 }
f92e85f7
MV
3642 else if (SCM_FRACTIONP (y))
3643 {
e4bc5d6c 3644 goto use_less;
f92e85f7 3645 }
0aacf84e
MD
3646 else
3647 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 3648 }
0aacf84e
MD
3649 else if (SCM_REALP (x))
3650 {
e11e83f3 3651 if (SCM_I_INUMP (y))
0aacf84e 3652 {
e11e83f3 3653 double z = SCM_I_INUM (y);
0aacf84e 3654 /* if x==NaN then "<" is false and we return NaN */
55f26379 3655 return (SCM_REAL_VALUE (x) < z) ? scm_from_double (z) : x;
0aacf84e
MD
3656 }
3657 else if (SCM_BIGP (y))
3658 {
b6f8f763 3659 SCM_SWAP (x, y);
2a06f791 3660 goto big_real;
0aacf84e
MD
3661 }
3662 else if (SCM_REALP (y))
3663 {
3664 /* if x==NaN then our explicit check means we return NaN
3665 if y==NaN then ">" is false and we return NaN
3666 calling isnan is unavoidable, since it's the only way to know
3667 which of x or y causes any compares to be false */
3668 double xx = SCM_REAL_VALUE (x);
3669 return (xisnan (xx) || xx > SCM_REAL_VALUE (y)) ? x : y;
3670 }
f92e85f7
MV
3671 else if (SCM_FRACTIONP (y))
3672 {
3673 double yy = scm_i_fraction2double (y);
3674 double xx = SCM_REAL_VALUE (x);
55f26379 3675 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
3676 }
3677 else
3678 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3679 }
3680 else if (SCM_FRACTIONP (x))
3681 {
e11e83f3 3682 if (SCM_I_INUMP (y))
f92e85f7 3683 {
e4bc5d6c 3684 goto use_less;
f92e85f7
MV
3685 }
3686 else if (SCM_BIGP (y))
3687 {
e4bc5d6c 3688 goto use_less;
f92e85f7
MV
3689 }
3690 else if (SCM_REALP (y))
3691 {
3692 double xx = scm_i_fraction2double (x);
55f26379 3693 return (xx < SCM_REAL_VALUE (y)) ? y : scm_from_double (xx);
f92e85f7
MV
3694 }
3695 else if (SCM_FRACTIONP (y))
3696 {
e4bc5d6c 3697 goto use_less;
f92e85f7 3698 }
0aacf84e
MD
3699 else
3700 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3701 }
0aacf84e 3702 else
f4c627b3 3703 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
3704}
3705
3706
9de33deb 3707SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
942e5b91
MG
3708/* "Return the minium of all parameter values."
3709 */
0f2d19dd 3710SCM
6e8d25a6 3711scm_min (SCM x, SCM y)
0f2d19dd 3712{
0aacf84e
MD
3713 if (SCM_UNBNDP (y))
3714 {
3715 if (SCM_UNBNDP (x))
3716 SCM_WTA_DISPATCH_0 (g_min, s_min);
e11e83f3 3717 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
3718 return x;
3719 else
3720 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3721 }
f4c627b3 3722
e11e83f3 3723 if (SCM_I_INUMP (x))
0aacf84e 3724 {
e11e83f3
MV
3725 long xx = SCM_I_INUM (x);
3726 if (SCM_I_INUMP (y))
0aacf84e 3727 {
e11e83f3 3728 long yy = SCM_I_INUM (y);
0aacf84e
MD
3729 return (xx < yy) ? x : y;
3730 }
3731 else if (SCM_BIGP (y))
3732 {
3733 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3734 scm_remember_upto_here_1 (y);
3735 return (sgn < 0) ? y : x;
3736 }
3737 else if (SCM_REALP (y))
3738 {
3739 double z = xx;
3740 /* if y==NaN then "<" is false and we return NaN */
55f26379 3741 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 3742 }
f92e85f7
MV
3743 else if (SCM_FRACTIONP (y))
3744 {
e4bc5d6c 3745 use_less:
73e4de09 3746 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 3747 }
0aacf84e
MD
3748 else
3749 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3750 }
0aacf84e
MD
3751 else if (SCM_BIGP (x))
3752 {
e11e83f3 3753 if (SCM_I_INUMP (y))
0aacf84e
MD
3754 {
3755 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3756 scm_remember_upto_here_1 (x);
3757 return (sgn < 0) ? x : y;
3758 }
3759 else if (SCM_BIGP (y))
3760 {
3761 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3762 scm_remember_upto_here_2 (x, y);
3763 return (cmp > 0) ? y : x;
3764 }
3765 else if (SCM_REALP (y))
3766 {
2a06f791
KR
3767 /* if y==NaN then xx<yy is false, so we return the NaN y */
3768 double xx, yy;
3769 big_real:
3770 xx = scm_i_big2dbl (x);
3771 yy = SCM_REAL_VALUE (y);
55f26379 3772 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 3773 }
f92e85f7
MV
3774 else if (SCM_FRACTIONP (y))
3775 {
e4bc5d6c 3776 goto use_less;
f92e85f7 3777 }
0aacf84e
MD
3778 else
3779 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 3780 }
0aacf84e
MD
3781 else if (SCM_REALP (x))
3782 {
e11e83f3 3783 if (SCM_I_INUMP (y))
0aacf84e 3784 {
e11e83f3 3785 double z = SCM_I_INUM (y);
0aacf84e 3786 /* if x==NaN then "<" is false and we return NaN */
55f26379 3787 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
3788 }
3789 else if (SCM_BIGP (y))
3790 {
b6f8f763 3791 SCM_SWAP (x, y);
2a06f791 3792 goto big_real;
0aacf84e
MD
3793 }
3794 else if (SCM_REALP (y))
3795 {
3796 /* if x==NaN then our explicit check means we return NaN
3797 if y==NaN then "<" is false and we return NaN
3798 calling isnan is unavoidable, since it's the only way to know
3799 which of x or y causes any compares to be false */
3800 double xx = SCM_REAL_VALUE (x);
3801 return (xisnan (xx) || xx < SCM_REAL_VALUE (y)) ? x : y;
3802 }
f92e85f7
MV
3803 else if (SCM_FRACTIONP (y))
3804 {
3805 double yy = scm_i_fraction2double (y);
3806 double xx = SCM_REAL_VALUE (x);
55f26379 3807 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 3808 }
0aacf84e
MD
3809 else
3810 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3811 }
f92e85f7
MV
3812 else if (SCM_FRACTIONP (x))
3813 {
e11e83f3 3814 if (SCM_I_INUMP (y))
f92e85f7 3815 {
e4bc5d6c 3816 goto use_less;
f92e85f7
MV
3817 }
3818 else if (SCM_BIGP (y))
3819 {
e4bc5d6c 3820 goto use_less;
f92e85f7
MV
3821 }
3822 else if (SCM_REALP (y))
3823 {
3824 double xx = scm_i_fraction2double (x);
55f26379 3825 return (SCM_REAL_VALUE (y) < xx) ? y : scm_from_double (xx);
f92e85f7
MV
3826 }
3827 else if (SCM_FRACTIONP (y))
3828 {
e4bc5d6c 3829 goto use_less;
f92e85f7
MV
3830 }
3831 else
3832 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3833 }
0aacf84e 3834 else
f4c627b3 3835 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
3836}
3837
3838
9de33deb 3839SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
942e5b91
MG
3840/* "Return the sum of all parameter values. Return 0 if called without\n"
3841 * "any parameters."
3842 */
0f2d19dd 3843SCM
6e8d25a6 3844scm_sum (SCM x, SCM y)
0f2d19dd 3845{
ca46fb90
RB
3846 if (SCM_UNBNDP (y))
3847 {
3848 if (SCM_NUMBERP (x)) return x;
3849 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 3850 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3851 }
c209c88e 3852
e11e83f3 3853 if (SCM_I_INUMP (x))
ca46fb90 3854 {
e11e83f3 3855 if (SCM_I_INUMP (y))
ca46fb90 3856 {
e11e83f3
MV
3857 long xx = SCM_I_INUM (x);
3858 long yy = SCM_I_INUM (y);
ca46fb90 3859 long int z = xx + yy;
d956fa6f 3860 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_long2big (z);
ca46fb90
RB
3861 }
3862 else if (SCM_BIGP (y))
3863 {
3864 SCM_SWAP (x, y);
3865 goto add_big_inum;
3866 }
3867 else if (SCM_REALP (y))
3868 {
e11e83f3 3869 long int xx = SCM_I_INUM (x);
55f26379 3870 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
3871 }
3872 else if (SCM_COMPLEXP (y))
3873 {
e11e83f3 3874 long int xx = SCM_I_INUM (x);
8507ec80 3875 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
3876 SCM_COMPLEX_IMAG (y));
3877 }
f92e85f7 3878 else if (SCM_FRACTIONP (y))
cba42c93 3879 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
3880 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
3881 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
3882 else
3883 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
3884 } else if (SCM_BIGP (x))
3885 {
e11e83f3 3886 if (SCM_I_INUMP (y))
0aacf84e
MD
3887 {
3888 long int inum;
3889 int bigsgn;
3890 add_big_inum:
e11e83f3 3891 inum = SCM_I_INUM (y);
0aacf84e
MD
3892 if (inum == 0)
3893 return x;
3894 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3895 if (inum < 0)
3896 {
3897 SCM result = scm_i_mkbig ();
3898 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
3899 scm_remember_upto_here_1 (x);
3900 /* we know the result will have to be a bignum */
3901 if (bigsgn == -1)
3902 return result;
3903 return scm_i_normbig (result);
3904 }
3905 else
3906 {
3907 SCM result = scm_i_mkbig ();
3908 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
3909 scm_remember_upto_here_1 (x);
3910 /* we know the result will have to be a bignum */
3911 if (bigsgn == 1)
3912 return result;
3913 return scm_i_normbig (result);
3914 }
3915 }
3916 else if (SCM_BIGP (y))
3917 {
3918 SCM result = scm_i_mkbig ();
3919 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
3920 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
3921 mpz_add (SCM_I_BIG_MPZ (result),
3922 SCM_I_BIG_MPZ (x),
3923 SCM_I_BIG_MPZ (y));
3924 scm_remember_upto_here_2 (x, y);
3925 /* we know the result will have to be a bignum */
3926 if (sgn_x == sgn_y)
3927 return result;
3928 return scm_i_normbig (result);
3929 }
3930 else if (SCM_REALP (y))
3931 {
3932 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
3933 scm_remember_upto_here_1 (x);
55f26379 3934 return scm_from_double (result);
0aacf84e
MD
3935 }
3936 else if (SCM_COMPLEXP (y))
3937 {
3938 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
3939 + SCM_COMPLEX_REAL (y));
3940 scm_remember_upto_here_1 (x);
8507ec80 3941 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 3942 }
f92e85f7 3943 else if (SCM_FRACTIONP (y))
cba42c93 3944 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
3945 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
3946 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
3947 else
3948 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 3949 }
0aacf84e
MD
3950 else if (SCM_REALP (x))
3951 {
e11e83f3 3952 if (SCM_I_INUMP (y))
55f26379 3953 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
3954 else if (SCM_BIGP (y))
3955 {
3956 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
3957 scm_remember_upto_here_1 (y);
55f26379 3958 return scm_from_double (result);
0aacf84e
MD
3959 }
3960 else if (SCM_REALP (y))
55f26379 3961 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 3962 else if (SCM_COMPLEXP (y))
8507ec80 3963 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 3964 SCM_COMPLEX_IMAG (y));
f92e85f7 3965 else if (SCM_FRACTIONP (y))
55f26379 3966 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
3967 else
3968 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3969 }
0aacf84e
MD
3970 else if (SCM_COMPLEXP (x))
3971 {
e11e83f3 3972 if (SCM_I_INUMP (y))
8507ec80 3973 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
3974 SCM_COMPLEX_IMAG (x));
3975 else if (SCM_BIGP (y))
3976 {
3977 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
3978 + SCM_COMPLEX_REAL (x));
3979 scm_remember_upto_here_1 (y);
8507ec80 3980 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
3981 }
3982 else if (SCM_REALP (y))
8507ec80 3983 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
3984 SCM_COMPLEX_IMAG (x));
3985 else if (SCM_COMPLEXP (y))
8507ec80 3986 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 3987 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 3988 else if (SCM_FRACTIONP (y))
8507ec80 3989 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
3990 SCM_COMPLEX_IMAG (x));
3991 else
3992 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3993 }
3994 else if (SCM_FRACTIONP (x))
3995 {
e11e83f3 3996 if (SCM_I_INUMP (y))
cba42c93 3997 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
3998 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
3999 SCM_FRACTION_DENOMINATOR (x));
4000 else if (SCM_BIGP (y))
cba42c93 4001 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4002 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
4003 SCM_FRACTION_DENOMINATOR (x));
4004 else if (SCM_REALP (y))
55f26379 4005 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 4006 else if (SCM_COMPLEXP (y))
8507ec80 4007 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
4008 SCM_COMPLEX_IMAG (y));
4009 else if (SCM_FRACTIONP (y))
4010 /* a/b + c/d = (ad + bc) / bd */
cba42c93 4011 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4012 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
4013 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4014 else
4015 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 4016 }
0aacf84e 4017 else
98cb6e75 4018 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
4019}
4020
4021
9de33deb 4022SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
609c3d30
MG
4023/* If called with one argument @var{z1}, -@var{z1} returned. Otherwise
4024 * the sum of all but the first argument are subtracted from the first
4025 * argument. */
c05e97b7 4026#define FUNC_NAME s_difference
0f2d19dd 4027SCM
6e8d25a6 4028scm_difference (SCM x, SCM y)
0f2d19dd 4029{
ca46fb90
RB
4030 if (SCM_UNBNDP (y))
4031 {
4032 if (SCM_UNBNDP (x))
4033 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
4034 else
e11e83f3 4035 if (SCM_I_INUMP (x))
ca46fb90 4036 {
e11e83f3 4037 long xx = -SCM_I_INUM (x);
ca46fb90 4038 if (SCM_FIXABLE (xx))
d956fa6f 4039 return SCM_I_MAKINUM (xx);
ca46fb90
RB
4040 else
4041 return scm_i_long2big (xx);
4042 }
4043 else if (SCM_BIGP (x))
4044 /* FIXME: do we really need to normalize here? */
4045 return scm_i_normbig (scm_i_clonebig (x, 0));
4046 else if (SCM_REALP (x))
55f26379 4047 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 4048 else if (SCM_COMPLEXP (x))
8507ec80 4049 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 4050 -SCM_COMPLEX_IMAG (x));
f92e85f7 4051 else if (SCM_FRACTIONP (x))
cba42c93 4052 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 4053 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
4054 else
4055 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 4056 }
ca46fb90 4057
e11e83f3 4058 if (SCM_I_INUMP (x))
0aacf84e 4059 {
e11e83f3 4060 if (SCM_I_INUMP (y))
0aacf84e 4061 {
e11e83f3
MV
4062 long int xx = SCM_I_INUM (x);
4063 long int yy = SCM_I_INUM (y);
0aacf84e
MD
4064 long int z = xx - yy;
4065 if (SCM_FIXABLE (z))
d956fa6f 4066 return SCM_I_MAKINUM (z);
0aacf84e
MD
4067 else
4068 return scm_i_long2big (z);
4069 }
4070 else if (SCM_BIGP (y))
4071 {
4072 /* inum-x - big-y */
e11e83f3 4073 long xx = SCM_I_INUM (x);
ca46fb90 4074
0aacf84e
MD
4075 if (xx == 0)
4076 return scm_i_clonebig (y, 0);
4077 else
4078 {
4079 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
4080 SCM result = scm_i_mkbig ();
ca46fb90 4081
0aacf84e
MD
4082 if (xx >= 0)
4083 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
4084 else
4085 {
4086 /* x - y == -(y + -x) */
4087 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
4088 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
4089 }
4090 scm_remember_upto_here_1 (y);
ca46fb90 4091
0aacf84e
MD
4092 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
4093 /* we know the result will have to be a bignum */
4094 return result;
4095 else
4096 return scm_i_normbig (result);
4097 }
4098 }
4099 else if (SCM_REALP (y))
4100 {
e11e83f3 4101 long int xx = SCM_I_INUM (x);
55f26379 4102 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
4103 }
4104 else if (SCM_COMPLEXP (y))
4105 {
e11e83f3 4106 long int xx = SCM_I_INUM (x);
8507ec80 4107 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
0aacf84e
MD
4108 - SCM_COMPLEX_IMAG (y));
4109 }
f92e85f7
MV
4110 else if (SCM_FRACTIONP (y))
4111 /* a - b/c = (ac - b) / c */
cba42c93 4112 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4113 SCM_FRACTION_NUMERATOR (y)),
4114 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4115 else
4116 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 4117 }
0aacf84e
MD
4118 else if (SCM_BIGP (x))
4119 {
e11e83f3 4120 if (SCM_I_INUMP (y))
0aacf84e
MD
4121 {
4122 /* big-x - inum-y */
e11e83f3 4123 long yy = SCM_I_INUM (y);
0aacf84e 4124 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 4125
0aacf84e
MD
4126 scm_remember_upto_here_1 (x);
4127 if (sgn_x == 0)
c71b0706
MV
4128 return (SCM_FIXABLE (-yy) ?
4129 SCM_I_MAKINUM (-yy) : scm_from_long (-yy));
0aacf84e
MD
4130 else
4131 {
4132 SCM result = scm_i_mkbig ();
ca46fb90 4133
708f22c6
KR
4134 if (yy >= 0)
4135 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
4136 else
4137 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 4138 scm_remember_upto_here_1 (x);
ca46fb90 4139
0aacf84e
MD
4140 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
4141 /* we know the result will have to be a bignum */
4142 return result;
4143 else
4144 return scm_i_normbig (result);
4145 }
4146 }
4147 else if (SCM_BIGP (y))
4148 {
4149 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
4150 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
4151 SCM result = scm_i_mkbig ();
4152 mpz_sub (SCM_I_BIG_MPZ (result),
4153 SCM_I_BIG_MPZ (x),
4154 SCM_I_BIG_MPZ (y));
4155 scm_remember_upto_here_2 (x, y);
4156 /* we know the result will have to be a bignum */
4157 if ((sgn_x == 1) && (sgn_y == -1))
4158 return result;
4159 if ((sgn_x == -1) && (sgn_y == 1))
4160 return result;
4161 return scm_i_normbig (result);
4162 }
4163 else if (SCM_REALP (y))
4164 {
4165 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
4166 scm_remember_upto_here_1 (x);
55f26379 4167 return scm_from_double (result);
0aacf84e
MD
4168 }
4169 else if (SCM_COMPLEXP (y))
4170 {
4171 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
4172 - SCM_COMPLEX_REAL (y));
4173 scm_remember_upto_here_1 (x);
8507ec80 4174 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 4175 }
f92e85f7 4176 else if (SCM_FRACTIONP (y))
cba42c93 4177 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4178 SCM_FRACTION_NUMERATOR (y)),
4179 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 4180 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 4181 }
0aacf84e
MD
4182 else if (SCM_REALP (x))
4183 {
e11e83f3 4184 if (SCM_I_INUMP (y))
55f26379 4185 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
4186 else if (SCM_BIGP (y))
4187 {
4188 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
4189 scm_remember_upto_here_1 (x);
55f26379 4190 return scm_from_double (result);
0aacf84e
MD
4191 }
4192 else if (SCM_REALP (y))
55f26379 4193 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 4194 else if (SCM_COMPLEXP (y))
8507ec80 4195 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 4196 -SCM_COMPLEX_IMAG (y));
f92e85f7 4197 else if (SCM_FRACTIONP (y))
55f26379 4198 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
4199 else
4200 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 4201 }
0aacf84e
MD
4202 else if (SCM_COMPLEXP (x))
4203 {
e11e83f3 4204 if (SCM_I_INUMP (y))
8507ec80 4205 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
4206 SCM_COMPLEX_IMAG (x));
4207 else if (SCM_BIGP (y))
4208 {
4209 double real_part = (SCM_COMPLEX_REAL (x)
4210 - mpz_get_d (SCM_I_BIG_MPZ (y)));
4211 scm_remember_upto_here_1 (x);
8507ec80 4212 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
4213 }
4214 else if (SCM_REALP (y))
8507ec80 4215 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
4216 SCM_COMPLEX_IMAG (x));
4217 else if (SCM_COMPLEXP (y))
8507ec80 4218 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 4219 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 4220 else if (SCM_FRACTIONP (y))
8507ec80 4221 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
4222 SCM_COMPLEX_IMAG (x));
4223 else
4224 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
4225 }
4226 else if (SCM_FRACTIONP (x))
4227 {
e11e83f3 4228 if (SCM_I_INUMP (y))
f92e85f7 4229 /* a/b - c = (a - cb) / b */
cba42c93 4230 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4231 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
4232 SCM_FRACTION_DENOMINATOR (x));
4233 else if (SCM_BIGP (y))
cba42c93 4234 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4235 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
4236 SCM_FRACTION_DENOMINATOR (x));
4237 else if (SCM_REALP (y))
55f26379 4238 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 4239 else if (SCM_COMPLEXP (y))
8507ec80 4240 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
4241 -SCM_COMPLEX_IMAG (y));
4242 else if (SCM_FRACTIONP (y))
4243 /* a/b - c/d = (ad - bc) / bd */
cba42c93 4244 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4245 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
4246 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4247 else
4248 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 4249 }
0aacf84e 4250 else
98cb6e75 4251 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 4252}
c05e97b7 4253#undef FUNC_NAME
0f2d19dd 4254
ca46fb90 4255
9de33deb 4256SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
942e5b91
MG
4257/* "Return the product of all arguments. If called without arguments,\n"
4258 * "1 is returned."
4259 */
0f2d19dd 4260SCM
6e8d25a6 4261scm_product (SCM x, SCM y)
0f2d19dd 4262{
0aacf84e
MD
4263 if (SCM_UNBNDP (y))
4264 {
4265 if (SCM_UNBNDP (x))
d956fa6f 4266 return SCM_I_MAKINUM (1L);
0aacf84e
MD
4267 else if (SCM_NUMBERP (x))
4268 return x;
4269 else
4270 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 4271 }
ca46fb90 4272
e11e83f3 4273 if (SCM_I_INUMP (x))
0aacf84e
MD
4274 {
4275 long xx;
f4c627b3 4276
0aacf84e 4277 intbig:
e11e83f3 4278 xx = SCM_I_INUM (x);
f4c627b3 4279
0aacf84e
MD
4280 switch (xx)
4281 {
ca46fb90
RB
4282 case 0: return x; break;
4283 case 1: return y; break;
0aacf84e 4284 }
f4c627b3 4285
e11e83f3 4286 if (SCM_I_INUMP (y))
0aacf84e 4287 {
e11e83f3 4288 long yy = SCM_I_INUM (y);
0aacf84e 4289 long kk = xx * yy;
d956fa6f 4290 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 4291 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
4292 return k;
4293 else
4294 {
4295 SCM result = scm_i_long2big (xx);
4296 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
4297 return scm_i_normbig (result);
4298 }
4299 }
4300 else if (SCM_BIGP (y))
4301 {
4302 SCM result = scm_i_mkbig ();
4303 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
4304 scm_remember_upto_here_1 (y);
4305 return result;
4306 }
4307 else if (SCM_REALP (y))
55f26379 4308 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 4309 else if (SCM_COMPLEXP (y))
8507ec80 4310 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 4311 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 4312 else if (SCM_FRACTIONP (y))
cba42c93 4313 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 4314 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4315 else
4316 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4317 }
0aacf84e
MD
4318 else if (SCM_BIGP (x))
4319 {
e11e83f3 4320 if (SCM_I_INUMP (y))
0aacf84e
MD
4321 {
4322 SCM_SWAP (x, y);
4323 goto intbig;
4324 }
4325 else if (SCM_BIGP (y))
4326 {
4327 SCM result = scm_i_mkbig ();
4328 mpz_mul (SCM_I_BIG_MPZ (result),
4329 SCM_I_BIG_MPZ (x),
4330 SCM_I_BIG_MPZ (y));
4331 scm_remember_upto_here_2 (x, y);
4332 return result;
4333 }
4334 else if (SCM_REALP (y))
4335 {
4336 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
4337 scm_remember_upto_here_1 (x);
55f26379 4338 return scm_from_double (result);
0aacf84e
MD
4339 }
4340 else if (SCM_COMPLEXP (y))
4341 {
4342 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
4343 scm_remember_upto_here_1 (x);
8507ec80 4344 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
4345 z * SCM_COMPLEX_IMAG (y));
4346 }
f92e85f7 4347 else if (SCM_FRACTIONP (y))
cba42c93 4348 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 4349 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4350 else
4351 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4352 }
0aacf84e
MD
4353 else if (SCM_REALP (x))
4354 {
e11e83f3 4355 if (SCM_I_INUMP (y))
55f26379 4356 return scm_from_double (SCM_I_INUM (y) * SCM_REAL_VALUE (x));
0aacf84e
MD
4357 else if (SCM_BIGP (y))
4358 {
4359 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
4360 scm_remember_upto_here_1 (y);
55f26379 4361 return scm_from_double (result);
0aacf84e
MD
4362 }
4363 else if (SCM_REALP (y))
55f26379 4364 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 4365 else if (SCM_COMPLEXP (y))
8507ec80 4366 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 4367 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 4368 else if (SCM_FRACTIONP (y))
55f26379 4369 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
4370 else
4371 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4372 }
0aacf84e
MD
4373 else if (SCM_COMPLEXP (x))
4374 {
e11e83f3 4375 if (SCM_I_INUMP (y))
8507ec80 4376 return scm_c_make_rectangular (SCM_I_INUM (y) * SCM_COMPLEX_REAL (x),
e11e83f3 4377 SCM_I_INUM (y) * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
4378 else if (SCM_BIGP (y))
4379 {
4380 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
4381 scm_remember_upto_here_1 (y);
8507ec80 4382 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 4383 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
4384 }
4385 else if (SCM_REALP (y))
8507ec80 4386 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
4387 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
4388 else if (SCM_COMPLEXP (y))
4389 {
8507ec80 4390 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
4391 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
4392 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
4393 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
4394 }
f92e85f7
MV
4395 else if (SCM_FRACTIONP (y))
4396 {
4397 double yy = scm_i_fraction2double (y);
8507ec80 4398 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
4399 yy * SCM_COMPLEX_IMAG (x));
4400 }
4401 else
4402 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
4403 }
4404 else if (SCM_FRACTIONP (x))
4405 {
e11e83f3 4406 if (SCM_I_INUMP (y))
cba42c93 4407 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
4408 SCM_FRACTION_DENOMINATOR (x));
4409 else if (SCM_BIGP (y))
cba42c93 4410 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
4411 SCM_FRACTION_DENOMINATOR (x));
4412 else if (SCM_REALP (y))
55f26379 4413 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
4414 else if (SCM_COMPLEXP (y))
4415 {
4416 double xx = scm_i_fraction2double (x);
8507ec80 4417 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
4418 xx * SCM_COMPLEX_IMAG (y));
4419 }
4420 else if (SCM_FRACTIONP (y))
4421 /* a/b * c/d = ac / bd */
cba42c93 4422 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4423 SCM_FRACTION_NUMERATOR (y)),
4424 scm_product (SCM_FRACTION_DENOMINATOR (x),
4425 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4426 else
4427 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4428 }
0aacf84e 4429 else
f4c627b3 4430 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
4431}
4432
7351e207
MV
4433#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
4434 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
4435#define ALLOW_DIVIDE_BY_ZERO
4436/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
4437#endif
0f2d19dd 4438
ba74ef4e
MV
4439/* The code below for complex division is adapted from the GNU
4440 libstdc++, which adapted it from f2c's libF77, and is subject to
4441 this copyright: */
4442
4443/****************************************************************
4444Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
4445
4446Permission to use, copy, modify, and distribute this software
4447and its documentation for any purpose and without fee is hereby
4448granted, provided that the above copyright notice appear in all
4449copies and that both that the copyright notice and this
4450permission notice and warranty disclaimer appear in supporting
4451documentation, and that the names of AT&T Bell Laboratories or
4452Bellcore or any of their entities not be used in advertising or
4453publicity pertaining to distribution of the software without
4454specific, written prior permission.
4455
4456AT&T and Bellcore disclaim all warranties with regard to this
4457software, including all implied warranties of merchantability
4458and fitness. In no event shall AT&T or Bellcore be liable for
4459any special, indirect or consequential damages or any damages
4460whatsoever resulting from loss of use, data or profits, whether
4461in an action of contract, negligence or other tortious action,
4462arising out of or in connection with the use or performance of
4463this software.
4464****************************************************************/
4465
9de33deb 4466SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
609c3d30
MG
4467/* Divide the first argument by the product of the remaining
4468 arguments. If called with one argument @var{z1}, 1/@var{z1} is
4469 returned. */
c05e97b7 4470#define FUNC_NAME s_divide
f92e85f7
MV
4471static SCM
4472scm_i_divide (SCM x, SCM y, int inexact)
0f2d19dd 4473{
f8de44c1
DH
4474 double a;
4475
0aacf84e
MD
4476 if (SCM_UNBNDP (y))
4477 {
4478 if (SCM_UNBNDP (x))
4479 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 4480 else if (SCM_I_INUMP (x))
0aacf84e 4481 {
e11e83f3 4482 long xx = SCM_I_INUM (x);
0aacf84e
MD
4483 if (xx == 1 || xx == -1)
4484 return x;
7351e207 4485#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4486 else if (xx == 0)
4487 scm_num_overflow (s_divide);
7351e207 4488#endif
0aacf84e 4489 else
f92e85f7
MV
4490 {
4491 if (inexact)
55f26379 4492 return scm_from_double (1.0 / (double) xx);
cba42c93 4493 else return scm_i_make_ratio (SCM_I_MAKINUM(1), x);
f92e85f7 4494 }
0aacf84e
MD
4495 }
4496 else if (SCM_BIGP (x))
f92e85f7
MV
4497 {
4498 if (inexact)
55f26379 4499 return scm_from_double (1.0 / scm_i_big2dbl (x));
cba42c93 4500 else return scm_i_make_ratio (SCM_I_MAKINUM(1), x);
f92e85f7 4501 }
0aacf84e
MD
4502 else if (SCM_REALP (x))
4503 {
4504 double xx = SCM_REAL_VALUE (x);
7351e207 4505#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4506 if (xx == 0.0)
4507 scm_num_overflow (s_divide);
4508 else
7351e207 4509#endif
55f26379 4510 return scm_from_double (1.0 / xx);
0aacf84e
MD
4511 }
4512 else if (SCM_COMPLEXP (x))
4513 {
4514 double r = SCM_COMPLEX_REAL (x);
4515 double i = SCM_COMPLEX_IMAG (x);
4516 if (r <= i)
4517 {
4518 double t = r / i;
4519 double d = i * (1.0 + t * t);
8507ec80 4520 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
4521 }
4522 else
4523 {
4524 double t = i / r;
4525 double d = r * (1.0 + t * t);
8507ec80 4526 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
4527 }
4528 }
f92e85f7 4529 else if (SCM_FRACTIONP (x))
cba42c93 4530 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 4531 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
4532 else
4533 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 4534 }
f8de44c1 4535
e11e83f3 4536 if (SCM_I_INUMP (x))
0aacf84e 4537 {
e11e83f3
MV
4538 long xx = SCM_I_INUM (x);
4539 if (SCM_I_INUMP (y))
0aacf84e 4540 {
e11e83f3 4541 long yy = SCM_I_INUM (y);
0aacf84e
MD
4542 if (yy == 0)
4543 {
7351e207 4544#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4545 scm_num_overflow (s_divide);
7351e207 4546#else
55f26379 4547 return scm_from_double ((double) xx / (double) yy);
7351e207 4548#endif
0aacf84e
MD
4549 }
4550 else if (xx % yy != 0)
f92e85f7
MV
4551 {
4552 if (inexact)
55f26379 4553 return scm_from_double ((double) xx / (double) yy);
cba42c93 4554 else return scm_i_make_ratio (x, y);
f92e85f7 4555 }
0aacf84e
MD
4556 else
4557 {
4558 long z = xx / yy;
4559 if (SCM_FIXABLE (z))
d956fa6f 4560 return SCM_I_MAKINUM (z);
0aacf84e
MD
4561 else
4562 return scm_i_long2big (z);
4563 }
f872b822 4564 }
0aacf84e 4565 else if (SCM_BIGP (y))
f92e85f7
MV
4566 {
4567 if (inexact)
55f26379 4568 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 4569 else return scm_i_make_ratio (x, y);
f92e85f7 4570 }
0aacf84e
MD
4571 else if (SCM_REALP (y))
4572 {
4573 double yy = SCM_REAL_VALUE (y);
7351e207 4574#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4575 if (yy == 0.0)
4576 scm_num_overflow (s_divide);
4577 else
7351e207 4578#endif
55f26379 4579 return scm_from_double ((double) xx / yy);
ba74ef4e 4580 }
0aacf84e
MD
4581 else if (SCM_COMPLEXP (y))
4582 {
4583 a = xx;
4584 complex_div: /* y _must_ be a complex number */
4585 {
4586 double r = SCM_COMPLEX_REAL (y);
4587 double i = SCM_COMPLEX_IMAG (y);
4588 if (r <= i)
4589 {
4590 double t = r / i;
4591 double d = i * (1.0 + t * t);
8507ec80 4592 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
4593 }
4594 else
4595 {
4596 double t = i / r;
4597 double d = r * (1.0 + t * t);
8507ec80 4598 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
4599 }
4600 }
4601 }
f92e85f7
MV
4602 else if (SCM_FRACTIONP (y))
4603 /* a / b/c = ac / b */
cba42c93 4604 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 4605 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
4606 else
4607 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 4608 }
0aacf84e
MD
4609 else if (SCM_BIGP (x))
4610 {
e11e83f3 4611 if (SCM_I_INUMP (y))
0aacf84e 4612 {
e11e83f3 4613 long int yy = SCM_I_INUM (y);
0aacf84e
MD
4614 if (yy == 0)
4615 {
7351e207 4616#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4617 scm_num_overflow (s_divide);
7351e207 4618#else
0aacf84e
MD
4619 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4620 scm_remember_upto_here_1 (x);
4621 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 4622#endif
0aacf84e
MD
4623 }
4624 else if (yy == 1)
4625 return x;
4626 else
4627 {
4628 /* FIXME: HMM, what are the relative performance issues here?
4629 We need to test. Is it faster on average to test
4630 divisible_p, then perform whichever operation, or is it
4631 faster to perform the integer div opportunistically and
4632 switch to real if there's a remainder? For now we take the
4633 middle ground: test, then if divisible, use the faster div
4634 func. */
4635
4636 long abs_yy = yy < 0 ? -yy : yy;
4637 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
4638
4639 if (divisible_p)
4640 {
4641 SCM result = scm_i_mkbig ();
4642 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
4643 scm_remember_upto_here_1 (x);
4644 if (yy < 0)
4645 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
4646 return scm_i_normbig (result);
4647 }
4648 else
f92e85f7
MV
4649 {
4650 if (inexact)
55f26379 4651 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 4652 else return scm_i_make_ratio (x, y);
f92e85f7 4653 }
0aacf84e
MD
4654 }
4655 }
4656 else if (SCM_BIGP (y))
4657 {
4658 int y_is_zero = (mpz_sgn (SCM_I_BIG_MPZ (y)) == 0);
4659 if (y_is_zero)
4660 {
ca46fb90 4661#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4662 scm_num_overflow (s_divide);
f872b822 4663#else
0aacf84e
MD
4664 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4665 scm_remember_upto_here_1 (x);
4666 return (sgn == 0) ? scm_nan () : scm_inf ();
f872b822 4667#endif
0aacf84e
MD
4668 }
4669 else
4670 {
4671 /* big_x / big_y */
4672 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
4673 SCM_I_BIG_MPZ (y));
4674 if (divisible_p)
4675 {
4676 SCM result = scm_i_mkbig ();
4677 mpz_divexact (SCM_I_BIG_MPZ (result),
4678 SCM_I_BIG_MPZ (x),
4679 SCM_I_BIG_MPZ (y));
4680 scm_remember_upto_here_2 (x, y);
4681 return scm_i_normbig (result);
4682 }
4683 else
4684 {
f92e85f7
MV
4685 if (inexact)
4686 {
4687 double dbx = mpz_get_d (SCM_I_BIG_MPZ (x));
4688 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4689 scm_remember_upto_here_2 (x, y);
55f26379 4690 return scm_from_double (dbx / dby);
f92e85f7 4691 }
cba42c93 4692 else return scm_i_make_ratio (x, y);
0aacf84e
MD
4693 }
4694 }
4695 }
4696 else if (SCM_REALP (y))
4697 {
4698 double yy = SCM_REAL_VALUE (y);
7351e207 4699#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4700 if (yy == 0.0)
4701 scm_num_overflow (s_divide);
4702 else
7351e207 4703#endif
55f26379 4704 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
4705 }
4706 else if (SCM_COMPLEXP (y))
4707 {
4708 a = scm_i_big2dbl (x);
4709 goto complex_div;
4710 }
f92e85f7 4711 else if (SCM_FRACTIONP (y))
cba42c93 4712 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 4713 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
4714 else
4715 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4716 }
0aacf84e
MD
4717 else if (SCM_REALP (x))
4718 {
4719 double rx = SCM_REAL_VALUE (x);
e11e83f3 4720 if (SCM_I_INUMP (y))
0aacf84e 4721 {
e11e83f3 4722 long int yy = SCM_I_INUM (y);
7351e207 4723#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4724 if (yy == 0)
4725 scm_num_overflow (s_divide);
4726 else
7351e207 4727#endif
55f26379 4728 return scm_from_double (rx / (double) yy);
0aacf84e
MD
4729 }
4730 else if (SCM_BIGP (y))
4731 {
4732 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4733 scm_remember_upto_here_1 (y);
55f26379 4734 return scm_from_double (rx / dby);
0aacf84e
MD
4735 }
4736 else if (SCM_REALP (y))
4737 {
4738 double yy = SCM_REAL_VALUE (y);
7351e207 4739#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4740 if (yy == 0.0)
4741 scm_num_overflow (s_divide);
4742 else
7351e207 4743#endif
55f26379 4744 return scm_from_double (rx / yy);
0aacf84e
MD
4745 }
4746 else if (SCM_COMPLEXP (y))
4747 {
4748 a = rx;
4749 goto complex_div;
4750 }
f92e85f7 4751 else if (SCM_FRACTIONP (y))
55f26379 4752 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
4753 else
4754 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4755 }
0aacf84e
MD
4756 else if (SCM_COMPLEXP (x))
4757 {
4758 double rx = SCM_COMPLEX_REAL (x);
4759 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 4760 if (SCM_I_INUMP (y))
0aacf84e 4761 {
e11e83f3 4762 long int yy = SCM_I_INUM (y);
7351e207 4763#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4764 if (yy == 0)
4765 scm_num_overflow (s_divide);
4766 else
7351e207 4767#endif
0aacf84e
MD
4768 {
4769 double d = yy;
8507ec80 4770 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
4771 }
4772 }
4773 else if (SCM_BIGP (y))
4774 {
4775 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4776 scm_remember_upto_here_1 (y);
8507ec80 4777 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
4778 }
4779 else if (SCM_REALP (y))
4780 {
4781 double yy = SCM_REAL_VALUE (y);
7351e207 4782#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4783 if (yy == 0.0)
4784 scm_num_overflow (s_divide);
4785 else
7351e207 4786#endif
8507ec80 4787 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
4788 }
4789 else if (SCM_COMPLEXP (y))
4790 {
4791 double ry = SCM_COMPLEX_REAL (y);
4792 double iy = SCM_COMPLEX_IMAG (y);
4793 if (ry <= iy)
4794 {
4795 double t = ry / iy;
4796 double d = iy * (1.0 + t * t);
8507ec80 4797 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
4798 }
4799 else
4800 {
4801 double t = iy / ry;
4802 double d = ry * (1.0 + t * t);
8507ec80 4803 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
4804 }
4805 }
f92e85f7
MV
4806 else if (SCM_FRACTIONP (y))
4807 {
4808 double yy = scm_i_fraction2double (y);
8507ec80 4809 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 4810 }
0aacf84e
MD
4811 else
4812 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 4813 }
f92e85f7
MV
4814 else if (SCM_FRACTIONP (x))
4815 {
e11e83f3 4816 if (SCM_I_INUMP (y))
f92e85f7 4817 {
e11e83f3 4818 long int yy = SCM_I_INUM (y);
f92e85f7
MV
4819#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
4820 if (yy == 0)
4821 scm_num_overflow (s_divide);
4822 else
4823#endif
cba42c93 4824 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4825 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
4826 }
4827 else if (SCM_BIGP (y))
4828 {
cba42c93 4829 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4830 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
4831 }
4832 else if (SCM_REALP (y))
4833 {
4834 double yy = SCM_REAL_VALUE (y);
4835#ifndef ALLOW_DIVIDE_BY_ZERO
4836 if (yy == 0.0)
4837 scm_num_overflow (s_divide);
4838 else
4839#endif
55f26379 4840 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
4841 }
4842 else if (SCM_COMPLEXP (y))
4843 {
4844 a = scm_i_fraction2double (x);
4845 goto complex_div;
4846 }
4847 else if (SCM_FRACTIONP (y))
cba42c93 4848 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4849 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
4850 else
4851 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
4852 }
0aacf84e 4853 else
f8de44c1 4854 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 4855}
f92e85f7
MV
4856
4857SCM
4858scm_divide (SCM x, SCM y)
4859{
4860 return scm_i_divide (x, y, 0);
4861}
4862
4863static SCM scm_divide2real (SCM x, SCM y)
4864{
4865 return scm_i_divide (x, y, 1);
4866}
c05e97b7 4867#undef FUNC_NAME
0f2d19dd 4868
fa605590 4869
0f2d19dd 4870double
6e8d25a6 4871scm_asinh (double x)
0f2d19dd 4872{
fa605590
KR
4873#if HAVE_ASINH
4874 return asinh (x);
4875#else
4876#define asinh scm_asinh
f872b822 4877 return log (x + sqrt (x * x + 1));
fa605590 4878#endif
0f2d19dd 4879}
fa605590
KR
4880SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_dsubr, (SCM (*)()) asinh, g_asinh);
4881/* "Return the inverse hyperbolic sine of @var{x}."
4882 */
0f2d19dd
JB
4883
4884
0f2d19dd 4885double
6e8d25a6 4886scm_acosh (double x)
0f2d19dd 4887{
fa605590
KR
4888#if HAVE_ACOSH
4889 return acosh (x);
4890#else
4891#define acosh scm_acosh
f872b822 4892 return log (x + sqrt (x * x - 1));
fa605590 4893#endif
0f2d19dd 4894}
fa605590
KR
4895SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_dsubr, (SCM (*)()) acosh, g_acosh);
4896/* "Return the inverse hyperbolic cosine of @var{x}."
4897 */
0f2d19dd
JB
4898
4899
0f2d19dd 4900double
6e8d25a6 4901scm_atanh (double x)
0f2d19dd 4902{
fa605590
KR
4903#if HAVE_ATANH
4904 return atanh (x);
4905#else
4906#define atanh scm_atanh
f872b822 4907 return 0.5 * log ((1 + x) / (1 - x));
fa605590 4908#endif
0f2d19dd 4909}
fa605590
KR
4910SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_dsubr, (SCM (*)()) atanh, g_atanh);
4911/* "Return the inverse hyperbolic tangent of @var{x}."
4912 */
0f2d19dd
JB
4913
4914
0f2d19dd 4915double
3101f40f 4916scm_c_truncate (double x)
0f2d19dd 4917{
fa605590
KR
4918#if HAVE_TRUNC
4919 return trunc (x);
4920#else
f872b822
MD
4921 if (x < 0.0)
4922 return -floor (-x);
4923 return floor (x);
fa605590 4924#endif
0f2d19dd 4925}
0f2d19dd 4926
3101f40f
MV
4927/* scm_c_round is done using floor(x+0.5) to round to nearest and with
4928 half-way case (ie. when x is an integer plus 0.5) going upwards.
4929 Then half-way cases are identified and adjusted down if the
4930 round-upwards didn't give the desired even integer.
6187f48b
KR
4931
4932 "plus_half == result" identifies a half-way case. If plus_half, which is
4933 x + 0.5, is an integer then x must be an integer plus 0.5.
4934
4935 An odd "result" value is identified with result/2 != floor(result/2).
4936 This is done with plus_half, since that value is ready for use sooner in
4937 a pipelined cpu, and we're already requiring plus_half == result.
4938
4939 Note however that we need to be careful when x is big and already an
4940 integer. In that case "x+0.5" may round to an adjacent integer, causing
4941 us to return such a value, incorrectly. For instance if the hardware is
4942 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
4943 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
4944 returned. Or if the hardware is in round-upwards mode, then other bigger
4945 values like say x == 2^128 will see x+0.5 rounding up to the next higher
4946 representable value, 2^128+2^76 (or whatever), again incorrect.
4947
4948 These bad roundings of x+0.5 are avoided by testing at the start whether
4949 x is already an integer. If it is then clearly that's the desired result
4950 already. And if it's not then the exponent must be small enough to allow
4951 an 0.5 to be represented, and hence added without a bad rounding. */
4952
0f2d19dd 4953double
3101f40f 4954scm_c_round (double x)
0f2d19dd 4955{
6187f48b
KR
4956 double plus_half, result;
4957
4958 if (x == floor (x))
4959 return x;
4960
4961 plus_half = x + 0.5;
4962 result = floor (plus_half);
3101f40f 4963 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
4964 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
4965 ? result - 1
4966 : result);
0f2d19dd
JB
4967}
4968
f92e85f7
MV
4969SCM_DEFINE (scm_truncate_number, "truncate", 1, 0, 0,
4970 (SCM x),
4971 "Round the number @var{x} towards zero.")
4972#define FUNC_NAME s_scm_truncate_number
4973{
73e4de09 4974 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
4975 return scm_floor (x);
4976 else
4977 return scm_ceiling (x);
4978}
4979#undef FUNC_NAME
4980
4981static SCM exactly_one_half;
4982
4983SCM_DEFINE (scm_round_number, "round", 1, 0, 0,
4984 (SCM x),
4985 "Round the number @var{x} towards the nearest integer. "
4986 "When it is exactly halfway between two integers, "
4987 "round towards the even one.")
4988#define FUNC_NAME s_scm_round_number
4989{
e11e83f3 4990 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
4991 return x;
4992 else if (SCM_REALP (x))
3101f40f 4993 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
f92e85f7 4994 else
bae30667
KR
4995 {
4996 /* OPTIMIZE-ME: Fraction case could be done more efficiently by a
4997 single quotient+remainder division then examining to see which way
4998 the rounding should go. */
4999 SCM plus_half = scm_sum (x, exactly_one_half);
5000 SCM result = scm_floor (plus_half);
3101f40f 5001 /* Adjust so that the rounding is towards even. */
73e4de09
MV
5002 if (scm_is_true (scm_num_eq_p (plus_half, result))
5003 && scm_is_true (scm_odd_p (result)))
d956fa6f 5004 return scm_difference (result, SCM_I_MAKINUM (1));
bae30667
KR
5005 else
5006 return result;
5007 }
f92e85f7
MV
5008}
5009#undef FUNC_NAME
5010
5011SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
5012 (SCM x),
5013 "Round the number @var{x} towards minus infinity.")
5014#define FUNC_NAME s_scm_floor
5015{
e11e83f3 5016 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
5017 return x;
5018 else if (SCM_REALP (x))
55f26379 5019 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7
MV
5020 else if (SCM_FRACTIONP (x))
5021 {
5022 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
5023 SCM_FRACTION_DENOMINATOR (x));
73e4de09 5024 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
5025 {
5026 /* For positive x, rounding towards zero is correct. */
5027 return q;
5028 }
5029 else
5030 {
5031 /* For negative x, we need to return q-1 unless x is an
5032 integer. But fractions are never integer, per our
5033 assumptions. */
d956fa6f 5034 return scm_difference (q, SCM_I_MAKINUM (1));
f92e85f7
MV
5035 }
5036 }
5037 else
5038 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
5039}
5040#undef FUNC_NAME
5041
5042SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
5043 (SCM x),
5044 "Round the number @var{x} towards infinity.")
5045#define FUNC_NAME s_scm_ceiling
5046{
e11e83f3 5047 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
5048 return x;
5049 else if (SCM_REALP (x))
55f26379 5050 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7
MV
5051 else if (SCM_FRACTIONP (x))
5052 {
5053 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
5054 SCM_FRACTION_DENOMINATOR (x));
73e4de09 5055 if (scm_is_false (scm_positive_p (x)))
f92e85f7
MV
5056 {
5057 /* For negative x, rounding towards zero is correct. */
5058 return q;
5059 }
5060 else
5061 {
5062 /* For positive x, we need to return q+1 unless x is an
5063 integer. But fractions are never integer, per our
5064 assumptions. */
d956fa6f 5065 return scm_sum (q, SCM_I_MAKINUM (1));
f92e85f7
MV
5066 }
5067 }
5068 else
5069 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
5070}
5071#undef FUNC_NAME
0f2d19dd 5072
14b18ed6 5073SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_dsubr, (SCM (*)()) sqrt, g_i_sqrt);
942e5b91
MG
5074/* "Return the square root of the real number @var{x}."
5075 */
14b18ed6 5076SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_dsubr, (SCM (*)()) fabs, g_i_abs);
942e5b91
MG
5077/* "Return the absolute value of the real number @var{x}."
5078 */
14b18ed6 5079SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_dsubr, (SCM (*)()) exp, g_i_exp);
942e5b91
MG
5080/* "Return the @var{x}th power of e."
5081 */
14b18ed6 5082SCM_GPROC1 (s_i_log, "$log", scm_tc7_dsubr, (SCM (*)()) log, g_i_log);
b3fcac34 5083/* "Return the natural logarithm of the real number @var{x}."
942e5b91 5084 */
14b18ed6 5085SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_dsubr, (SCM (*)()) sin, g_i_sin);
942e5b91
MG
5086/* "Return the sine of the real number @var{x}."
5087 */
14b18ed6 5088SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_dsubr, (SCM (*)()) cos, g_i_cos);
942e5b91
MG
5089/* "Return the cosine of the real number @var{x}."
5090 */
14b18ed6 5091SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_dsubr, (SCM (*)()) tan, g_i_tan);
942e5b91
MG
5092/* "Return the tangent of the real number @var{x}."
5093 */
14b18ed6 5094SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_dsubr, (SCM (*)()) asin, g_i_asin);
942e5b91
MG
5095/* "Return the arc sine of the real number @var{x}."
5096 */
14b18ed6 5097SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_dsubr, (SCM (*)()) acos, g_i_acos);
942e5b91
MG
5098/* "Return the arc cosine of the real number @var{x}."
5099 */
14b18ed6 5100SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_dsubr, (SCM (*)()) atan, g_i_atan);
942e5b91
MG
5101/* "Return the arc tangent of the real number @var{x}."
5102 */
14b18ed6 5103SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_dsubr, (SCM (*)()) sinh, g_i_sinh);
942e5b91
MG
5104/* "Return the hyperbolic sine of the real number @var{x}."
5105 */
14b18ed6 5106SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_dsubr, (SCM (*)()) cosh, g_i_cosh);
942e5b91
MG
5107/* "Return the hyperbolic cosine of the real number @var{x}."
5108 */
14b18ed6 5109SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_dsubr, (SCM (*)()) tanh, g_i_tanh);
942e5b91
MG
5110/* "Return the hyperbolic tangent of the real number @var{x}."
5111 */
f872b822
MD
5112
5113struct dpair
5114{
5115 double x, y;
5116};
5117
27c37006
NJ
5118static void scm_two_doubles (SCM x,
5119 SCM y,
3eeba8d4
JB
5120 const char *sstring,
5121 struct dpair * xy);
f872b822
MD
5122
5123static void
27c37006
NJ
5124scm_two_doubles (SCM x, SCM y, const char *sstring, struct dpair *xy)
5125{
e11e83f3
MV
5126 if (SCM_I_INUMP (x))
5127 xy->x = SCM_I_INUM (x);
0aacf84e 5128 else if (SCM_BIGP (x))
1be6b49c 5129 xy->x = scm_i_big2dbl (x);
0aacf84e 5130 else if (SCM_REALP (x))
27c37006 5131 xy->x = SCM_REAL_VALUE (x);
f92e85f7
MV
5132 else if (SCM_FRACTIONP (x))
5133 xy->x = scm_i_fraction2double (x);
0aacf84e 5134 else
27c37006 5135 scm_wrong_type_arg (sstring, SCM_ARG1, x);
98cb6e75 5136
e11e83f3
MV
5137 if (SCM_I_INUMP (y))
5138 xy->y = SCM_I_INUM (y);
0aacf84e 5139 else if (SCM_BIGP (y))
1be6b49c 5140 xy->y = scm_i_big2dbl (y);
0aacf84e 5141 else if (SCM_REALP (y))
27c37006 5142 xy->y = SCM_REAL_VALUE (y);
f92e85f7
MV
5143 else if (SCM_FRACTIONP (y))
5144 xy->y = scm_i_fraction2double (y);
0aacf84e 5145 else
27c37006 5146 scm_wrong_type_arg (sstring, SCM_ARG2, y);
0f2d19dd
JB
5147}
5148
5149
a1ec6916 5150SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
27c37006
NJ
5151 (SCM x, SCM y),
5152 "Return @var{x} raised to the power of @var{y}. This\n"
0137a31b 5153 "procedure does not accept complex arguments.")
1bbd0b84 5154#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
5155{
5156 struct dpair xy;
27c37006 5157 scm_two_doubles (x, y, FUNC_NAME, &xy);
55f26379 5158 return scm_from_double (pow (xy.x, xy.y));
0f2d19dd 5159}
1bbd0b84 5160#undef FUNC_NAME
0f2d19dd
JB
5161
5162
a1ec6916 5163SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
27c37006
NJ
5164 (SCM x, SCM y),
5165 "Return the arc tangent of the two arguments @var{x} and\n"
5166 "@var{y}. This is similar to calculating the arc tangent of\n"
5167 "@var{x} / @var{y}, except that the signs of both arguments\n"
0137a31b
MG
5168 "are used to determine the quadrant of the result. This\n"
5169 "procedure does not accept complex arguments.")
1bbd0b84 5170#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
5171{
5172 struct dpair xy;
27c37006 5173 scm_two_doubles (x, y, FUNC_NAME, &xy);
55f26379 5174 return scm_from_double (atan2 (xy.x, xy.y));
0f2d19dd 5175}
1bbd0b84 5176#undef FUNC_NAME
0f2d19dd 5177
8507ec80
MV
5178SCM
5179scm_c_make_rectangular (double re, double im)
5180{
5181 if (im == 0.0)
5182 return scm_from_double (re);
5183 else
5184 {
5185 SCM z;
5186 SCM_NEWSMOB (z, scm_tc16_complex, scm_gc_malloc (sizeof (scm_t_complex),
5187 "complex"));
5188 SCM_COMPLEX_REAL (z) = re;
5189 SCM_COMPLEX_IMAG (z) = im;
5190 return z;
5191 }
5192}
0f2d19dd 5193
a1ec6916 5194SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794 5195 (SCM real, SCM imaginary),
942e5b91
MG
5196 "Return a complex number constructed of the given @var{real} and\n"
5197 "@var{imaginary} parts.")
1bbd0b84 5198#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
5199{
5200 struct dpair xy;
bb628794 5201 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
8507ec80 5202 return scm_c_make_rectangular (xy.x, xy.y);
0f2d19dd 5203}
1bbd0b84 5204#undef FUNC_NAME
0f2d19dd 5205
8507ec80
MV
5206SCM
5207scm_c_make_polar (double mag, double ang)
5208{
5209 double s, c;
5210#if HAVE_SINCOS
5211 sincos (ang, &s, &c);
5212#else
5213 s = sin (ang);
5214 c = cos (ang);
5215#endif
5216 return scm_c_make_rectangular (mag * c, mag * s);
5217}
0f2d19dd 5218
a1ec6916 5219SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
27c37006 5220 (SCM x, SCM y),
942e5b91 5221 "Return the complex number @var{x} * e^(i * @var{y}).")
1bbd0b84 5222#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
5223{
5224 struct dpair xy;
27c37006 5225 scm_two_doubles (x, y, FUNC_NAME, &xy);
8507ec80 5226 return scm_c_make_polar (xy.x, xy.y);
0f2d19dd 5227}
1bbd0b84 5228#undef FUNC_NAME
0f2d19dd
JB
5229
5230
152f82bf 5231SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
942e5b91
MG
5232/* "Return the real part of the number @var{z}."
5233 */
0f2d19dd 5234SCM
6e8d25a6 5235scm_real_part (SCM z)
0f2d19dd 5236{
e11e83f3 5237 if (SCM_I_INUMP (z))
c2ff8ab0 5238 return z;
0aacf84e 5239 else if (SCM_BIGP (z))
c2ff8ab0 5240 return z;
0aacf84e 5241 else if (SCM_REALP (z))
c2ff8ab0 5242 return z;
0aacf84e 5243 else if (SCM_COMPLEXP (z))
55f26379 5244 return scm_from_double (SCM_COMPLEX_REAL (z));
f92e85f7 5245 else if (SCM_FRACTIONP (z))
2fa2d879 5246 return z;
0aacf84e 5247 else
c2ff8ab0 5248 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
0f2d19dd
JB
5249}
5250
5251
152f82bf 5252SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
942e5b91
MG
5253/* "Return the imaginary part of the number @var{z}."
5254 */
0f2d19dd 5255SCM
6e8d25a6 5256scm_imag_part (SCM z)
0f2d19dd 5257{
e11e83f3 5258 if (SCM_I_INUMP (z))
f872b822 5259 return SCM_INUM0;
0aacf84e 5260 else if (SCM_BIGP (z))
f872b822 5261 return SCM_INUM0;
0aacf84e 5262 else if (SCM_REALP (z))
c2ff8ab0 5263 return scm_flo0;
0aacf84e 5264 else if (SCM_COMPLEXP (z))
55f26379 5265 return scm_from_double (SCM_COMPLEX_IMAG (z));
f92e85f7
MV
5266 else if (SCM_FRACTIONP (z))
5267 return SCM_INUM0;
0aacf84e 5268 else
c2ff8ab0 5269 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
0f2d19dd
JB
5270}
5271
f92e85f7
MV
5272SCM_GPROC (s_numerator, "numerator", 1, 0, 0, scm_numerator, g_numerator);
5273/* "Return the numerator of the number @var{z}."
5274 */
5275SCM
5276scm_numerator (SCM z)
5277{
e11e83f3 5278 if (SCM_I_INUMP (z))
f92e85f7
MV
5279 return z;
5280 else if (SCM_BIGP (z))
5281 return z;
5282 else if (SCM_FRACTIONP (z))
5283 {
5284 scm_i_fraction_reduce (z);
5285 return SCM_FRACTION_NUMERATOR (z);
5286 }
5287 else if (SCM_REALP (z))
5288 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
5289 else
5290 SCM_WTA_DISPATCH_1 (g_numerator, z, SCM_ARG1, s_numerator);
5291}
5292
5293
5294SCM_GPROC (s_denominator, "denominator", 1, 0, 0, scm_denominator, g_denominator);
5295/* "Return the denominator of the number @var{z}."
5296 */
5297SCM
5298scm_denominator (SCM z)
5299{
e11e83f3 5300 if (SCM_I_INUMP (z))
d956fa6f 5301 return SCM_I_MAKINUM (1);
f92e85f7 5302 else if (SCM_BIGP (z))
d956fa6f 5303 return SCM_I_MAKINUM (1);
f92e85f7
MV
5304 else if (SCM_FRACTIONP (z))
5305 {
5306 scm_i_fraction_reduce (z);
5307 return SCM_FRACTION_DENOMINATOR (z);
5308 }
5309 else if (SCM_REALP (z))
5310 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
5311 else
5312 SCM_WTA_DISPATCH_1 (g_denominator, z, SCM_ARG1, s_denominator);
5313}
0f2d19dd 5314
9de33deb 5315SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
942e5b91
MG
5316/* "Return the magnitude of the number @var{z}. This is the same as\n"
5317 * "@code{abs} for real arguments, but also allows complex numbers."
5318 */
0f2d19dd 5319SCM
6e8d25a6 5320scm_magnitude (SCM z)
0f2d19dd 5321{
e11e83f3 5322 if (SCM_I_INUMP (z))
0aacf84e 5323 {
e11e83f3 5324 long int zz = SCM_I_INUM (z);
0aacf84e
MD
5325 if (zz >= 0)
5326 return z;
5327 else if (SCM_POSFIXABLE (-zz))
d956fa6f 5328 return SCM_I_MAKINUM (-zz);
0aacf84e
MD
5329 else
5330 return scm_i_long2big (-zz);
5986c47d 5331 }
0aacf84e
MD
5332 else if (SCM_BIGP (z))
5333 {
5334 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
5335 scm_remember_upto_here_1 (z);
5336 if (sgn < 0)
5337 return scm_i_clonebig (z, 0);
5338 else
5339 return z;
5986c47d 5340 }
0aacf84e 5341 else if (SCM_REALP (z))
55f26379 5342 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 5343 else if (SCM_COMPLEXP (z))
55f26379 5344 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
5345 else if (SCM_FRACTIONP (z))
5346 {
73e4de09 5347 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 5348 return z;
cba42c93 5349 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
5350 SCM_FRACTION_DENOMINATOR (z));
5351 }
0aacf84e 5352 else
c2ff8ab0 5353 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
0f2d19dd
JB
5354}
5355
5356
9de33deb 5357SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
942e5b91
MG
5358/* "Return the angle of the complex number @var{z}."
5359 */
0f2d19dd 5360SCM
6e8d25a6 5361scm_angle (SCM z)
0f2d19dd 5362{
c8ae173e 5363 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
55f26379 5364 scm_flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
5365 But if atan2 follows the floating point rounding mode, then the value
5366 is not a constant. Maybe it'd be close enough though. */
e11e83f3 5367 if (SCM_I_INUMP (z))
0aacf84e 5368 {
e11e83f3 5369 if (SCM_I_INUM (z) >= 0)
c8ae173e 5370 return scm_flo0;
0aacf84e 5371 else
55f26379 5372 return scm_from_double (atan2 (0.0, -1.0));
f872b822 5373 }
0aacf84e
MD
5374 else if (SCM_BIGP (z))
5375 {
5376 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
5377 scm_remember_upto_here_1 (z);
5378 if (sgn < 0)
55f26379 5379 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 5380 else
c8ae173e 5381 return scm_flo0;
0f2d19dd 5382 }
0aacf84e 5383 else if (SCM_REALP (z))
c8ae173e
KR
5384 {
5385 if (SCM_REAL_VALUE (z) >= 0)
5386 return scm_flo0;
5387 else
55f26379 5388 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 5389 }
0aacf84e 5390 else if (SCM_COMPLEXP (z))
55f26379 5391 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
5392 else if (SCM_FRACTIONP (z))
5393 {
73e4de09 5394 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 5395 return scm_flo0;
55f26379 5396 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 5397 }
0aacf84e 5398 else
f4c627b3 5399 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
0f2d19dd
JB
5400}
5401
5402
3c9a524f
DH
5403SCM_GPROC (s_exact_to_inexact, "exact->inexact", 1, 0, 0, scm_exact_to_inexact, g_exact_to_inexact);
5404/* Convert the number @var{x} to its inexact representation.\n"
5405 */
5406SCM
5407scm_exact_to_inexact (SCM z)
5408{
e11e83f3 5409 if (SCM_I_INUMP (z))
55f26379 5410 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 5411 else if (SCM_BIGP (z))
55f26379 5412 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 5413 else if (SCM_FRACTIONP (z))
55f26379 5414 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
5415 else if (SCM_INEXACTP (z))
5416 return z;
5417 else
5418 SCM_WTA_DISPATCH_1 (g_exact_to_inexact, z, 1, s_exact_to_inexact);
5419}
5420
5421
a1ec6916 5422SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 5423 (SCM z),
1e6808ea 5424 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 5425#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 5426{
e11e83f3 5427 if (SCM_I_INUMP (z))
f872b822 5428 return z;
0aacf84e 5429 else if (SCM_BIGP (z))
f872b822 5430 return z;
0aacf84e
MD
5431 else if (SCM_REALP (z))
5432 {
f92e85f7
MV
5433 if (xisinf (SCM_REAL_VALUE (z)) || xisnan (SCM_REAL_VALUE (z)))
5434 SCM_OUT_OF_RANGE (1, z);
2be24db4 5435 else
f92e85f7
MV
5436 {
5437 mpq_t frac;
5438 SCM q;
5439
5440 mpq_init (frac);
5441 mpq_set_d (frac, SCM_REAL_VALUE (z));
cba42c93 5442 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
f92e85f7
MV
5443 scm_i_mpz2num (mpq_denref (frac)));
5444
cba42c93 5445 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
5446 for frac...
5447 */
5448 mpq_clear (frac);
5449 return q;
5450 }
c2ff8ab0 5451 }
f92e85f7
MV
5452 else if (SCM_FRACTIONP (z))
5453 return z;
0aacf84e 5454 else
c2ff8ab0 5455 SCM_WRONG_TYPE_ARG (1, z);
0f2d19dd 5456}
1bbd0b84 5457#undef FUNC_NAME
0f2d19dd 5458
f92e85f7
MV
5459SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
5460 (SCM x, SCM err),
5461 "Return an exact number that is within @var{err} of @var{x}.")
5462#define FUNC_NAME s_scm_rationalize
5463{
e11e83f3 5464 if (SCM_I_INUMP (x))
f92e85f7
MV
5465 return x;
5466 else if (SCM_BIGP (x))
5467 return x;
5468 else if ((SCM_REALP (x)) || SCM_FRACTIONP (x))
5469 {
5470 /* Use continued fractions to find closest ratio. All
5471 arithmetic is done with exact numbers.
5472 */
5473
5474 SCM ex = scm_inexact_to_exact (x);
5475 SCM int_part = scm_floor (ex);
d956fa6f
MV
5476 SCM tt = SCM_I_MAKINUM (1);
5477 SCM a1 = SCM_I_MAKINUM (0), a2 = SCM_I_MAKINUM (1), a = SCM_I_MAKINUM (0);
5478 SCM b1 = SCM_I_MAKINUM (1), b2 = SCM_I_MAKINUM (0), b = SCM_I_MAKINUM (0);
f92e85f7
MV
5479 SCM rx;
5480 int i = 0;
5481
73e4de09 5482 if (scm_is_true (scm_num_eq_p (ex, int_part)))
f92e85f7
MV
5483 return ex;
5484
5485 ex = scm_difference (ex, int_part); /* x = x-int_part */
5486 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
5487
5488 /* We stop after a million iterations just to be absolutely sure
5489 that we don't go into an infinite loop. The process normally
5490 converges after less than a dozen iterations.
5491 */
5492
5493 err = scm_abs (err);
5494 while (++i < 1000000)
5495 {
5496 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
5497 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
5498 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
5499 scm_is_false
f92e85f7
MV
5500 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
5501 err))) /* abs(x-a/b) <= err */
02164269
MV
5502 {
5503 SCM res = scm_sum (int_part, scm_divide (a, b));
73e4de09
MV
5504 if (scm_is_false (scm_exact_p (x))
5505 || scm_is_false (scm_exact_p (err)))
02164269
MV
5506 return scm_exact_to_inexact (res);
5507 else
5508 return res;
5509 }
f92e85f7
MV
5510 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
5511 SCM_UNDEFINED);
5512 tt = scm_floor (rx); /* tt = floor (rx) */
5513 a2 = a1;
5514 b2 = b1;
5515 a1 = a;
5516 b1 = b;
5517 }
5518 scm_num_overflow (s_scm_rationalize);
5519 }
5520 else
5521 SCM_WRONG_TYPE_ARG (1, x);
5522}
5523#undef FUNC_NAME
5524
73e4de09
MV
5525/* conversion functions */
5526
5527int
5528scm_is_integer (SCM val)
5529{
5530 return scm_is_true (scm_integer_p (val));
5531}
5532
5533int
5534scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
5535{
e11e83f3 5536 if (SCM_I_INUMP (val))
73e4de09 5537 {
e11e83f3 5538 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
5539 return n >= min && n <= max;
5540 }
5541 else if (SCM_BIGP (val))
5542 {
5543 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
5544 return 0;
5545 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
5546 {
5547 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
5548 {
5549 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
5550 return n >= min && n <= max;
5551 }
5552 else
5553 return 0;
5554 }
73e4de09
MV
5555 else
5556 {
d956fa6f
MV
5557 scm_t_intmax n;
5558 size_t count;
73e4de09 5559
d956fa6f
MV
5560 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
5561 > CHAR_BIT*sizeof (scm_t_uintmax))
5562 return 0;
5563
5564 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
5565 SCM_I_BIG_MPZ (val));
73e4de09 5566
d956fa6f 5567 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 5568 {
d956fa6f
MV
5569 if (n < 0)
5570 return 0;
73e4de09 5571 }
73e4de09
MV
5572 else
5573 {
d956fa6f
MV
5574 n = -n;
5575 if (n >= 0)
5576 return 0;
73e4de09 5577 }
d956fa6f
MV
5578
5579 return n >= min && n <= max;
73e4de09
MV
5580 }
5581 }
73e4de09
MV
5582 else
5583 return 0;
5584}
5585
5586int
5587scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
5588{
e11e83f3 5589 if (SCM_I_INUMP (val))
73e4de09 5590 {
e11e83f3 5591 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
5592 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
5593 }
5594 else if (SCM_BIGP (val))
5595 {
5596 if (max <= SCM_MOST_POSITIVE_FIXNUM)
5597 return 0;
5598 else if (max <= ULONG_MAX)
d956fa6f
MV
5599 {
5600 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
5601 {
5602 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
5603 return n >= min && n <= max;
5604 }
5605 else
5606 return 0;
5607 }
73e4de09
MV
5608 else
5609 {
d956fa6f
MV
5610 scm_t_uintmax n;
5611 size_t count;
73e4de09 5612
d956fa6f
MV
5613 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
5614 return 0;
73e4de09 5615
d956fa6f
MV
5616 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
5617 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 5618 return 0;
d956fa6f
MV
5619
5620 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
5621 SCM_I_BIG_MPZ (val));
73e4de09 5622
d956fa6f 5623 return n >= min && n <= max;
73e4de09
MV
5624 }
5625 }
73e4de09
MV
5626 else
5627 return 0;
5628}
5629
1713d319
MV
5630static void
5631scm_i_range_error (SCM bad_val, SCM min, SCM max)
5632{
5633 scm_error (scm_out_of_range_key,
5634 NULL,
5635 "Value out of range ~S to ~S: ~S",
5636 scm_list_3 (min, max, bad_val),
5637 scm_list_1 (bad_val));
5638}
5639
bfd7932e
MV
5640#define TYPE scm_t_intmax
5641#define TYPE_MIN min
5642#define TYPE_MAX max
5643#define SIZEOF_TYPE 0
5644#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
5645#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
5646#include "libguile/conv-integer.i.c"
5647
5648#define TYPE scm_t_uintmax
5649#define TYPE_MIN min
5650#define TYPE_MAX max
5651#define SIZEOF_TYPE 0
5652#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
5653#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
5654#include "libguile/conv-uinteger.i.c"
5655
5656#define TYPE scm_t_int8
5657#define TYPE_MIN SCM_T_INT8_MIN
5658#define TYPE_MAX SCM_T_INT8_MAX
5659#define SIZEOF_TYPE 1
5660#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
5661#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
5662#include "libguile/conv-integer.i.c"
5663
5664#define TYPE scm_t_uint8
5665#define TYPE_MIN 0
5666#define TYPE_MAX SCM_T_UINT8_MAX
5667#define SIZEOF_TYPE 1
5668#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
5669#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
5670#include "libguile/conv-uinteger.i.c"
5671
5672#define TYPE scm_t_int16
5673#define TYPE_MIN SCM_T_INT16_MIN
5674#define TYPE_MAX SCM_T_INT16_MAX
5675#define SIZEOF_TYPE 2
5676#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
5677#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
5678#include "libguile/conv-integer.i.c"
5679
5680#define TYPE scm_t_uint16
5681#define TYPE_MIN 0
5682#define TYPE_MAX SCM_T_UINT16_MAX
5683#define SIZEOF_TYPE 2
5684#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
5685#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
5686#include "libguile/conv-uinteger.i.c"
5687
5688#define TYPE scm_t_int32
5689#define TYPE_MIN SCM_T_INT32_MIN
5690#define TYPE_MAX SCM_T_INT32_MAX
5691#define SIZEOF_TYPE 4
5692#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
5693#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
5694#include "libguile/conv-integer.i.c"
5695
5696#define TYPE scm_t_uint32
5697#define TYPE_MIN 0
5698#define TYPE_MAX SCM_T_UINT32_MAX
5699#define SIZEOF_TYPE 4
5700#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
5701#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
5702#include "libguile/conv-uinteger.i.c"
5703
5704#if SCM_HAVE_T_INT64
5705
5706#define TYPE scm_t_int64
5707#define TYPE_MIN SCM_T_INT64_MIN
5708#define TYPE_MAX SCM_T_INT64_MAX
5709#define SIZEOF_TYPE 8
5710#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
5711#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
5712#include "libguile/conv-integer.i.c"
5713
5714#define TYPE scm_t_uint64
5715#define TYPE_MIN 0
5716#define TYPE_MAX SCM_T_UINT64_MAX
5717#define SIZEOF_TYPE 8
5718#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
5719#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
5720#include "libguile/conv-uinteger.i.c"
73e4de09 5721
bfd7932e 5722#endif
73e4de09 5723
cd036260
MV
5724void
5725scm_to_mpz (SCM val, mpz_t rop)
5726{
5727 if (SCM_I_INUMP (val))
5728 mpz_set_si (rop, SCM_I_INUM (val));
5729 else if (SCM_BIGP (val))
5730 mpz_set (rop, SCM_I_BIG_MPZ (val));
5731 else
5732 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
5733}
5734
5735SCM
5736scm_from_mpz (mpz_t val)
5737{
5738 return scm_i_mpz2num (val);
5739}
5740
73e4de09
MV
5741int
5742scm_is_real (SCM val)
5743{
5744 return scm_is_true (scm_real_p (val));
5745}
5746
55f26379
MV
5747int
5748scm_is_rational (SCM val)
5749{
5750 return scm_is_true (scm_rational_p (val));
5751}
5752
73e4de09
MV
5753double
5754scm_to_double (SCM val)
5755{
55f26379
MV
5756 if (SCM_I_INUMP (val))
5757 return SCM_I_INUM (val);
5758 else if (SCM_BIGP (val))
5759 return scm_i_big2dbl (val);
5760 else if (SCM_FRACTIONP (val))
5761 return scm_i_fraction2double (val);
5762 else if (SCM_REALP (val))
5763 return SCM_REAL_VALUE (val);
5764 else
7a1aba42 5765 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
5766}
5767
5768SCM
5769scm_from_double (double val)
5770{
55f26379
MV
5771 SCM z = scm_double_cell (scm_tc16_real, 0, 0, 0);
5772 SCM_REAL_VALUE (z) = val;
5773 return z;
73e4de09
MV
5774}
5775
55f26379
MV
5776#if SCM_ENABLE_DISCOURAGED == 1
5777
5778float
5779scm_num2float (SCM num, unsigned long int pos, const char *s_caller)
5780{
5781 if (SCM_BIGP (num))
5782 {
5783 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
5784 if (!xisinf (res))
5785 return res;
5786 else
5787 scm_out_of_range (NULL, num);
5788 }
5789 else
5790 return scm_to_double (num);
5791}
5792
5793double
5794scm_num2double (SCM num, unsigned long int pos, const char *s_caller)
5795{
5796 if (SCM_BIGP (num))
5797 {
5798 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
5799 if (!xisinf (res))
5800 return res;
5801 else
5802 scm_out_of_range (NULL, num);
5803 }
5804 else
5805 return scm_to_double (num);
5806}
5807
5808#endif
5809
8507ec80
MV
5810int
5811scm_is_complex (SCM val)
5812{
5813 return scm_is_true (scm_complex_p (val));
5814}
5815
5816double
5817scm_c_real_part (SCM z)
5818{
5819 if (SCM_COMPLEXP (z))
5820 return SCM_COMPLEX_REAL (z);
5821 else
5822 {
5823 /* Use the scm_real_part to get proper error checking and
5824 dispatching.
5825 */
5826 return scm_to_double (scm_real_part (z));
5827 }
5828}
5829
5830double
5831scm_c_imag_part (SCM z)
5832{
5833 if (SCM_COMPLEXP (z))
5834 return SCM_COMPLEX_IMAG (z);
5835 else
5836 {
5837 /* Use the scm_imag_part to get proper error checking and
5838 dispatching. The result will almost always be 0.0, but not
5839 always.
5840 */
5841 return scm_to_double (scm_imag_part (z));
5842 }
5843}
5844
5845double
5846scm_c_magnitude (SCM z)
5847{
5848 return scm_to_double (scm_magnitude (z));
5849}
5850
5851double
5852scm_c_angle (SCM z)
5853{
5854 return scm_to_double (scm_angle (z));
5855}
5856
5857int
5858scm_is_number (SCM z)
5859{
5860 return scm_is_true (scm_number_p (z));
5861}
5862
0f2d19dd
JB
5863void
5864scm_init_numbers ()
0f2d19dd 5865{
0b799eea
MV
5866 int i;
5867
713a4259
KR
5868 mpz_init_set_si (z_negative_one, -1);
5869
a261c0e9
DH
5870 /* It may be possible to tune the performance of some algorithms by using
5871 * the following constants to avoid the creation of bignums. Please, before
5872 * using these values, remember the two rules of program optimization:
5873 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 5874 scm_c_define ("most-positive-fixnum",
d956fa6f 5875 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 5876 scm_c_define ("most-negative-fixnum",
d956fa6f 5877 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 5878
f3ae5d60
MD
5879 scm_add_feature ("complex");
5880 scm_add_feature ("inexact");
55f26379 5881 scm_flo0 = scm_from_double (0.0);
0b799eea
MV
5882
5883 /* determine floating point precision */
55f26379 5884 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
5885 {
5886 init_dblprec(&scm_dblprec[i-2],i);
5887 init_fx_radix(fx_per_radix[i-2],i);
5888 }
f872b822 5889#ifdef DBL_DIG
0b799eea
MV
5890 /* hard code precision for base 10 if the preprocessor tells us to... */
5891 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
5892#endif
1be6b49c 5893
d956fa6f
MV
5894 exactly_one_half = scm_permanent_object (scm_divide (SCM_I_MAKINUM (1),
5895 SCM_I_MAKINUM (2)));
a0599745 5896#include "libguile/numbers.x"
0f2d19dd 5897}
89e00824
ML
5898
5899/*
5900 Local Variables:
5901 c-file-style: "gnu"
5902 End:
5903*/