docs: fix typos in manual, and a couple in code comments.
[bpt/guile.git] / libguile / numbers.c
CommitLineData
8e43ed5d 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005, 2006, 2007, 2008, 2009, 2010, 2011 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 7 * This library is free software; you can redistribute it and/or
53befeb7
NJ
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 3 of
10 * the License, or (at your option) any later version.
0f2d19dd 11 *
53befeb7
NJ
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
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
53befeb7
NJ
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA
73be1d9e 21 */
1bbd0b84 22
0f2d19dd 23\f
ca46fb90 24/* General assumptions:
ca46fb90
RB
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.
c7218482 28 * XXX What about infinities? They are equal to their own floor! -mhw
f92e85f7 29 * All objects satisfying SCM_FRACTIONP are never an integer.
ca46fb90
RB
30 */
31
32/* TODO:
33
34 - see if special casing bignums and reals in integer-exponent when
35 possible (to use mpz_pow and mpf_pow_ui) is faster.
36
37 - look in to better short-circuiting of common cases in
38 integer-expt and elsewhere.
39
40 - see if direct mpz operations can help in ash and elsewhere.
41
42 */
0f2d19dd 43
dbb605f5 44#ifdef HAVE_CONFIG_H
ee33d62a
RB
45# include <config.h>
46#endif
47
0f2d19dd 48#include <math.h>
fc194577 49#include <string.h>
3f47e526
MG
50#include <unicase.h>
51#include <unictype.h>
f92e85f7 52
8ab3d8a0
KR
53#if HAVE_COMPLEX_H
54#include <complex.h>
55#endif
56
a0599745 57#include "libguile/_scm.h"
a0599745
MD
58#include "libguile/feature.h"
59#include "libguile/ports.h"
60#include "libguile/root.h"
61#include "libguile/smob.h"
62#include "libguile/strings.h"
864e7d42 63#include "libguile/bdw-gc.h"
a0599745
MD
64
65#include "libguile/validate.h"
66#include "libguile/numbers.h"
1be6b49c 67#include "libguile/deprecation.h"
f4c627b3 68
f92e85f7
MV
69#include "libguile/eq.h"
70
8ab3d8a0
KR
71/* values per glibc, if not already defined */
72#ifndef M_LOG10E
73#define M_LOG10E 0.43429448190325182765
74#endif
75#ifndef M_PI
76#define M_PI 3.14159265358979323846
77#endif
78
e25f3727
AW
79typedef scm_t_signed_bits scm_t_inum;
80#define scm_from_inum(x) (scm_from_signed_integer (x))
81
7112615f
MW
82/* Tests to see if a C double is neither infinite nor a NaN.
83 TODO: if it's available, use C99's isfinite(x) instead */
84#define DOUBLE_IS_FINITE(x) (!isinf(x) && !isnan(x))
85
041fccf6
MW
86/* On some platforms, isinf(x) returns 0, 1 or -1, indicating the sign
87 of the infinity, but other platforms return a boolean only. */
88#define DOUBLE_IS_POSITIVE_INFINITY(x) (isinf(x) && ((x) > 0))
89#define DOUBLE_IS_NEGATIVE_INFINITY(x) (isinf(x) && ((x) < 0))
90
0f2d19dd 91\f
f4c627b3 92
ca46fb90
RB
93/*
94 Wonder if this might be faster for some of our code? A switch on
95 the numtag would jump directly to the right case, and the
96 SCM_I_NUMTAG code might be faster than repeated SCM_FOOP tests...
97
98 #define SCM_I_NUMTAG_NOTNUM 0
99 #define SCM_I_NUMTAG_INUM 1
100 #define SCM_I_NUMTAG_BIG scm_tc16_big
101 #define SCM_I_NUMTAG_REAL scm_tc16_real
102 #define SCM_I_NUMTAG_COMPLEX scm_tc16_complex
103 #define SCM_I_NUMTAG(x) \
e11e83f3 104 (SCM_I_INUMP(x) ? SCM_I_NUMTAG_INUM \
ca46fb90 105 : (SCM_IMP(x) ? SCM_I_NUMTAG_NOTNUM \
534c55a9 106 : (((0xfcff & SCM_CELL_TYPE (x)) == scm_tc7_number) ? SCM_TYP16(x) \
ca46fb90
RB
107 : SCM_I_NUMTAG_NOTNUM)))
108*/
f92e85f7 109/* the macro above will not work as is with fractions */
f4c627b3
DH
110
111
e7efe8e7 112static SCM flo0;
ff62c168 113static SCM exactly_one_half;
e7efe8e7 114
34d19ef6 115#define SCM_SWAP(x, y) do { SCM __t = x; x = y; y = __t; } while (0)
09fb7599 116
56e55ac7 117/* FLOBUFLEN is the maximum number of characters neccessary for the
3a9809df
DH
118 * printed or scm_string representation of an inexact number.
119 */
0b799eea 120#define FLOBUFLEN (40+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
3a9809df 121
b127c712 122
ad79736c
AW
123#if !defined (HAVE_ASINH)
124static double asinh (double x) { return log (x + sqrt (x * x + 1)); }
125#endif
126#if !defined (HAVE_ACOSH)
127static double acosh (double x) { return log (x + sqrt (x * x - 1)); }
128#endif
129#if !defined (HAVE_ATANH)
130static double atanh (double x) { return 0.5 * log ((1 + x) / (1 - x)); }
131#endif
132
f8a8200b
KR
133/* mpz_cmp_d in gmp 4.1.3 doesn't recognise infinities, so xmpz_cmp_d uses
134 an explicit check. In some future gmp (don't know what version number),
135 mpz_cmp_d is supposed to do this itself. */
136#if 1
b127c712 137#define xmpz_cmp_d(z, d) \
2e65b52f 138 (isinf (d) ? (d < 0.0 ? 1 : -1) : mpz_cmp_d (z, d))
b127c712
KR
139#else
140#define xmpz_cmp_d(z, d) mpz_cmp_d (z, d)
141#endif
142
f92e85f7 143
4b26c03e 144#if defined (GUILE_I)
bca69a9f 145#if HAVE_COMPLEX_DOUBLE
8ab3d8a0
KR
146
147/* For an SCM object Z which is a complex number (ie. satisfies
148 SCM_COMPLEXP), return its value as a C level "complex double". */
149#define SCM_COMPLEX_VALUE(z) \
4b26c03e 150 (SCM_COMPLEX_REAL (z) + GUILE_I * SCM_COMPLEX_IMAG (z))
8ab3d8a0 151
7a35784c 152static inline SCM scm_from_complex_double (complex double z) SCM_UNUSED;
8ab3d8a0
KR
153
154/* Convert a C "complex double" to an SCM value. */
7a35784c 155static inline SCM
8ab3d8a0
KR
156scm_from_complex_double (complex double z)
157{
158 return scm_c_make_rectangular (creal (z), cimag (z));
159}
bca69a9f 160
8ab3d8a0 161#endif /* HAVE_COMPLEX_DOUBLE */
bca69a9f 162#endif /* GUILE_I */
8ab3d8a0 163
0f2d19dd
JB
164\f
165
713a4259 166static mpz_t z_negative_one;
ac0c002c
DH
167
168\f
864e7d42
LC
169/* Clear the `mpz_t' embedded in bignum PTR. */
170static void
171finalize_bignum (GC_PTR ptr, GC_PTR data)
172{
173 SCM bignum;
174
175 bignum = PTR2SCM (ptr);
176 mpz_clear (SCM_I_BIG_MPZ (bignum));
177}
178
d017fcdf
LC
179/* Return a new uninitialized bignum. */
180static inline SCM
181make_bignum (void)
182{
183 scm_t_bits *p;
864e7d42
LC
184 GC_finalization_proc prev_finalizer;
185 GC_PTR prev_finalizer_data;
d017fcdf
LC
186
187 /* Allocate one word for the type tag and enough room for an `mpz_t'. */
188 p = scm_gc_malloc_pointerless (sizeof (scm_t_bits) + sizeof (mpz_t),
189 "bignum");
190 p[0] = scm_tc16_big;
191
864e7d42
LC
192 GC_REGISTER_FINALIZER_NO_ORDER (p, finalize_bignum, NULL,
193 &prev_finalizer,
194 &prev_finalizer_data);
195
d017fcdf
LC
196 return SCM_PACK (p);
197}
ac0c002c 198
864e7d42 199
189171c5 200SCM
ca46fb90
RB
201scm_i_mkbig ()
202{
203 /* Return a newly created bignum. */
d017fcdf 204 SCM z = make_bignum ();
ca46fb90
RB
205 mpz_init (SCM_I_BIG_MPZ (z));
206 return z;
207}
208
e25f3727
AW
209static SCM
210scm_i_inum2big (scm_t_inum x)
211{
212 /* Return a newly created bignum initialized to X. */
213 SCM z = make_bignum ();
214#if SIZEOF_VOID_P == SIZEOF_LONG
215 mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
216#else
217 /* Note that in this case, you'll also have to check all mpz_*_ui and
218 mpz_*_si invocations in Guile. */
219#error creation of mpz not implemented for this inum size
220#endif
221 return z;
222}
223
189171c5 224SCM
c71b0706
MV
225scm_i_long2big (long x)
226{
227 /* Return a newly created bignum initialized to X. */
d017fcdf 228 SCM z = make_bignum ();
c71b0706
MV
229 mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
230 return z;
231}
232
189171c5 233SCM
c71b0706
MV
234scm_i_ulong2big (unsigned long x)
235{
236 /* Return a newly created bignum initialized to X. */
d017fcdf 237 SCM z = make_bignum ();
c71b0706
MV
238 mpz_init_set_ui (SCM_I_BIG_MPZ (z), x);
239 return z;
240}
241
189171c5 242SCM
ca46fb90
RB
243scm_i_clonebig (SCM src_big, int same_sign_p)
244{
245 /* Copy src_big's value, negate it if same_sign_p is false, and return. */
d017fcdf 246 SCM z = make_bignum ();
ca46fb90 247 mpz_init_set (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (src_big));
0aacf84e
MD
248 if (!same_sign_p)
249 mpz_neg (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (z));
ca46fb90
RB
250 return z;
251}
252
189171c5 253int
ca46fb90
RB
254scm_i_bigcmp (SCM x, SCM y)
255{
256 /* Return neg if x < y, pos if x > y, and 0 if x == y */
257 /* presume we already know x and y are bignums */
258 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
259 scm_remember_upto_here_2 (x, y);
260 return result;
261}
262
189171c5 263SCM
ca46fb90
RB
264scm_i_dbl2big (double d)
265{
266 /* results are only defined if d is an integer */
d017fcdf 267 SCM z = make_bignum ();
ca46fb90
RB
268 mpz_init_set_d (SCM_I_BIG_MPZ (z), d);
269 return z;
270}
271
f92e85f7
MV
272/* Convert a integer in double representation to a SCM number. */
273
189171c5 274SCM
f92e85f7
MV
275scm_i_dbl2num (double u)
276{
277 /* SCM_MOST_POSITIVE_FIXNUM+1 and SCM_MOST_NEGATIVE_FIXNUM are both
278 powers of 2, so there's no rounding when making "double" values
279 from them. If plain SCM_MOST_POSITIVE_FIXNUM was used it could
280 get rounded on a 64-bit machine, hence the "+1".
281
282 The use of floor() to force to an integer value ensures we get a
283 "numerically closest" value without depending on how a
284 double->long cast or how mpz_set_d will round. For reference,
285 double->long probably follows the hardware rounding mode,
286 mpz_set_d truncates towards zero. */
287
288 /* XXX - what happens when SCM_MOST_POSITIVE_FIXNUM etc is not
289 representable as a double? */
290
291 if (u < (double) (SCM_MOST_POSITIVE_FIXNUM+1)
292 && u >= (double) SCM_MOST_NEGATIVE_FIXNUM)
e25f3727 293 return SCM_I_MAKINUM ((scm_t_inum) u);
f92e85f7
MV
294 else
295 return scm_i_dbl2big (u);
296}
297
089c9a59
KR
298/* scm_i_big2dbl() rounds to the closest representable double, in accordance
299 with R5RS exact->inexact.
300
301 The approach is to use mpz_get_d to pick out the high DBL_MANT_DIG bits
f8a8200b
KR
302 (ie. truncate towards zero), then adjust to get the closest double by
303 examining the next lower bit and adding 1 (to the absolute value) if
304 necessary.
305
306 Bignums exactly half way between representable doubles are rounded to the
307 next higher absolute value (ie. away from zero). This seems like an
308 adequate interpretation of R5RS "numerically closest", and it's easier
309 and faster than a full "nearest-even" style.
310
311 The bit test must be done on the absolute value of the mpz_t, which means
312 we need to use mpz_getlimbn. mpz_tstbit is not right, it treats
313 negatives as twos complement.
314
315 In current gmp 4.1.3, mpz_get_d rounding is unspecified. It ends up
316 following the hardware rounding mode, but applied to the absolute value
317 of the mpz_t operand. This is not what we want so we put the high
318 DBL_MANT_DIG bits into a temporary. In some future gmp, don't know when,
319 mpz_get_d is supposed to always truncate towards zero.
320
321 ENHANCE-ME: The temporary init+clear to force the rounding in gmp 4.1.3
322 is a slowdown. It'd be faster to pick out the relevant high bits with
323 mpz_getlimbn if we could be bothered coding that, and if the new
324 truncating gmp doesn't come out. */
089c9a59
KR
325
326double
ca46fb90
RB
327scm_i_big2dbl (SCM b)
328{
089c9a59
KR
329 double result;
330 size_t bits;
331
332 bits = mpz_sizeinbase (SCM_I_BIG_MPZ (b), 2);
333
f8a8200b 334#if 1
089c9a59 335 {
f8a8200b 336 /* Current GMP, eg. 4.1.3, force truncation towards zero */
089c9a59
KR
337 mpz_t tmp;
338 if (bits > DBL_MANT_DIG)
339 {
340 size_t shift = bits - DBL_MANT_DIG;
341 mpz_init2 (tmp, DBL_MANT_DIG);
342 mpz_tdiv_q_2exp (tmp, SCM_I_BIG_MPZ (b), shift);
343 result = ldexp (mpz_get_d (tmp), shift);
344 mpz_clear (tmp);
345 }
346 else
347 {
348 result = mpz_get_d (SCM_I_BIG_MPZ (b));
349 }
350 }
351#else
f8a8200b 352 /* Future GMP */
089c9a59
KR
353 result = mpz_get_d (SCM_I_BIG_MPZ (b));
354#endif
355
356 if (bits > DBL_MANT_DIG)
357 {
358 unsigned long pos = bits - DBL_MANT_DIG - 1;
359 /* test bit number "pos" in absolute value */
360 if (mpz_getlimbn (SCM_I_BIG_MPZ (b), pos / GMP_NUMB_BITS)
361 & ((mp_limb_t) 1 << (pos % GMP_NUMB_BITS)))
362 {
363 result += ldexp ((double) mpz_sgn (SCM_I_BIG_MPZ (b)), pos + 1);
364 }
365 }
366
ca46fb90
RB
367 scm_remember_upto_here_1 (b);
368 return result;
369}
370
189171c5 371SCM
ca46fb90
RB
372scm_i_normbig (SCM b)
373{
374 /* convert a big back to a fixnum if it'll fit */
375 /* presume b is a bignum */
376 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (b)))
377 {
e25f3727 378 scm_t_inum val = mpz_get_si (SCM_I_BIG_MPZ (b));
ca46fb90 379 if (SCM_FIXABLE (val))
d956fa6f 380 b = SCM_I_MAKINUM (val);
ca46fb90
RB
381 }
382 return b;
383}
f872b822 384
f92e85f7
MV
385static SCM_C_INLINE_KEYWORD SCM
386scm_i_mpz2num (mpz_t b)
387{
388 /* convert a mpz number to a SCM number. */
389 if (mpz_fits_slong_p (b))
390 {
e25f3727 391 scm_t_inum val = mpz_get_si (b);
f92e85f7 392 if (SCM_FIXABLE (val))
d956fa6f 393 return SCM_I_MAKINUM (val);
f92e85f7
MV
394 }
395
396 {
d017fcdf 397 SCM z = make_bignum ();
f92e85f7
MV
398 mpz_init_set (SCM_I_BIG_MPZ (z), b);
399 return z;
400 }
401}
402
403/* this is needed when we want scm_divide to make a float, not a ratio, even if passed two ints */
404static SCM scm_divide2real (SCM x, SCM y);
405
cba42c93
MV
406static SCM
407scm_i_make_ratio (SCM numerator, SCM denominator)
c60e130c 408#define FUNC_NAME "make-ratio"
f92e85f7 409{
c60e130c
MV
410 /* First make sure the arguments are proper.
411 */
e11e83f3 412 if (SCM_I_INUMP (denominator))
f92e85f7 413 {
bc36d050 414 if (scm_is_eq (denominator, SCM_INUM0))
f92e85f7 415 scm_num_overflow ("make-ratio");
cff5fa33 416 if (scm_is_eq (denominator, SCM_INUM1))
f92e85f7
MV
417 return numerator;
418 }
419 else
420 {
421 if (!(SCM_BIGP(denominator)))
422 SCM_WRONG_TYPE_ARG (2, denominator);
423 }
e11e83f3 424 if (!SCM_I_INUMP (numerator) && !SCM_BIGP (numerator))
c60e130c
MV
425 SCM_WRONG_TYPE_ARG (1, numerator);
426
427 /* Then flip signs so that the denominator is positive.
428 */
73e4de09 429 if (scm_is_true (scm_negative_p (denominator)))
c60e130c
MV
430 {
431 numerator = scm_difference (numerator, SCM_UNDEFINED);
432 denominator = scm_difference (denominator, SCM_UNDEFINED);
433 }
434
435 /* Now consider for each of the four fixnum/bignum combinations
436 whether the rational number is really an integer.
437 */
e11e83f3 438 if (SCM_I_INUMP (numerator))
f92e85f7 439 {
e25f3727 440 scm_t_inum x = SCM_I_INUM (numerator);
bc36d050 441 if (scm_is_eq (numerator, SCM_INUM0))
f92e85f7 442 return SCM_INUM0;
e11e83f3 443 if (SCM_I_INUMP (denominator))
f92e85f7 444 {
e25f3727 445 scm_t_inum y;
e11e83f3 446 y = SCM_I_INUM (denominator);
f92e85f7 447 if (x == y)
cff5fa33 448 return SCM_INUM1;
f92e85f7 449 if ((x % y) == 0)
d956fa6f 450 return SCM_I_MAKINUM (x / y);
f92e85f7 451 }
dd5130ca
KR
452 else
453 {
454 /* When x == SCM_MOST_NEGATIVE_FIXNUM we could have the negative
3271a325
KR
455 of that value for the denominator, as a bignum. Apart from
456 that case, abs(bignum) > abs(inum) so inum/bignum is not an
457 integer. */
458 if (x == SCM_MOST_NEGATIVE_FIXNUM
459 && mpz_cmp_ui (SCM_I_BIG_MPZ (denominator),
460 - SCM_MOST_NEGATIVE_FIXNUM) == 0)
d956fa6f 461 return SCM_I_MAKINUM(-1);
dd5130ca 462 }
f92e85f7 463 }
c60e130c 464 else if (SCM_BIGP (numerator))
f92e85f7 465 {
e11e83f3 466 if (SCM_I_INUMP (denominator))
c60e130c 467 {
e25f3727 468 scm_t_inum yy = SCM_I_INUM (denominator);
c60e130c
MV
469 if (mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), yy))
470 return scm_divide (numerator, denominator);
471 }
472 else
f92e85f7 473 {
bc36d050 474 if (scm_is_eq (numerator, denominator))
cff5fa33 475 return SCM_INUM1;
c60e130c
MV
476 if (mpz_divisible_p (SCM_I_BIG_MPZ (numerator),
477 SCM_I_BIG_MPZ (denominator)))
478 return scm_divide(numerator, denominator);
f92e85f7 479 }
f92e85f7 480 }
c60e130c
MV
481
482 /* No, it's a proper fraction.
483 */
e2bf3b19
HWN
484 {
485 SCM divisor = scm_gcd (numerator, denominator);
cff5fa33 486 if (!(scm_is_eq (divisor, SCM_INUM1)))
e2bf3b19
HWN
487 {
488 numerator = scm_divide (numerator, divisor);
489 denominator = scm_divide (denominator, divisor);
490 }
491
492 return scm_double_cell (scm_tc16_fraction,
493 SCM_UNPACK (numerator),
494 SCM_UNPACK (denominator), 0);
495 }
f92e85f7 496}
c60e130c 497#undef FUNC_NAME
f92e85f7 498
f92e85f7
MV
499double
500scm_i_fraction2double (SCM z)
501{
55f26379
MV
502 return scm_to_double (scm_divide2real (SCM_FRACTION_NUMERATOR (z),
503 SCM_FRACTION_DENOMINATOR (z)));
f92e85f7
MV
504}
505
2e274311
MW
506static int
507double_is_non_negative_zero (double x)
508{
509 static double zero = 0.0;
510
511 return !memcmp (&x, &zero, sizeof(double));
512}
513
2519490c
MW
514SCM_PRIMITIVE_GENERIC (scm_exact_p, "exact?", 1, 0, 0,
515 (SCM x),
942e5b91
MG
516 "Return @code{#t} if @var{x} is an exact number, @code{#f}\n"
517 "otherwise.")
1bbd0b84 518#define FUNC_NAME s_scm_exact_p
0f2d19dd 519{
41df63cf
MW
520 if (SCM_INEXACTP (x))
521 return SCM_BOOL_F;
522 else if (SCM_NUMBERP (x))
0aacf84e 523 return SCM_BOOL_T;
41df63cf 524 else
2519490c 525 SCM_WTA_DISPATCH_1 (g_scm_exact_p, x, 1, s_scm_exact_p);
41df63cf
MW
526}
527#undef FUNC_NAME
528
529
2519490c 530SCM_PRIMITIVE_GENERIC (scm_inexact_p, "inexact?", 1, 0, 0,
41df63cf
MW
531 (SCM x),
532 "Return @code{#t} if @var{x} is an inexact number, @code{#f}\n"
533 "else.")
534#define FUNC_NAME s_scm_inexact_p
535{
536 if (SCM_INEXACTP (x))
f92e85f7 537 return SCM_BOOL_T;
41df63cf 538 else if (SCM_NUMBERP (x))
eb927cb9 539 return SCM_BOOL_F;
41df63cf 540 else
2519490c 541 SCM_WTA_DISPATCH_1 (g_scm_inexact_p, x, 1, s_scm_inexact_p);
0f2d19dd 542}
1bbd0b84 543#undef FUNC_NAME
0f2d19dd 544
4219f20d 545
2519490c 546SCM_PRIMITIVE_GENERIC (scm_odd_p, "odd?", 1, 0, 0,
1bbd0b84 547 (SCM n),
942e5b91
MG
548 "Return @code{#t} if @var{n} is an odd number, @code{#f}\n"
549 "otherwise.")
1bbd0b84 550#define FUNC_NAME s_scm_odd_p
0f2d19dd 551{
e11e83f3 552 if (SCM_I_INUMP (n))
0aacf84e 553 {
e25f3727 554 scm_t_inum val = SCM_I_INUM (n);
73e4de09 555 return scm_from_bool ((val & 1L) != 0);
0aacf84e
MD
556 }
557 else if (SCM_BIGP (n))
558 {
559 int odd_p = mpz_odd_p (SCM_I_BIG_MPZ (n));
560 scm_remember_upto_here_1 (n);
73e4de09 561 return scm_from_bool (odd_p);
0aacf84e 562 }
f92e85f7
MV
563 else if (SCM_REALP (n))
564 {
2519490c
MW
565 double val = SCM_REAL_VALUE (n);
566 if (DOUBLE_IS_FINITE (val))
567 {
568 double rem = fabs (fmod (val, 2.0));
569 if (rem == 1.0)
570 return SCM_BOOL_T;
571 else if (rem == 0.0)
572 return SCM_BOOL_F;
573 }
f92e85f7 574 }
2519490c 575 SCM_WTA_DISPATCH_1 (g_scm_odd_p, n, 1, s_scm_odd_p);
0f2d19dd 576}
1bbd0b84 577#undef FUNC_NAME
0f2d19dd 578
4219f20d 579
2519490c 580SCM_PRIMITIVE_GENERIC (scm_even_p, "even?", 1, 0, 0,
1bbd0b84 581 (SCM n),
942e5b91
MG
582 "Return @code{#t} if @var{n} is an even number, @code{#f}\n"
583 "otherwise.")
1bbd0b84 584#define FUNC_NAME s_scm_even_p
0f2d19dd 585{
e11e83f3 586 if (SCM_I_INUMP (n))
0aacf84e 587 {
e25f3727 588 scm_t_inum val = SCM_I_INUM (n);
73e4de09 589 return scm_from_bool ((val & 1L) == 0);
0aacf84e
MD
590 }
591 else if (SCM_BIGP (n))
592 {
593 int even_p = mpz_even_p (SCM_I_BIG_MPZ (n));
594 scm_remember_upto_here_1 (n);
73e4de09 595 return scm_from_bool (even_p);
0aacf84e 596 }
f92e85f7
MV
597 else if (SCM_REALP (n))
598 {
2519490c
MW
599 double val = SCM_REAL_VALUE (n);
600 if (DOUBLE_IS_FINITE (val))
601 {
602 double rem = fabs (fmod (val, 2.0));
603 if (rem == 1.0)
604 return SCM_BOOL_F;
605 else if (rem == 0.0)
606 return SCM_BOOL_T;
607 }
f92e85f7 608 }
2519490c 609 SCM_WTA_DISPATCH_1 (g_scm_even_p, n, 1, s_scm_even_p);
0f2d19dd 610}
1bbd0b84 611#undef FUNC_NAME
0f2d19dd 612
2519490c
MW
613SCM_PRIMITIVE_GENERIC (scm_finite_p, "finite?", 1, 0, 0,
614 (SCM x),
10391e06
AW
615 "Return @code{#t} if the real number @var{x} is neither\n"
616 "infinite nor a NaN, @code{#f} otherwise.")
7112615f
MW
617#define FUNC_NAME s_scm_finite_p
618{
619 if (SCM_REALP (x))
620 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
10391e06 621 else if (scm_is_real (x))
7112615f
MW
622 return SCM_BOOL_T;
623 else
2519490c 624 SCM_WTA_DISPATCH_1 (g_scm_finite_p, x, 1, s_scm_finite_p);
7112615f
MW
625}
626#undef FUNC_NAME
627
2519490c
MW
628SCM_PRIMITIVE_GENERIC (scm_inf_p, "inf?", 1, 0, 0,
629 (SCM x),
630 "Return @code{#t} if the real number @var{x} is @samp{+inf.0} or\n"
631 "@samp{-inf.0}. Otherwise return @code{#f}.")
7351e207
MV
632#define FUNC_NAME s_scm_inf_p
633{
b1092b3a 634 if (SCM_REALP (x))
2e65b52f 635 return scm_from_bool (isinf (SCM_REAL_VALUE (x)));
10391e06 636 else if (scm_is_real (x))
7351e207 637 return SCM_BOOL_F;
10391e06 638 else
2519490c 639 SCM_WTA_DISPATCH_1 (g_scm_inf_p, x, 1, s_scm_inf_p);
7351e207
MV
640}
641#undef FUNC_NAME
642
2519490c
MW
643SCM_PRIMITIVE_GENERIC (scm_nan_p, "nan?", 1, 0, 0,
644 (SCM x),
10391e06
AW
645 "Return @code{#t} if the real number @var{x} is a NaN,\n"
646 "or @code{#f} otherwise.")
7351e207
MV
647#define FUNC_NAME s_scm_nan_p
648{
10391e06
AW
649 if (SCM_REALP (x))
650 return scm_from_bool (isnan (SCM_REAL_VALUE (x)));
651 else if (scm_is_real (x))
7351e207 652 return SCM_BOOL_F;
10391e06 653 else
2519490c 654 SCM_WTA_DISPATCH_1 (g_scm_nan_p, x, 1, s_scm_nan_p);
7351e207
MV
655}
656#undef FUNC_NAME
657
658/* Guile's idea of infinity. */
659static double guile_Inf;
660
661/* Guile's idea of not a number. */
662static double guile_NaN;
663
664static void
665guile_ieee_init (void)
666{
7351e207
MV
667/* Some version of gcc on some old version of Linux used to crash when
668 trying to make Inf and NaN. */
669
240a27d2
KR
670#ifdef INFINITY
671 /* C99 INFINITY, when available.
672 FIXME: The standard allows for INFINITY to be something that overflows
673 at compile time. We ought to have a configure test to check for that
674 before trying to use it. (But in practice we believe this is not a
675 problem on any system guile is likely to target.) */
676 guile_Inf = INFINITY;
56a3dcd4 677#elif defined HAVE_DINFINITY
240a27d2 678 /* OSF */
7351e207 679 extern unsigned int DINFINITY[2];
eaa94eaa 680 guile_Inf = (*((double *) (DINFINITY)));
7351e207
MV
681#else
682 double tmp = 1e+10;
683 guile_Inf = tmp;
684 for (;;)
685 {
686 guile_Inf *= 1e+10;
687 if (guile_Inf == tmp)
688 break;
689 tmp = guile_Inf;
690 }
691#endif
692
240a27d2
KR
693#ifdef NAN
694 /* C99 NAN, when available */
695 guile_NaN = NAN;
56a3dcd4 696#elif defined HAVE_DQNAN
eaa94eaa
LC
697 {
698 /* OSF */
699 extern unsigned int DQNAN[2];
700 guile_NaN = (*((double *)(DQNAN)));
701 }
7351e207
MV
702#else
703 guile_NaN = guile_Inf / guile_Inf;
704#endif
7351e207
MV
705}
706
707SCM_DEFINE (scm_inf, "inf", 0, 0, 0,
708 (void),
709 "Return Inf.")
710#define FUNC_NAME s_scm_inf
711{
712 static int initialized = 0;
713 if (! initialized)
714 {
715 guile_ieee_init ();
716 initialized = 1;
717 }
55f26379 718 return scm_from_double (guile_Inf);
7351e207
MV
719}
720#undef FUNC_NAME
721
722SCM_DEFINE (scm_nan, "nan", 0, 0, 0,
723 (void),
724 "Return NaN.")
725#define FUNC_NAME s_scm_nan
726{
727 static int initialized = 0;
0aacf84e 728 if (!initialized)
7351e207
MV
729 {
730 guile_ieee_init ();
731 initialized = 1;
732 }
55f26379 733 return scm_from_double (guile_NaN);
7351e207
MV
734}
735#undef FUNC_NAME
736
4219f20d 737
a48d60b1
MD
738SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
739 (SCM x),
740 "Return the absolute value of @var{x}.")
2519490c 741#define FUNC_NAME s_scm_abs
0f2d19dd 742{
e11e83f3 743 if (SCM_I_INUMP (x))
0aacf84e 744 {
e25f3727 745 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
746 if (xx >= 0)
747 return x;
748 else if (SCM_POSFIXABLE (-xx))
d956fa6f 749 return SCM_I_MAKINUM (-xx);
0aacf84e 750 else
e25f3727 751 return scm_i_inum2big (-xx);
4219f20d 752 }
9b9ef10c
MW
753 else if (SCM_LIKELY (SCM_REALP (x)))
754 {
755 double xx = SCM_REAL_VALUE (x);
756 /* If x is a NaN then xx<0 is false so we return x unchanged */
757 if (xx < 0.0)
758 return scm_from_double (-xx);
759 /* Handle signed zeroes properly */
760 else if (SCM_UNLIKELY (xx == 0.0))
761 return flo0;
762 else
763 return x;
764 }
0aacf84e
MD
765 else if (SCM_BIGP (x))
766 {
767 const int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
768 if (sgn < 0)
769 return scm_i_clonebig (x, 0);
770 else
771 return x;
4219f20d 772 }
f92e85f7
MV
773 else if (SCM_FRACTIONP (x))
774 {
73e4de09 775 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (x))))
f92e85f7 776 return x;
cba42c93 777 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7
MV
778 SCM_FRACTION_DENOMINATOR (x));
779 }
0aacf84e 780 else
a48d60b1 781 SCM_WTA_DISPATCH_1 (g_scm_abs, x, 1, s_scm_abs);
0f2d19dd 782}
a48d60b1 783#undef FUNC_NAME
0f2d19dd 784
4219f20d 785
2519490c
MW
786SCM_PRIMITIVE_GENERIC (scm_quotient, "quotient", 2, 0, 0,
787 (SCM x, SCM y),
788 "Return the quotient of the numbers @var{x} and @var{y}.")
789#define FUNC_NAME s_scm_quotient
0f2d19dd 790{
a16982ca 791 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 792 {
e25f3727 793 scm_t_inum xx = SCM_I_INUM (x);
a16982ca 794 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 795 {
e25f3727 796 scm_t_inum yy = SCM_I_INUM (y);
a16982ca 797 if (SCM_UNLIKELY (yy == 0))
2519490c 798 scm_num_overflow (s_scm_quotient);
0aacf84e
MD
799 else
800 {
e25f3727 801 scm_t_inum z = xx / yy;
a16982ca 802 if (SCM_LIKELY (SCM_FIXABLE (z)))
d956fa6f 803 return SCM_I_MAKINUM (z);
0aacf84e 804 else
e25f3727 805 return scm_i_inum2big (z);
0aacf84e 806 }
828865c3 807 }
0aacf84e 808 else if (SCM_BIGP (y))
ac0c002c 809 {
e11e83f3 810 if ((SCM_I_INUM (x) == SCM_MOST_NEGATIVE_FIXNUM)
4dc09ee4
KR
811 && (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
812 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
813 {
814 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
815 scm_remember_upto_here_1 (y);
d956fa6f 816 return SCM_I_MAKINUM (-1);
4dc09ee4 817 }
0aacf84e 818 else
cff5fa33 819 return SCM_INUM0;
ac0c002c
DH
820 }
821 else
2519490c 822 SCM_WTA_DISPATCH_2 (g_scm_quotient, x, y, SCM_ARG2, s_scm_quotient);
828865c3 823 }
0aacf84e
MD
824 else if (SCM_BIGP (x))
825 {
a16982ca 826 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 827 {
e25f3727 828 scm_t_inum yy = SCM_I_INUM (y);
a16982ca 829 if (SCM_UNLIKELY (yy == 0))
2519490c 830 scm_num_overflow (s_scm_quotient);
a16982ca 831 else if (SCM_UNLIKELY (yy == 1))
0aacf84e
MD
832 return x;
833 else
834 {
835 SCM result = scm_i_mkbig ();
836 if (yy < 0)
837 {
838 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (result),
839 SCM_I_BIG_MPZ (x),
840 - yy);
841 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
842 }
843 else
844 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
845 scm_remember_upto_here_1 (x);
846 return scm_i_normbig (result);
847 }
848 }
849 else if (SCM_BIGP (y))
850 {
851 SCM result = scm_i_mkbig ();
852 mpz_tdiv_q (SCM_I_BIG_MPZ (result),
853 SCM_I_BIG_MPZ (x),
854 SCM_I_BIG_MPZ (y));
855 scm_remember_upto_here_2 (x, y);
856 return scm_i_normbig (result);
857 }
858 else
2519490c 859 SCM_WTA_DISPATCH_2 (g_scm_quotient, x, y, SCM_ARG2, s_scm_quotient);
f872b822 860 }
0aacf84e 861 else
2519490c 862 SCM_WTA_DISPATCH_2 (g_scm_quotient, x, y, SCM_ARG1, s_scm_quotient);
0f2d19dd 863}
2519490c 864#undef FUNC_NAME
0f2d19dd 865
2519490c
MW
866SCM_PRIMITIVE_GENERIC (scm_remainder, "remainder", 2, 0, 0,
867 (SCM x, SCM y),
868 "Return the remainder of the numbers @var{x} and @var{y}.\n"
869 "@lisp\n"
870 "(remainder 13 4) @result{} 1\n"
871 "(remainder -13 4) @result{} -1\n"
872 "@end lisp")
873#define FUNC_NAME s_scm_remainder
0f2d19dd 874{
a16982ca 875 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 876 {
a16982ca 877 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 878 {
e25f3727 879 scm_t_inum yy = SCM_I_INUM (y);
a16982ca 880 if (SCM_UNLIKELY (yy == 0))
2519490c 881 scm_num_overflow (s_scm_remainder);
0aacf84e
MD
882 else
883 {
a16982ca
MW
884 /* C99 specifies that "%" is the remainder corresponding to a
885 quotient rounded towards zero, and that's also traditional
886 for machine division, so z here should be well defined. */
e25f3727 887 scm_t_inum z = SCM_I_INUM (x) % yy;
d956fa6f 888 return SCM_I_MAKINUM (z);
0aacf84e
MD
889 }
890 }
891 else if (SCM_BIGP (y))
ac0c002c 892 {
e11e83f3 893 if ((SCM_I_INUM (x) == SCM_MOST_NEGATIVE_FIXNUM)
4dc09ee4
KR
894 && (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
895 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
896 {
897 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
898 scm_remember_upto_here_1 (y);
cff5fa33 899 return SCM_INUM0;
4dc09ee4 900 }
0aacf84e
MD
901 else
902 return x;
ac0c002c
DH
903 }
904 else
2519490c 905 SCM_WTA_DISPATCH_2 (g_scm_remainder, x, y, SCM_ARG2, s_scm_remainder);
89a7e495 906 }
0aacf84e
MD
907 else if (SCM_BIGP (x))
908 {
a16982ca 909 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 910 {
e25f3727 911 scm_t_inum yy = SCM_I_INUM (y);
a16982ca 912 if (SCM_UNLIKELY (yy == 0))
2519490c 913 scm_num_overflow (s_scm_remainder);
0aacf84e
MD
914 else
915 {
916 SCM result = scm_i_mkbig ();
917 if (yy < 0)
918 yy = - yy;
919 mpz_tdiv_r_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ(x), yy);
920 scm_remember_upto_here_1 (x);
921 return scm_i_normbig (result);
922 }
923 }
924 else if (SCM_BIGP (y))
925 {
926 SCM result = scm_i_mkbig ();
927 mpz_tdiv_r (SCM_I_BIG_MPZ (result),
928 SCM_I_BIG_MPZ (x),
929 SCM_I_BIG_MPZ (y));
930 scm_remember_upto_here_2 (x, y);
931 return scm_i_normbig (result);
932 }
933 else
2519490c 934 SCM_WTA_DISPATCH_2 (g_scm_remainder, x, y, SCM_ARG2, s_scm_remainder);
f872b822 935 }
0aacf84e 936 else
2519490c 937 SCM_WTA_DISPATCH_2 (g_scm_remainder, x, y, SCM_ARG1, s_scm_remainder);
0f2d19dd 938}
2519490c 939#undef FUNC_NAME
0f2d19dd 940
89a7e495 941
2519490c
MW
942SCM_PRIMITIVE_GENERIC (scm_modulo, "modulo", 2, 0, 0,
943 (SCM x, SCM y),
944 "Return the modulo of the numbers @var{x} and @var{y}.\n"
945 "@lisp\n"
946 "(modulo 13 4) @result{} 1\n"
947 "(modulo -13 4) @result{} 3\n"
948 "@end lisp")
949#define FUNC_NAME s_scm_modulo
0f2d19dd 950{
a16982ca 951 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 952 {
e25f3727 953 scm_t_inum xx = SCM_I_INUM (x);
a16982ca 954 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 955 {
e25f3727 956 scm_t_inum yy = SCM_I_INUM (y);
a16982ca 957 if (SCM_UNLIKELY (yy == 0))
2519490c 958 scm_num_overflow (s_scm_modulo);
0aacf84e
MD
959 else
960 {
66b1c775
KR
961 /* C99 specifies that "%" is the remainder corresponding to a
962 quotient rounded towards zero, and that's also traditional
963 for machine division, so z here should be well defined. */
e25f3727
AW
964 scm_t_inum z = xx % yy;
965 scm_t_inum result;
0aacf84e
MD
966
967 if (yy < 0)
968 {
969 if (z > 0)
970 result = z + yy;
971 else
972 result = z;
973 }
974 else
975 {
976 if (z < 0)
977 result = z + yy;
978 else
979 result = z;
980 }
d956fa6f 981 return SCM_I_MAKINUM (result);
0aacf84e
MD
982 }
983 }
984 else if (SCM_BIGP (y))
985 {
986 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
0aacf84e
MD
987 {
988 mpz_t z_x;
989 SCM result;
990
991 if (sgn_y < 0)
992 {
993 SCM pos_y = scm_i_clonebig (y, 0);
994 /* do this after the last scm_op */
995 mpz_init_set_si (z_x, xx);
996 result = pos_y; /* re-use this bignum */
997 mpz_mod (SCM_I_BIG_MPZ (result),
998 z_x,
999 SCM_I_BIG_MPZ (pos_y));
1000 scm_remember_upto_here_1 (pos_y);
1001 }
1002 else
1003 {
1004 result = scm_i_mkbig ();
1005 /* do this after the last scm_op */
1006 mpz_init_set_si (z_x, xx);
1007 mpz_mod (SCM_I_BIG_MPZ (result),
1008 z_x,
1009 SCM_I_BIG_MPZ (y));
1010 scm_remember_upto_here_1 (y);
1011 }
ca46fb90 1012
0aacf84e
MD
1013 if ((sgn_y < 0) && mpz_sgn (SCM_I_BIG_MPZ (result)) != 0)
1014 mpz_add (SCM_I_BIG_MPZ (result),
1015 SCM_I_BIG_MPZ (y),
1016 SCM_I_BIG_MPZ (result));
1017 scm_remember_upto_here_1 (y);
1018 /* and do this before the next one */
1019 mpz_clear (z_x);
1020 return scm_i_normbig (result);
1021 }
1022 }
1023 else
2519490c 1024 SCM_WTA_DISPATCH_2 (g_scm_modulo, x, y, SCM_ARG2, s_scm_modulo);
f872b822 1025 }
0aacf84e
MD
1026 else if (SCM_BIGP (x))
1027 {
a16982ca 1028 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 1029 {
e25f3727 1030 scm_t_inum yy = SCM_I_INUM (y);
a16982ca 1031 if (SCM_UNLIKELY (yy == 0))
2519490c 1032 scm_num_overflow (s_scm_modulo);
0aacf84e
MD
1033 else
1034 {
1035 SCM result = scm_i_mkbig ();
1036 mpz_mod_ui (SCM_I_BIG_MPZ (result),
1037 SCM_I_BIG_MPZ (x),
1038 (yy < 0) ? - yy : yy);
1039 scm_remember_upto_here_1 (x);
1040 if ((yy < 0) && (mpz_sgn (SCM_I_BIG_MPZ (result)) != 0))
1041 mpz_sub_ui (SCM_I_BIG_MPZ (result),
1042 SCM_I_BIG_MPZ (result),
1043 - yy);
1044 return scm_i_normbig (result);
1045 }
1046 }
1047 else if (SCM_BIGP (y))
1048 {
a16982ca
MW
1049 SCM result = scm_i_mkbig ();
1050 int y_sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
1051 SCM pos_y = scm_i_clonebig (y, y_sgn >= 0);
1052 mpz_mod (SCM_I_BIG_MPZ (result),
1053 SCM_I_BIG_MPZ (x),
1054 SCM_I_BIG_MPZ (pos_y));
ca46fb90 1055
a16982ca
MW
1056 scm_remember_upto_here_1 (x);
1057 if ((y_sgn < 0) && (mpz_sgn (SCM_I_BIG_MPZ (result)) != 0))
1058 mpz_add (SCM_I_BIG_MPZ (result),
1059 SCM_I_BIG_MPZ (y),
1060 SCM_I_BIG_MPZ (result));
1061 scm_remember_upto_here_2 (y, pos_y);
1062 return scm_i_normbig (result);
0aacf84e
MD
1063 }
1064 else
2519490c 1065 SCM_WTA_DISPATCH_2 (g_scm_modulo, x, y, SCM_ARG2, s_scm_modulo);
828865c3 1066 }
0aacf84e 1067 else
2519490c 1068 SCM_WTA_DISPATCH_2 (g_scm_modulo, x, y, SCM_ARG1, s_scm_modulo);
0f2d19dd 1069}
2519490c 1070#undef FUNC_NAME
0f2d19dd 1071
ff62c168
MW
1072static SCM scm_i_inexact_euclidean_quotient (double x, double y);
1073static SCM scm_i_slow_exact_euclidean_quotient (SCM x, SCM y);
1074
1075SCM_PRIMITIVE_GENERIC (scm_euclidean_quotient, "euclidean-quotient", 2, 0, 0,
1076 (SCM x, SCM y),
1077 "Return the integer @var{q} such that\n"
1078 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1079 "where @math{0 <= @var{r} < abs(@var{y})}.\n"
1080 "@lisp\n"
1081 "(euclidean-quotient 123 10) @result{} 12\n"
1082 "(euclidean-quotient 123 -10) @result{} -12\n"
1083 "(euclidean-quotient -123 10) @result{} -13\n"
1084 "(euclidean-quotient -123 -10) @result{} 13\n"
1085 "(euclidean-quotient -123.2 -63.5) @result{} 2.0\n"
1086 "(euclidean-quotient 16/3 -10/7) @result{} -3\n"
1087 "@end lisp")
1088#define FUNC_NAME s_scm_euclidean_quotient
1089{
1090 if (SCM_LIKELY (SCM_I_INUMP (x)))
1091 {
1092 if (SCM_LIKELY (SCM_I_INUMP (y)))
1093 {
1094 scm_t_inum yy = SCM_I_INUM (y);
1095 if (SCM_UNLIKELY (yy == 0))
1096 scm_num_overflow (s_scm_euclidean_quotient);
1097 else
1098 {
1099 scm_t_inum xx = SCM_I_INUM (x);
1100 scm_t_inum qq = xx / yy;
1101 if (xx < qq * yy)
1102 {
1103 if (yy > 0)
1104 qq--;
1105 else
1106 qq++;
1107 }
1108 return SCM_I_MAKINUM (qq);
1109 }
1110 }
1111 else if (SCM_BIGP (y))
1112 {
1113 if (SCM_I_INUM (x) >= 0)
1114 return SCM_INUM0;
1115 else
1116 return SCM_I_MAKINUM (- mpz_sgn (SCM_I_BIG_MPZ (y)));
1117 }
1118 else if (SCM_REALP (y))
1119 return scm_i_inexact_euclidean_quotient
1120 (SCM_I_INUM (x), SCM_REAL_VALUE (y));
1121 else if (SCM_FRACTIONP (y))
1122 return scm_i_slow_exact_euclidean_quotient (x, y);
1123 else
1124 SCM_WTA_DISPATCH_2 (g_scm_euclidean_quotient, x, y, SCM_ARG2,
1125 s_scm_euclidean_quotient);
1126 }
1127 else if (SCM_BIGP (x))
1128 {
1129 if (SCM_LIKELY (SCM_I_INUMP (y)))
1130 {
1131 scm_t_inum yy = SCM_I_INUM (y);
1132 if (SCM_UNLIKELY (yy == 0))
1133 scm_num_overflow (s_scm_euclidean_quotient);
1134 else
1135 {
1136 SCM q = scm_i_mkbig ();
1137 if (yy > 0)
1138 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1139 else
1140 {
1141 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1142 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1143 }
1144 scm_remember_upto_here_1 (x);
1145 return scm_i_normbig (q);
1146 }
1147 }
1148 else if (SCM_BIGP (y))
1149 {
1150 SCM q = scm_i_mkbig ();
1151 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
1152 mpz_fdiv_q (SCM_I_BIG_MPZ (q),
1153 SCM_I_BIG_MPZ (x),
1154 SCM_I_BIG_MPZ (y));
1155 else
1156 mpz_cdiv_q (SCM_I_BIG_MPZ (q),
1157 SCM_I_BIG_MPZ (x),
1158 SCM_I_BIG_MPZ (y));
1159 scm_remember_upto_here_2 (x, y);
1160 return scm_i_normbig (q);
1161 }
1162 else if (SCM_REALP (y))
1163 return scm_i_inexact_euclidean_quotient
1164 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1165 else if (SCM_FRACTIONP (y))
1166 return scm_i_slow_exact_euclidean_quotient (x, y);
1167 else
1168 SCM_WTA_DISPATCH_2 (g_scm_euclidean_quotient, x, y, SCM_ARG2,
1169 s_scm_euclidean_quotient);
1170 }
1171 else if (SCM_REALP (x))
1172 {
1173 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1174 SCM_BIGP (y) || SCM_FRACTIONP (y))
1175 return scm_i_inexact_euclidean_quotient
1176 (SCM_REAL_VALUE (x), scm_to_double (y));
1177 else
1178 SCM_WTA_DISPATCH_2 (g_scm_euclidean_quotient, x, y, SCM_ARG2,
1179 s_scm_euclidean_quotient);
1180 }
1181 else if (SCM_FRACTIONP (x))
1182 {
1183 if (SCM_REALP (y))
1184 return scm_i_inexact_euclidean_quotient
1185 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1186 else
1187 return scm_i_slow_exact_euclidean_quotient (x, y);
1188 }
1189 else
1190 SCM_WTA_DISPATCH_2 (g_scm_euclidean_quotient, x, y, SCM_ARG1,
1191 s_scm_euclidean_quotient);
1192}
1193#undef FUNC_NAME
1194
1195static SCM
1196scm_i_inexact_euclidean_quotient (double x, double y)
1197{
1198 if (SCM_LIKELY (y > 0))
1199 return scm_from_double (floor (x / y));
1200 else if (SCM_LIKELY (y < 0))
1201 return scm_from_double (ceil (x / y));
1202 else if (y == 0)
1203 scm_num_overflow (s_scm_euclidean_quotient); /* or return a NaN? */
1204 else
1205 return scm_nan ();
1206}
1207
1208/* Compute exact euclidean_quotient the slow way.
1209 We use this only if both arguments are exact,
1210 and at least one of them is a fraction */
1211static SCM
1212scm_i_slow_exact_euclidean_quotient (SCM x, SCM y)
1213{
1214 if (!(SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x)))
1215 SCM_WTA_DISPATCH_2 (g_scm_euclidean_quotient, x, y, SCM_ARG1,
1216 s_scm_euclidean_quotient);
1217 else if (!(SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y)))
1218 SCM_WTA_DISPATCH_2 (g_scm_euclidean_quotient, x, y, SCM_ARG2,
1219 s_scm_euclidean_quotient);
1220 else if (scm_is_true (scm_positive_p (y)))
1221 return scm_floor (scm_divide (x, y));
1222 else if (scm_is_true (scm_negative_p (y)))
1223 return scm_ceiling (scm_divide (x, y));
1224 else
1225 scm_num_overflow (s_scm_euclidean_quotient);
1226}
1227
1228static SCM scm_i_inexact_euclidean_remainder (double x, double y);
1229static SCM scm_i_slow_exact_euclidean_remainder (SCM x, SCM y);
1230
1231SCM_PRIMITIVE_GENERIC (scm_euclidean_remainder, "euclidean-remainder", 2, 0, 0,
1232 (SCM x, SCM y),
1233 "Return the real number @var{r} such that\n"
1234 "@math{0 <= @var{r} < abs(@var{y})} and\n"
1235 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1236 "for some integer @var{q}.\n"
1237 "@lisp\n"
1238 "(euclidean-remainder 123 10) @result{} 3\n"
1239 "(euclidean-remainder 123 -10) @result{} 3\n"
1240 "(euclidean-remainder -123 10) @result{} 7\n"
1241 "(euclidean-remainder -123 -10) @result{} 7\n"
1242 "(euclidean-remainder -123.2 -63.5) @result{} 3.8\n"
1243 "(euclidean-remainder 16/3 -10/7) @result{} 22/21\n"
1244 "@end lisp")
1245#define FUNC_NAME s_scm_euclidean_remainder
1246{
1247 if (SCM_LIKELY (SCM_I_INUMP (x)))
1248 {
1249 if (SCM_LIKELY (SCM_I_INUMP (y)))
1250 {
1251 scm_t_inum yy = SCM_I_INUM (y);
1252 if (SCM_UNLIKELY (yy == 0))
1253 scm_num_overflow (s_scm_euclidean_remainder);
1254 else
1255 {
1256 scm_t_inum rr = SCM_I_INUM (x) % yy;
1257 if (rr >= 0)
1258 return SCM_I_MAKINUM (rr);
1259 else if (yy > 0)
1260 return SCM_I_MAKINUM (rr + yy);
1261 else
1262 return SCM_I_MAKINUM (rr - yy);
1263 }
1264 }
1265 else if (SCM_BIGP (y))
1266 {
1267 scm_t_inum xx = SCM_I_INUM (x);
1268 if (xx >= 0)
1269 return x;
1270 else if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
1271 {
1272 SCM r = scm_i_mkbig ();
1273 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1274 scm_remember_upto_here_1 (y);
1275 return scm_i_normbig (r);
1276 }
1277 else
1278 {
1279 SCM r = scm_i_mkbig ();
1280 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1281 scm_remember_upto_here_1 (y);
1282 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1283 return scm_i_normbig (r);
1284 }
1285 }
1286 else if (SCM_REALP (y))
1287 return scm_i_inexact_euclidean_remainder
1288 (SCM_I_INUM (x), SCM_REAL_VALUE (y));
1289 else if (SCM_FRACTIONP (y))
1290 return scm_i_slow_exact_euclidean_remainder (x, y);
1291 else
1292 SCM_WTA_DISPATCH_2 (g_scm_euclidean_remainder, x, y, SCM_ARG2,
1293 s_scm_euclidean_remainder);
1294 }
1295 else if (SCM_BIGP (x))
1296 {
1297 if (SCM_LIKELY (SCM_I_INUMP (y)))
1298 {
1299 scm_t_inum yy = SCM_I_INUM (y);
1300 if (SCM_UNLIKELY (yy == 0))
1301 scm_num_overflow (s_scm_euclidean_remainder);
1302 else
1303 {
1304 scm_t_inum rr;
1305 if (yy < 0)
1306 yy = -yy;
1307 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), yy);
1308 scm_remember_upto_here_1 (x);
1309 return SCM_I_MAKINUM (rr);
1310 }
1311 }
1312 else if (SCM_BIGP (y))
1313 {
1314 SCM r = scm_i_mkbig ();
1315 mpz_mod (SCM_I_BIG_MPZ (r),
1316 SCM_I_BIG_MPZ (x),
1317 SCM_I_BIG_MPZ (y));
1318 scm_remember_upto_here_2 (x, y);
1319 return scm_i_normbig (r);
1320 }
1321 else if (SCM_REALP (y))
1322 return scm_i_inexact_euclidean_remainder
1323 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1324 else if (SCM_FRACTIONP (y))
1325 return scm_i_slow_exact_euclidean_remainder (x, y);
1326 else
1327 SCM_WTA_DISPATCH_2 (g_scm_euclidean_remainder, x, y, SCM_ARG2,
1328 s_scm_euclidean_remainder);
1329 }
1330 else if (SCM_REALP (x))
1331 {
1332 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1333 SCM_BIGP (y) || SCM_FRACTIONP (y))
1334 return scm_i_inexact_euclidean_remainder
1335 (SCM_REAL_VALUE (x), scm_to_double (y));
1336 else
1337 SCM_WTA_DISPATCH_2 (g_scm_euclidean_remainder, x, y, SCM_ARG2,
1338 s_scm_euclidean_remainder);
1339 }
1340 else if (SCM_FRACTIONP (x))
1341 {
1342 if (SCM_REALP (y))
1343 return scm_i_inexact_euclidean_remainder
1344 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1345 else
1346 return scm_i_slow_exact_euclidean_remainder (x, y);
1347 }
1348 else
1349 SCM_WTA_DISPATCH_2 (g_scm_euclidean_remainder, x, y, SCM_ARG1,
1350 s_scm_euclidean_remainder);
1351}
1352#undef FUNC_NAME
1353
1354static SCM
1355scm_i_inexact_euclidean_remainder (double x, double y)
1356{
1357 double q;
1358
1359 /* Although it would be more efficient to use fmod here, we can't
1360 because it would in some cases produce results inconsistent with
1361 scm_i_inexact_euclidean_quotient, such that x != q * y + r (not
1362 even close). In particular, when x is very close to a multiple of
1363 y, then r might be either 0.0 or abs(y)-epsilon, but those two
1364 cases must correspond to different choices of q. If r = 0.0 then q
1365 must be x/y, and if r = abs(y) then q must be (x-r)/y. If quotient
1366 chooses one and remainder chooses the other, it would be bad. This
1367 problem was observed with x = 130.0 and y = 10/7. */
1368 if (SCM_LIKELY (y > 0))
1369 q = floor (x / y);
1370 else if (SCM_LIKELY (y < 0))
1371 q = ceil (x / y);
1372 else if (y == 0)
1373 scm_num_overflow (s_scm_euclidean_remainder); /* or return a NaN? */
1374 else
1375 return scm_nan ();
1376 return scm_from_double (x - q * y);
1377}
1378
1379/* Compute exact euclidean_remainder the slow way.
1380 We use this only if both arguments are exact,
1381 and at least one of them is a fraction */
1382static SCM
1383scm_i_slow_exact_euclidean_remainder (SCM x, SCM y)
1384{
1385 SCM q;
1386
1387 if (!(SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x)))
1388 SCM_WTA_DISPATCH_2 (g_scm_euclidean_remainder, x, y, SCM_ARG1,
1389 s_scm_euclidean_remainder);
1390 else if (!(SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y)))
1391 SCM_WTA_DISPATCH_2 (g_scm_euclidean_remainder, x, y, SCM_ARG2,
1392 s_scm_euclidean_remainder);
1393 else if (scm_is_true (scm_positive_p (y)))
1394 q = scm_floor (scm_divide (x, y));
1395 else if (scm_is_true (scm_negative_p (y)))
1396 q = scm_ceiling (scm_divide (x, y));
1397 else
1398 scm_num_overflow (s_scm_euclidean_remainder);
1399 return scm_difference (x, scm_product (y, q));
1400}
1401
1402
ac6ce16b
MW
1403static SCM scm_i_inexact_euclidean_divide (double x, double y);
1404static SCM scm_i_slow_exact_euclidean_divide (SCM x, SCM y);
ff62c168 1405
ac6ce16b 1406SCM_PRIMITIVE_GENERIC (scm_euclidean_divide, "euclidean/", 2, 0, 0,
ff62c168
MW
1407 (SCM x, SCM y),
1408 "Return the integer @var{q} and the real number @var{r}\n"
1409 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1410 "and @math{0 <= @var{r} < abs(@var{y})}.\n"
1411 "@lisp\n"
1412 "(euclidean/ 123 10) @result{} 12 and 3\n"
1413 "(euclidean/ 123 -10) @result{} -12 and 3\n"
1414 "(euclidean/ -123 10) @result{} -13 and 7\n"
1415 "(euclidean/ -123 -10) @result{} 13 and 7\n"
1416 "(euclidean/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
1417 "(euclidean/ 16/3 -10/7) @result{} -3 and 22/21\n"
1418 "@end lisp")
ac6ce16b 1419#define FUNC_NAME s_scm_euclidean_divide
ff62c168
MW
1420{
1421 if (SCM_LIKELY (SCM_I_INUMP (x)))
1422 {
1423 if (SCM_LIKELY (SCM_I_INUMP (y)))
1424 {
1425 scm_t_inum yy = SCM_I_INUM (y);
1426 if (SCM_UNLIKELY (yy == 0))
ac6ce16b 1427 scm_num_overflow (s_scm_euclidean_divide);
ff62c168
MW
1428 else
1429 {
1430 scm_t_inum xx = SCM_I_INUM (x);
1431 scm_t_inum qq = xx / yy;
1432 scm_t_inum rr = xx - qq * yy;
1433 if (rr < 0)
1434 {
1435 if (yy > 0)
1436 { rr += yy; qq--; }
1437 else
1438 { rr -= yy; qq++; }
1439 }
1440 return scm_values (scm_list_2 (SCM_I_MAKINUM (qq),
1441 SCM_I_MAKINUM (rr)));
1442 }
1443 }
1444 else if (SCM_BIGP (y))
1445 {
1446 scm_t_inum xx = SCM_I_INUM (x);
1447 if (xx >= 0)
1448 return scm_values (scm_list_2 (SCM_INUM0, x));
1449 else if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
1450 {
1451 SCM r = scm_i_mkbig ();
1452 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1453 scm_remember_upto_here_1 (y);
1454 return scm_values
1455 (scm_list_2 (SCM_I_MAKINUM (-1), scm_i_normbig (r)));
1456 }
1457 else
1458 {
1459 SCM r = scm_i_mkbig ();
1460 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1461 scm_remember_upto_here_1 (y);
1462 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1463 return scm_values (scm_list_2 (SCM_INUM1, scm_i_normbig (r)));
1464 }
1465 }
1466 else if (SCM_REALP (y))
ac6ce16b 1467 return scm_i_inexact_euclidean_divide
ff62c168
MW
1468 (SCM_I_INUM (x), SCM_REAL_VALUE (y));
1469 else if (SCM_FRACTIONP (y))
ac6ce16b 1470 return scm_i_slow_exact_euclidean_divide (x, y);
ff62c168 1471 else
ac6ce16b
MW
1472 SCM_WTA_DISPATCH_2 (g_scm_euclidean_divide, x, y, SCM_ARG2,
1473 s_scm_euclidean_divide);
ff62c168
MW
1474 }
1475 else if (SCM_BIGP (x))
1476 {
1477 if (SCM_LIKELY (SCM_I_INUMP (y)))
1478 {
1479 scm_t_inum yy = SCM_I_INUM (y);
1480 if (SCM_UNLIKELY (yy == 0))
ac6ce16b 1481 scm_num_overflow (s_scm_euclidean_divide);
ff62c168
MW
1482 else
1483 {
1484 SCM q = scm_i_mkbig ();
1485 SCM r = scm_i_mkbig ();
1486 if (yy > 0)
1487 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1488 SCM_I_BIG_MPZ (x), yy);
1489 else
1490 {
1491 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1492 SCM_I_BIG_MPZ (x), -yy);
1493 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1494 }
1495 scm_remember_upto_here_1 (x);
1496 return scm_values (scm_list_2 (scm_i_normbig (q),
1497 scm_i_normbig (r)));
1498 }
1499 }
1500 else if (SCM_BIGP (y))
1501 {
1502 SCM q = scm_i_mkbig ();
1503 SCM r = scm_i_mkbig ();
1504 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
1505 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1506 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1507 else
1508 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1509 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1510 scm_remember_upto_here_2 (x, y);
1511 return scm_values (scm_list_2 (scm_i_normbig (q),
1512 scm_i_normbig (r)));
1513 }
1514 else if (SCM_REALP (y))
ac6ce16b 1515 return scm_i_inexact_euclidean_divide
ff62c168
MW
1516 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1517 else if (SCM_FRACTIONP (y))
ac6ce16b 1518 return scm_i_slow_exact_euclidean_divide (x, y);
ff62c168 1519 else
ac6ce16b
MW
1520 SCM_WTA_DISPATCH_2 (g_scm_euclidean_divide, x, y, SCM_ARG2,
1521 s_scm_euclidean_divide);
ff62c168
MW
1522 }
1523 else if (SCM_REALP (x))
1524 {
1525 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1526 SCM_BIGP (y) || SCM_FRACTIONP (y))
ac6ce16b 1527 return scm_i_inexact_euclidean_divide
ff62c168
MW
1528 (SCM_REAL_VALUE (x), scm_to_double (y));
1529 else
ac6ce16b
MW
1530 SCM_WTA_DISPATCH_2 (g_scm_euclidean_divide, x, y, SCM_ARG2,
1531 s_scm_euclidean_divide);
ff62c168
MW
1532 }
1533 else if (SCM_FRACTIONP (x))
1534 {
1535 if (SCM_REALP (y))
ac6ce16b 1536 return scm_i_inexact_euclidean_divide
ff62c168
MW
1537 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1538 else
ac6ce16b 1539 return scm_i_slow_exact_euclidean_divide (x, y);
ff62c168
MW
1540 }
1541 else
ac6ce16b
MW
1542 SCM_WTA_DISPATCH_2 (g_scm_euclidean_divide, x, y, SCM_ARG1,
1543 s_scm_euclidean_divide);
ff62c168
MW
1544}
1545#undef FUNC_NAME
1546
1547static SCM
ac6ce16b 1548scm_i_inexact_euclidean_divide (double x, double y)
ff62c168
MW
1549{
1550 double q, r;
1551
1552 if (SCM_LIKELY (y > 0))
1553 q = floor (x / y);
1554 else if (SCM_LIKELY (y < 0))
1555 q = ceil (x / y);
1556 else if (y == 0)
ac6ce16b 1557 scm_num_overflow (s_scm_euclidean_divide); /* or return a NaN? */
ff62c168
MW
1558 else
1559 q = guile_NaN;
1560 r = x - q * y;
1561 return scm_values (scm_list_2 (scm_from_double (q),
1562 scm_from_double (r)));
1563}
1564
1565/* Compute exact euclidean quotient and remainder the slow way.
1566 We use this only if both arguments are exact,
1567 and at least one of them is a fraction */
1568static SCM
ac6ce16b 1569scm_i_slow_exact_euclidean_divide (SCM x, SCM y)
ff62c168
MW
1570{
1571 SCM q, r;
1572
1573 if (!(SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x)))
ac6ce16b
MW
1574 SCM_WTA_DISPATCH_2 (g_scm_euclidean_divide, x, y, SCM_ARG1,
1575 s_scm_euclidean_divide);
ff62c168 1576 else if (!(SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y)))
ac6ce16b
MW
1577 SCM_WTA_DISPATCH_2 (g_scm_euclidean_divide, x, y, SCM_ARG2,
1578 s_scm_euclidean_divide);
ff62c168
MW
1579 else if (scm_is_true (scm_positive_p (y)))
1580 q = scm_floor (scm_divide (x, y));
1581 else if (scm_is_true (scm_negative_p (y)))
1582 q = scm_ceiling (scm_divide (x, y));
1583 else
ac6ce16b 1584 scm_num_overflow (s_scm_euclidean_divide);
ff62c168
MW
1585 r = scm_difference (x, scm_product (q, y));
1586 return scm_values (scm_list_2 (q, r));
1587}
1588
1589static SCM scm_i_inexact_centered_quotient (double x, double y);
1590static SCM scm_i_bigint_centered_quotient (SCM x, SCM y);
1591static SCM scm_i_slow_exact_centered_quotient (SCM x, SCM y);
1592
1593SCM_PRIMITIVE_GENERIC (scm_centered_quotient, "centered-quotient", 2, 0, 0,
1594 (SCM x, SCM y),
1595 "Return the integer @var{q} such that\n"
1596 "@math{@var{x} = @var{q}*@var{y} + @var{r}} where\n"
1597 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
1598 "@lisp\n"
1599 "(centered-quotient 123 10) @result{} 12\n"
1600 "(centered-quotient 123 -10) @result{} -12\n"
1601 "(centered-quotient -123 10) @result{} -12\n"
1602 "(centered-quotient -123 -10) @result{} 12\n"
1603 "(centered-quotient -123.2 -63.5) @result{} 2.0\n"
1604 "(centered-quotient 16/3 -10/7) @result{} -4\n"
1605 "@end lisp")
1606#define FUNC_NAME s_scm_centered_quotient
1607{
1608 if (SCM_LIKELY (SCM_I_INUMP (x)))
1609 {
1610 if (SCM_LIKELY (SCM_I_INUMP (y)))
1611 {
1612 scm_t_inum yy = SCM_I_INUM (y);
1613 if (SCM_UNLIKELY (yy == 0))
1614 scm_num_overflow (s_scm_centered_quotient);
1615 else
1616 {
1617 scm_t_inum xx = SCM_I_INUM (x);
1618 scm_t_inum qq = xx / yy;
1619 scm_t_inum rr = xx - qq * yy;
1620 if (SCM_LIKELY (xx > 0))
1621 {
1622 if (SCM_LIKELY (yy > 0))
1623 {
1624 if (rr >= (yy + 1) / 2)
1625 qq++;
1626 }
1627 else
1628 {
1629 if (rr >= (1 - yy) / 2)
1630 qq--;
1631 }
1632 }
1633 else
1634 {
1635 if (SCM_LIKELY (yy > 0))
1636 {
1637 if (rr < -yy / 2)
1638 qq--;
1639 }
1640 else
1641 {
1642 if (rr < yy / 2)
1643 qq++;
1644 }
1645 }
1646 return SCM_I_MAKINUM (qq);
1647 }
1648 }
1649 else if (SCM_BIGP (y))
1650 {
1651 /* Pass a denormalized bignum version of x (even though it
1652 can fit in a fixnum) to scm_i_bigint_centered_quotient */
1653 return scm_i_bigint_centered_quotient
1654 (scm_i_long2big (SCM_I_INUM (x)), y);
1655 }
1656 else if (SCM_REALP (y))
1657 return scm_i_inexact_centered_quotient
1658 (SCM_I_INUM (x), SCM_REAL_VALUE (y));
1659 else if (SCM_FRACTIONP (y))
1660 return scm_i_slow_exact_centered_quotient (x, y);
1661 else
1662 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
1663 s_scm_centered_quotient);
1664 }
1665 else if (SCM_BIGP (x))
1666 {
1667 if (SCM_LIKELY (SCM_I_INUMP (y)))
1668 {
1669 scm_t_inum yy = SCM_I_INUM (y);
1670 if (SCM_UNLIKELY (yy == 0))
1671 scm_num_overflow (s_scm_centered_quotient);
1672 else
1673 {
1674 SCM q = scm_i_mkbig ();
1675 scm_t_inum rr;
1676 /* Arrange for rr to initially be non-positive,
1677 because that simplifies the test to see
1678 if it is within the needed bounds. */
1679 if (yy > 0)
1680 {
1681 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
1682 SCM_I_BIG_MPZ (x), yy);
1683 scm_remember_upto_here_1 (x);
1684 if (rr < -yy / 2)
1685 mpz_sub_ui (SCM_I_BIG_MPZ (q),
1686 SCM_I_BIG_MPZ (q), 1);
1687 }
1688 else
1689 {
1690 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
1691 SCM_I_BIG_MPZ (x), -yy);
1692 scm_remember_upto_here_1 (x);
1693 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1694 if (rr < yy / 2)
1695 mpz_add_ui (SCM_I_BIG_MPZ (q),
1696 SCM_I_BIG_MPZ (q), 1);
1697 }
1698 return scm_i_normbig (q);
1699 }
1700 }
1701 else if (SCM_BIGP (y))
1702 return scm_i_bigint_centered_quotient (x, y);
1703 else if (SCM_REALP (y))
1704 return scm_i_inexact_centered_quotient
1705 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1706 else if (SCM_FRACTIONP (y))
1707 return scm_i_slow_exact_centered_quotient (x, y);
1708 else
1709 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
1710 s_scm_centered_quotient);
1711 }
1712 else if (SCM_REALP (x))
1713 {
1714 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1715 SCM_BIGP (y) || SCM_FRACTIONP (y))
1716 return scm_i_inexact_centered_quotient
1717 (SCM_REAL_VALUE (x), scm_to_double (y));
1718 else
1719 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
1720 s_scm_centered_quotient);
1721 }
1722 else if (SCM_FRACTIONP (x))
1723 {
1724 if (SCM_REALP (y))
1725 return scm_i_inexact_centered_quotient
1726 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1727 else
1728 return scm_i_slow_exact_centered_quotient (x, y);
1729 }
1730 else
1731 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG1,
1732 s_scm_centered_quotient);
1733}
1734#undef FUNC_NAME
1735
1736static SCM
1737scm_i_inexact_centered_quotient (double x, double y)
1738{
1739 if (SCM_LIKELY (y > 0))
1740 return scm_from_double (floor (x/y + 0.5));
1741 else if (SCM_LIKELY (y < 0))
1742 return scm_from_double (ceil (x/y - 0.5));
1743 else if (y == 0)
1744 scm_num_overflow (s_scm_centered_quotient); /* or return a NaN? */
1745 else
1746 return scm_nan ();
1747}
1748
1749/* Assumes that both x and y are bigints, though
1750 x might be able to fit into a fixnum. */
1751static SCM
1752scm_i_bigint_centered_quotient (SCM x, SCM y)
1753{
1754 SCM q, r, min_r;
1755
1756 /* Note that x might be small enough to fit into a
1757 fixnum, so we must not let it escape into the wild */
1758 q = scm_i_mkbig ();
1759 r = scm_i_mkbig ();
1760
1761 /* min_r will eventually become -abs(y)/2 */
1762 min_r = scm_i_mkbig ();
1763 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
1764 SCM_I_BIG_MPZ (y), 1);
1765
1766 /* Arrange for rr to initially be non-positive,
1767 because that simplifies the test to see
1768 if it is within the needed bounds. */
1769 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
1770 {
1771 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1772 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1773 scm_remember_upto_here_2 (x, y);
1774 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
1775 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
1776 mpz_sub_ui (SCM_I_BIG_MPZ (q),
1777 SCM_I_BIG_MPZ (q), 1);
1778 }
1779 else
1780 {
1781 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1782 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1783 scm_remember_upto_here_2 (x, y);
1784 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
1785 mpz_add_ui (SCM_I_BIG_MPZ (q),
1786 SCM_I_BIG_MPZ (q), 1);
1787 }
1788 scm_remember_upto_here_2 (r, min_r);
1789 return scm_i_normbig (q);
1790}
1791
1792/* Compute exact centered quotient the slow way.
1793 We use this only if both arguments are exact,
1794 and at least one of them is a fraction */
1795static SCM
1796scm_i_slow_exact_centered_quotient (SCM x, SCM y)
1797{
1798 if (!(SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x)))
1799 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG1,
1800 s_scm_centered_quotient);
1801 else if (!(SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y)))
1802 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
1803 s_scm_centered_quotient);
1804 else if (scm_is_true (scm_positive_p (y)))
1805 return scm_floor (scm_sum (scm_divide (x, y),
1806 exactly_one_half));
1807 else if (scm_is_true (scm_negative_p (y)))
1808 return scm_ceiling (scm_difference (scm_divide (x, y),
1809 exactly_one_half));
1810 else
1811 scm_num_overflow (s_scm_centered_quotient);
1812}
1813
1814static SCM scm_i_inexact_centered_remainder (double x, double y);
1815static SCM scm_i_bigint_centered_remainder (SCM x, SCM y);
1816static SCM scm_i_slow_exact_centered_remainder (SCM x, SCM y);
1817
1818SCM_PRIMITIVE_GENERIC (scm_centered_remainder, "centered-remainder", 2, 0, 0,
1819 (SCM x, SCM y),
1820 "Return the real number @var{r} such that\n"
1821 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}\n"
1822 "and @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1823 "for some integer @var{q}.\n"
1824 "@lisp\n"
1825 "(centered-remainder 123 10) @result{} 3\n"
1826 "(centered-remainder 123 -10) @result{} 3\n"
1827 "(centered-remainder -123 10) @result{} -3\n"
1828 "(centered-remainder -123 -10) @result{} -3\n"
1829 "(centered-remainder -123.2 -63.5) @result{} 3.8\n"
1830 "(centered-remainder 16/3 -10/7) @result{} -8/21\n"
1831 "@end lisp")
1832#define FUNC_NAME s_scm_centered_remainder
1833{
1834 if (SCM_LIKELY (SCM_I_INUMP (x)))
1835 {
1836 if (SCM_LIKELY (SCM_I_INUMP (y)))
1837 {
1838 scm_t_inum yy = SCM_I_INUM (y);
1839 if (SCM_UNLIKELY (yy == 0))
1840 scm_num_overflow (s_scm_centered_remainder);
1841 else
1842 {
1843 scm_t_inum xx = SCM_I_INUM (x);
1844 scm_t_inum rr = xx % yy;
1845 if (SCM_LIKELY (xx > 0))
1846 {
1847 if (SCM_LIKELY (yy > 0))
1848 {
1849 if (rr >= (yy + 1) / 2)
1850 rr -= yy;
1851 }
1852 else
1853 {
1854 if (rr >= (1 - yy) / 2)
1855 rr += yy;
1856 }
1857 }
1858 else
1859 {
1860 if (SCM_LIKELY (yy > 0))
1861 {
1862 if (rr < -yy / 2)
1863 rr += yy;
1864 }
1865 else
1866 {
1867 if (rr < yy / 2)
1868 rr -= yy;
1869 }
1870 }
1871 return SCM_I_MAKINUM (rr);
1872 }
1873 }
1874 else if (SCM_BIGP (y))
1875 {
1876 /* Pass a denormalized bignum version of x (even though it
1877 can fit in a fixnum) to scm_i_bigint_centered_remainder */
1878 return scm_i_bigint_centered_remainder
1879 (scm_i_long2big (SCM_I_INUM (x)), y);
1880 }
1881 else if (SCM_REALP (y))
1882 return scm_i_inexact_centered_remainder
1883 (SCM_I_INUM (x), SCM_REAL_VALUE (y));
1884 else if (SCM_FRACTIONP (y))
1885 return scm_i_slow_exact_centered_remainder (x, y);
1886 else
1887 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
1888 s_scm_centered_remainder);
1889 }
1890 else if (SCM_BIGP (x))
1891 {
1892 if (SCM_LIKELY (SCM_I_INUMP (y)))
1893 {
1894 scm_t_inum yy = SCM_I_INUM (y);
1895 if (SCM_UNLIKELY (yy == 0))
1896 scm_num_overflow (s_scm_centered_remainder);
1897 else
1898 {
1899 scm_t_inum rr;
1900 /* Arrange for rr to initially be non-positive,
1901 because that simplifies the test to see
1902 if it is within the needed bounds. */
1903 if (yy > 0)
1904 {
1905 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
1906 scm_remember_upto_here_1 (x);
1907 if (rr < -yy / 2)
1908 rr += yy;
1909 }
1910 else
1911 {
1912 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1913 scm_remember_upto_here_1 (x);
1914 if (rr < yy / 2)
1915 rr -= yy;
1916 }
1917 return SCM_I_MAKINUM (rr);
1918 }
1919 }
1920 else if (SCM_BIGP (y))
1921 return scm_i_bigint_centered_remainder (x, y);
1922 else if (SCM_REALP (y))
1923 return scm_i_inexact_centered_remainder
1924 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1925 else if (SCM_FRACTIONP (y))
1926 return scm_i_slow_exact_centered_remainder (x, y);
1927 else
1928 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
1929 s_scm_centered_remainder);
1930 }
1931 else if (SCM_REALP (x))
1932 {
1933 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1934 SCM_BIGP (y) || SCM_FRACTIONP (y))
1935 return scm_i_inexact_centered_remainder
1936 (SCM_REAL_VALUE (x), scm_to_double (y));
1937 else
1938 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
1939 s_scm_centered_remainder);
1940 }
1941 else if (SCM_FRACTIONP (x))
1942 {
1943 if (SCM_REALP (y))
1944 return scm_i_inexact_centered_remainder
1945 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1946 else
1947 return scm_i_slow_exact_centered_remainder (x, y);
1948 }
1949 else
1950 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG1,
1951 s_scm_centered_remainder);
1952}
1953#undef FUNC_NAME
1954
1955static SCM
1956scm_i_inexact_centered_remainder (double x, double y)
1957{
1958 double q;
1959
1960 /* Although it would be more efficient to use fmod here, we can't
1961 because it would in some cases produce results inconsistent with
1962 scm_i_inexact_centered_quotient, such that x != r + q * y (not even
1963 close). In particular, when x-y/2 is very close to a multiple of
1964 y, then r might be either -abs(y/2) or abs(y/2)-epsilon, but those
1965 two cases must correspond to different choices of q. If quotient
1966 chooses one and remainder chooses the other, it would be bad. */
1967 if (SCM_LIKELY (y > 0))
1968 q = floor (x/y + 0.5);
1969 else if (SCM_LIKELY (y < 0))
1970 q = ceil (x/y - 0.5);
1971 else if (y == 0)
1972 scm_num_overflow (s_scm_centered_remainder); /* or return a NaN? */
1973 else
1974 return scm_nan ();
1975 return scm_from_double (x - q * y);
1976}
1977
1978/* Assumes that both x and y are bigints, though
1979 x might be able to fit into a fixnum. */
1980static SCM
1981scm_i_bigint_centered_remainder (SCM x, SCM y)
1982{
1983 SCM r, min_r;
1984
1985 /* Note that x might be small enough to fit into a
1986 fixnum, so we must not let it escape into the wild */
1987 r = scm_i_mkbig ();
1988
1989 /* min_r will eventually become -abs(y)/2 */
1990 min_r = scm_i_mkbig ();
1991 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
1992 SCM_I_BIG_MPZ (y), 1);
1993
1994 /* Arrange for rr to initially be non-positive,
1995 because that simplifies the test to see
1996 if it is within the needed bounds. */
1997 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
1998 {
1999 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
2000 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2001 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2002 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2003 mpz_add (SCM_I_BIG_MPZ (r),
2004 SCM_I_BIG_MPZ (r),
2005 SCM_I_BIG_MPZ (y));
2006 }
2007 else
2008 {
2009 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
2010 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2011 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2012 mpz_sub (SCM_I_BIG_MPZ (r),
2013 SCM_I_BIG_MPZ (r),
2014 SCM_I_BIG_MPZ (y));
2015 }
2016 scm_remember_upto_here_2 (x, y);
2017 return scm_i_normbig (r);
2018}
2019
2020/* Compute exact centered_remainder the slow way.
2021 We use this only if both arguments are exact,
2022 and at least one of them is a fraction */
2023static SCM
2024scm_i_slow_exact_centered_remainder (SCM x, SCM y)
2025{
2026 SCM q;
2027
2028 if (!(SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x)))
2029 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG1,
2030 s_scm_centered_remainder);
2031 else if (!(SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y)))
2032 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2033 s_scm_centered_remainder);
2034 else if (scm_is_true (scm_positive_p (y)))
2035 q = scm_floor (scm_sum (scm_divide (x, y), exactly_one_half));
2036 else if (scm_is_true (scm_negative_p (y)))
2037 q = scm_ceiling (scm_difference (scm_divide (x, y), exactly_one_half));
2038 else
2039 scm_num_overflow (s_scm_centered_remainder);
2040 return scm_difference (x, scm_product (y, q));
2041}
2042
2043
ac6ce16b
MW
2044static SCM scm_i_inexact_centered_divide (double x, double y);
2045static SCM scm_i_bigint_centered_divide (SCM x, SCM y);
2046static SCM scm_i_slow_exact_centered_divide (SCM x, SCM y);
ff62c168 2047
ac6ce16b 2048SCM_PRIMITIVE_GENERIC (scm_centered_divide, "centered/", 2, 0, 0,
ff62c168
MW
2049 (SCM x, SCM y),
2050 "Return the integer @var{q} and the real number @var{r}\n"
2051 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2052 "and @math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2053 "@lisp\n"
2054 "(centered/ 123 10) @result{} 12 and 3\n"
2055 "(centered/ 123 -10) @result{} -12 and 3\n"
2056 "(centered/ -123 10) @result{} -12 and -3\n"
2057 "(centered/ -123 -10) @result{} 12 and -3\n"
2058 "(centered/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
2059 "(centered/ 16/3 -10/7) @result{} -4 and -8/21\n"
2060 "@end lisp")
ac6ce16b 2061#define FUNC_NAME s_scm_centered_divide
ff62c168
MW
2062{
2063 if (SCM_LIKELY (SCM_I_INUMP (x)))
2064 {
2065 if (SCM_LIKELY (SCM_I_INUMP (y)))
2066 {
2067 scm_t_inum yy = SCM_I_INUM (y);
2068 if (SCM_UNLIKELY (yy == 0))
ac6ce16b 2069 scm_num_overflow (s_scm_centered_divide);
ff62c168
MW
2070 else
2071 {
2072 scm_t_inum xx = SCM_I_INUM (x);
2073 scm_t_inum qq = xx / yy;
2074 scm_t_inum rr = xx - qq * yy;
2075 if (SCM_LIKELY (xx > 0))
2076 {
2077 if (SCM_LIKELY (yy > 0))
2078 {
2079 if (rr >= (yy + 1) / 2)
2080 { qq++; rr -= yy; }
2081 }
2082 else
2083 {
2084 if (rr >= (1 - yy) / 2)
2085 { qq--; rr += yy; }
2086 }
2087 }
2088 else
2089 {
2090 if (SCM_LIKELY (yy > 0))
2091 {
2092 if (rr < -yy / 2)
2093 { qq--; rr += yy; }
2094 }
2095 else
2096 {
2097 if (rr < yy / 2)
2098 { qq++; rr -= yy; }
2099 }
2100 }
2101 return scm_values (scm_list_2 (SCM_I_MAKINUM (qq),
2102 SCM_I_MAKINUM (rr)));
2103 }
2104 }
2105 else if (SCM_BIGP (y))
2106 {
2107 /* Pass a denormalized bignum version of x (even though it
ac6ce16b
MW
2108 can fit in a fixnum) to scm_i_bigint_centered_divide */
2109 return scm_i_bigint_centered_divide
ff62c168
MW
2110 (scm_i_long2big (SCM_I_INUM (x)), y);
2111 }
2112 else if (SCM_REALP (y))
ac6ce16b 2113 return scm_i_inexact_centered_divide
ff62c168
MW
2114 (SCM_I_INUM (x), SCM_REAL_VALUE (y));
2115 else if (SCM_FRACTIONP (y))
ac6ce16b 2116 return scm_i_slow_exact_centered_divide (x, y);
ff62c168 2117 else
ac6ce16b
MW
2118 SCM_WTA_DISPATCH_2 (g_scm_centered_divide, x, y, SCM_ARG2,
2119 s_scm_centered_divide);
ff62c168
MW
2120 }
2121 else if (SCM_BIGP (x))
2122 {
2123 if (SCM_LIKELY (SCM_I_INUMP (y)))
2124 {
2125 scm_t_inum yy = SCM_I_INUM (y);
2126 if (SCM_UNLIKELY (yy == 0))
ac6ce16b 2127 scm_num_overflow (s_scm_centered_divide);
ff62c168
MW
2128 else
2129 {
2130 SCM q = scm_i_mkbig ();
2131 scm_t_inum rr;
2132 /* Arrange for rr to initially be non-positive,
2133 because that simplifies the test to see
2134 if it is within the needed bounds. */
2135 if (yy > 0)
2136 {
2137 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2138 SCM_I_BIG_MPZ (x), yy);
2139 scm_remember_upto_here_1 (x);
2140 if (rr < -yy / 2)
2141 {
2142 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2143 SCM_I_BIG_MPZ (q), 1);
2144 rr += yy;
2145 }
2146 }
2147 else
2148 {
2149 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2150 SCM_I_BIG_MPZ (x), -yy);
2151 scm_remember_upto_here_1 (x);
2152 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2153 if (rr < yy / 2)
2154 {
2155 mpz_add_ui (SCM_I_BIG_MPZ (q),
2156 SCM_I_BIG_MPZ (q), 1);
2157 rr -= yy;
2158 }
2159 }
2160 return scm_values (scm_list_2 (scm_i_normbig (q),
2161 SCM_I_MAKINUM (rr)));
2162 }
2163 }
2164 else if (SCM_BIGP (y))
ac6ce16b 2165 return scm_i_bigint_centered_divide (x, y);
ff62c168 2166 else if (SCM_REALP (y))
ac6ce16b 2167 return scm_i_inexact_centered_divide
ff62c168
MW
2168 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2169 else if (SCM_FRACTIONP (y))
ac6ce16b 2170 return scm_i_slow_exact_centered_divide (x, y);
ff62c168 2171 else
ac6ce16b
MW
2172 SCM_WTA_DISPATCH_2 (g_scm_centered_divide, x, y, SCM_ARG2,
2173 s_scm_centered_divide);
ff62c168
MW
2174 }
2175 else if (SCM_REALP (x))
2176 {
2177 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2178 SCM_BIGP (y) || SCM_FRACTIONP (y))
ac6ce16b 2179 return scm_i_inexact_centered_divide
ff62c168
MW
2180 (SCM_REAL_VALUE (x), scm_to_double (y));
2181 else
ac6ce16b
MW
2182 SCM_WTA_DISPATCH_2 (g_scm_centered_divide, x, y, SCM_ARG2,
2183 s_scm_centered_divide);
ff62c168
MW
2184 }
2185 else if (SCM_FRACTIONP (x))
2186 {
2187 if (SCM_REALP (y))
ac6ce16b 2188 return scm_i_inexact_centered_divide
ff62c168
MW
2189 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2190 else
ac6ce16b 2191 return scm_i_slow_exact_centered_divide (x, y);
ff62c168
MW
2192 }
2193 else
ac6ce16b
MW
2194 SCM_WTA_DISPATCH_2 (g_scm_centered_divide, x, y, SCM_ARG1,
2195 s_scm_centered_divide);
ff62c168
MW
2196}
2197#undef FUNC_NAME
2198
2199static SCM
ac6ce16b 2200scm_i_inexact_centered_divide (double x, double y)
ff62c168
MW
2201{
2202 double q, r;
2203
2204 if (SCM_LIKELY (y > 0))
2205 q = floor (x/y + 0.5);
2206 else if (SCM_LIKELY (y < 0))
2207 q = ceil (x/y - 0.5);
2208 else if (y == 0)
ac6ce16b 2209 scm_num_overflow (s_scm_centered_divide); /* or return a NaN? */
ff62c168
MW
2210 else
2211 q = guile_NaN;
2212 r = x - q * y;
2213 return scm_values (scm_list_2 (scm_from_double (q),
2214 scm_from_double (r)));
2215}
2216
2217/* Assumes that both x and y are bigints, though
2218 x might be able to fit into a fixnum. */
2219static SCM
ac6ce16b 2220scm_i_bigint_centered_divide (SCM x, SCM y)
ff62c168
MW
2221{
2222 SCM q, r, min_r;
2223
2224 /* Note that x might be small enough to fit into a
2225 fixnum, so we must not let it escape into the wild */
2226 q = scm_i_mkbig ();
2227 r = scm_i_mkbig ();
2228
2229 /* min_r will eventually become -abs(y/2) */
2230 min_r = scm_i_mkbig ();
2231 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2232 SCM_I_BIG_MPZ (y), 1);
2233
2234 /* Arrange for rr to initially be non-positive,
2235 because that simplifies the test to see
2236 if it is within the needed bounds. */
2237 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2238 {
2239 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2240 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2241 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2242 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2243 {
2244 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2245 SCM_I_BIG_MPZ (q), 1);
2246 mpz_add (SCM_I_BIG_MPZ (r),
2247 SCM_I_BIG_MPZ (r),
2248 SCM_I_BIG_MPZ (y));
2249 }
2250 }
2251 else
2252 {
2253 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2254 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2255 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2256 {
2257 mpz_add_ui (SCM_I_BIG_MPZ (q),
2258 SCM_I_BIG_MPZ (q), 1);
2259 mpz_sub (SCM_I_BIG_MPZ (r),
2260 SCM_I_BIG_MPZ (r),
2261 SCM_I_BIG_MPZ (y));
2262 }
2263 }
2264 scm_remember_upto_here_2 (x, y);
2265 return scm_values (scm_list_2 (scm_i_normbig (q),
2266 scm_i_normbig (r)));
2267}
2268
2269/* Compute exact centered quotient and remainder the slow way.
2270 We use this only if both arguments are exact,
2271 and at least one of them is a fraction */
2272static SCM
ac6ce16b 2273scm_i_slow_exact_centered_divide (SCM x, SCM y)
ff62c168
MW
2274{
2275 SCM q, r;
2276
2277 if (!(SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x)))
ac6ce16b
MW
2278 SCM_WTA_DISPATCH_2 (g_scm_centered_divide, x, y, SCM_ARG1,
2279 s_scm_centered_divide);
ff62c168 2280 else if (!(SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y)))
ac6ce16b
MW
2281 SCM_WTA_DISPATCH_2 (g_scm_centered_divide, x, y, SCM_ARG2,
2282 s_scm_centered_divide);
ff62c168
MW
2283 else if (scm_is_true (scm_positive_p (y)))
2284 q = scm_floor (scm_sum (scm_divide (x, y),
2285 exactly_one_half));
2286 else if (scm_is_true (scm_negative_p (y)))
2287 q = scm_ceiling (scm_difference (scm_divide (x, y),
2288 exactly_one_half));
2289 else
ac6ce16b 2290 scm_num_overflow (s_scm_centered_divide);
ff62c168
MW
2291 r = scm_difference (x, scm_product (q, y));
2292 return scm_values (scm_list_2 (q, r));
2293}
2294
2295
78d3deb1
AW
2296SCM_PRIMITIVE_GENERIC (scm_i_gcd, "gcd", 0, 2, 1,
2297 (SCM x, SCM y, SCM rest),
2298 "Return the greatest common divisor of all parameter values.\n"
2299 "If called without arguments, 0 is returned.")
2300#define FUNC_NAME s_scm_i_gcd
2301{
2302 while (!scm_is_null (rest))
2303 { x = scm_gcd (x, y);
2304 y = scm_car (rest);
2305 rest = scm_cdr (rest);
2306 }
2307 return scm_gcd (x, y);
2308}
2309#undef FUNC_NAME
2310
2311#define s_gcd s_scm_i_gcd
2312#define g_gcd g_scm_i_gcd
2313
0f2d19dd 2314SCM
6e8d25a6 2315scm_gcd (SCM x, SCM y)
0f2d19dd 2316{
ca46fb90 2317 if (SCM_UNBNDP (y))
1dd79792 2318 return SCM_UNBNDP (x) ? SCM_INUM0 : scm_abs (x);
ca46fb90 2319
e11e83f3 2320 if (SCM_I_INUMP (x))
ca46fb90 2321 {
e11e83f3 2322 if (SCM_I_INUMP (y))
ca46fb90 2323 {
e25f3727
AW
2324 scm_t_inum xx = SCM_I_INUM (x);
2325 scm_t_inum yy = SCM_I_INUM (y);
2326 scm_t_inum u = xx < 0 ? -xx : xx;
2327 scm_t_inum v = yy < 0 ? -yy : yy;
2328 scm_t_inum result;
0aacf84e
MD
2329 if (xx == 0)
2330 result = v;
2331 else if (yy == 0)
2332 result = u;
2333 else
2334 {
e25f3727
AW
2335 scm_t_inum k = 1;
2336 scm_t_inum t;
0aacf84e
MD
2337 /* Determine a common factor 2^k */
2338 while (!(1 & (u | v)))
2339 {
2340 k <<= 1;
2341 u >>= 1;
2342 v >>= 1;
2343 }
2344 /* Now, any factor 2^n can be eliminated */
2345 if (u & 1)
2346 t = -v;
2347 else
2348 {
2349 t = u;
2350 b3:
2351 t = SCM_SRS (t, 1);
2352 }
2353 if (!(1 & t))
2354 goto b3;
2355 if (t > 0)
2356 u = t;
2357 else
2358 v = -t;
2359 t = u - v;
2360 if (t != 0)
2361 goto b3;
2362 result = u * k;
2363 }
2364 return (SCM_POSFIXABLE (result)
d956fa6f 2365 ? SCM_I_MAKINUM (result)
e25f3727 2366 : scm_i_inum2big (result));
ca46fb90
RB
2367 }
2368 else if (SCM_BIGP (y))
2369 {
0bff4dce
KR
2370 SCM_SWAP (x, y);
2371 goto big_inum;
ca46fb90
RB
2372 }
2373 else
2374 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 2375 }
ca46fb90
RB
2376 else if (SCM_BIGP (x))
2377 {
e11e83f3 2378 if (SCM_I_INUMP (y))
ca46fb90 2379 {
e25f3727
AW
2380 scm_t_bits result;
2381 scm_t_inum yy;
0bff4dce 2382 big_inum:
e11e83f3 2383 yy = SCM_I_INUM (y);
8c5b0afc
KR
2384 if (yy == 0)
2385 return scm_abs (x);
0aacf84e
MD
2386 if (yy < 0)
2387 yy = -yy;
ca46fb90
RB
2388 result = mpz_gcd_ui (NULL, SCM_I_BIG_MPZ (x), yy);
2389 scm_remember_upto_here_1 (x);
0aacf84e 2390 return (SCM_POSFIXABLE (result)
d956fa6f 2391 ? SCM_I_MAKINUM (result)
e25f3727 2392 : scm_from_unsigned_integer (result));
ca46fb90
RB
2393 }
2394 else if (SCM_BIGP (y))
2395 {
2396 SCM result = scm_i_mkbig ();
0aacf84e
MD
2397 mpz_gcd (SCM_I_BIG_MPZ (result),
2398 SCM_I_BIG_MPZ (x),
2399 SCM_I_BIG_MPZ (y));
2400 scm_remember_upto_here_2 (x, y);
ca46fb90
RB
2401 return scm_i_normbig (result);
2402 }
2403 else
2404 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
09fb7599 2405 }
ca46fb90 2406 else
09fb7599 2407 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
0f2d19dd
JB
2408}
2409
78d3deb1
AW
2410SCM_PRIMITIVE_GENERIC (scm_i_lcm, "lcm", 0, 2, 1,
2411 (SCM x, SCM y, SCM rest),
2412 "Return the least common multiple of the arguments.\n"
2413 "If called without arguments, 1 is returned.")
2414#define FUNC_NAME s_scm_i_lcm
2415{
2416 while (!scm_is_null (rest))
2417 { x = scm_lcm (x, y);
2418 y = scm_car (rest);
2419 rest = scm_cdr (rest);
2420 }
2421 return scm_lcm (x, y);
2422}
2423#undef FUNC_NAME
2424
2425#define s_lcm s_scm_i_lcm
2426#define g_lcm g_scm_i_lcm
2427
0f2d19dd 2428SCM
6e8d25a6 2429scm_lcm (SCM n1, SCM n2)
0f2d19dd 2430{
ca46fb90
RB
2431 if (SCM_UNBNDP (n2))
2432 {
2433 if (SCM_UNBNDP (n1))
d956fa6f
MV
2434 return SCM_I_MAKINUM (1L);
2435 n2 = SCM_I_MAKINUM (1L);
09fb7599 2436 }
09fb7599 2437
e11e83f3 2438 SCM_GASSERT2 (SCM_I_INUMP (n1) || SCM_BIGP (n1),
ca46fb90 2439 g_lcm, n1, n2, SCM_ARG1, s_lcm);
e11e83f3 2440 SCM_GASSERT2 (SCM_I_INUMP (n2) || SCM_BIGP (n2),
ca46fb90 2441 g_lcm, n1, n2, SCM_ARGn, s_lcm);
09fb7599 2442
e11e83f3 2443 if (SCM_I_INUMP (n1))
ca46fb90 2444 {
e11e83f3 2445 if (SCM_I_INUMP (n2))
ca46fb90
RB
2446 {
2447 SCM d = scm_gcd (n1, n2);
bc36d050 2448 if (scm_is_eq (d, SCM_INUM0))
ca46fb90
RB
2449 return d;
2450 else
2451 return scm_abs (scm_product (n1, scm_quotient (n2, d)));
2452 }
2453 else
2454 {
2455 /* inum n1, big n2 */
2456 inumbig:
2457 {
2458 SCM result = scm_i_mkbig ();
e25f3727 2459 scm_t_inum nn1 = SCM_I_INUM (n1);
ca46fb90
RB
2460 if (nn1 == 0) return SCM_INUM0;
2461 if (nn1 < 0) nn1 = - nn1;
2462 mpz_lcm_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n2), nn1);
2463 scm_remember_upto_here_1 (n2);
2464 return result;
2465 }
2466 }
2467 }
2468 else
2469 {
2470 /* big n1 */
e11e83f3 2471 if (SCM_I_INUMP (n2))
ca46fb90
RB
2472 {
2473 SCM_SWAP (n1, n2);
2474 goto inumbig;
2475 }
2476 else
2477 {
2478 SCM result = scm_i_mkbig ();
2479 mpz_lcm(SCM_I_BIG_MPZ (result),
2480 SCM_I_BIG_MPZ (n1),
2481 SCM_I_BIG_MPZ (n2));
2482 scm_remember_upto_here_2(n1, n2);
2483 /* shouldn't need to normalize b/c lcm of 2 bigs should be big */
2484 return result;
2485 }
f872b822 2486 }
0f2d19dd
JB
2487}
2488
8a525303
GB
2489/* Emulating 2's complement bignums with sign magnitude arithmetic:
2490
2491 Logand:
2492 X Y Result Method:
2493 (len)
2494 + + + x (map digit:logand X Y)
2495 + - + x (map digit:logand X (lognot (+ -1 Y)))
2496 - + + y (map digit:logand (lognot (+ -1 X)) Y)
2497 - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y)))
2498
2499 Logior:
2500 X Y Result Method:
2501
2502 + + + (map digit:logior X Y)
2503 + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y)))
2504 - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y)))
2505 - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y)))
2506
2507 Logxor:
2508 X Y Result Method:
2509
2510 + + + (map digit:logxor X Y)
2511 + - - (+ 1 (map digit:logxor X (+ -1 Y)))
2512 - + - (+ 1 (map digit:logxor (+ -1 X) Y))
2513 - - + (map digit:logxor (+ -1 X) (+ -1 Y))
2514
2515 Logtest:
2516 X Y Result
2517
2518 + + (any digit:logand X Y)
2519 + - (any digit:logand X (lognot (+ -1 Y)))
2520 - + (any digit:logand (lognot (+ -1 X)) Y)
2521 - - #t
2522
2523*/
2524
78d3deb1
AW
2525SCM_DEFINE (scm_i_logand, "logand", 0, 2, 1,
2526 (SCM x, SCM y, SCM rest),
2527 "Return the bitwise AND of the integer arguments.\n\n"
2528 "@lisp\n"
2529 "(logand) @result{} -1\n"
2530 "(logand 7) @result{} 7\n"
2531 "(logand #b111 #b011 #b001) @result{} 1\n"
2532 "@end lisp")
2533#define FUNC_NAME s_scm_i_logand
2534{
2535 while (!scm_is_null (rest))
2536 { x = scm_logand (x, y);
2537 y = scm_car (rest);
2538 rest = scm_cdr (rest);
2539 }
2540 return scm_logand (x, y);
2541}
2542#undef FUNC_NAME
2543
2544#define s_scm_logand s_scm_i_logand
2545
2546SCM scm_logand (SCM n1, SCM n2)
1bbd0b84 2547#define FUNC_NAME s_scm_logand
0f2d19dd 2548{
e25f3727 2549 scm_t_inum nn1;
9a00c9fc 2550
0aacf84e
MD
2551 if (SCM_UNBNDP (n2))
2552 {
2553 if (SCM_UNBNDP (n1))
d956fa6f 2554 return SCM_I_MAKINUM (-1);
0aacf84e
MD
2555 else if (!SCM_NUMBERP (n1))
2556 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
2557 else if (SCM_NUMBERP (n1))
2558 return n1;
2559 else
2560 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 2561 }
09fb7599 2562
e11e83f3 2563 if (SCM_I_INUMP (n1))
0aacf84e 2564 {
e11e83f3
MV
2565 nn1 = SCM_I_INUM (n1);
2566 if (SCM_I_INUMP (n2))
0aacf84e 2567 {
e25f3727 2568 scm_t_inum nn2 = SCM_I_INUM (n2);
d956fa6f 2569 return SCM_I_MAKINUM (nn1 & nn2);
0aacf84e
MD
2570 }
2571 else if SCM_BIGP (n2)
2572 {
2573 intbig:
2574 if (n1 == 0)
2575 return SCM_INUM0;
2576 {
2577 SCM result_z = scm_i_mkbig ();
2578 mpz_t nn1_z;
2579 mpz_init_set_si (nn1_z, nn1);
2580 mpz_and (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
2581 scm_remember_upto_here_1 (n2);
2582 mpz_clear (nn1_z);
2583 return scm_i_normbig (result_z);
2584 }
2585 }
2586 else
2587 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
2588 }
2589 else if (SCM_BIGP (n1))
2590 {
e11e83f3 2591 if (SCM_I_INUMP (n2))
0aacf84e
MD
2592 {
2593 SCM_SWAP (n1, n2);
e11e83f3 2594 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
2595 goto intbig;
2596 }
2597 else if (SCM_BIGP (n2))
2598 {
2599 SCM result_z = scm_i_mkbig ();
2600 mpz_and (SCM_I_BIG_MPZ (result_z),
2601 SCM_I_BIG_MPZ (n1),
2602 SCM_I_BIG_MPZ (n2));
2603 scm_remember_upto_here_2 (n1, n2);
2604 return scm_i_normbig (result_z);
2605 }
2606 else
2607 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 2608 }
0aacf84e 2609 else
09fb7599 2610 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 2611}
1bbd0b84 2612#undef FUNC_NAME
0f2d19dd 2613
09fb7599 2614
78d3deb1
AW
2615SCM_DEFINE (scm_i_logior, "logior", 0, 2, 1,
2616 (SCM x, SCM y, SCM rest),
2617 "Return the bitwise OR of the integer arguments.\n\n"
2618 "@lisp\n"
2619 "(logior) @result{} 0\n"
2620 "(logior 7) @result{} 7\n"
2621 "(logior #b000 #b001 #b011) @result{} 3\n"
2622 "@end lisp")
2623#define FUNC_NAME s_scm_i_logior
2624{
2625 while (!scm_is_null (rest))
2626 { x = scm_logior (x, y);
2627 y = scm_car (rest);
2628 rest = scm_cdr (rest);
2629 }
2630 return scm_logior (x, y);
2631}
2632#undef FUNC_NAME
2633
2634#define s_scm_logior s_scm_i_logior
2635
2636SCM scm_logior (SCM n1, SCM n2)
1bbd0b84 2637#define FUNC_NAME s_scm_logior
0f2d19dd 2638{
e25f3727 2639 scm_t_inum nn1;
9a00c9fc 2640
0aacf84e
MD
2641 if (SCM_UNBNDP (n2))
2642 {
2643 if (SCM_UNBNDP (n1))
2644 return SCM_INUM0;
2645 else if (SCM_NUMBERP (n1))
2646 return n1;
2647 else
2648 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 2649 }
09fb7599 2650
e11e83f3 2651 if (SCM_I_INUMP (n1))
0aacf84e 2652 {
e11e83f3
MV
2653 nn1 = SCM_I_INUM (n1);
2654 if (SCM_I_INUMP (n2))
0aacf84e 2655 {
e11e83f3 2656 long nn2 = SCM_I_INUM (n2);
d956fa6f 2657 return SCM_I_MAKINUM (nn1 | nn2);
0aacf84e
MD
2658 }
2659 else if (SCM_BIGP (n2))
2660 {
2661 intbig:
2662 if (nn1 == 0)
2663 return n2;
2664 {
2665 SCM result_z = scm_i_mkbig ();
2666 mpz_t nn1_z;
2667 mpz_init_set_si (nn1_z, nn1);
2668 mpz_ior (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
2669 scm_remember_upto_here_1 (n2);
2670 mpz_clear (nn1_z);
9806de0d 2671 return scm_i_normbig (result_z);
0aacf84e
MD
2672 }
2673 }
2674 else
2675 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
2676 }
2677 else if (SCM_BIGP (n1))
2678 {
e11e83f3 2679 if (SCM_I_INUMP (n2))
0aacf84e
MD
2680 {
2681 SCM_SWAP (n1, n2);
e11e83f3 2682 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
2683 goto intbig;
2684 }
2685 else if (SCM_BIGP (n2))
2686 {
2687 SCM result_z = scm_i_mkbig ();
2688 mpz_ior (SCM_I_BIG_MPZ (result_z),
2689 SCM_I_BIG_MPZ (n1),
2690 SCM_I_BIG_MPZ (n2));
2691 scm_remember_upto_here_2 (n1, n2);
9806de0d 2692 return scm_i_normbig (result_z);
0aacf84e
MD
2693 }
2694 else
2695 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 2696 }
0aacf84e 2697 else
09fb7599 2698 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 2699}
1bbd0b84 2700#undef FUNC_NAME
0f2d19dd 2701
09fb7599 2702
78d3deb1
AW
2703SCM_DEFINE (scm_i_logxor, "logxor", 0, 2, 1,
2704 (SCM x, SCM y, SCM rest),
3c3db128
GH
2705 "Return the bitwise XOR of the integer arguments. A bit is\n"
2706 "set in the result if it is set in an odd number of arguments.\n"
2707 "@lisp\n"
2708 "(logxor) @result{} 0\n"
2709 "(logxor 7) @result{} 7\n"
2710 "(logxor #b000 #b001 #b011) @result{} 2\n"
2711 "(logxor #b000 #b001 #b011 #b011) @result{} 1\n"
1e6808ea 2712 "@end lisp")
78d3deb1
AW
2713#define FUNC_NAME s_scm_i_logxor
2714{
2715 while (!scm_is_null (rest))
2716 { x = scm_logxor (x, y);
2717 y = scm_car (rest);
2718 rest = scm_cdr (rest);
2719 }
2720 return scm_logxor (x, y);
2721}
2722#undef FUNC_NAME
2723
2724#define s_scm_logxor s_scm_i_logxor
2725
2726SCM scm_logxor (SCM n1, SCM n2)
1bbd0b84 2727#define FUNC_NAME s_scm_logxor
0f2d19dd 2728{
e25f3727 2729 scm_t_inum nn1;
9a00c9fc 2730
0aacf84e
MD
2731 if (SCM_UNBNDP (n2))
2732 {
2733 if (SCM_UNBNDP (n1))
2734 return SCM_INUM0;
2735 else if (SCM_NUMBERP (n1))
2736 return n1;
2737 else
2738 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 2739 }
09fb7599 2740
e11e83f3 2741 if (SCM_I_INUMP (n1))
0aacf84e 2742 {
e11e83f3
MV
2743 nn1 = SCM_I_INUM (n1);
2744 if (SCM_I_INUMP (n2))
0aacf84e 2745 {
e25f3727 2746 scm_t_inum nn2 = SCM_I_INUM (n2);
d956fa6f 2747 return SCM_I_MAKINUM (nn1 ^ nn2);
0aacf84e
MD
2748 }
2749 else if (SCM_BIGP (n2))
2750 {
2751 intbig:
2752 {
2753 SCM result_z = scm_i_mkbig ();
2754 mpz_t nn1_z;
2755 mpz_init_set_si (nn1_z, nn1);
2756 mpz_xor (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
2757 scm_remember_upto_here_1 (n2);
2758 mpz_clear (nn1_z);
2759 return scm_i_normbig (result_z);
2760 }
2761 }
2762 else
2763 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
2764 }
2765 else if (SCM_BIGP (n1))
2766 {
e11e83f3 2767 if (SCM_I_INUMP (n2))
0aacf84e
MD
2768 {
2769 SCM_SWAP (n1, n2);
e11e83f3 2770 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
2771 goto intbig;
2772 }
2773 else if (SCM_BIGP (n2))
2774 {
2775 SCM result_z = scm_i_mkbig ();
2776 mpz_xor (SCM_I_BIG_MPZ (result_z),
2777 SCM_I_BIG_MPZ (n1),
2778 SCM_I_BIG_MPZ (n2));
2779 scm_remember_upto_here_2 (n1, n2);
2780 return scm_i_normbig (result_z);
2781 }
2782 else
2783 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 2784 }
0aacf84e 2785 else
09fb7599 2786 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 2787}
1bbd0b84 2788#undef FUNC_NAME
0f2d19dd 2789
09fb7599 2790
a1ec6916 2791SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1e6808ea 2792 (SCM j, SCM k),
ba6e7231
KR
2793 "Test whether @var{j} and @var{k} have any 1 bits in common.\n"
2794 "This is equivalent to @code{(not (zero? (logand j k)))}, but\n"
2795 "without actually calculating the @code{logand}, just testing\n"
2796 "for non-zero.\n"
2797 "\n"
1e6808ea 2798 "@lisp\n"
b380b885
MD
2799 "(logtest #b0100 #b1011) @result{} #f\n"
2800 "(logtest #b0100 #b0111) @result{} #t\n"
1e6808ea 2801 "@end lisp")
1bbd0b84 2802#define FUNC_NAME s_scm_logtest
0f2d19dd 2803{
e25f3727 2804 scm_t_inum nj;
9a00c9fc 2805
e11e83f3 2806 if (SCM_I_INUMP (j))
0aacf84e 2807 {
e11e83f3
MV
2808 nj = SCM_I_INUM (j);
2809 if (SCM_I_INUMP (k))
0aacf84e 2810 {
e25f3727 2811 scm_t_inum nk = SCM_I_INUM (k);
73e4de09 2812 return scm_from_bool (nj & nk);
0aacf84e
MD
2813 }
2814 else if (SCM_BIGP (k))
2815 {
2816 intbig:
2817 if (nj == 0)
2818 return SCM_BOOL_F;
2819 {
2820 SCM result;
2821 mpz_t nj_z;
2822 mpz_init_set_si (nj_z, nj);
2823 mpz_and (nj_z, nj_z, SCM_I_BIG_MPZ (k));
2824 scm_remember_upto_here_1 (k);
73e4de09 2825 result = scm_from_bool (mpz_sgn (nj_z) != 0);
0aacf84e
MD
2826 mpz_clear (nj_z);
2827 return result;
2828 }
2829 }
2830 else
2831 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
2832 }
2833 else if (SCM_BIGP (j))
2834 {
e11e83f3 2835 if (SCM_I_INUMP (k))
0aacf84e
MD
2836 {
2837 SCM_SWAP (j, k);
e11e83f3 2838 nj = SCM_I_INUM (j);
0aacf84e
MD
2839 goto intbig;
2840 }
2841 else if (SCM_BIGP (k))
2842 {
2843 SCM result;
2844 mpz_t result_z;
2845 mpz_init (result_z);
2846 mpz_and (result_z,
2847 SCM_I_BIG_MPZ (j),
2848 SCM_I_BIG_MPZ (k));
2849 scm_remember_upto_here_2 (j, k);
73e4de09 2850 result = scm_from_bool (mpz_sgn (result_z) != 0);
0aacf84e
MD
2851 mpz_clear (result_z);
2852 return result;
2853 }
2854 else
2855 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
2856 }
2857 else
2858 SCM_WRONG_TYPE_ARG (SCM_ARG1, j);
0f2d19dd 2859}
1bbd0b84 2860#undef FUNC_NAME
0f2d19dd 2861
c1bfcf60 2862
a1ec6916 2863SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 2864 (SCM index, SCM j),
ba6e7231
KR
2865 "Test whether bit number @var{index} in @var{j} is set.\n"
2866 "@var{index} starts from 0 for the least significant bit.\n"
2867 "\n"
1e6808ea 2868 "@lisp\n"
b380b885
MD
2869 "(logbit? 0 #b1101) @result{} #t\n"
2870 "(logbit? 1 #b1101) @result{} #f\n"
2871 "(logbit? 2 #b1101) @result{} #t\n"
2872 "(logbit? 3 #b1101) @result{} #t\n"
2873 "(logbit? 4 #b1101) @result{} #f\n"
1e6808ea 2874 "@end lisp")
1bbd0b84 2875#define FUNC_NAME s_scm_logbit_p
0f2d19dd 2876{
78166ad5 2877 unsigned long int iindex;
5efd3c7d 2878 iindex = scm_to_ulong (index);
78166ad5 2879
e11e83f3 2880 if (SCM_I_INUMP (j))
0d75f6d8
KR
2881 {
2882 /* bits above what's in an inum follow the sign bit */
20fcc8ed 2883 iindex = min (iindex, SCM_LONG_BIT - 1);
e11e83f3 2884 return scm_from_bool ((1L << iindex) & SCM_I_INUM (j));
0d75f6d8 2885 }
0aacf84e
MD
2886 else if (SCM_BIGP (j))
2887 {
2888 int val = mpz_tstbit (SCM_I_BIG_MPZ (j), iindex);
2889 scm_remember_upto_here_1 (j);
73e4de09 2890 return scm_from_bool (val);
0aacf84e
MD
2891 }
2892 else
78166ad5 2893 SCM_WRONG_TYPE_ARG (SCM_ARG2, j);
0f2d19dd 2894}
1bbd0b84 2895#undef FUNC_NAME
0f2d19dd 2896
78166ad5 2897
a1ec6916 2898SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 2899 (SCM n),
4d814788 2900 "Return the integer which is the ones-complement of the integer\n"
1e6808ea
MG
2901 "argument.\n"
2902 "\n"
b380b885
MD
2903 "@lisp\n"
2904 "(number->string (lognot #b10000000) 2)\n"
2905 " @result{} \"-10000001\"\n"
2906 "(number->string (lognot #b0) 2)\n"
2907 " @result{} \"-1\"\n"
1e6808ea 2908 "@end lisp")
1bbd0b84 2909#define FUNC_NAME s_scm_lognot
0f2d19dd 2910{
e11e83f3 2911 if (SCM_I_INUMP (n)) {
f9811f9f
KR
2912 /* No overflow here, just need to toggle all the bits making up the inum.
2913 Enhancement: No need to strip the tag and add it back, could just xor
2914 a block of 1 bits, if that worked with the various debug versions of
2915 the SCM typedef. */
e11e83f3 2916 return SCM_I_MAKINUM (~ SCM_I_INUM (n));
f9811f9f
KR
2917
2918 } else if (SCM_BIGP (n)) {
2919 SCM result = scm_i_mkbig ();
2920 mpz_com (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n));
2921 scm_remember_upto_here_1 (n);
2922 return result;
2923
2924 } else {
2925 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
2926 }
0f2d19dd 2927}
1bbd0b84 2928#undef FUNC_NAME
0f2d19dd 2929
518b7508
KR
2930/* returns 0 if IN is not an integer. OUT must already be
2931 initialized. */
2932static int
2933coerce_to_big (SCM in, mpz_t out)
2934{
2935 if (SCM_BIGP (in))
2936 mpz_set (out, SCM_I_BIG_MPZ (in));
e11e83f3
MV
2937 else if (SCM_I_INUMP (in))
2938 mpz_set_si (out, SCM_I_INUM (in));
518b7508
KR
2939 else
2940 return 0;
2941
2942 return 1;
2943}
2944
d885e204 2945SCM_DEFINE (scm_modulo_expt, "modulo-expt", 3, 0, 0,
518b7508
KR
2946 (SCM n, SCM k, SCM m),
2947 "Return @var{n} raised to the integer exponent\n"
2948 "@var{k}, modulo @var{m}.\n"
2949 "\n"
2950 "@lisp\n"
2951 "(modulo-expt 2 3 5)\n"
2952 " @result{} 3\n"
2953 "@end lisp")
d885e204 2954#define FUNC_NAME s_scm_modulo_expt
518b7508
KR
2955{
2956 mpz_t n_tmp;
2957 mpz_t k_tmp;
2958 mpz_t m_tmp;
2959
2960 /* There are two classes of error we might encounter --
2961 1) Math errors, which we'll report by calling scm_num_overflow,
2962 and
2963 2) wrong-type errors, which of course we'll report by calling
2964 SCM_WRONG_TYPE_ARG.
2965 We don't report those errors immediately, however; instead we do
2966 some cleanup first. These variables tell us which error (if
2967 any) we should report after cleaning up.
2968 */
2969 int report_overflow = 0;
2970
2971 int position_of_wrong_type = 0;
2972 SCM value_of_wrong_type = SCM_INUM0;
2973
2974 SCM result = SCM_UNDEFINED;
2975
2976 mpz_init (n_tmp);
2977 mpz_init (k_tmp);
2978 mpz_init (m_tmp);
2979
bc36d050 2980 if (scm_is_eq (m, SCM_INUM0))
518b7508
KR
2981 {
2982 report_overflow = 1;
2983 goto cleanup;
2984 }
2985
2986 if (!coerce_to_big (n, n_tmp))
2987 {
2988 value_of_wrong_type = n;
2989 position_of_wrong_type = 1;
2990 goto cleanup;
2991 }
2992
2993 if (!coerce_to_big (k, k_tmp))
2994 {
2995 value_of_wrong_type = k;
2996 position_of_wrong_type = 2;
2997 goto cleanup;
2998 }
2999
3000 if (!coerce_to_big (m, m_tmp))
3001 {
3002 value_of_wrong_type = m;
3003 position_of_wrong_type = 3;
3004 goto cleanup;
3005 }
3006
3007 /* if the exponent K is negative, and we simply call mpz_powm, we
3008 will get a divide-by-zero exception when an inverse 1/n mod m
3009 doesn't exist (or is not unique). Since exceptions are hard to
3010 handle, we'll attempt the inversion "by hand" -- that way, we get
3011 a simple failure code, which is easy to handle. */
3012
3013 if (-1 == mpz_sgn (k_tmp))
3014 {
3015 if (!mpz_invert (n_tmp, n_tmp, m_tmp))
3016 {
3017 report_overflow = 1;
3018 goto cleanup;
3019 }
3020 mpz_neg (k_tmp, k_tmp);
3021 }
3022
3023 result = scm_i_mkbig ();
3024 mpz_powm (SCM_I_BIG_MPZ (result),
3025 n_tmp,
3026 k_tmp,
3027 m_tmp);
b7b8c575
KR
3028
3029 if (mpz_sgn (m_tmp) < 0 && mpz_sgn (SCM_I_BIG_MPZ (result)) != 0)
3030 mpz_add (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), m_tmp);
3031
518b7508
KR
3032 cleanup:
3033 mpz_clear (m_tmp);
3034 mpz_clear (k_tmp);
3035 mpz_clear (n_tmp);
3036
3037 if (report_overflow)
3038 scm_num_overflow (FUNC_NAME);
3039
3040 if (position_of_wrong_type)
3041 SCM_WRONG_TYPE_ARG (position_of_wrong_type,
3042 value_of_wrong_type);
3043
3044 return scm_i_normbig (result);
3045}
3046#undef FUNC_NAME
3047
a1ec6916 3048SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 3049 (SCM n, SCM k),
ba6e7231
KR
3050 "Return @var{n} raised to the power @var{k}. @var{k} must be an\n"
3051 "exact integer, @var{n} can be any number.\n"
3052 "\n"
2519490c
MW
3053 "Negative @var{k} is supported, and results in\n"
3054 "@math{1/@var{n}^abs(@var{k})} in the usual way.\n"
3055 "@math{@var{n}^0} is 1, as usual, and that\n"
ba6e7231 3056 "includes @math{0^0} is 1.\n"
1e6808ea 3057 "\n"
b380b885 3058 "@lisp\n"
ba6e7231
KR
3059 "(integer-expt 2 5) @result{} 32\n"
3060 "(integer-expt -3 3) @result{} -27\n"
3061 "(integer-expt 5 -3) @result{} 1/125\n"
3062 "(integer-expt 0 0) @result{} 1\n"
b380b885 3063 "@end lisp")
1bbd0b84 3064#define FUNC_NAME s_scm_integer_expt
0f2d19dd 3065{
e25f3727 3066 scm_t_inum i2 = 0;
1c35cb19
RB
3067 SCM z_i2 = SCM_BOOL_F;
3068 int i2_is_big = 0;
d956fa6f 3069 SCM acc = SCM_I_MAKINUM (1L);
ca46fb90 3070
bfe1f03a
MW
3071 /* Specifically refrain from checking the type of the first argument.
3072 This allows us to exponentiate any object that can be multiplied.
3073 If we must raise to a negative power, we must also be able to
3074 take its reciprocal. */
3075 if (!SCM_LIKELY (SCM_I_INUMP (k)) && !SCM_LIKELY (SCM_BIGP (k)))
01c7284a 3076 SCM_WRONG_TYPE_ARG (2, k);
5a8fc758 3077
bfe1f03a
MW
3078 if (SCM_UNLIKELY (scm_is_eq (k, SCM_INUM0)))
3079 return SCM_INUM1; /* n^(exact0) is exact 1, regardless of n */
3080 else if (SCM_UNLIKELY (scm_is_eq (n, SCM_I_MAKINUM (-1L))))
3081 return scm_is_false (scm_even_p (k)) ? n : SCM_INUM1;
3082 /* The next check is necessary only because R6RS specifies different
3083 behavior for 0^(-k) than for (/ 0). If n is not a scheme number,
3084 we simply skip this case and move on. */
3085 else if (SCM_NUMBERP (n) && scm_is_true (scm_zero_p (n)))
3086 {
3087 /* k cannot be 0 at this point, because we
3088 have already checked for that case above */
3089 if (scm_is_true (scm_positive_p (k)))
01c7284a
MW
3090 return n;
3091 else /* return NaN for (0 ^ k) for negative k per R6RS */
3092 return scm_nan ();
3093 }
ca46fb90 3094
e11e83f3
MV
3095 if (SCM_I_INUMP (k))
3096 i2 = SCM_I_INUM (k);
ca46fb90
RB
3097 else if (SCM_BIGP (k))
3098 {
3099 z_i2 = scm_i_clonebig (k, 1);
ca46fb90
RB
3100 scm_remember_upto_here_1 (k);
3101 i2_is_big = 1;
3102 }
2830fd91 3103 else
ca46fb90
RB
3104 SCM_WRONG_TYPE_ARG (2, k);
3105
3106 if (i2_is_big)
f872b822 3107 {
ca46fb90
RB
3108 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == -1)
3109 {
3110 mpz_neg (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2));
3111 n = scm_divide (n, SCM_UNDEFINED);
3112 }
3113 while (1)
3114 {
3115 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == 0)
3116 {
ca46fb90
RB
3117 return acc;
3118 }
3119 if (mpz_cmp_ui(SCM_I_BIG_MPZ (z_i2), 1) == 0)
3120 {
ca46fb90
RB
3121 return scm_product (acc, n);
3122 }
3123 if (mpz_tstbit(SCM_I_BIG_MPZ (z_i2), 0))
3124 acc = scm_product (acc, n);
3125 n = scm_product (n, n);
3126 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2), 1);
3127 }
f872b822 3128 }
ca46fb90 3129 else
f872b822 3130 {
ca46fb90
RB
3131 if (i2 < 0)
3132 {
3133 i2 = -i2;
3134 n = scm_divide (n, SCM_UNDEFINED);
3135 }
3136 while (1)
3137 {
3138 if (0 == i2)
3139 return acc;
3140 if (1 == i2)
3141 return scm_product (acc, n);
3142 if (i2 & 1)
3143 acc = scm_product (acc, n);
3144 n = scm_product (n, n);
3145 i2 >>= 1;
3146 }
f872b822 3147 }
0f2d19dd 3148}
1bbd0b84 3149#undef FUNC_NAME
0f2d19dd 3150
a1ec6916 3151SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 3152 (SCM n, SCM cnt),
32f19569
KR
3153 "Return @var{n} shifted left by @var{cnt} bits, or shifted right\n"
3154 "if @var{cnt} is negative. This is an ``arithmetic'' shift.\n"
1e6808ea 3155 "\n"
e7644cb2 3156 "This is effectively a multiplication by 2^@var{cnt}, and when\n"
32f19569
KR
3157 "@var{cnt} is negative it's a division, rounded towards negative\n"
3158 "infinity. (Note that this is not the same rounding as\n"
3159 "@code{quotient} does.)\n"
3160 "\n"
3161 "With @var{n} viewed as an infinite precision twos complement,\n"
3162 "@code{ash} means a left shift introducing zero bits, or a right\n"
3163 "shift dropping bits.\n"
1e6808ea 3164 "\n"
b380b885 3165 "@lisp\n"
1e6808ea
MG
3166 "(number->string (ash #b1 3) 2) @result{} \"1000\"\n"
3167 "(number->string (ash #b1010 -1) 2) @result{} \"101\"\n"
32f19569
KR
3168 "\n"
3169 ";; -23 is bits ...11101001, -6 is bits ...111010\n"
3170 "(ash -23 -2) @result{} -6\n"
a3c8b9fc 3171 "@end lisp")
1bbd0b84 3172#define FUNC_NAME s_scm_ash
0f2d19dd 3173{
3ab9f56e 3174 long bits_to_shift;
5efd3c7d 3175 bits_to_shift = scm_to_long (cnt);
ca46fb90 3176
788aca27
KR
3177 if (SCM_I_INUMP (n))
3178 {
e25f3727 3179 scm_t_inum nn = SCM_I_INUM (n);
788aca27
KR
3180
3181 if (bits_to_shift > 0)
3182 {
3183 /* Left shift of bits_to_shift >= SCM_I_FIXNUM_BIT-1 will always
3184 overflow a non-zero fixnum. For smaller shifts we check the
3185 bits going into positions above SCM_I_FIXNUM_BIT-1. If they're
3186 all 0s for nn>=0, or all 1s for nn<0 then there's no overflow.
3187 Those bits are "nn >> (SCM_I_FIXNUM_BIT-1 -
3188 bits_to_shift)". */
3189
3190 if (nn == 0)
3191 return n;
3192
3193 if (bits_to_shift < SCM_I_FIXNUM_BIT-1
e25f3727 3194 && ((scm_t_bits)
788aca27
KR
3195 (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
3196 <= 1))
3197 {
3198 return SCM_I_MAKINUM (nn << bits_to_shift);
3199 }
3200 else
3201 {
e25f3727 3202 SCM result = scm_i_inum2big (nn);
788aca27
KR
3203 mpz_mul_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
3204 bits_to_shift);
3205 return result;
3206 }
3207 }
3208 else
3209 {
3210 bits_to_shift = -bits_to_shift;
3211 if (bits_to_shift >= SCM_LONG_BIT)
cff5fa33 3212 return (nn >= 0 ? SCM_INUM0 : SCM_I_MAKINUM(-1));
788aca27
KR
3213 else
3214 return SCM_I_MAKINUM (SCM_SRS (nn, bits_to_shift));
3215 }
3216
3217 }
3218 else if (SCM_BIGP (n))
ca46fb90 3219 {
788aca27
KR
3220 SCM result;
3221
3222 if (bits_to_shift == 0)
3223 return n;
3224
3225 result = scm_i_mkbig ();
3226 if (bits_to_shift >= 0)
3227 {
3228 mpz_mul_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n),
3229 bits_to_shift);
3230 return result;
3231 }
ca46fb90 3232 else
788aca27
KR
3233 {
3234 /* GMP doesn't have an fdiv_q_2exp variant returning just a long, so
3235 we have to allocate a bignum even if the result is going to be a
3236 fixnum. */
3237 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n),
3238 -bits_to_shift);
3239 return scm_i_normbig (result);
3240 }
3241
ca46fb90
RB
3242 }
3243 else
788aca27
KR
3244 {
3245 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
3246 }
0f2d19dd 3247}
1bbd0b84 3248#undef FUNC_NAME
0f2d19dd 3249
3c9f20f8 3250
a1ec6916 3251SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 3252 (SCM n, SCM start, SCM end),
1e6808ea
MG
3253 "Return the integer composed of the @var{start} (inclusive)\n"
3254 "through @var{end} (exclusive) bits of @var{n}. The\n"
3255 "@var{start}th bit becomes the 0-th bit in the result.\n"
3256 "\n"
b380b885
MD
3257 "@lisp\n"
3258 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
3259 " @result{} \"1010\"\n"
3260 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
3261 " @result{} \"10110\"\n"
3262 "@end lisp")
1bbd0b84 3263#define FUNC_NAME s_scm_bit_extract
0f2d19dd 3264{
7f848242 3265 unsigned long int istart, iend, bits;
5efd3c7d
MV
3266 istart = scm_to_ulong (start);
3267 iend = scm_to_ulong (end);
c1bfcf60 3268 SCM_ASSERT_RANGE (3, end, (iend >= istart));
78166ad5 3269
7f848242
KR
3270 /* how many bits to keep */
3271 bits = iend - istart;
3272
e11e83f3 3273 if (SCM_I_INUMP (n))
0aacf84e 3274 {
e25f3727 3275 scm_t_inum in = SCM_I_INUM (n);
7f848242
KR
3276
3277 /* When istart>=SCM_I_FIXNUM_BIT we can just limit the shift to
d77ad560 3278 SCM_I_FIXNUM_BIT-1 to get either 0 or -1 per the sign of "in". */
857ae6af 3279 in = SCM_SRS (in, min (istart, SCM_I_FIXNUM_BIT-1));
ac0c002c 3280
0aacf84e
MD
3281 if (in < 0 && bits >= SCM_I_FIXNUM_BIT)
3282 {
3283 /* Since we emulate two's complement encoded numbers, this
3284 * special case requires us to produce a result that has
7f848242 3285 * more bits than can be stored in a fixnum.
0aacf84e 3286 */
e25f3727 3287 SCM result = scm_i_inum2big (in);
7f848242
KR
3288 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
3289 bits);
3290 return result;
0aacf84e 3291 }
ac0c002c 3292
7f848242 3293 /* mask down to requisite bits */
857ae6af 3294 bits = min (bits, SCM_I_FIXNUM_BIT);
d956fa6f 3295 return SCM_I_MAKINUM (in & ((1L << bits) - 1));
0aacf84e
MD
3296 }
3297 else if (SCM_BIGP (n))
ac0c002c 3298 {
7f848242
KR
3299 SCM result;
3300 if (bits == 1)
3301 {
d956fa6f 3302 result = SCM_I_MAKINUM (mpz_tstbit (SCM_I_BIG_MPZ (n), istart));
7f848242
KR
3303 }
3304 else
3305 {
3306 /* ENHANCE-ME: It'd be nice not to allocate a new bignum when
3307 bits<SCM_I_FIXNUM_BIT. Would want some help from GMP to get
3308 such bits into a ulong. */
3309 result = scm_i_mkbig ();
3310 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(n), istart);
3311 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(result), bits);
3312 result = scm_i_normbig (result);
3313 }
3314 scm_remember_upto_here_1 (n);
3315 return result;
ac0c002c 3316 }
0aacf84e 3317 else
78166ad5 3318 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 3319}
1bbd0b84 3320#undef FUNC_NAME
0f2d19dd 3321
7f848242 3322
e4755e5c
JB
3323static const char scm_logtab[] = {
3324 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
3325};
1cc91f1b 3326
a1ec6916 3327SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 3328 (SCM n),
1e6808ea
MG
3329 "Return the number of bits in integer @var{n}. If integer is\n"
3330 "positive, the 1-bits in its binary representation are counted.\n"
3331 "If negative, the 0-bits in its two's-complement binary\n"
3332 "representation are counted. If 0, 0 is returned.\n"
3333 "\n"
b380b885
MD
3334 "@lisp\n"
3335 "(logcount #b10101010)\n"
ca46fb90
RB
3336 " @result{} 4\n"
3337 "(logcount 0)\n"
3338 " @result{} 0\n"
3339 "(logcount -2)\n"
3340 " @result{} 1\n"
3341 "@end lisp")
3342#define FUNC_NAME s_scm_logcount
3343{
e11e83f3 3344 if (SCM_I_INUMP (n))
f872b822 3345 {
e25f3727
AW
3346 unsigned long c = 0;
3347 scm_t_inum nn = SCM_I_INUM (n);
ca46fb90
RB
3348 if (nn < 0)
3349 nn = -1 - nn;
3350 while (nn)
3351 {
3352 c += scm_logtab[15 & nn];
3353 nn >>= 4;
3354 }
d956fa6f 3355 return SCM_I_MAKINUM (c);
f872b822 3356 }
ca46fb90 3357 else if (SCM_BIGP (n))
f872b822 3358 {
ca46fb90 3359 unsigned long count;
713a4259
KR
3360 if (mpz_sgn (SCM_I_BIG_MPZ (n)) >= 0)
3361 count = mpz_popcount (SCM_I_BIG_MPZ (n));
ca46fb90 3362 else
713a4259
KR
3363 count = mpz_hamdist (SCM_I_BIG_MPZ (n), z_negative_one);
3364 scm_remember_upto_here_1 (n);
d956fa6f 3365 return SCM_I_MAKINUM (count);
f872b822 3366 }
ca46fb90
RB
3367 else
3368 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 3369}
ca46fb90 3370#undef FUNC_NAME
0f2d19dd
JB
3371
3372
ca46fb90
RB
3373static const char scm_ilentab[] = {
3374 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
3375};
3376
0f2d19dd 3377
ca46fb90
RB
3378SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
3379 (SCM n),
3380 "Return the number of bits necessary to represent @var{n}.\n"
3381 "\n"
3382 "@lisp\n"
3383 "(integer-length #b10101010)\n"
3384 " @result{} 8\n"
3385 "(integer-length 0)\n"
3386 " @result{} 0\n"
3387 "(integer-length #b1111)\n"
3388 " @result{} 4\n"
3389 "@end lisp")
3390#define FUNC_NAME s_scm_integer_length
3391{
e11e83f3 3392 if (SCM_I_INUMP (n))
0aacf84e 3393 {
e25f3727 3394 unsigned long c = 0;
0aacf84e 3395 unsigned int l = 4;
e25f3727 3396 scm_t_inum nn = SCM_I_INUM (n);
0aacf84e
MD
3397 if (nn < 0)
3398 nn = -1 - nn;
3399 while (nn)
3400 {
3401 c += 4;
3402 l = scm_ilentab [15 & nn];
3403 nn >>= 4;
3404 }
d956fa6f 3405 return SCM_I_MAKINUM (c - 4 + l);
0aacf84e
MD
3406 }
3407 else if (SCM_BIGP (n))
3408 {
3409 /* mpz_sizeinbase looks at the absolute value of negatives, whereas we
3410 want a ones-complement. If n is ...111100..00 then mpz_sizeinbase is
3411 1 too big, so check for that and adjust. */
3412 size_t size = mpz_sizeinbase (SCM_I_BIG_MPZ (n), 2);
3413 if (mpz_sgn (SCM_I_BIG_MPZ (n)) < 0
3414 && mpz_scan0 (SCM_I_BIG_MPZ (n), /* no 0 bits above the lowest 1 */
3415 mpz_scan1 (SCM_I_BIG_MPZ (n), 0)) == ULONG_MAX)
3416 size--;
3417 scm_remember_upto_here_1 (n);
d956fa6f 3418 return SCM_I_MAKINUM (size);
0aacf84e
MD
3419 }
3420 else
ca46fb90 3421 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
ca46fb90
RB
3422}
3423#undef FUNC_NAME
0f2d19dd
JB
3424
3425/*** NUMBERS -> STRINGS ***/
0b799eea
MV
3426#define SCM_MAX_DBL_PREC 60
3427#define SCM_MAX_DBL_RADIX 36
3428
3429/* this is an array starting with radix 2, and ending with radix SCM_MAX_DBL_RADIX */
3430static int scm_dblprec[SCM_MAX_DBL_RADIX - 1];
3431static double fx_per_radix[SCM_MAX_DBL_RADIX - 1][SCM_MAX_DBL_PREC];
3432
3433static
3434void init_dblprec(int *prec, int radix) {
3435 /* determine floating point precision by adding successively
3436 smaller increments to 1.0 until it is considered == 1.0 */
3437 double f = ((double)1.0)/radix;
3438 double fsum = 1.0 + f;
3439
3440 *prec = 0;
3441 while (fsum != 1.0)
3442 {
3443 if (++(*prec) > SCM_MAX_DBL_PREC)
3444 fsum = 1.0;
3445 else
3446 {
3447 f /= radix;
3448 fsum = f + 1.0;
3449 }
3450 }
3451 (*prec) -= 1;
3452}
3453
3454static
3455void init_fx_radix(double *fx_list, int radix)
3456{
3457 /* initialize a per-radix list of tolerances. When added
3458 to a number < 1.0, we can determine if we should raund
3459 up and quit converting a number to a string. */
3460 int i;
3461 fx_list[0] = 0.0;
3462 fx_list[1] = 0.5;
3463 for( i = 2 ; i < SCM_MAX_DBL_PREC; ++i )
3464 fx_list[i] = (fx_list[i-1] / radix);
3465}
3466
3467/* use this array as a way to generate a single digit */
9b5fcde6 3468static const char number_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
0f2d19dd 3469
1be6b49c 3470static size_t
0b799eea 3471idbl2str (double f, char *a, int radix)
0f2d19dd 3472{
0b799eea
MV
3473 int efmt, dpt, d, i, wp;
3474 double *fx;
3475#ifdef DBL_MIN_10_EXP
3476 double f_cpy;
3477 int exp_cpy;
3478#endif /* DBL_MIN_10_EXP */
3479 size_t ch = 0;
3480 int exp = 0;
3481
3482 if(radix < 2 ||
3483 radix > SCM_MAX_DBL_RADIX)
3484 {
3485 /* revert to existing behavior */
3486 radix = 10;
3487 }
3488
3489 wp = scm_dblprec[radix-2];
3490 fx = fx_per_radix[radix-2];
0f2d19dd 3491
f872b822 3492 if (f == 0.0)
abb7e44d
MV
3493 {
3494#ifdef HAVE_COPYSIGN
3495 double sgn = copysign (1.0, f);
3496
3497 if (sgn < 0.0)
3498 a[ch++] = '-';
3499#endif
abb7e44d
MV
3500 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
3501 }
7351e207 3502
2e65b52f 3503 if (isinf (f))
7351e207
MV
3504 {
3505 if (f < 0)
3506 strcpy (a, "-inf.0");
3507 else
3508 strcpy (a, "+inf.0");
3509 return ch+6;
3510 }
2e65b52f 3511 else if (isnan (f))
7351e207
MV
3512 {
3513 strcpy (a, "+nan.0");
3514 return ch+6;
3515 }
3516
f872b822
MD
3517 if (f < 0.0)
3518 {
3519 f = -f;
3520 a[ch++] = '-';
3521 }
7351e207 3522
f872b822
MD
3523#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
3524 make-uniform-vector, from causing infinite loops. */
0b799eea
MV
3525 /* just do the checking...if it passes, we do the conversion for our
3526 radix again below */
3527 f_cpy = f;
3528 exp_cpy = exp;
3529
3530 while (f_cpy < 1.0)
f872b822 3531 {
0b799eea
MV
3532 f_cpy *= 10.0;
3533 if (exp_cpy-- < DBL_MIN_10_EXP)
7351e207
MV
3534 {
3535 a[ch++] = '#';
3536 a[ch++] = '.';
3537 a[ch++] = '#';
3538 return ch;
3539 }
f872b822 3540 }
0b799eea 3541 while (f_cpy > 10.0)
f872b822 3542 {
0b799eea
MV
3543 f_cpy *= 0.10;
3544 if (exp_cpy++ > DBL_MAX_10_EXP)
7351e207
MV
3545 {
3546 a[ch++] = '#';
3547 a[ch++] = '.';
3548 a[ch++] = '#';
3549 return ch;
3550 }
f872b822 3551 }
0b799eea
MV
3552#endif
3553
f872b822
MD
3554 while (f < 1.0)
3555 {
0b799eea 3556 f *= radix;
f872b822
MD
3557 exp--;
3558 }
0b799eea 3559 while (f > radix)
f872b822 3560 {
0b799eea 3561 f /= radix;
f872b822
MD
3562 exp++;
3563 }
0b799eea
MV
3564
3565 if (f + fx[wp] >= radix)
f872b822
MD
3566 {
3567 f = 1.0;
3568 exp++;
3569 }
0f2d19dd 3570 zero:
0b799eea
MV
3571#ifdef ENGNOT
3572 /* adding 9999 makes this equivalent to abs(x) % 3 */
f872b822 3573 dpt = (exp + 9999) % 3;
0f2d19dd
JB
3574 exp -= dpt++;
3575 efmt = 1;
f872b822
MD
3576#else
3577 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 3578 if (!efmt)
cda139a7
MD
3579 {
3580 if (exp < 0)
3581 {
3582 a[ch++] = '0';
3583 a[ch++] = '.';
3584 dpt = exp;
f872b822
MD
3585 while (++dpt)
3586 a[ch++] = '0';
cda139a7
MD
3587 }
3588 else
f872b822 3589 dpt = exp + 1;
cda139a7 3590 }
0f2d19dd
JB
3591 else
3592 dpt = 1;
f872b822
MD
3593#endif
3594
3595 do
3596 {
3597 d = f;
3598 f -= d;
0b799eea 3599 a[ch++] = number_chars[d];
f872b822
MD
3600 if (f < fx[wp])
3601 break;
3602 if (f + fx[wp] >= 1.0)
3603 {
0b799eea 3604 a[ch - 1] = number_chars[d+1];
f872b822
MD
3605 break;
3606 }
0b799eea 3607 f *= radix;
f872b822
MD
3608 if (!(--dpt))
3609 a[ch++] = '.';
0f2d19dd 3610 }
f872b822 3611 while (wp--);
0f2d19dd
JB
3612
3613 if (dpt > 0)
cda139a7 3614 {
f872b822 3615#ifndef ENGNOT
cda139a7
MD
3616 if ((dpt > 4) && (exp > 6))
3617 {
f872b822 3618 d = (a[0] == '-' ? 2 : 1);
cda139a7 3619 for (i = ch++; i > d; i--)
f872b822 3620 a[i] = a[i - 1];
cda139a7
MD
3621 a[d] = '.';
3622 efmt = 1;
3623 }
3624 else
f872b822 3625#endif
cda139a7 3626 {
f872b822
MD
3627 while (--dpt)
3628 a[ch++] = '0';
cda139a7
MD
3629 a[ch++] = '.';
3630 }
3631 }
f872b822
MD
3632 if (a[ch - 1] == '.')
3633 a[ch++] = '0'; /* trailing zero */
3634 if (efmt && exp)
3635 {
3636 a[ch++] = 'e';
3637 if (exp < 0)
3638 {
3639 exp = -exp;
3640 a[ch++] = '-';
3641 }
0b799eea
MV
3642 for (i = radix; i <= exp; i *= radix);
3643 for (i /= radix; i; i /= radix)
f872b822 3644 {
0b799eea 3645 a[ch++] = number_chars[exp / i];
f872b822
MD
3646 exp %= i;
3647 }
0f2d19dd 3648 }
0f2d19dd
JB
3649 return ch;
3650}
3651
7a1aba42
MV
3652
3653static size_t
3654icmplx2str (double real, double imag, char *str, int radix)
3655{
3656 size_t i;
c7218482 3657 double sgn;
7a1aba42
MV
3658
3659 i = idbl2str (real, str, radix);
c7218482
MW
3660#ifdef HAVE_COPYSIGN
3661 sgn = copysign (1.0, imag);
3662#else
3663 sgn = imag;
3664#endif
3665 /* Don't output a '+' for negative numbers or for Inf and
3666 NaN. They will provide their own sign. */
3667 if (sgn >= 0 && DOUBLE_IS_FINITE (imag))
3668 str[i++] = '+';
3669 i += idbl2str (imag, &str[i], radix);
3670 str[i++] = 'i';
7a1aba42
MV
3671 return i;
3672}
3673
1be6b49c 3674static size_t
0b799eea 3675iflo2str (SCM flt, char *str, int radix)
0f2d19dd 3676{
1be6b49c 3677 size_t i;
3c9a524f 3678 if (SCM_REALP (flt))
0b799eea 3679 i = idbl2str (SCM_REAL_VALUE (flt), str, radix);
0f2d19dd 3680 else
7a1aba42
MV
3681 i = icmplx2str (SCM_COMPLEX_REAL (flt), SCM_COMPLEX_IMAG (flt),
3682 str, radix);
0f2d19dd
JB
3683 return i;
3684}
0f2d19dd 3685
2881e77b 3686/* convert a scm_t_intmax to a string (unterminated). returns the number of
1bbd0b84
GB
3687 characters in the result.
3688 rad is output base
3689 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 3690size_t
2881e77b
MV
3691scm_iint2str (scm_t_intmax num, int rad, char *p)
3692{
3693 if (num < 0)
3694 {
3695 *p++ = '-';
3696 return scm_iuint2str (-num, rad, p) + 1;
3697 }
3698 else
3699 return scm_iuint2str (num, rad, p);
3700}
3701
3702/* convert a scm_t_intmax to a string (unterminated). returns the number of
3703 characters in the result.
3704 rad is output base
3705 p is destination: worst case (base 2) is SCM_INTBUFLEN */
3706size_t
3707scm_iuint2str (scm_t_uintmax num, int rad, char *p)
0f2d19dd 3708{
1be6b49c
ML
3709 size_t j = 1;
3710 size_t i;
2881e77b 3711 scm_t_uintmax n = num;
5c11cc9d 3712
a6f3af16
AW
3713 if (rad < 2 || rad > 36)
3714 scm_out_of_range ("scm_iuint2str", scm_from_int (rad));
3715
f872b822 3716 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
3717 j++;
3718
3719 i = j;
2881e77b 3720 n = num;
f872b822
MD
3721 while (i--)
3722 {
5c11cc9d
GH
3723 int d = n % rad;
3724
f872b822 3725 n /= rad;
a6f3af16 3726 p[i] = number_chars[d];
f872b822 3727 }
0f2d19dd
JB
3728 return j;
3729}
3730
a1ec6916 3731SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
3732 (SCM n, SCM radix),
3733 "Return a string holding the external representation of the\n"
942e5b91
MG
3734 "number @var{n} in the given @var{radix}. If @var{n} is\n"
3735 "inexact, a radix of 10 will be used.")
1bbd0b84 3736#define FUNC_NAME s_scm_number_to_string
0f2d19dd 3737{
1bbd0b84 3738 int base;
98cb6e75 3739
0aacf84e 3740 if (SCM_UNBNDP (radix))
98cb6e75 3741 base = 10;
0aacf84e 3742 else
5efd3c7d 3743 base = scm_to_signed_integer (radix, 2, 36);
98cb6e75 3744
e11e83f3 3745 if (SCM_I_INUMP (n))
0aacf84e
MD
3746 {
3747 char num_buf [SCM_INTBUFLEN];
e11e83f3 3748 size_t length = scm_iint2str (SCM_I_INUM (n), base, num_buf);
cc95e00a 3749 return scm_from_locale_stringn (num_buf, length);
0aacf84e
MD
3750 }
3751 else if (SCM_BIGP (n))
3752 {
3753 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
3754 scm_remember_upto_here_1 (n);
cc95e00a 3755 return scm_take_locale_string (str);
0aacf84e 3756 }
f92e85f7
MV
3757 else if (SCM_FRACTIONP (n))
3758 {
f92e85f7 3759 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
cc95e00a 3760 scm_from_locale_string ("/"),
f92e85f7
MV
3761 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
3762 }
0aacf84e
MD
3763 else if (SCM_INEXACTP (n))
3764 {
3765 char num_buf [FLOBUFLEN];
cc95e00a 3766 return scm_from_locale_stringn (num_buf, iflo2str (n, num_buf, base));
0aacf84e
MD
3767 }
3768 else
bb628794 3769 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 3770}
1bbd0b84 3771#undef FUNC_NAME
0f2d19dd
JB
3772
3773
ca46fb90
RB
3774/* These print routines used to be stubbed here so that scm_repl.c
3775 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 3776
0f2d19dd 3777int
e81d98ec 3778scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 3779{
56e55ac7 3780 char num_buf[FLOBUFLEN];
0b799eea 3781 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
0f2d19dd
JB
3782 return !0;
3783}
3784
b479fe9a
MV
3785void
3786scm_i_print_double (double val, SCM port)
3787{
3788 char num_buf[FLOBUFLEN];
3789 scm_lfwrite (num_buf, idbl2str (val, num_buf, 10), port);
3790}
3791
f3ae5d60 3792int
e81d98ec 3793scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 3794
f3ae5d60 3795{
56e55ac7 3796 char num_buf[FLOBUFLEN];
0b799eea 3797 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
f3ae5d60
MD
3798 return !0;
3799}
1cc91f1b 3800
7a1aba42
MV
3801void
3802scm_i_print_complex (double real, double imag, SCM port)
3803{
3804 char num_buf[FLOBUFLEN];
3805 scm_lfwrite (num_buf, icmplx2str (real, imag, num_buf, 10), port);
3806}
3807
f92e85f7
MV
3808int
3809scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
3810{
3811 SCM str;
f92e85f7 3812 str = scm_number_to_string (sexp, SCM_UNDEFINED);
a9178715 3813 scm_display (str, port);
f92e85f7
MV
3814 scm_remember_upto_here_1 (str);
3815 return !0;
3816}
3817
0f2d19dd 3818int
e81d98ec 3819scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 3820{
ca46fb90
RB
3821 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
3822 scm_remember_upto_here_1 (exp);
3823 scm_lfwrite (str, (size_t) strlen (str), port);
3824 free (str);
0f2d19dd
JB
3825 return !0;
3826}
3827/*** END nums->strs ***/
3828
3c9a524f 3829
0f2d19dd 3830/*** STRINGS -> NUMBERS ***/
2a8fecee 3831
3c9a524f
DH
3832/* The following functions implement the conversion from strings to numbers.
3833 * The implementation somehow follows the grammar for numbers as it is given
3834 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
3835 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
3836 * points should be noted about the implementation:
3837 * * Each function keeps a local index variable 'idx' that points at the
3838 * current position within the parsed string. The global index is only
3839 * updated if the function could parse the corresponding syntactic unit
3840 * successfully.
3841 * * Similarly, the functions keep track of indicators of inexactness ('#',
3842 * '.' or exponents) using local variables ('hash_seen', 'x'). Again, the
3843 * global exactness information is only updated after each part has been
3844 * successfully parsed.
3845 * * Sequences of digits are parsed into temporary variables holding fixnums.
3846 * Only if these fixnums would overflow, the result variables are updated
3847 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
3848 * the temporary variables holding the fixnums are cleared, and the process
3849 * starts over again. If for example fixnums were able to store five decimal
3850 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
3851 * and the result was computed as 12345 * 100000 + 67890. In other words,
3852 * only every five digits two bignum operations were performed.
3853 */
3854
3855enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
3856
3857/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
3858
a6f3af16
AW
3859/* Caller is responsible for checking that the return value is in range
3860 for the given radix, which should be <= 36. */
3861static unsigned int
3862char_decimal_value (scm_t_uint32 c)
3863{
3864 /* uc_decimal_value returns -1 on error. When cast to an unsigned int,
3865 that's certainly above any valid decimal, so we take advantage of
3866 that to elide some tests. */
3867 unsigned int d = (unsigned int) uc_decimal_value (c);
3868
3869 /* If that failed, try extended hexadecimals, then. Only accept ascii
3870 hexadecimals. */
3871 if (d >= 10U)
3872 {
3873 c = uc_tolower (c);
3874 if (c >= (scm_t_uint32) 'a')
3875 d = c - (scm_t_uint32)'a' + 10U;
3876 }
3877 return d;
3878}
3c9a524f 3879
2a8fecee 3880static SCM
3f47e526 3881mem2uinteger (SCM mem, unsigned int *p_idx,
3c9a524f 3882 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 3883{
3c9a524f
DH
3884 unsigned int idx = *p_idx;
3885 unsigned int hash_seen = 0;
3886 scm_t_bits shift = 1;
3887 scm_t_bits add = 0;
3888 unsigned int digit_value;
3889 SCM result;
3890 char c;
3f47e526 3891 size_t len = scm_i_string_length (mem);
3c9a524f
DH
3892
3893 if (idx == len)
3894 return SCM_BOOL_F;
2a8fecee 3895
3f47e526 3896 c = scm_i_string_ref (mem, idx);
a6f3af16 3897 digit_value = char_decimal_value (c);
3c9a524f
DH
3898 if (digit_value >= radix)
3899 return SCM_BOOL_F;
3900
3901 idx++;
d956fa6f 3902 result = SCM_I_MAKINUM (digit_value);
3c9a524f 3903 while (idx != len)
f872b822 3904 {
3f47e526 3905 scm_t_wchar c = scm_i_string_ref (mem, idx);
a6f3af16 3906 if (c == '#')
3c9a524f
DH
3907 {
3908 hash_seen = 1;
3909 digit_value = 0;
3910 }
a6f3af16
AW
3911 else if (hash_seen)
3912 break;
3c9a524f 3913 else
a6f3af16
AW
3914 {
3915 digit_value = char_decimal_value (c);
3916 /* This check catches non-decimals in addition to out-of-range
3917 decimals. */
3918 if (digit_value >= radix)
3919 break;
3920 }
3c9a524f
DH
3921
3922 idx++;
3923 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
3924 {
d956fa6f 3925 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 3926 if (add > 0)
d956fa6f 3927 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
3928
3929 shift = radix;
3930 add = digit_value;
3931 }
3932 else
3933 {
3934 shift = shift * radix;
3935 add = add * radix + digit_value;
3936 }
3937 };
3938
3939 if (shift > 1)
d956fa6f 3940 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 3941 if (add > 0)
d956fa6f 3942 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
3943
3944 *p_idx = idx;
3945 if (hash_seen)
3946 *p_exactness = INEXACT;
3947
3948 return result;
2a8fecee
JB
3949}
3950
3951
3c9a524f
DH
3952/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
3953 * covers the parts of the rules that start at a potential point. The value
3954 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
3955 * in variable result. The content of *p_exactness indicates, whether a hash
3956 * has already been seen in the digits before the point.
3c9a524f 3957 */
1cc91f1b 3958
3f47e526 3959#define DIGIT2UINT(d) (uc_numeric_value(d).numerator)
3c9a524f
DH
3960
3961static SCM
3f47e526 3962mem2decimal_from_point (SCM result, SCM mem,
3c9a524f 3963 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 3964{
3c9a524f
DH
3965 unsigned int idx = *p_idx;
3966 enum t_exactness x = *p_exactness;
3f47e526 3967 size_t len = scm_i_string_length (mem);
3c9a524f
DH
3968
3969 if (idx == len)
79d34f68 3970 return result;
3c9a524f 3971
3f47e526 3972 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
3973 {
3974 scm_t_bits shift = 1;
3975 scm_t_bits add = 0;
3976 unsigned int digit_value;
cff5fa33 3977 SCM big_shift = SCM_INUM1;
3c9a524f
DH
3978
3979 idx++;
3980 while (idx != len)
3981 {
3f47e526
MG
3982 scm_t_wchar c = scm_i_string_ref (mem, idx);
3983 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
3984 {
3985 if (x == INEXACT)
3986 return SCM_BOOL_F;
3987 else
3988 digit_value = DIGIT2UINT (c);
3989 }
3990 else if (c == '#')
3991 {
3992 x = INEXACT;
3993 digit_value = 0;
3994 }
3995 else
3996 break;
3997
3998 idx++;
3999 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
4000 {
d956fa6f
MV
4001 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
4002 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 4003 if (add > 0)
d956fa6f 4004 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
4005
4006 shift = 10;
4007 add = digit_value;
4008 }
4009 else
4010 {
4011 shift = shift * 10;
4012 add = add * 10 + digit_value;
4013 }
4014 };
4015
4016 if (add > 0)
4017 {
d956fa6f
MV
4018 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
4019 result = scm_product (result, SCM_I_MAKINUM (shift));
4020 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
4021 }
4022
d8592269 4023 result = scm_divide (result, big_shift);
79d34f68 4024
3c9a524f
DH
4025 /* We've seen a decimal point, thus the value is implicitly inexact. */
4026 x = INEXACT;
f872b822 4027 }
3c9a524f 4028
3c9a524f 4029 if (idx != len)
f872b822 4030 {
3c9a524f
DH
4031 int sign = 1;
4032 unsigned int start;
3f47e526 4033 scm_t_wchar c;
3c9a524f
DH
4034 int exponent;
4035 SCM e;
4036
4037 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
4038
3f47e526 4039 switch (scm_i_string_ref (mem, idx))
f872b822 4040 {
3c9a524f
DH
4041 case 'd': case 'D':
4042 case 'e': case 'E':
4043 case 'f': case 'F':
4044 case 'l': case 'L':
4045 case 's': case 'S':
4046 idx++;
ee0ddd21
AW
4047 if (idx == len)
4048 return SCM_BOOL_F;
4049
3c9a524f 4050 start = idx;
3f47e526 4051 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4052 if (c == '-')
4053 {
4054 idx++;
ee0ddd21
AW
4055 if (idx == len)
4056 return SCM_BOOL_F;
4057
3c9a524f 4058 sign = -1;
3f47e526 4059 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4060 }
4061 else if (c == '+')
4062 {
4063 idx++;
ee0ddd21
AW
4064 if (idx == len)
4065 return SCM_BOOL_F;
4066
3c9a524f 4067 sign = 1;
3f47e526 4068 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4069 }
4070 else
4071 sign = 1;
4072
3f47e526 4073 if (!uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
4074 return SCM_BOOL_F;
4075
4076 idx++;
4077 exponent = DIGIT2UINT (c);
4078 while (idx != len)
f872b822 4079 {
3f47e526
MG
4080 scm_t_wchar c = scm_i_string_ref (mem, idx);
4081 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
4082 {
4083 idx++;
4084 if (exponent <= SCM_MAXEXP)
4085 exponent = exponent * 10 + DIGIT2UINT (c);
4086 }
4087 else
4088 break;
f872b822 4089 }
3c9a524f
DH
4090
4091 if (exponent > SCM_MAXEXP)
f872b822 4092 {
3c9a524f 4093 size_t exp_len = idx - start;
3f47e526 4094 SCM exp_string = scm_i_substring_copy (mem, start, start + exp_len);
3c9a524f
DH
4095 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
4096 scm_out_of_range ("string->number", exp_num);
f872b822 4097 }
3c9a524f 4098
d956fa6f 4099 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
4100 if (sign == 1)
4101 result = scm_product (result, e);
4102 else
f92e85f7 4103 result = scm_divide2real (result, e);
3c9a524f
DH
4104
4105 /* We've seen an exponent, thus the value is implicitly inexact. */
4106 x = INEXACT;
4107
f872b822 4108 break;
3c9a524f 4109
f872b822 4110 default:
3c9a524f 4111 break;
f872b822 4112 }
0f2d19dd 4113 }
3c9a524f
DH
4114
4115 *p_idx = idx;
4116 if (x == INEXACT)
4117 *p_exactness = x;
4118
4119 return result;
0f2d19dd 4120}
0f2d19dd 4121
3c9a524f
DH
4122
4123/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
4124
4125static SCM
3f47e526 4126mem2ureal (SCM mem, unsigned int *p_idx,
9d427b2c 4127 unsigned int radix, enum t_exactness forced_x)
0f2d19dd 4128{
3c9a524f 4129 unsigned int idx = *p_idx;
164d2481 4130 SCM result;
3f47e526 4131 size_t len = scm_i_string_length (mem);
3c9a524f 4132
40f89215
NJ
4133 /* Start off believing that the number will be exact. This changes
4134 to INEXACT if we see a decimal point or a hash. */
9d427b2c 4135 enum t_exactness implicit_x = EXACT;
40f89215 4136
3c9a524f
DH
4137 if (idx == len)
4138 return SCM_BOOL_F;
4139
3f47e526 4140 if (idx+5 <= len && !scm_i_string_strcmp (mem, idx, "inf.0"))
7351e207
MV
4141 {
4142 *p_idx = idx+5;
4143 return scm_inf ();
4144 }
4145
3f47e526 4146 if (idx+4 < len && !scm_i_string_strcmp (mem, idx, "nan."))
7351e207 4147 {
d8592269
MV
4148 /* Cobble up the fractional part. We might want to set the
4149 NaN's mantissa from it. */
7351e207 4150 idx += 4;
9d427b2c 4151 mem2uinteger (mem, &idx, 10, &implicit_x);
7351e207
MV
4152 *p_idx = idx;
4153 return scm_nan ();
4154 }
4155
3f47e526 4156 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
4157 {
4158 if (radix != 10)
4159 return SCM_BOOL_F;
4160 else if (idx + 1 == len)
4161 return SCM_BOOL_F;
3f47e526 4162 else if (!uc_is_property_decimal_digit ((scm_t_uint32) scm_i_string_ref (mem, idx+1)))
3c9a524f
DH
4163 return SCM_BOOL_F;
4164 else
cff5fa33 4165 result = mem2decimal_from_point (SCM_INUM0, mem,
9d427b2c 4166 p_idx, &implicit_x);
f872b822 4167 }
3c9a524f
DH
4168 else
4169 {
3c9a524f 4170 SCM uinteger;
3c9a524f 4171
9d427b2c 4172 uinteger = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 4173 if (scm_is_false (uinteger))
3c9a524f
DH
4174 return SCM_BOOL_F;
4175
4176 if (idx == len)
4177 result = uinteger;
3f47e526 4178 else if (scm_i_string_ref (mem, idx) == '/')
f872b822 4179 {
3c9a524f
DH
4180 SCM divisor;
4181
4182 idx++;
ee0ddd21
AW
4183 if (idx == len)
4184 return SCM_BOOL_F;
3c9a524f 4185
9d427b2c 4186 divisor = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 4187 if (scm_is_false (divisor))
3c9a524f
DH
4188 return SCM_BOOL_F;
4189
f92e85f7 4190 /* both are int/big here, I assume */
cba42c93 4191 result = scm_i_make_ratio (uinteger, divisor);
f872b822 4192 }
3c9a524f
DH
4193 else if (radix == 10)
4194 {
9d427b2c 4195 result = mem2decimal_from_point (uinteger, mem, &idx, &implicit_x);
73e4de09 4196 if (scm_is_false (result))
3c9a524f
DH
4197 return SCM_BOOL_F;
4198 }
4199 else
4200 result = uinteger;
4201
4202 *p_idx = idx;
f872b822 4203 }
164d2481 4204
9d427b2c
MW
4205 switch (forced_x)
4206 {
4207 case EXACT:
4208 if (SCM_INEXACTP (result))
4209 return scm_inexact_to_exact (result);
4210 else
4211 return result;
4212 case INEXACT:
4213 if (SCM_INEXACTP (result))
4214 return result;
4215 else
4216 return scm_exact_to_inexact (result);
4217 case NO_EXACTNESS:
4218 if (implicit_x == INEXACT)
4219 {
4220 if (SCM_INEXACTP (result))
4221 return result;
4222 else
4223 return scm_exact_to_inexact (result);
4224 }
4225 else
4226 return result;
4227 }
164d2481 4228
9d427b2c
MW
4229 /* We should never get here */
4230 scm_syserror ("mem2ureal");
3c9a524f 4231}
0f2d19dd 4232
0f2d19dd 4233
3c9a524f 4234/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 4235
3c9a524f 4236static SCM
3f47e526 4237mem2complex (SCM mem, unsigned int idx,
9d427b2c 4238 unsigned int radix, enum t_exactness forced_x)
3c9a524f 4239{
3f47e526 4240 scm_t_wchar c;
3c9a524f
DH
4241 int sign = 0;
4242 SCM ureal;
3f47e526 4243 size_t len = scm_i_string_length (mem);
3c9a524f
DH
4244
4245 if (idx == len)
4246 return SCM_BOOL_F;
4247
3f47e526 4248 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4249 if (c == '+')
4250 {
4251 idx++;
4252 sign = 1;
4253 }
4254 else if (c == '-')
4255 {
4256 idx++;
4257 sign = -1;
0f2d19dd 4258 }
0f2d19dd 4259
3c9a524f
DH
4260 if (idx == len)
4261 return SCM_BOOL_F;
4262
9d427b2c 4263 ureal = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 4264 if (scm_is_false (ureal))
f872b822 4265 {
3c9a524f
DH
4266 /* input must be either +i or -i */
4267
4268 if (sign == 0)
4269 return SCM_BOOL_F;
4270
3f47e526
MG
4271 if (scm_i_string_ref (mem, idx) == 'i'
4272 || scm_i_string_ref (mem, idx) == 'I')
f872b822 4273 {
3c9a524f
DH
4274 idx++;
4275 if (idx != len)
4276 return SCM_BOOL_F;
4277
cff5fa33 4278 return scm_make_rectangular (SCM_INUM0, SCM_I_MAKINUM (sign));
f872b822 4279 }
3c9a524f
DH
4280 else
4281 return SCM_BOOL_F;
0f2d19dd 4282 }
3c9a524f
DH
4283 else
4284 {
73e4de09 4285 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 4286 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 4287
3c9a524f
DH
4288 if (idx == len)
4289 return ureal;
4290
3f47e526 4291 c = scm_i_string_ref (mem, idx);
3c9a524f 4292 switch (c)
f872b822 4293 {
3c9a524f
DH
4294 case 'i': case 'I':
4295 /* either +<ureal>i or -<ureal>i */
4296
4297 idx++;
4298 if (sign == 0)
4299 return SCM_BOOL_F;
4300 if (idx != len)
4301 return SCM_BOOL_F;
cff5fa33 4302 return scm_make_rectangular (SCM_INUM0, ureal);
3c9a524f
DH
4303
4304 case '@':
4305 /* polar input: <real>@<real>. */
4306
4307 idx++;
4308 if (idx == len)
4309 return SCM_BOOL_F;
4310 else
f872b822 4311 {
3c9a524f
DH
4312 int sign;
4313 SCM angle;
4314 SCM result;
4315
3f47e526 4316 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4317 if (c == '+')
4318 {
4319 idx++;
ee0ddd21
AW
4320 if (idx == len)
4321 return SCM_BOOL_F;
3c9a524f
DH
4322 sign = 1;
4323 }
4324 else if (c == '-')
4325 {
4326 idx++;
ee0ddd21
AW
4327 if (idx == len)
4328 return SCM_BOOL_F;
3c9a524f
DH
4329 sign = -1;
4330 }
4331 else
4332 sign = 1;
4333
9d427b2c 4334 angle = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 4335 if (scm_is_false (angle))
3c9a524f
DH
4336 return SCM_BOOL_F;
4337 if (idx != len)
4338 return SCM_BOOL_F;
4339
73e4de09 4340 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
4341 angle = scm_difference (angle, SCM_UNDEFINED);
4342
4343 result = scm_make_polar (ureal, angle);
4344 return result;
f872b822 4345 }
3c9a524f
DH
4346 case '+':
4347 case '-':
4348 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 4349
3c9a524f
DH
4350 idx++;
4351 if (idx == len)
4352 return SCM_BOOL_F;
4353 else
4354 {
4355 int sign = (c == '+') ? 1 : -1;
9d427b2c 4356 SCM imag = mem2ureal (mem, &idx, radix, forced_x);
0f2d19dd 4357
73e4de09 4358 if (scm_is_false (imag))
d956fa6f 4359 imag = SCM_I_MAKINUM (sign);
23295dc3 4360 else if (sign == -1 && scm_is_false (scm_nan_p (imag)))
1fe5e088 4361 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 4362
3c9a524f
DH
4363 if (idx == len)
4364 return SCM_BOOL_F;
3f47e526
MG
4365 if (scm_i_string_ref (mem, idx) != 'i'
4366 && scm_i_string_ref (mem, idx) != 'I')
3c9a524f 4367 return SCM_BOOL_F;
0f2d19dd 4368
3c9a524f
DH
4369 idx++;
4370 if (idx != len)
4371 return SCM_BOOL_F;
0f2d19dd 4372
1fe5e088 4373 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
4374 }
4375 default:
4376 return SCM_BOOL_F;
4377 }
4378 }
0f2d19dd 4379}
0f2d19dd
JB
4380
4381
3c9a524f
DH
4382/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
4383
4384enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 4385
0f2d19dd 4386SCM
3f47e526 4387scm_i_string_to_number (SCM mem, unsigned int default_radix)
0f2d19dd 4388{
3c9a524f
DH
4389 unsigned int idx = 0;
4390 unsigned int radix = NO_RADIX;
4391 enum t_exactness forced_x = NO_EXACTNESS;
3f47e526 4392 size_t len = scm_i_string_length (mem);
3c9a524f
DH
4393
4394 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
3f47e526 4395 while (idx + 2 < len && scm_i_string_ref (mem, idx) == '#')
3c9a524f 4396 {
3f47e526 4397 switch (scm_i_string_ref (mem, idx + 1))
3c9a524f
DH
4398 {
4399 case 'b': case 'B':
4400 if (radix != NO_RADIX)
4401 return SCM_BOOL_F;
4402 radix = DUAL;
4403 break;
4404 case 'd': case 'D':
4405 if (radix != NO_RADIX)
4406 return SCM_BOOL_F;
4407 radix = DEC;
4408 break;
4409 case 'i': case 'I':
4410 if (forced_x != NO_EXACTNESS)
4411 return SCM_BOOL_F;
4412 forced_x = INEXACT;
4413 break;
4414 case 'e': case 'E':
4415 if (forced_x != NO_EXACTNESS)
4416 return SCM_BOOL_F;
4417 forced_x = EXACT;
4418 break;
4419 case 'o': case 'O':
4420 if (radix != NO_RADIX)
4421 return SCM_BOOL_F;
4422 radix = OCT;
4423 break;
4424 case 'x': case 'X':
4425 if (radix != NO_RADIX)
4426 return SCM_BOOL_F;
4427 radix = HEX;
4428 break;
4429 default:
f872b822 4430 return SCM_BOOL_F;
3c9a524f
DH
4431 }
4432 idx += 2;
4433 }
4434
4435 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
4436 if (radix == NO_RADIX)
9d427b2c 4437 radix = default_radix;
f872b822 4438
9d427b2c 4439 return mem2complex (mem, idx, radix, forced_x);
0f2d19dd
JB
4440}
4441
3f47e526
MG
4442SCM
4443scm_c_locale_stringn_to_number (const char* mem, size_t len,
4444 unsigned int default_radix)
4445{
4446 SCM str = scm_from_locale_stringn (mem, len);
4447
4448 return scm_i_string_to_number (str, default_radix);
4449}
4450
0f2d19dd 4451
a1ec6916 4452SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 4453 (SCM string, SCM radix),
1e6808ea 4454 "Return a number of the maximally precise representation\n"
942e5b91 4455 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
4456 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
4457 "is a default radix that may be overridden by an explicit radix\n"
4458 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
4459 "supplied, then the default radix is 10. If string is not a\n"
4460 "syntactically valid notation for a number, then\n"
4461 "@code{string->number} returns @code{#f}.")
1bbd0b84 4462#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
4463{
4464 SCM answer;
5efd3c7d 4465 unsigned int base;
a6d9e5ab 4466 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
4467
4468 if (SCM_UNBNDP (radix))
4469 base = 10;
4470 else
4471 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
4472
3f47e526 4473 answer = scm_i_string_to_number (string, base);
8824ac88
MV
4474 scm_remember_upto_here_1 (string);
4475 return answer;
0f2d19dd 4476}
1bbd0b84 4477#undef FUNC_NAME
3c9a524f
DH
4478
4479
0f2d19dd
JB
4480/*** END strs->nums ***/
4481
5986c47d 4482
8507ec80
MV
4483SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
4484 (SCM x),
4485 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
4486 "otherwise.")
4487#define FUNC_NAME s_scm_number_p
4488{
4489 return scm_from_bool (SCM_NUMBERP (x));
4490}
4491#undef FUNC_NAME
4492
4493SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 4494 (SCM x),
942e5b91 4495 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 4496 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
4497 "values form subsets of the set of complex numbers, i. e. the\n"
4498 "predicate will also be fulfilled if @var{x} is a real,\n"
4499 "rational or integer number.")
8507ec80 4500#define FUNC_NAME s_scm_complex_p
0f2d19dd 4501{
8507ec80
MV
4502 /* all numbers are complex. */
4503 return scm_number_p (x);
0f2d19dd 4504}
1bbd0b84 4505#undef FUNC_NAME
0f2d19dd 4506
f92e85f7
MV
4507SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
4508 (SCM x),
4509 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
4510 "otherwise. Note that the set of integer values forms a subset of\n"
4511 "the set of real numbers, i. e. the predicate will also be\n"
4512 "fulfilled if @var{x} is an integer number.")
4513#define FUNC_NAME s_scm_real_p
4514{
c960e556
MW
4515 return scm_from_bool
4516 (SCM_I_INUMP (x) || SCM_REALP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x));
f92e85f7
MV
4517}
4518#undef FUNC_NAME
4519
4520SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 4521 (SCM x),
942e5b91 4522 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 4523 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 4524 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
4525 "fulfilled if @var{x} is an integer number.")
4526#define FUNC_NAME s_scm_rational_p
0f2d19dd 4527{
c960e556 4528 if (SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x))
f92e85f7
MV
4529 return SCM_BOOL_T;
4530 else if (SCM_REALP (x))
c960e556
MW
4531 /* due to their limited precision, finite floating point numbers are
4532 rational as well. (finite means neither infinity nor a NaN) */
4533 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
0aacf84e 4534 else
bb628794 4535 return SCM_BOOL_F;
0f2d19dd 4536}
1bbd0b84 4537#undef FUNC_NAME
0f2d19dd 4538
a1ec6916 4539SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 4540 (SCM x),
942e5b91
MG
4541 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
4542 "else.")
1bbd0b84 4543#define FUNC_NAME s_scm_integer_p
0f2d19dd 4544{
c960e556 4545 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f872b822 4546 return SCM_BOOL_T;
c960e556
MW
4547 else if (SCM_REALP (x))
4548 {
4549 double val = SCM_REAL_VALUE (x);
4550 return scm_from_bool (!isinf (val) && (val == floor (val)));
4551 }
4552 else
8e43ed5d 4553 return SCM_BOOL_F;
0f2d19dd 4554}
1bbd0b84 4555#undef FUNC_NAME
0f2d19dd
JB
4556
4557
8a1f4f98
AW
4558SCM scm_i_num_eq_p (SCM, SCM, SCM);
4559SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
4560 (SCM x, SCM y, SCM rest),
4561 "Return @code{#t} if all parameters are numerically equal.")
4562#define FUNC_NAME s_scm_i_num_eq_p
4563{
4564 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4565 return SCM_BOOL_T;
4566 while (!scm_is_null (rest))
4567 {
4568 if (scm_is_false (scm_num_eq_p (x, y)))
4569 return SCM_BOOL_F;
4570 x = y;
4571 y = scm_car (rest);
4572 rest = scm_cdr (rest);
4573 }
4574 return scm_num_eq_p (x, y);
4575}
4576#undef FUNC_NAME
0f2d19dd 4577SCM
6e8d25a6 4578scm_num_eq_p (SCM x, SCM y)
0f2d19dd 4579{
d8b95e27 4580 again:
e11e83f3 4581 if (SCM_I_INUMP (x))
0aacf84e 4582 {
e25f3727 4583 scm_t_signed_bits xx = SCM_I_INUM (x);
e11e83f3 4584 if (SCM_I_INUMP (y))
0aacf84e 4585 {
e25f3727 4586 scm_t_signed_bits yy = SCM_I_INUM (y);
73e4de09 4587 return scm_from_bool (xx == yy);
0aacf84e
MD
4588 }
4589 else if (SCM_BIGP (y))
4590 return SCM_BOOL_F;
4591 else if (SCM_REALP (y))
e8c5b1f2
KR
4592 {
4593 /* On a 32-bit system an inum fits a double, we can cast the inum
4594 to a double and compare.
4595
4596 But on a 64-bit system an inum is bigger than a double and
4597 casting it to a double (call that dxx) will round. dxx is at
4598 worst 1 bigger or smaller than xx, so if dxx==yy we know yy is
4599 an integer and fits a long. So we cast yy to a long and
4600 compare with plain xx.
4601
4602 An alternative (for any size system actually) would be to check
4603 yy is an integer (with floor) and is in range of an inum
4604 (compare against appropriate powers of 2) then test
e25f3727
AW
4605 xx==(scm_t_signed_bits)yy. It's just a matter of which
4606 casts/comparisons might be fastest or easiest for the cpu. */
e8c5b1f2
KR
4607
4608 double yy = SCM_REAL_VALUE (y);
3a1b45fd
MV
4609 return scm_from_bool ((double) xx == yy
4610 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 4611 || xx == (scm_t_signed_bits) yy));
e8c5b1f2 4612 }
0aacf84e 4613 else if (SCM_COMPLEXP (y))
73e4de09 4614 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 4615 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
4616 else if (SCM_FRACTIONP (y))
4617 return SCM_BOOL_F;
0aacf84e 4618 else
8a1f4f98 4619 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 4620 }
0aacf84e
MD
4621 else if (SCM_BIGP (x))
4622 {
e11e83f3 4623 if (SCM_I_INUMP (y))
0aacf84e
MD
4624 return SCM_BOOL_F;
4625 else if (SCM_BIGP (y))
4626 {
4627 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
4628 scm_remember_upto_here_2 (x, y);
73e4de09 4629 return scm_from_bool (0 == cmp);
0aacf84e
MD
4630 }
4631 else if (SCM_REALP (y))
4632 {
4633 int cmp;
2e65b52f 4634 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
4635 return SCM_BOOL_F;
4636 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
4637 scm_remember_upto_here_1 (x);
73e4de09 4638 return scm_from_bool (0 == cmp);
0aacf84e
MD
4639 }
4640 else if (SCM_COMPLEXP (y))
4641 {
4642 int cmp;
4643 if (0.0 != SCM_COMPLEX_IMAG (y))
4644 return SCM_BOOL_F;
2e65b52f 4645 if (isnan (SCM_COMPLEX_REAL (y)))
0aacf84e
MD
4646 return SCM_BOOL_F;
4647 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
4648 scm_remember_upto_here_1 (x);
73e4de09 4649 return scm_from_bool (0 == cmp);
0aacf84e 4650 }
f92e85f7
MV
4651 else if (SCM_FRACTIONP (y))
4652 return SCM_BOOL_F;
0aacf84e 4653 else
8a1f4f98 4654 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 4655 }
0aacf84e
MD
4656 else if (SCM_REALP (x))
4657 {
e8c5b1f2 4658 double xx = SCM_REAL_VALUE (x);
e11e83f3 4659 if (SCM_I_INUMP (y))
e8c5b1f2
KR
4660 {
4661 /* see comments with inum/real above */
e25f3727 4662 scm_t_signed_bits yy = SCM_I_INUM (y);
3a1b45fd
MV
4663 return scm_from_bool (xx == (double) yy
4664 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 4665 || (scm_t_signed_bits) xx == yy));
e8c5b1f2 4666 }
0aacf84e
MD
4667 else if (SCM_BIGP (y))
4668 {
4669 int cmp;
2e65b52f 4670 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
4671 return SCM_BOOL_F;
4672 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
4673 scm_remember_upto_here_1 (y);
73e4de09 4674 return scm_from_bool (0 == cmp);
0aacf84e
MD
4675 }
4676 else if (SCM_REALP (y))
73e4de09 4677 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 4678 else if (SCM_COMPLEXP (y))
73e4de09 4679 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 4680 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 4681 else if (SCM_FRACTIONP (y))
d8b95e27
KR
4682 {
4683 double xx = SCM_REAL_VALUE (x);
2e65b52f 4684 if (isnan (xx))
d8b95e27 4685 return SCM_BOOL_F;
2e65b52f 4686 if (isinf (xx))
73e4de09 4687 return scm_from_bool (xx < 0.0);
d8b95e27
KR
4688 x = scm_inexact_to_exact (x); /* with x as frac or int */
4689 goto again;
4690 }
0aacf84e 4691 else
8a1f4f98 4692 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 4693 }
0aacf84e
MD
4694 else if (SCM_COMPLEXP (x))
4695 {
e11e83f3
MV
4696 if (SCM_I_INUMP (y))
4697 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
4698 && (SCM_COMPLEX_IMAG (x) == 0.0));
4699 else if (SCM_BIGP (y))
4700 {
4701 int cmp;
4702 if (0.0 != SCM_COMPLEX_IMAG (x))
4703 return SCM_BOOL_F;
2e65b52f 4704 if (isnan (SCM_COMPLEX_REAL (x)))
0aacf84e
MD
4705 return SCM_BOOL_F;
4706 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
4707 scm_remember_upto_here_1 (y);
73e4de09 4708 return scm_from_bool (0 == cmp);
0aacf84e
MD
4709 }
4710 else if (SCM_REALP (y))
73e4de09 4711 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
4712 && (SCM_COMPLEX_IMAG (x) == 0.0));
4713 else if (SCM_COMPLEXP (y))
73e4de09 4714 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 4715 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 4716 else if (SCM_FRACTIONP (y))
d8b95e27
KR
4717 {
4718 double xx;
4719 if (SCM_COMPLEX_IMAG (x) != 0.0)
4720 return SCM_BOOL_F;
4721 xx = SCM_COMPLEX_REAL (x);
2e65b52f 4722 if (isnan (xx))
d8b95e27 4723 return SCM_BOOL_F;
2e65b52f 4724 if (isinf (xx))
73e4de09 4725 return scm_from_bool (xx < 0.0);
d8b95e27
KR
4726 x = scm_inexact_to_exact (x); /* with x as frac or int */
4727 goto again;
4728 }
f92e85f7 4729 else
8a1f4f98 4730 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f92e85f7
MV
4731 }
4732 else if (SCM_FRACTIONP (x))
4733 {
e11e83f3 4734 if (SCM_I_INUMP (y))
f92e85f7
MV
4735 return SCM_BOOL_F;
4736 else if (SCM_BIGP (y))
4737 return SCM_BOOL_F;
4738 else if (SCM_REALP (y))
d8b95e27
KR
4739 {
4740 double yy = SCM_REAL_VALUE (y);
2e65b52f 4741 if (isnan (yy))
d8b95e27 4742 return SCM_BOOL_F;
2e65b52f 4743 if (isinf (yy))
73e4de09 4744 return scm_from_bool (0.0 < yy);
d8b95e27
KR
4745 y = scm_inexact_to_exact (y); /* with y as frac or int */
4746 goto again;
4747 }
f92e85f7 4748 else if (SCM_COMPLEXP (y))
d8b95e27
KR
4749 {
4750 double yy;
4751 if (SCM_COMPLEX_IMAG (y) != 0.0)
4752 return SCM_BOOL_F;
4753 yy = SCM_COMPLEX_REAL (y);
2e65b52f 4754 if (isnan (yy))
d8b95e27 4755 return SCM_BOOL_F;
2e65b52f 4756 if (isinf (yy))
73e4de09 4757 return scm_from_bool (0.0 < yy);
d8b95e27
KR
4758 y = scm_inexact_to_exact (y); /* with y as frac or int */
4759 goto again;
4760 }
f92e85f7
MV
4761 else if (SCM_FRACTIONP (y))
4762 return scm_i_fraction_equalp (x, y);
0aacf84e 4763 else
8a1f4f98 4764 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 4765 }
0aacf84e 4766 else
8a1f4f98 4767 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARG1, s_scm_i_num_eq_p);
0f2d19dd
JB
4768}
4769
4770
a5f0b599
KR
4771/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
4772 done are good for inums, but for bignums an answer can almost always be
4773 had by just examining a few high bits of the operands, as done by GMP in
4774 mpq_cmp. flonum/frac compares likewise, but with the slight complication
4775 of the float exponent to take into account. */
4776
8c93b597 4777SCM_INTERNAL SCM scm_i_num_less_p (SCM, SCM, SCM);
8a1f4f98
AW
4778SCM_PRIMITIVE_GENERIC (scm_i_num_less_p, "<", 0, 2, 1,
4779 (SCM x, SCM y, SCM rest),
4780 "Return @code{#t} if the list of parameters is monotonically\n"
4781 "increasing.")
4782#define FUNC_NAME s_scm_i_num_less_p
4783{
4784 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4785 return SCM_BOOL_T;
4786 while (!scm_is_null (rest))
4787 {
4788 if (scm_is_false (scm_less_p (x, y)))
4789 return SCM_BOOL_F;
4790 x = y;
4791 y = scm_car (rest);
4792 rest = scm_cdr (rest);
4793 }
4794 return scm_less_p (x, y);
4795}
4796#undef FUNC_NAME
0f2d19dd 4797SCM
6e8d25a6 4798scm_less_p (SCM x, SCM y)
0f2d19dd 4799{
a5f0b599 4800 again:
e11e83f3 4801 if (SCM_I_INUMP (x))
0aacf84e 4802 {
e25f3727 4803 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 4804 if (SCM_I_INUMP (y))
0aacf84e 4805 {
e25f3727 4806 scm_t_inum yy = SCM_I_INUM (y);
73e4de09 4807 return scm_from_bool (xx < yy);
0aacf84e
MD
4808 }
4809 else if (SCM_BIGP (y))
4810 {
4811 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
4812 scm_remember_upto_here_1 (y);
73e4de09 4813 return scm_from_bool (sgn > 0);
0aacf84e
MD
4814 }
4815 else if (SCM_REALP (y))
73e4de09 4816 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 4817 else if (SCM_FRACTIONP (y))
a5f0b599
KR
4818 {
4819 /* "x < a/b" becomes "x*b < a" */
4820 int_frac:
4821 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
4822 y = SCM_FRACTION_NUMERATOR (y);
4823 goto again;
4824 }
0aacf84e 4825 else
8a1f4f98 4826 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 4827 }
0aacf84e
MD
4828 else if (SCM_BIGP (x))
4829 {
e11e83f3 4830 if (SCM_I_INUMP (y))
0aacf84e
MD
4831 {
4832 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4833 scm_remember_upto_here_1 (x);
73e4de09 4834 return scm_from_bool (sgn < 0);
0aacf84e
MD
4835 }
4836 else if (SCM_BIGP (y))
4837 {
4838 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
4839 scm_remember_upto_here_2 (x, y);
73e4de09 4840 return scm_from_bool (cmp < 0);
0aacf84e
MD
4841 }
4842 else if (SCM_REALP (y))
4843 {
4844 int cmp;
2e65b52f 4845 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
4846 return SCM_BOOL_F;
4847 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
4848 scm_remember_upto_here_1 (x);
73e4de09 4849 return scm_from_bool (cmp < 0);
0aacf84e 4850 }
f92e85f7 4851 else if (SCM_FRACTIONP (y))
a5f0b599 4852 goto int_frac;
0aacf84e 4853 else
8a1f4f98 4854 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f4c627b3 4855 }
0aacf84e
MD
4856 else if (SCM_REALP (x))
4857 {
e11e83f3
MV
4858 if (SCM_I_INUMP (y))
4859 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
4860 else if (SCM_BIGP (y))
4861 {
4862 int cmp;
2e65b52f 4863 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
4864 return SCM_BOOL_F;
4865 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
4866 scm_remember_upto_here_1 (y);
73e4de09 4867 return scm_from_bool (cmp > 0);
0aacf84e
MD
4868 }
4869 else if (SCM_REALP (y))
73e4de09 4870 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 4871 else if (SCM_FRACTIONP (y))
a5f0b599
KR
4872 {
4873 double xx = SCM_REAL_VALUE (x);
2e65b52f 4874 if (isnan (xx))
a5f0b599 4875 return SCM_BOOL_F;
2e65b52f 4876 if (isinf (xx))
73e4de09 4877 return scm_from_bool (xx < 0.0);
a5f0b599
KR
4878 x = scm_inexact_to_exact (x); /* with x as frac or int */
4879 goto again;
4880 }
f92e85f7 4881 else
8a1f4f98 4882 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f92e85f7
MV
4883 }
4884 else if (SCM_FRACTIONP (x))
4885 {
e11e83f3 4886 if (SCM_I_INUMP (y) || SCM_BIGP (y))
a5f0b599
KR
4887 {
4888 /* "a/b < y" becomes "a < y*b" */
4889 y = scm_product (y, SCM_FRACTION_DENOMINATOR (x));
4890 x = SCM_FRACTION_NUMERATOR (x);
4891 goto again;
4892 }
f92e85f7 4893 else if (SCM_REALP (y))
a5f0b599
KR
4894 {
4895 double yy = SCM_REAL_VALUE (y);
2e65b52f 4896 if (isnan (yy))
a5f0b599 4897 return SCM_BOOL_F;
2e65b52f 4898 if (isinf (yy))
73e4de09 4899 return scm_from_bool (0.0 < yy);
a5f0b599
KR
4900 y = scm_inexact_to_exact (y); /* with y as frac or int */
4901 goto again;
4902 }
f92e85f7 4903 else if (SCM_FRACTIONP (y))
a5f0b599
KR
4904 {
4905 /* "a/b < c/d" becomes "a*d < c*b" */
4906 SCM new_x = scm_product (SCM_FRACTION_NUMERATOR (x),
4907 SCM_FRACTION_DENOMINATOR (y));
4908 SCM new_y = scm_product (SCM_FRACTION_NUMERATOR (y),
4909 SCM_FRACTION_DENOMINATOR (x));
4910 x = new_x;
4911 y = new_y;
4912 goto again;
4913 }
0aacf84e 4914 else
8a1f4f98 4915 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 4916 }
0aacf84e 4917 else
8a1f4f98 4918 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARG1, s_scm_i_num_less_p);
0f2d19dd
JB
4919}
4920
4921
8a1f4f98
AW
4922SCM scm_i_num_gr_p (SCM, SCM, SCM);
4923SCM_PRIMITIVE_GENERIC (scm_i_num_gr_p, ">", 0, 2, 1,
4924 (SCM x, SCM y, SCM rest),
4925 "Return @code{#t} if the list of parameters is monotonically\n"
4926 "decreasing.")
4927#define FUNC_NAME s_scm_i_num_gr_p
4928{
4929 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4930 return SCM_BOOL_T;
4931 while (!scm_is_null (rest))
4932 {
4933 if (scm_is_false (scm_gr_p (x, y)))
4934 return SCM_BOOL_F;
4935 x = y;
4936 y = scm_car (rest);
4937 rest = scm_cdr (rest);
4938 }
4939 return scm_gr_p (x, y);
4940}
4941#undef FUNC_NAME
4942#define FUNC_NAME s_scm_i_num_gr_p
c76b1eaf
MD
4943SCM
4944scm_gr_p (SCM x, SCM y)
0f2d19dd 4945{
c76b1eaf 4946 if (!SCM_NUMBERP (x))
8a1f4f98 4947 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 4948 else if (!SCM_NUMBERP (y))
8a1f4f98 4949 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG2, FUNC_NAME);
c76b1eaf
MD
4950 else
4951 return scm_less_p (y, x);
0f2d19dd 4952}
1bbd0b84 4953#undef FUNC_NAME
0f2d19dd
JB
4954
4955
8a1f4f98
AW
4956SCM scm_i_num_leq_p (SCM, SCM, SCM);
4957SCM_PRIMITIVE_GENERIC (scm_i_num_leq_p, "<=", 0, 2, 1,
4958 (SCM x, SCM y, SCM rest),
4959 "Return @code{#t} if the list of parameters is monotonically\n"
4960 "non-decreasing.")
4961#define FUNC_NAME s_scm_i_num_leq_p
4962{
4963 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4964 return SCM_BOOL_T;
4965 while (!scm_is_null (rest))
4966 {
4967 if (scm_is_false (scm_leq_p (x, y)))
4968 return SCM_BOOL_F;
4969 x = y;
4970 y = scm_car (rest);
4971 rest = scm_cdr (rest);
4972 }
4973 return scm_leq_p (x, y);
4974}
4975#undef FUNC_NAME
4976#define FUNC_NAME s_scm_i_num_leq_p
c76b1eaf
MD
4977SCM
4978scm_leq_p (SCM x, SCM y)
0f2d19dd 4979{
c76b1eaf 4980 if (!SCM_NUMBERP (x))
8a1f4f98 4981 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 4982 else if (!SCM_NUMBERP (y))
8a1f4f98 4983 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 4984 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 4985 return SCM_BOOL_F;
c76b1eaf 4986 else
73e4de09 4987 return scm_not (scm_less_p (y, x));
0f2d19dd 4988}
1bbd0b84 4989#undef FUNC_NAME
0f2d19dd
JB
4990
4991
8a1f4f98
AW
4992SCM scm_i_num_geq_p (SCM, SCM, SCM);
4993SCM_PRIMITIVE_GENERIC (scm_i_num_geq_p, ">=", 0, 2, 1,
4994 (SCM x, SCM y, SCM rest),
4995 "Return @code{#t} if the list of parameters is monotonically\n"
4996 "non-increasing.")
4997#define FUNC_NAME s_scm_i_num_geq_p
4998{
4999 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
5000 return SCM_BOOL_T;
5001 while (!scm_is_null (rest))
5002 {
5003 if (scm_is_false (scm_geq_p (x, y)))
5004 return SCM_BOOL_F;
5005 x = y;
5006 y = scm_car (rest);
5007 rest = scm_cdr (rest);
5008 }
5009 return scm_geq_p (x, y);
5010}
5011#undef FUNC_NAME
5012#define FUNC_NAME s_scm_i_num_geq_p
c76b1eaf
MD
5013SCM
5014scm_geq_p (SCM x, SCM y)
0f2d19dd 5015{
c76b1eaf 5016 if (!SCM_NUMBERP (x))
8a1f4f98 5017 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 5018 else if (!SCM_NUMBERP (y))
8a1f4f98 5019 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 5020 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 5021 return SCM_BOOL_F;
c76b1eaf 5022 else
73e4de09 5023 return scm_not (scm_less_p (x, y));
0f2d19dd 5024}
1bbd0b84 5025#undef FUNC_NAME
0f2d19dd
JB
5026
5027
2519490c
MW
5028SCM_PRIMITIVE_GENERIC (scm_zero_p, "zero?", 1, 0, 0,
5029 (SCM z),
5030 "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
5031 "zero.")
5032#define FUNC_NAME s_scm_zero_p
0f2d19dd 5033{
e11e83f3 5034 if (SCM_I_INUMP (z))
bc36d050 5035 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 5036 else if (SCM_BIGP (z))
c2ff8ab0 5037 return SCM_BOOL_F;
0aacf84e 5038 else if (SCM_REALP (z))
73e4de09 5039 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 5040 else if (SCM_COMPLEXP (z))
73e4de09 5041 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 5042 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
5043 else if (SCM_FRACTIONP (z))
5044 return SCM_BOOL_F;
0aacf84e 5045 else
2519490c 5046 SCM_WTA_DISPATCH_1 (g_scm_zero_p, z, SCM_ARG1, s_scm_zero_p);
0f2d19dd 5047}
2519490c 5048#undef FUNC_NAME
0f2d19dd
JB
5049
5050
2519490c
MW
5051SCM_PRIMITIVE_GENERIC (scm_positive_p, "positive?", 1, 0, 0,
5052 (SCM x),
5053 "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
5054 "zero.")
5055#define FUNC_NAME s_scm_positive_p
0f2d19dd 5056{
e11e83f3
MV
5057 if (SCM_I_INUMP (x))
5058 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
5059 else if (SCM_BIGP (x))
5060 {
5061 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5062 scm_remember_upto_here_1 (x);
73e4de09 5063 return scm_from_bool (sgn > 0);
0aacf84e
MD
5064 }
5065 else if (SCM_REALP (x))
73e4de09 5066 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
5067 else if (SCM_FRACTIONP (x))
5068 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 5069 else
2519490c 5070 SCM_WTA_DISPATCH_1 (g_scm_positive_p, x, SCM_ARG1, s_scm_positive_p);
0f2d19dd 5071}
2519490c 5072#undef FUNC_NAME
0f2d19dd
JB
5073
5074
2519490c
MW
5075SCM_PRIMITIVE_GENERIC (scm_negative_p, "negative?", 1, 0, 0,
5076 (SCM x),
5077 "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
5078 "zero.")
5079#define FUNC_NAME s_scm_negative_p
0f2d19dd 5080{
e11e83f3
MV
5081 if (SCM_I_INUMP (x))
5082 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
5083 else if (SCM_BIGP (x))
5084 {
5085 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5086 scm_remember_upto_here_1 (x);
73e4de09 5087 return scm_from_bool (sgn < 0);
0aacf84e
MD
5088 }
5089 else if (SCM_REALP (x))
73e4de09 5090 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
5091 else if (SCM_FRACTIONP (x))
5092 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 5093 else
2519490c 5094 SCM_WTA_DISPATCH_1 (g_scm_negative_p, x, SCM_ARG1, s_scm_negative_p);
0f2d19dd 5095}
2519490c 5096#undef FUNC_NAME
0f2d19dd
JB
5097
5098
2a06f791
KR
5099/* scm_min and scm_max return an inexact when either argument is inexact, as
5100 required by r5rs. On that basis, for exact/inexact combinations the
5101 exact is converted to inexact to compare and possibly return. This is
5102 unlike scm_less_p above which takes some trouble to preserve all bits in
5103 its test, such trouble is not required for min and max. */
5104
78d3deb1
AW
5105SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
5106 (SCM x, SCM y, SCM rest),
5107 "Return the maximum of all parameter values.")
5108#define FUNC_NAME s_scm_i_max
5109{
5110 while (!scm_is_null (rest))
5111 { x = scm_max (x, y);
5112 y = scm_car (rest);
5113 rest = scm_cdr (rest);
5114 }
5115 return scm_max (x, y);
5116}
5117#undef FUNC_NAME
5118
5119#define s_max s_scm_i_max
5120#define g_max g_scm_i_max
5121
0f2d19dd 5122SCM
6e8d25a6 5123scm_max (SCM x, SCM y)
0f2d19dd 5124{
0aacf84e
MD
5125 if (SCM_UNBNDP (y))
5126 {
5127 if (SCM_UNBNDP (x))
5128 SCM_WTA_DISPATCH_0 (g_max, s_max);
e11e83f3 5129 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
5130 return x;
5131 else
5132 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 5133 }
f4c627b3 5134
e11e83f3 5135 if (SCM_I_INUMP (x))
0aacf84e 5136 {
e25f3727 5137 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 5138 if (SCM_I_INUMP (y))
0aacf84e 5139 {
e25f3727 5140 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
5141 return (xx < yy) ? y : x;
5142 }
5143 else if (SCM_BIGP (y))
5144 {
5145 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
5146 scm_remember_upto_here_1 (y);
5147 return (sgn < 0) ? x : y;
5148 }
5149 else if (SCM_REALP (y))
5150 {
2e274311
MW
5151 double xxd = xx;
5152 double yyd = SCM_REAL_VALUE (y);
5153
5154 if (xxd > yyd)
5155 return scm_from_double (xxd);
5156 /* If y is a NaN, then "==" is false and we return the NaN */
5157 else if (SCM_LIKELY (!(xxd == yyd)))
5158 return y;
5159 /* Handle signed zeroes properly */
5160 else if (xx == 0)
5161 return flo0;
5162 else
5163 return y;
0aacf84e 5164 }
f92e85f7
MV
5165 else if (SCM_FRACTIONP (y))
5166 {
e4bc5d6c 5167 use_less:
73e4de09 5168 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 5169 }
0aacf84e
MD
5170 else
5171 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 5172 }
0aacf84e
MD
5173 else if (SCM_BIGP (x))
5174 {
e11e83f3 5175 if (SCM_I_INUMP (y))
0aacf84e
MD
5176 {
5177 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5178 scm_remember_upto_here_1 (x);
5179 return (sgn < 0) ? y : x;
5180 }
5181 else if (SCM_BIGP (y))
5182 {
5183 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
5184 scm_remember_upto_here_2 (x, y);
5185 return (cmp > 0) ? x : y;
5186 }
5187 else if (SCM_REALP (y))
5188 {
2a06f791
KR
5189 /* if y==NaN then xx>yy is false, so we return the NaN y */
5190 double xx, yy;
5191 big_real:
5192 xx = scm_i_big2dbl (x);
5193 yy = SCM_REAL_VALUE (y);
55f26379 5194 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 5195 }
f92e85f7
MV
5196 else if (SCM_FRACTIONP (y))
5197 {
e4bc5d6c 5198 goto use_less;
f92e85f7 5199 }
0aacf84e
MD
5200 else
5201 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 5202 }
0aacf84e
MD
5203 else if (SCM_REALP (x))
5204 {
e11e83f3 5205 if (SCM_I_INUMP (y))
0aacf84e 5206 {
2e274311
MW
5207 scm_t_inum yy = SCM_I_INUM (y);
5208 double xxd = SCM_REAL_VALUE (x);
5209 double yyd = yy;
5210
5211 if (yyd > xxd)
5212 return scm_from_double (yyd);
5213 /* If x is a NaN, then "==" is false and we return the NaN */
5214 else if (SCM_LIKELY (!(xxd == yyd)))
5215 return x;
5216 /* Handle signed zeroes properly */
5217 else if (yy == 0)
5218 return flo0;
5219 else
5220 return x;
0aacf84e
MD
5221 }
5222 else if (SCM_BIGP (y))
5223 {
b6f8f763 5224 SCM_SWAP (x, y);
2a06f791 5225 goto big_real;
0aacf84e
MD
5226 }
5227 else if (SCM_REALP (y))
5228 {
0aacf84e 5229 double xx = SCM_REAL_VALUE (x);
2e274311
MW
5230 double yy = SCM_REAL_VALUE (y);
5231
5232 /* For purposes of max: +inf.0 > nan > everything else, per R6RS */
5233 if (xx > yy)
5234 return x;
5235 else if (SCM_LIKELY (xx < yy))
5236 return y;
5237 /* If neither (xx > yy) nor (xx < yy), then
5238 either they're equal or one is a NaN */
5239 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 5240 return DOUBLE_IS_POSITIVE_INFINITY (yy) ? y : x;
2e274311 5241 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 5242 return DOUBLE_IS_POSITIVE_INFINITY (xx) ? x : y;
2e274311
MW
5243 /* xx == yy, but handle signed zeroes properly */
5244 else if (double_is_non_negative_zero (yy))
5245 return y;
5246 else
5247 return x;
0aacf84e 5248 }
f92e85f7
MV
5249 else if (SCM_FRACTIONP (y))
5250 {
5251 double yy = scm_i_fraction2double (y);
5252 double xx = SCM_REAL_VALUE (x);
55f26379 5253 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
5254 }
5255 else
5256 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
5257 }
5258 else if (SCM_FRACTIONP (x))
5259 {
e11e83f3 5260 if (SCM_I_INUMP (y))
f92e85f7 5261 {
e4bc5d6c 5262 goto use_less;
f92e85f7
MV
5263 }
5264 else if (SCM_BIGP (y))
5265 {
e4bc5d6c 5266 goto use_less;
f92e85f7
MV
5267 }
5268 else if (SCM_REALP (y))
5269 {
5270 double xx = scm_i_fraction2double (x);
2e274311
MW
5271 /* if y==NaN then ">" is false, so we return the NaN y */
5272 return (xx > SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
5273 }
5274 else if (SCM_FRACTIONP (y))
5275 {
e4bc5d6c 5276 goto use_less;
f92e85f7 5277 }
0aacf84e
MD
5278 else
5279 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 5280 }
0aacf84e 5281 else
f4c627b3 5282 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
5283}
5284
5285
78d3deb1
AW
5286SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
5287 (SCM x, SCM y, SCM rest),
5288 "Return the minimum of all parameter values.")
5289#define FUNC_NAME s_scm_i_min
5290{
5291 while (!scm_is_null (rest))
5292 { x = scm_min (x, y);
5293 y = scm_car (rest);
5294 rest = scm_cdr (rest);
5295 }
5296 return scm_min (x, y);
5297}
5298#undef FUNC_NAME
5299
5300#define s_min s_scm_i_min
5301#define g_min g_scm_i_min
5302
0f2d19dd 5303SCM
6e8d25a6 5304scm_min (SCM x, SCM y)
0f2d19dd 5305{
0aacf84e
MD
5306 if (SCM_UNBNDP (y))
5307 {
5308 if (SCM_UNBNDP (x))
5309 SCM_WTA_DISPATCH_0 (g_min, s_min);
e11e83f3 5310 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
5311 return x;
5312 else
5313 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 5314 }
f4c627b3 5315
e11e83f3 5316 if (SCM_I_INUMP (x))
0aacf84e 5317 {
e25f3727 5318 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 5319 if (SCM_I_INUMP (y))
0aacf84e 5320 {
e25f3727 5321 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
5322 return (xx < yy) ? x : y;
5323 }
5324 else if (SCM_BIGP (y))
5325 {
5326 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
5327 scm_remember_upto_here_1 (y);
5328 return (sgn < 0) ? y : x;
5329 }
5330 else if (SCM_REALP (y))
5331 {
5332 double z = xx;
5333 /* if y==NaN then "<" is false and we return NaN */
55f26379 5334 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 5335 }
f92e85f7
MV
5336 else if (SCM_FRACTIONP (y))
5337 {
e4bc5d6c 5338 use_less:
73e4de09 5339 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 5340 }
0aacf84e
MD
5341 else
5342 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 5343 }
0aacf84e
MD
5344 else if (SCM_BIGP (x))
5345 {
e11e83f3 5346 if (SCM_I_INUMP (y))
0aacf84e
MD
5347 {
5348 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5349 scm_remember_upto_here_1 (x);
5350 return (sgn < 0) ? x : y;
5351 }
5352 else if (SCM_BIGP (y))
5353 {
5354 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
5355 scm_remember_upto_here_2 (x, y);
5356 return (cmp > 0) ? y : x;
5357 }
5358 else if (SCM_REALP (y))
5359 {
2a06f791
KR
5360 /* if y==NaN then xx<yy is false, so we return the NaN y */
5361 double xx, yy;
5362 big_real:
5363 xx = scm_i_big2dbl (x);
5364 yy = SCM_REAL_VALUE (y);
55f26379 5365 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 5366 }
f92e85f7
MV
5367 else if (SCM_FRACTIONP (y))
5368 {
e4bc5d6c 5369 goto use_less;
f92e85f7 5370 }
0aacf84e
MD
5371 else
5372 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 5373 }
0aacf84e
MD
5374 else if (SCM_REALP (x))
5375 {
e11e83f3 5376 if (SCM_I_INUMP (y))
0aacf84e 5377 {
e11e83f3 5378 double z = SCM_I_INUM (y);
0aacf84e 5379 /* if x==NaN then "<" is false and we return NaN */
55f26379 5380 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
5381 }
5382 else if (SCM_BIGP (y))
5383 {
b6f8f763 5384 SCM_SWAP (x, y);
2a06f791 5385 goto big_real;
0aacf84e
MD
5386 }
5387 else if (SCM_REALP (y))
5388 {
0aacf84e 5389 double xx = SCM_REAL_VALUE (x);
2e274311
MW
5390 double yy = SCM_REAL_VALUE (y);
5391
5392 /* For purposes of min: -inf.0 < nan < everything else, per R6RS */
5393 if (xx < yy)
5394 return x;
5395 else if (SCM_LIKELY (xx > yy))
5396 return y;
5397 /* If neither (xx < yy) nor (xx > yy), then
5398 either they're equal or one is a NaN */
5399 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 5400 return DOUBLE_IS_NEGATIVE_INFINITY (yy) ? y : x;
2e274311 5401 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 5402 return DOUBLE_IS_NEGATIVE_INFINITY (xx) ? x : y;
2e274311
MW
5403 /* xx == yy, but handle signed zeroes properly */
5404 else if (double_is_non_negative_zero (xx))
5405 return y;
5406 else
5407 return x;
0aacf84e 5408 }
f92e85f7
MV
5409 else if (SCM_FRACTIONP (y))
5410 {
5411 double yy = scm_i_fraction2double (y);
5412 double xx = SCM_REAL_VALUE (x);
55f26379 5413 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 5414 }
0aacf84e
MD
5415 else
5416 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 5417 }
f92e85f7
MV
5418 else if (SCM_FRACTIONP (x))
5419 {
e11e83f3 5420 if (SCM_I_INUMP (y))
f92e85f7 5421 {
e4bc5d6c 5422 goto use_less;
f92e85f7
MV
5423 }
5424 else if (SCM_BIGP (y))
5425 {
e4bc5d6c 5426 goto use_less;
f92e85f7
MV
5427 }
5428 else if (SCM_REALP (y))
5429 {
5430 double xx = scm_i_fraction2double (x);
2e274311
MW
5431 /* if y==NaN then "<" is false, so we return the NaN y */
5432 return (xx < SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
5433 }
5434 else if (SCM_FRACTIONP (y))
5435 {
e4bc5d6c 5436 goto use_less;
f92e85f7
MV
5437 }
5438 else
78d3deb1 5439 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f92e85f7 5440 }
0aacf84e 5441 else
f4c627b3 5442 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
5443}
5444
5445
8ccd24f7
AW
5446SCM_PRIMITIVE_GENERIC (scm_i_sum, "+", 0, 2, 1,
5447 (SCM x, SCM y, SCM rest),
5448 "Return the sum of all parameter values. Return 0 if called without\n"
5449 "any parameters." )
5450#define FUNC_NAME s_scm_i_sum
5451{
5452 while (!scm_is_null (rest))
5453 { x = scm_sum (x, y);
5454 y = scm_car (rest);
5455 rest = scm_cdr (rest);
5456 }
5457 return scm_sum (x, y);
5458}
5459#undef FUNC_NAME
5460
5461#define s_sum s_scm_i_sum
5462#define g_sum g_scm_i_sum
5463
0f2d19dd 5464SCM
6e8d25a6 5465scm_sum (SCM x, SCM y)
0f2d19dd 5466{
9cc37597 5467 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
5468 {
5469 if (SCM_NUMBERP (x)) return x;
5470 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 5471 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 5472 }
c209c88e 5473
9cc37597 5474 if (SCM_LIKELY (SCM_I_INUMP (x)))
ca46fb90 5475 {
9cc37597 5476 if (SCM_LIKELY (SCM_I_INUMP (y)))
ca46fb90 5477 {
e25f3727
AW
5478 scm_t_inum xx = SCM_I_INUM (x);
5479 scm_t_inum yy = SCM_I_INUM (y);
5480 scm_t_inum z = xx + yy;
5481 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_inum2big (z);
ca46fb90
RB
5482 }
5483 else if (SCM_BIGP (y))
5484 {
5485 SCM_SWAP (x, y);
5486 goto add_big_inum;
5487 }
5488 else if (SCM_REALP (y))
5489 {
e25f3727 5490 scm_t_inum xx = SCM_I_INUM (x);
55f26379 5491 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
5492 }
5493 else if (SCM_COMPLEXP (y))
5494 {
e25f3727 5495 scm_t_inum xx = SCM_I_INUM (x);
8507ec80 5496 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
5497 SCM_COMPLEX_IMAG (y));
5498 }
f92e85f7 5499 else if (SCM_FRACTIONP (y))
cba42c93 5500 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
5501 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
5502 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
5503 else
5504 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
5505 } else if (SCM_BIGP (x))
5506 {
e11e83f3 5507 if (SCM_I_INUMP (y))
0aacf84e 5508 {
e25f3727 5509 scm_t_inum inum;
0aacf84e
MD
5510 int bigsgn;
5511 add_big_inum:
e11e83f3 5512 inum = SCM_I_INUM (y);
0aacf84e
MD
5513 if (inum == 0)
5514 return x;
5515 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5516 if (inum < 0)
5517 {
5518 SCM result = scm_i_mkbig ();
5519 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
5520 scm_remember_upto_here_1 (x);
5521 /* we know the result will have to be a bignum */
5522 if (bigsgn == -1)
5523 return result;
5524 return scm_i_normbig (result);
5525 }
5526 else
5527 {
5528 SCM result = scm_i_mkbig ();
5529 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
5530 scm_remember_upto_here_1 (x);
5531 /* we know the result will have to be a bignum */
5532 if (bigsgn == 1)
5533 return result;
5534 return scm_i_normbig (result);
5535 }
5536 }
5537 else if (SCM_BIGP (y))
5538 {
5539 SCM result = scm_i_mkbig ();
5540 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
5541 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
5542 mpz_add (SCM_I_BIG_MPZ (result),
5543 SCM_I_BIG_MPZ (x),
5544 SCM_I_BIG_MPZ (y));
5545 scm_remember_upto_here_2 (x, y);
5546 /* we know the result will have to be a bignum */
5547 if (sgn_x == sgn_y)
5548 return result;
5549 return scm_i_normbig (result);
5550 }
5551 else if (SCM_REALP (y))
5552 {
5553 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
5554 scm_remember_upto_here_1 (x);
55f26379 5555 return scm_from_double (result);
0aacf84e
MD
5556 }
5557 else if (SCM_COMPLEXP (y))
5558 {
5559 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
5560 + SCM_COMPLEX_REAL (y));
5561 scm_remember_upto_here_1 (x);
8507ec80 5562 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 5563 }
f92e85f7 5564 else if (SCM_FRACTIONP (y))
cba42c93 5565 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
5566 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
5567 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
5568 else
5569 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 5570 }
0aacf84e
MD
5571 else if (SCM_REALP (x))
5572 {
e11e83f3 5573 if (SCM_I_INUMP (y))
55f26379 5574 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
5575 else if (SCM_BIGP (y))
5576 {
5577 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
5578 scm_remember_upto_here_1 (y);
55f26379 5579 return scm_from_double (result);
0aacf84e
MD
5580 }
5581 else if (SCM_REALP (y))
55f26379 5582 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 5583 else if (SCM_COMPLEXP (y))
8507ec80 5584 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 5585 SCM_COMPLEX_IMAG (y));
f92e85f7 5586 else if (SCM_FRACTIONP (y))
55f26379 5587 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
5588 else
5589 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 5590 }
0aacf84e
MD
5591 else if (SCM_COMPLEXP (x))
5592 {
e11e83f3 5593 if (SCM_I_INUMP (y))
8507ec80 5594 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
5595 SCM_COMPLEX_IMAG (x));
5596 else if (SCM_BIGP (y))
5597 {
5598 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
5599 + SCM_COMPLEX_REAL (x));
5600 scm_remember_upto_here_1 (y);
8507ec80 5601 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
5602 }
5603 else if (SCM_REALP (y))
8507ec80 5604 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
5605 SCM_COMPLEX_IMAG (x));
5606 else if (SCM_COMPLEXP (y))
8507ec80 5607 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 5608 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 5609 else if (SCM_FRACTIONP (y))
8507ec80 5610 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
5611 SCM_COMPLEX_IMAG (x));
5612 else
5613 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
5614 }
5615 else if (SCM_FRACTIONP (x))
5616 {
e11e83f3 5617 if (SCM_I_INUMP (y))
cba42c93 5618 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5619 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
5620 SCM_FRACTION_DENOMINATOR (x));
5621 else if (SCM_BIGP (y))
cba42c93 5622 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5623 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
5624 SCM_FRACTION_DENOMINATOR (x));
5625 else if (SCM_REALP (y))
55f26379 5626 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 5627 else if (SCM_COMPLEXP (y))
8507ec80 5628 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
5629 SCM_COMPLEX_IMAG (y));
5630 else if (SCM_FRACTIONP (y))
5631 /* a/b + c/d = (ad + bc) / bd */
cba42c93 5632 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5633 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
5634 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
5635 else
5636 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 5637 }
0aacf84e 5638 else
98cb6e75 5639 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
5640}
5641
5642
40882e3d
KR
5643SCM_DEFINE (scm_oneplus, "1+", 1, 0, 0,
5644 (SCM x),
5645 "Return @math{@var{x}+1}.")
5646#define FUNC_NAME s_scm_oneplus
5647{
cff5fa33 5648 return scm_sum (x, SCM_INUM1);
40882e3d
KR
5649}
5650#undef FUNC_NAME
5651
5652
78d3deb1
AW
5653SCM_PRIMITIVE_GENERIC (scm_i_difference, "-", 0, 2, 1,
5654 (SCM x, SCM y, SCM rest),
5655 "If called with one argument @var{z1}, -@var{z1} returned. Otherwise\n"
5656 "the sum of all but the first argument are subtracted from the first\n"
5657 "argument.")
5658#define FUNC_NAME s_scm_i_difference
5659{
5660 while (!scm_is_null (rest))
5661 { x = scm_difference (x, y);
5662 y = scm_car (rest);
5663 rest = scm_cdr (rest);
5664 }
5665 return scm_difference (x, y);
5666}
5667#undef FUNC_NAME
5668
5669#define s_difference s_scm_i_difference
5670#define g_difference g_scm_i_difference
5671
0f2d19dd 5672SCM
6e8d25a6 5673scm_difference (SCM x, SCM y)
78d3deb1 5674#define FUNC_NAME s_difference
0f2d19dd 5675{
9cc37597 5676 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
5677 {
5678 if (SCM_UNBNDP (x))
5679 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
5680 else
e11e83f3 5681 if (SCM_I_INUMP (x))
ca46fb90 5682 {
e25f3727 5683 scm_t_inum xx = -SCM_I_INUM (x);
ca46fb90 5684 if (SCM_FIXABLE (xx))
d956fa6f 5685 return SCM_I_MAKINUM (xx);
ca46fb90 5686 else
e25f3727 5687 return scm_i_inum2big (xx);
ca46fb90
RB
5688 }
5689 else if (SCM_BIGP (x))
a9ad4847
KR
5690 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
5691 bignum, but negating that gives a fixnum. */
ca46fb90
RB
5692 return scm_i_normbig (scm_i_clonebig (x, 0));
5693 else if (SCM_REALP (x))
55f26379 5694 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 5695 else if (SCM_COMPLEXP (x))
8507ec80 5696 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 5697 -SCM_COMPLEX_IMAG (x));
f92e85f7 5698 else if (SCM_FRACTIONP (x))
cba42c93 5699 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 5700 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
5701 else
5702 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 5703 }
ca46fb90 5704
9cc37597 5705 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 5706 {
9cc37597 5707 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 5708 {
e25f3727
AW
5709 scm_t_inum xx = SCM_I_INUM (x);
5710 scm_t_inum yy = SCM_I_INUM (y);
5711 scm_t_inum z = xx - yy;
0aacf84e 5712 if (SCM_FIXABLE (z))
d956fa6f 5713 return SCM_I_MAKINUM (z);
0aacf84e 5714 else
e25f3727 5715 return scm_i_inum2big (z);
0aacf84e
MD
5716 }
5717 else if (SCM_BIGP (y))
5718 {
5719 /* inum-x - big-y */
e25f3727 5720 scm_t_inum xx = SCM_I_INUM (x);
ca46fb90 5721
0aacf84e 5722 if (xx == 0)
b5c40589
MW
5723 {
5724 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
5725 bignum, but negating that gives a fixnum. */
5726 return scm_i_normbig (scm_i_clonebig (y, 0));
5727 }
0aacf84e
MD
5728 else
5729 {
5730 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
5731 SCM result = scm_i_mkbig ();
ca46fb90 5732
0aacf84e
MD
5733 if (xx >= 0)
5734 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
5735 else
5736 {
5737 /* x - y == -(y + -x) */
5738 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
5739 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
5740 }
5741 scm_remember_upto_here_1 (y);
ca46fb90 5742
0aacf84e
MD
5743 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
5744 /* we know the result will have to be a bignum */
5745 return result;
5746 else
5747 return scm_i_normbig (result);
5748 }
5749 }
5750 else if (SCM_REALP (y))
5751 {
e25f3727 5752 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
5753
5754 /*
5755 * We need to handle x == exact 0
5756 * specially because R6RS states that:
5757 * (- 0.0) ==> -0.0 and
5758 * (- 0.0 0.0) ==> 0.0
5759 * and the scheme compiler changes
5760 * (- 0.0) into (- 0 0.0)
5761 * So we need to treat (- 0 0.0) like (- 0.0).
5762 * At the C level, (-x) is different than (0.0 - x).
5763 * (0.0 - 0.0) ==> 0.0, but (- 0.0) ==> -0.0.
5764 */
5765 if (xx == 0)
5766 return scm_from_double (- SCM_REAL_VALUE (y));
5767 else
5768 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
5769 }
5770 else if (SCM_COMPLEXP (y))
5771 {
e25f3727 5772 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
5773
5774 /* We need to handle x == exact 0 specially.
5775 See the comment above (for SCM_REALP (y)) */
5776 if (xx == 0)
5777 return scm_c_make_rectangular (- SCM_COMPLEX_REAL (y),
5778 - SCM_COMPLEX_IMAG (y));
5779 else
5780 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
5781 - SCM_COMPLEX_IMAG (y));
0aacf84e 5782 }
f92e85f7
MV
5783 else if (SCM_FRACTIONP (y))
5784 /* a - b/c = (ac - b) / c */
cba42c93 5785 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5786 SCM_FRACTION_NUMERATOR (y)),
5787 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
5788 else
5789 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 5790 }
0aacf84e
MD
5791 else if (SCM_BIGP (x))
5792 {
e11e83f3 5793 if (SCM_I_INUMP (y))
0aacf84e
MD
5794 {
5795 /* big-x - inum-y */
e25f3727 5796 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e 5797 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 5798
0aacf84e
MD
5799 scm_remember_upto_here_1 (x);
5800 if (sgn_x == 0)
c71b0706 5801 return (SCM_FIXABLE (-yy) ?
e25f3727 5802 SCM_I_MAKINUM (-yy) : scm_from_inum (-yy));
0aacf84e
MD
5803 else
5804 {
5805 SCM result = scm_i_mkbig ();
ca46fb90 5806
708f22c6
KR
5807 if (yy >= 0)
5808 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
5809 else
5810 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 5811 scm_remember_upto_here_1 (x);
ca46fb90 5812
0aacf84e
MD
5813 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
5814 /* we know the result will have to be a bignum */
5815 return result;
5816 else
5817 return scm_i_normbig (result);
5818 }
5819 }
5820 else if (SCM_BIGP (y))
5821 {
5822 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
5823 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
5824 SCM result = scm_i_mkbig ();
5825 mpz_sub (SCM_I_BIG_MPZ (result),
5826 SCM_I_BIG_MPZ (x),
5827 SCM_I_BIG_MPZ (y));
5828 scm_remember_upto_here_2 (x, y);
5829 /* we know the result will have to be a bignum */
5830 if ((sgn_x == 1) && (sgn_y == -1))
5831 return result;
5832 if ((sgn_x == -1) && (sgn_y == 1))
5833 return result;
5834 return scm_i_normbig (result);
5835 }
5836 else if (SCM_REALP (y))
5837 {
5838 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
5839 scm_remember_upto_here_1 (x);
55f26379 5840 return scm_from_double (result);
0aacf84e
MD
5841 }
5842 else if (SCM_COMPLEXP (y))
5843 {
5844 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
5845 - SCM_COMPLEX_REAL (y));
5846 scm_remember_upto_here_1 (x);
8507ec80 5847 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 5848 }
f92e85f7 5849 else if (SCM_FRACTIONP (y))
cba42c93 5850 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5851 SCM_FRACTION_NUMERATOR (y)),
5852 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 5853 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 5854 }
0aacf84e
MD
5855 else if (SCM_REALP (x))
5856 {
e11e83f3 5857 if (SCM_I_INUMP (y))
55f26379 5858 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
5859 else if (SCM_BIGP (y))
5860 {
5861 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
5862 scm_remember_upto_here_1 (x);
55f26379 5863 return scm_from_double (result);
0aacf84e
MD
5864 }
5865 else if (SCM_REALP (y))
55f26379 5866 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 5867 else if (SCM_COMPLEXP (y))
8507ec80 5868 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 5869 -SCM_COMPLEX_IMAG (y));
f92e85f7 5870 else if (SCM_FRACTIONP (y))
55f26379 5871 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
5872 else
5873 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 5874 }
0aacf84e
MD
5875 else if (SCM_COMPLEXP (x))
5876 {
e11e83f3 5877 if (SCM_I_INUMP (y))
8507ec80 5878 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
5879 SCM_COMPLEX_IMAG (x));
5880 else if (SCM_BIGP (y))
5881 {
5882 double real_part = (SCM_COMPLEX_REAL (x)
5883 - mpz_get_d (SCM_I_BIG_MPZ (y)));
5884 scm_remember_upto_here_1 (x);
8507ec80 5885 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
5886 }
5887 else if (SCM_REALP (y))
8507ec80 5888 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
5889 SCM_COMPLEX_IMAG (x));
5890 else if (SCM_COMPLEXP (y))
8507ec80 5891 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 5892 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 5893 else if (SCM_FRACTIONP (y))
8507ec80 5894 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
5895 SCM_COMPLEX_IMAG (x));
5896 else
5897 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
5898 }
5899 else if (SCM_FRACTIONP (x))
5900 {
e11e83f3 5901 if (SCM_I_INUMP (y))
f92e85f7 5902 /* a/b - c = (a - cb) / b */
cba42c93 5903 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5904 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
5905 SCM_FRACTION_DENOMINATOR (x));
5906 else if (SCM_BIGP (y))
cba42c93 5907 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5908 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
5909 SCM_FRACTION_DENOMINATOR (x));
5910 else if (SCM_REALP (y))
55f26379 5911 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 5912 else if (SCM_COMPLEXP (y))
8507ec80 5913 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
5914 -SCM_COMPLEX_IMAG (y));
5915 else if (SCM_FRACTIONP (y))
5916 /* a/b - c/d = (ad - bc) / bd */
cba42c93 5917 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5918 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
5919 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
5920 else
5921 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 5922 }
0aacf84e 5923 else
98cb6e75 5924 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 5925}
c05e97b7 5926#undef FUNC_NAME
0f2d19dd 5927
ca46fb90 5928
40882e3d
KR
5929SCM_DEFINE (scm_oneminus, "1-", 1, 0, 0,
5930 (SCM x),
5931 "Return @math{@var{x}-1}.")
5932#define FUNC_NAME s_scm_oneminus
5933{
cff5fa33 5934 return scm_difference (x, SCM_INUM1);
40882e3d
KR
5935}
5936#undef FUNC_NAME
5937
5938
78d3deb1
AW
5939SCM_PRIMITIVE_GENERIC (scm_i_product, "*", 0, 2, 1,
5940 (SCM x, SCM y, SCM rest),
5941 "Return the product of all arguments. If called without arguments,\n"
5942 "1 is returned.")
5943#define FUNC_NAME s_scm_i_product
5944{
5945 while (!scm_is_null (rest))
5946 { x = scm_product (x, y);
5947 y = scm_car (rest);
5948 rest = scm_cdr (rest);
5949 }
5950 return scm_product (x, y);
5951}
5952#undef FUNC_NAME
5953
5954#define s_product s_scm_i_product
5955#define g_product g_scm_i_product
5956
0f2d19dd 5957SCM
6e8d25a6 5958scm_product (SCM x, SCM y)
0f2d19dd 5959{
9cc37597 5960 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
5961 {
5962 if (SCM_UNBNDP (x))
d956fa6f 5963 return SCM_I_MAKINUM (1L);
0aacf84e
MD
5964 else if (SCM_NUMBERP (x))
5965 return x;
5966 else
5967 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 5968 }
ca46fb90 5969
9cc37597 5970 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 5971 {
e25f3727 5972 scm_t_inum xx;
f4c627b3 5973
5e791807 5974 xinum:
e11e83f3 5975 xx = SCM_I_INUM (x);
f4c627b3 5976
0aacf84e
MD
5977 switch (xx)
5978 {
5e791807
MW
5979 case 1:
5980 /* exact1 is the universal multiplicative identity */
5981 return y;
5982 break;
5983 case 0:
5984 /* exact0 times a fixnum is exact0: optimize this case */
5985 if (SCM_LIKELY (SCM_I_INUMP (y)))
5986 return SCM_INUM0;
5987 /* if the other argument is inexact, the result is inexact,
5988 and we must do the multiplication in order to handle
5989 infinities and NaNs properly. */
5990 else if (SCM_REALP (y))
5991 return scm_from_double (0.0 * SCM_REAL_VALUE (y));
5992 else if (SCM_COMPLEXP (y))
5993 return scm_c_make_rectangular (0.0 * SCM_COMPLEX_REAL (y),
5994 0.0 * SCM_COMPLEX_IMAG (y));
5995 /* we've already handled inexact numbers,
5996 so y must be exact, and we return exact0 */
5997 else if (SCM_NUMP (y))
5998 return SCM_INUM0;
5999 else
6000 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
6001 break;
6002 case -1:
b5c40589 6003 /*
5e791807
MW
6004 * This case is important for more than just optimization.
6005 * It handles the case of negating
b5c40589
MW
6006 * (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
6007 * which is a bignum that must be changed back into a fixnum.
6008 * Failure to do so will cause the following to return #f:
6009 * (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
6010 */
b5c40589
MW
6011 return scm_difference(y, SCM_UNDEFINED);
6012 break;
0aacf84e 6013 }
f4c627b3 6014
9cc37597 6015 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 6016 {
e25f3727
AW
6017 scm_t_inum yy = SCM_I_INUM (y);
6018 scm_t_inum kk = xx * yy;
d956fa6f 6019 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 6020 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
6021 return k;
6022 else
6023 {
e25f3727 6024 SCM result = scm_i_inum2big (xx);
0aacf84e
MD
6025 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
6026 return scm_i_normbig (result);
6027 }
6028 }
6029 else if (SCM_BIGP (y))
6030 {
6031 SCM result = scm_i_mkbig ();
6032 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
6033 scm_remember_upto_here_1 (y);
6034 return result;
6035 }
6036 else if (SCM_REALP (y))
55f26379 6037 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 6038 else if (SCM_COMPLEXP (y))
8507ec80 6039 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 6040 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 6041 else if (SCM_FRACTIONP (y))
cba42c93 6042 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 6043 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
6044 else
6045 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6046 }
0aacf84e
MD
6047 else if (SCM_BIGP (x))
6048 {
e11e83f3 6049 if (SCM_I_INUMP (y))
0aacf84e
MD
6050 {
6051 SCM_SWAP (x, y);
5e791807 6052 goto xinum;
0aacf84e
MD
6053 }
6054 else if (SCM_BIGP (y))
6055 {
6056 SCM result = scm_i_mkbig ();
6057 mpz_mul (SCM_I_BIG_MPZ (result),
6058 SCM_I_BIG_MPZ (x),
6059 SCM_I_BIG_MPZ (y));
6060 scm_remember_upto_here_2 (x, y);
6061 return result;
6062 }
6063 else if (SCM_REALP (y))
6064 {
6065 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
6066 scm_remember_upto_here_1 (x);
55f26379 6067 return scm_from_double (result);
0aacf84e
MD
6068 }
6069 else if (SCM_COMPLEXP (y))
6070 {
6071 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
6072 scm_remember_upto_here_1 (x);
8507ec80 6073 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
6074 z * SCM_COMPLEX_IMAG (y));
6075 }
f92e85f7 6076 else if (SCM_FRACTIONP (y))
cba42c93 6077 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 6078 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
6079 else
6080 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6081 }
0aacf84e
MD
6082 else if (SCM_REALP (x))
6083 {
e11e83f3 6084 if (SCM_I_INUMP (y))
5e791807
MW
6085 {
6086 SCM_SWAP (x, y);
6087 goto xinum;
6088 }
0aacf84e
MD
6089 else if (SCM_BIGP (y))
6090 {
6091 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
6092 scm_remember_upto_here_1 (y);
55f26379 6093 return scm_from_double (result);
0aacf84e
MD
6094 }
6095 else if (SCM_REALP (y))
55f26379 6096 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 6097 else if (SCM_COMPLEXP (y))
8507ec80 6098 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 6099 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 6100 else if (SCM_FRACTIONP (y))
55f26379 6101 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
6102 else
6103 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6104 }
0aacf84e
MD
6105 else if (SCM_COMPLEXP (x))
6106 {
e11e83f3 6107 if (SCM_I_INUMP (y))
5e791807
MW
6108 {
6109 SCM_SWAP (x, y);
6110 goto xinum;
6111 }
0aacf84e
MD
6112 else if (SCM_BIGP (y))
6113 {
6114 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
6115 scm_remember_upto_here_1 (y);
8507ec80 6116 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 6117 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
6118 }
6119 else if (SCM_REALP (y))
8507ec80 6120 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
6121 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
6122 else if (SCM_COMPLEXP (y))
6123 {
8507ec80 6124 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
6125 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
6126 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
6127 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
6128 }
f92e85f7
MV
6129 else if (SCM_FRACTIONP (y))
6130 {
6131 double yy = scm_i_fraction2double (y);
8507ec80 6132 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
6133 yy * SCM_COMPLEX_IMAG (x));
6134 }
6135 else
6136 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
6137 }
6138 else if (SCM_FRACTIONP (x))
6139 {
e11e83f3 6140 if (SCM_I_INUMP (y))
cba42c93 6141 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
6142 SCM_FRACTION_DENOMINATOR (x));
6143 else if (SCM_BIGP (y))
cba42c93 6144 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
6145 SCM_FRACTION_DENOMINATOR (x));
6146 else if (SCM_REALP (y))
55f26379 6147 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
6148 else if (SCM_COMPLEXP (y))
6149 {
6150 double xx = scm_i_fraction2double (x);
8507ec80 6151 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
6152 xx * SCM_COMPLEX_IMAG (y));
6153 }
6154 else if (SCM_FRACTIONP (y))
6155 /* a/b * c/d = ac / bd */
cba42c93 6156 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6157 SCM_FRACTION_NUMERATOR (y)),
6158 scm_product (SCM_FRACTION_DENOMINATOR (x),
6159 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
6160 else
6161 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6162 }
0aacf84e 6163 else
f4c627b3 6164 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
6165}
6166
7351e207
MV
6167#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
6168 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
6169#define ALLOW_DIVIDE_BY_ZERO
6170/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
6171#endif
0f2d19dd 6172
ba74ef4e
MV
6173/* The code below for complex division is adapted from the GNU
6174 libstdc++, which adapted it from f2c's libF77, and is subject to
6175 this copyright: */
6176
6177/****************************************************************
6178Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
6179
6180Permission to use, copy, modify, and distribute this software
6181and its documentation for any purpose and without fee is hereby
6182granted, provided that the above copyright notice appear in all
6183copies and that both that the copyright notice and this
6184permission notice and warranty disclaimer appear in supporting
6185documentation, and that the names of AT&T Bell Laboratories or
6186Bellcore or any of their entities not be used in advertising or
6187publicity pertaining to distribution of the software without
6188specific, written prior permission.
6189
6190AT&T and Bellcore disclaim all warranties with regard to this
6191software, including all implied warranties of merchantability
6192and fitness. In no event shall AT&T or Bellcore be liable for
6193any special, indirect or consequential damages or any damages
6194whatsoever resulting from loss of use, data or profits, whether
6195in an action of contract, negligence or other tortious action,
6196arising out of or in connection with the use or performance of
6197this software.
6198****************************************************************/
6199
78d3deb1
AW
6200SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
6201 (SCM x, SCM y, SCM rest),
6202 "Divide the first argument by the product of the remaining\n"
6203 "arguments. If called with one argument @var{z1}, 1/@var{z1} is\n"
6204 "returned.")
6205#define FUNC_NAME s_scm_i_divide
6206{
6207 while (!scm_is_null (rest))
6208 { x = scm_divide (x, y);
6209 y = scm_car (rest);
6210 rest = scm_cdr (rest);
6211 }
6212 return scm_divide (x, y);
6213}
6214#undef FUNC_NAME
6215
6216#define s_divide s_scm_i_divide
6217#define g_divide g_scm_i_divide
6218
f92e85f7 6219static SCM
78d3deb1
AW
6220do_divide (SCM x, SCM y, int inexact)
6221#define FUNC_NAME s_divide
0f2d19dd 6222{
f8de44c1
DH
6223 double a;
6224
9cc37597 6225 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
6226 {
6227 if (SCM_UNBNDP (x))
6228 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 6229 else if (SCM_I_INUMP (x))
0aacf84e 6230 {
e25f3727 6231 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
6232 if (xx == 1 || xx == -1)
6233 return x;
7351e207 6234#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6235 else if (xx == 0)
6236 scm_num_overflow (s_divide);
7351e207 6237#endif
0aacf84e 6238 else
f92e85f7
MV
6239 {
6240 if (inexact)
55f26379 6241 return scm_from_double (1.0 / (double) xx);
cff5fa33 6242 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 6243 }
0aacf84e
MD
6244 }
6245 else if (SCM_BIGP (x))
f92e85f7
MV
6246 {
6247 if (inexact)
55f26379 6248 return scm_from_double (1.0 / scm_i_big2dbl (x));
cff5fa33 6249 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 6250 }
0aacf84e
MD
6251 else if (SCM_REALP (x))
6252 {
6253 double xx = SCM_REAL_VALUE (x);
7351e207 6254#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6255 if (xx == 0.0)
6256 scm_num_overflow (s_divide);
6257 else
7351e207 6258#endif
55f26379 6259 return scm_from_double (1.0 / xx);
0aacf84e
MD
6260 }
6261 else if (SCM_COMPLEXP (x))
6262 {
6263 double r = SCM_COMPLEX_REAL (x);
6264 double i = SCM_COMPLEX_IMAG (x);
4c6e36a6 6265 if (fabs(r) <= fabs(i))
0aacf84e
MD
6266 {
6267 double t = r / i;
6268 double d = i * (1.0 + t * t);
8507ec80 6269 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
6270 }
6271 else
6272 {
6273 double t = i / r;
6274 double d = r * (1.0 + t * t);
8507ec80 6275 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
6276 }
6277 }
f92e85f7 6278 else if (SCM_FRACTIONP (x))
cba42c93 6279 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 6280 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
6281 else
6282 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 6283 }
f8de44c1 6284
9cc37597 6285 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 6286 {
e25f3727 6287 scm_t_inum xx = SCM_I_INUM (x);
9cc37597 6288 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 6289 {
e25f3727 6290 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6291 if (yy == 0)
6292 {
7351e207 6293#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 6294 scm_num_overflow (s_divide);
7351e207 6295#else
55f26379 6296 return scm_from_double ((double) xx / (double) yy);
7351e207 6297#endif
0aacf84e
MD
6298 }
6299 else if (xx % yy != 0)
f92e85f7
MV
6300 {
6301 if (inexact)
55f26379 6302 return scm_from_double ((double) xx / (double) yy);
cba42c93 6303 else return scm_i_make_ratio (x, y);
f92e85f7 6304 }
0aacf84e
MD
6305 else
6306 {
e25f3727 6307 scm_t_inum z = xx / yy;
0aacf84e 6308 if (SCM_FIXABLE (z))
d956fa6f 6309 return SCM_I_MAKINUM (z);
0aacf84e 6310 else
e25f3727 6311 return scm_i_inum2big (z);
0aacf84e 6312 }
f872b822 6313 }
0aacf84e 6314 else if (SCM_BIGP (y))
f92e85f7
MV
6315 {
6316 if (inexact)
55f26379 6317 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 6318 else return scm_i_make_ratio (x, y);
f92e85f7 6319 }
0aacf84e
MD
6320 else if (SCM_REALP (y))
6321 {
6322 double yy = SCM_REAL_VALUE (y);
7351e207 6323#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6324 if (yy == 0.0)
6325 scm_num_overflow (s_divide);
6326 else
7351e207 6327#endif
55f26379 6328 return scm_from_double ((double) xx / yy);
ba74ef4e 6329 }
0aacf84e
MD
6330 else if (SCM_COMPLEXP (y))
6331 {
6332 a = xx;
6333 complex_div: /* y _must_ be a complex number */
6334 {
6335 double r = SCM_COMPLEX_REAL (y);
6336 double i = SCM_COMPLEX_IMAG (y);
4c6e36a6 6337 if (fabs(r) <= fabs(i))
0aacf84e
MD
6338 {
6339 double t = r / i;
6340 double d = i * (1.0 + t * t);
8507ec80 6341 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
6342 }
6343 else
6344 {
6345 double t = i / r;
6346 double d = r * (1.0 + t * t);
8507ec80 6347 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
6348 }
6349 }
6350 }
f92e85f7
MV
6351 else if (SCM_FRACTIONP (y))
6352 /* a / b/c = ac / b */
cba42c93 6353 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 6354 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
6355 else
6356 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 6357 }
0aacf84e
MD
6358 else if (SCM_BIGP (x))
6359 {
e11e83f3 6360 if (SCM_I_INUMP (y))
0aacf84e 6361 {
e25f3727 6362 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6363 if (yy == 0)
6364 {
7351e207 6365#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 6366 scm_num_overflow (s_divide);
7351e207 6367#else
0aacf84e
MD
6368 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6369 scm_remember_upto_here_1 (x);
6370 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 6371#endif
0aacf84e
MD
6372 }
6373 else if (yy == 1)
6374 return x;
6375 else
6376 {
6377 /* FIXME: HMM, what are the relative performance issues here?
6378 We need to test. Is it faster on average to test
6379 divisible_p, then perform whichever operation, or is it
6380 faster to perform the integer div opportunistically and
6381 switch to real if there's a remainder? For now we take the
6382 middle ground: test, then if divisible, use the faster div
6383 func. */
6384
e25f3727 6385 scm_t_inum abs_yy = yy < 0 ? -yy : yy;
0aacf84e
MD
6386 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
6387
6388 if (divisible_p)
6389 {
6390 SCM result = scm_i_mkbig ();
6391 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
6392 scm_remember_upto_here_1 (x);
6393 if (yy < 0)
6394 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
6395 return scm_i_normbig (result);
6396 }
6397 else
f92e85f7
MV
6398 {
6399 if (inexact)
55f26379 6400 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 6401 else return scm_i_make_ratio (x, y);
f92e85f7 6402 }
0aacf84e
MD
6403 }
6404 }
6405 else if (SCM_BIGP (y))
6406 {
a4955a04
MW
6407 /* big_x / big_y */
6408 if (inexact)
0aacf84e 6409 {
a4955a04
MW
6410 /* It's easily possible for the ratio x/y to fit a double
6411 but one or both x and y be too big to fit a double,
6412 hence the use of mpq_get_d rather than converting and
6413 dividing. */
6414 mpq_t q;
6415 *mpq_numref(q) = *SCM_I_BIG_MPZ (x);
6416 *mpq_denref(q) = *SCM_I_BIG_MPZ (y);
6417 return scm_from_double (mpq_get_d (q));
0aacf84e
MD
6418 }
6419 else
6420 {
a4955a04
MW
6421 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
6422 SCM_I_BIG_MPZ (y));
6423 if (divisible_p)
6424 {
6425 SCM result = scm_i_mkbig ();
6426 mpz_divexact (SCM_I_BIG_MPZ (result),
6427 SCM_I_BIG_MPZ (x),
6428 SCM_I_BIG_MPZ (y));
6429 scm_remember_upto_here_2 (x, y);
6430 return scm_i_normbig (result);
6431 }
6432 else
6433 return scm_i_make_ratio (x, y);
0aacf84e
MD
6434 }
6435 }
6436 else if (SCM_REALP (y))
6437 {
6438 double yy = SCM_REAL_VALUE (y);
7351e207 6439#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6440 if (yy == 0.0)
6441 scm_num_overflow (s_divide);
6442 else
7351e207 6443#endif
55f26379 6444 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
6445 }
6446 else if (SCM_COMPLEXP (y))
6447 {
6448 a = scm_i_big2dbl (x);
6449 goto complex_div;
6450 }
f92e85f7 6451 else if (SCM_FRACTIONP (y))
cba42c93 6452 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 6453 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
6454 else
6455 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 6456 }
0aacf84e
MD
6457 else if (SCM_REALP (x))
6458 {
6459 double rx = SCM_REAL_VALUE (x);
e11e83f3 6460 if (SCM_I_INUMP (y))
0aacf84e 6461 {
e25f3727 6462 scm_t_inum yy = SCM_I_INUM (y);
7351e207 6463#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6464 if (yy == 0)
6465 scm_num_overflow (s_divide);
6466 else
7351e207 6467#endif
55f26379 6468 return scm_from_double (rx / (double) yy);
0aacf84e
MD
6469 }
6470 else if (SCM_BIGP (y))
6471 {
6472 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
6473 scm_remember_upto_here_1 (y);
55f26379 6474 return scm_from_double (rx / dby);
0aacf84e
MD
6475 }
6476 else if (SCM_REALP (y))
6477 {
6478 double yy = SCM_REAL_VALUE (y);
7351e207 6479#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6480 if (yy == 0.0)
6481 scm_num_overflow (s_divide);
6482 else
7351e207 6483#endif
55f26379 6484 return scm_from_double (rx / yy);
0aacf84e
MD
6485 }
6486 else if (SCM_COMPLEXP (y))
6487 {
6488 a = rx;
6489 goto complex_div;
6490 }
f92e85f7 6491 else if (SCM_FRACTIONP (y))
55f26379 6492 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
6493 else
6494 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 6495 }
0aacf84e
MD
6496 else if (SCM_COMPLEXP (x))
6497 {
6498 double rx = SCM_COMPLEX_REAL (x);
6499 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 6500 if (SCM_I_INUMP (y))
0aacf84e 6501 {
e25f3727 6502 scm_t_inum yy = SCM_I_INUM (y);
7351e207 6503#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6504 if (yy == 0)
6505 scm_num_overflow (s_divide);
6506 else
7351e207 6507#endif
0aacf84e
MD
6508 {
6509 double d = yy;
8507ec80 6510 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
6511 }
6512 }
6513 else if (SCM_BIGP (y))
6514 {
6515 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
6516 scm_remember_upto_here_1 (y);
8507ec80 6517 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
6518 }
6519 else if (SCM_REALP (y))
6520 {
6521 double yy = SCM_REAL_VALUE (y);
7351e207 6522#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6523 if (yy == 0.0)
6524 scm_num_overflow (s_divide);
6525 else
7351e207 6526#endif
8507ec80 6527 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
6528 }
6529 else if (SCM_COMPLEXP (y))
6530 {
6531 double ry = SCM_COMPLEX_REAL (y);
6532 double iy = SCM_COMPLEX_IMAG (y);
4c6e36a6 6533 if (fabs(ry) <= fabs(iy))
0aacf84e
MD
6534 {
6535 double t = ry / iy;
6536 double d = iy * (1.0 + t * t);
8507ec80 6537 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
6538 }
6539 else
6540 {
6541 double t = iy / ry;
6542 double d = ry * (1.0 + t * t);
8507ec80 6543 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
6544 }
6545 }
f92e85f7
MV
6546 else if (SCM_FRACTIONP (y))
6547 {
6548 double yy = scm_i_fraction2double (y);
8507ec80 6549 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 6550 }
0aacf84e
MD
6551 else
6552 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 6553 }
f92e85f7
MV
6554 else if (SCM_FRACTIONP (x))
6555 {
e11e83f3 6556 if (SCM_I_INUMP (y))
f92e85f7 6557 {
e25f3727 6558 scm_t_inum yy = SCM_I_INUM (y);
f92e85f7
MV
6559#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
6560 if (yy == 0)
6561 scm_num_overflow (s_divide);
6562 else
6563#endif
cba42c93 6564 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6565 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
6566 }
6567 else if (SCM_BIGP (y))
6568 {
cba42c93 6569 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6570 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
6571 }
6572 else if (SCM_REALP (y))
6573 {
6574 double yy = SCM_REAL_VALUE (y);
6575#ifndef ALLOW_DIVIDE_BY_ZERO
6576 if (yy == 0.0)
6577 scm_num_overflow (s_divide);
6578 else
6579#endif
55f26379 6580 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
6581 }
6582 else if (SCM_COMPLEXP (y))
6583 {
6584 a = scm_i_fraction2double (x);
6585 goto complex_div;
6586 }
6587 else if (SCM_FRACTIONP (y))
cba42c93 6588 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
6589 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
6590 else
6591 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
6592 }
0aacf84e 6593 else
f8de44c1 6594 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 6595}
f92e85f7
MV
6596
6597SCM
6598scm_divide (SCM x, SCM y)
6599{
78d3deb1 6600 return do_divide (x, y, 0);
f92e85f7
MV
6601}
6602
6603static SCM scm_divide2real (SCM x, SCM y)
6604{
78d3deb1 6605 return do_divide (x, y, 1);
f92e85f7 6606}
c05e97b7 6607#undef FUNC_NAME
0f2d19dd 6608
fa605590 6609
0f2d19dd 6610double
3101f40f 6611scm_c_truncate (double x)
0f2d19dd 6612{
fa605590
KR
6613#if HAVE_TRUNC
6614 return trunc (x);
6615#else
f872b822
MD
6616 if (x < 0.0)
6617 return -floor (-x);
6618 return floor (x);
fa605590 6619#endif
0f2d19dd 6620}
0f2d19dd 6621
3101f40f
MV
6622/* scm_c_round is done using floor(x+0.5) to round to nearest and with
6623 half-way case (ie. when x is an integer plus 0.5) going upwards.
6624 Then half-way cases are identified and adjusted down if the
6625 round-upwards didn't give the desired even integer.
6187f48b
KR
6626
6627 "plus_half == result" identifies a half-way case. If plus_half, which is
6628 x + 0.5, is an integer then x must be an integer plus 0.5.
6629
6630 An odd "result" value is identified with result/2 != floor(result/2).
6631 This is done with plus_half, since that value is ready for use sooner in
6632 a pipelined cpu, and we're already requiring plus_half == result.
6633
6634 Note however that we need to be careful when x is big and already an
6635 integer. In that case "x+0.5" may round to an adjacent integer, causing
6636 us to return such a value, incorrectly. For instance if the hardware is
6637 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
6638 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
6639 returned. Or if the hardware is in round-upwards mode, then other bigger
6640 values like say x == 2^128 will see x+0.5 rounding up to the next higher
6641 representable value, 2^128+2^76 (or whatever), again incorrect.
6642
6643 These bad roundings of x+0.5 are avoided by testing at the start whether
6644 x is already an integer. If it is then clearly that's the desired result
6645 already. And if it's not then the exponent must be small enough to allow
6646 an 0.5 to be represented, and hence added without a bad rounding. */
6647
0f2d19dd 6648double
3101f40f 6649scm_c_round (double x)
0f2d19dd 6650{
6187f48b
KR
6651 double plus_half, result;
6652
6653 if (x == floor (x))
6654 return x;
6655
6656 plus_half = x + 0.5;
6657 result = floor (plus_half);
3101f40f 6658 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
6659 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
6660 ? result - 1
6661 : result);
0f2d19dd
JB
6662}
6663
f92e85f7
MV
6664SCM_DEFINE (scm_truncate_number, "truncate", 1, 0, 0,
6665 (SCM x),
6666 "Round the number @var{x} towards zero.")
6667#define FUNC_NAME s_scm_truncate_number
6668{
73e4de09 6669 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
6670 return scm_floor (x);
6671 else
6672 return scm_ceiling (x);
6673}
6674#undef FUNC_NAME
6675
f92e85f7
MV
6676SCM_DEFINE (scm_round_number, "round", 1, 0, 0,
6677 (SCM x),
6678 "Round the number @var{x} towards the nearest integer. "
6679 "When it is exactly halfway between two integers, "
6680 "round towards the even one.")
6681#define FUNC_NAME s_scm_round_number
6682{
e11e83f3 6683 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
6684 return x;
6685 else if (SCM_REALP (x))
3101f40f 6686 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
f92e85f7 6687 else
bae30667
KR
6688 {
6689 /* OPTIMIZE-ME: Fraction case could be done more efficiently by a
6690 single quotient+remainder division then examining to see which way
6691 the rounding should go. */
6692 SCM plus_half = scm_sum (x, exactly_one_half);
6693 SCM result = scm_floor (plus_half);
3101f40f 6694 /* Adjust so that the rounding is towards even. */
73e4de09
MV
6695 if (scm_is_true (scm_num_eq_p (plus_half, result))
6696 && scm_is_true (scm_odd_p (result)))
cff5fa33 6697 return scm_difference (result, SCM_INUM1);
bae30667
KR
6698 else
6699 return result;
6700 }
f92e85f7
MV
6701}
6702#undef FUNC_NAME
6703
6704SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
6705 (SCM x),
6706 "Round the number @var{x} towards minus infinity.")
6707#define FUNC_NAME s_scm_floor
6708{
e11e83f3 6709 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
6710 return x;
6711 else if (SCM_REALP (x))
55f26379 6712 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7
MV
6713 else if (SCM_FRACTIONP (x))
6714 {
6715 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
6716 SCM_FRACTION_DENOMINATOR (x));
73e4de09 6717 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
6718 {
6719 /* For positive x, rounding towards zero is correct. */
6720 return q;
6721 }
6722 else
6723 {
6724 /* For negative x, we need to return q-1 unless x is an
6725 integer. But fractions are never integer, per our
6726 assumptions. */
cff5fa33 6727 return scm_difference (q, SCM_INUM1);
f92e85f7
MV
6728 }
6729 }
6730 else
6731 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
6732}
6733#undef FUNC_NAME
6734
6735SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
6736 (SCM x),
6737 "Round the number @var{x} towards infinity.")
6738#define FUNC_NAME s_scm_ceiling
6739{
e11e83f3 6740 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
6741 return x;
6742 else if (SCM_REALP (x))
55f26379 6743 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7
MV
6744 else if (SCM_FRACTIONP (x))
6745 {
6746 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
6747 SCM_FRACTION_DENOMINATOR (x));
73e4de09 6748 if (scm_is_false (scm_positive_p (x)))
f92e85f7
MV
6749 {
6750 /* For negative x, rounding towards zero is correct. */
6751 return q;
6752 }
6753 else
6754 {
6755 /* For positive x, we need to return q+1 unless x is an
6756 integer. But fractions are never integer, per our
6757 assumptions. */
cff5fa33 6758 return scm_sum (q, SCM_INUM1);
f92e85f7
MV
6759 }
6760 }
6761 else
6762 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
6763}
6764#undef FUNC_NAME
0f2d19dd 6765
2519490c
MW
6766SCM_PRIMITIVE_GENERIC (scm_expt, "expt", 2, 0, 0,
6767 (SCM x, SCM y),
6768 "Return @var{x} raised to the power of @var{y}.")
6fc4d012 6769#define FUNC_NAME s_scm_expt
0f2d19dd 6770{
01c7284a
MW
6771 if (scm_is_integer (y))
6772 {
6773 if (scm_is_true (scm_exact_p (y)))
6774 return scm_integer_expt (x, y);
6775 else
6776 {
6777 /* Here we handle the case where the exponent is an inexact
6778 integer. We make the exponent exact in order to use
6779 scm_integer_expt, and thus avoid the spurious imaginary
6780 parts that may result from round-off errors in the general
6781 e^(y log x) method below (for example when squaring a large
6782 negative number). In this case, we must return an inexact
6783 result for correctness. We also make the base inexact so
6784 that scm_integer_expt will use fast inexact arithmetic
6785 internally. Note that making the base inexact is not
6786 sufficient to guarantee an inexact result, because
6787 scm_integer_expt will return an exact 1 when the exponent
6788 is 0, even if the base is inexact. */
6789 return scm_exact_to_inexact
6790 (scm_integer_expt (scm_exact_to_inexact (x),
6791 scm_inexact_to_exact (y)));
6792 }
6793 }
6fc4d012
AW
6794 else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
6795 {
6796 return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
6797 }
2519490c 6798 else if (scm_is_complex (x) && scm_is_complex (y))
6fc4d012 6799 return scm_exp (scm_product (scm_log (x), y));
2519490c
MW
6800 else if (scm_is_complex (x))
6801 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG2, s_scm_expt);
6802 else
6803 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG1, s_scm_expt);
0f2d19dd 6804}
1bbd0b84 6805#undef FUNC_NAME
0f2d19dd 6806
7f41099e
MW
6807/* sin/cos/tan/asin/acos/atan
6808 sinh/cosh/tanh/asinh/acosh/atanh
6809 Derived from "Transcen.scm", Complex trancendental functions for SCM.
6810 Written by Jerry D. Hedden, (C) FSF.
6811 See the file `COPYING' for terms applying to this program. */
6812
ad79736c
AW
6813SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
6814 (SCM z),
6815 "Compute the sine of @var{z}.")
6816#define FUNC_NAME s_scm_sin
6817{
8deddc94
MW
6818 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6819 return z; /* sin(exact0) = exact0 */
6820 else if (scm_is_real (z))
ad79736c
AW
6821 return scm_from_double (sin (scm_to_double (z)));
6822 else if (SCM_COMPLEXP (z))
6823 { double x, y;
6824 x = SCM_COMPLEX_REAL (z);
6825 y = SCM_COMPLEX_IMAG (z);
6826 return scm_c_make_rectangular (sin (x) * cosh (y),
6827 cos (x) * sinh (y));
6828 }
6829 else
6830 SCM_WTA_DISPATCH_1 (g_scm_sin, z, 1, s_scm_sin);
6831}
6832#undef FUNC_NAME
0f2d19dd 6833
ad79736c
AW
6834SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
6835 (SCM z),
6836 "Compute the cosine of @var{z}.")
6837#define FUNC_NAME s_scm_cos
6838{
8deddc94
MW
6839 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6840 return SCM_INUM1; /* cos(exact0) = exact1 */
6841 else if (scm_is_real (z))
ad79736c
AW
6842 return scm_from_double (cos (scm_to_double (z)));
6843 else if (SCM_COMPLEXP (z))
6844 { double x, y;
6845 x = SCM_COMPLEX_REAL (z);
6846 y = SCM_COMPLEX_IMAG (z);
6847 return scm_c_make_rectangular (cos (x) * cosh (y),
6848 -sin (x) * sinh (y));
6849 }
6850 else
6851 SCM_WTA_DISPATCH_1 (g_scm_cos, z, 1, s_scm_cos);
6852}
6853#undef FUNC_NAME
6854
6855SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
6856 (SCM z),
6857 "Compute the tangent of @var{z}.")
6858#define FUNC_NAME s_scm_tan
0f2d19dd 6859{
8deddc94
MW
6860 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6861 return z; /* tan(exact0) = exact0 */
6862 else if (scm_is_real (z))
ad79736c
AW
6863 return scm_from_double (tan (scm_to_double (z)));
6864 else if (SCM_COMPLEXP (z))
6865 { double x, y, w;
6866 x = 2.0 * SCM_COMPLEX_REAL (z);
6867 y = 2.0 * SCM_COMPLEX_IMAG (z);
6868 w = cos (x) + cosh (y);
6869#ifndef ALLOW_DIVIDE_BY_ZERO
6870 if (w == 0.0)
6871 scm_num_overflow (s_scm_tan);
6872#endif
6873 return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
6874 }
6875 else
6876 SCM_WTA_DISPATCH_1 (g_scm_tan, z, 1, s_scm_tan);
6877}
6878#undef FUNC_NAME
6879
6880SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
6881 (SCM z),
6882 "Compute the hyperbolic sine of @var{z}.")
6883#define FUNC_NAME s_scm_sinh
6884{
8deddc94
MW
6885 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6886 return z; /* sinh(exact0) = exact0 */
6887 else if (scm_is_real (z))
ad79736c
AW
6888 return scm_from_double (sinh (scm_to_double (z)));
6889 else if (SCM_COMPLEXP (z))
6890 { double x, y;
6891 x = SCM_COMPLEX_REAL (z);
6892 y = SCM_COMPLEX_IMAG (z);
6893 return scm_c_make_rectangular (sinh (x) * cos (y),
6894 cosh (x) * sin (y));
6895 }
6896 else
6897 SCM_WTA_DISPATCH_1 (g_scm_sinh, z, 1, s_scm_sinh);
6898}
6899#undef FUNC_NAME
6900
6901SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
6902 (SCM z),
6903 "Compute the hyperbolic cosine of @var{z}.")
6904#define FUNC_NAME s_scm_cosh
6905{
8deddc94
MW
6906 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6907 return SCM_INUM1; /* cosh(exact0) = exact1 */
6908 else if (scm_is_real (z))
ad79736c
AW
6909 return scm_from_double (cosh (scm_to_double (z)));
6910 else if (SCM_COMPLEXP (z))
6911 { double x, y;
6912 x = SCM_COMPLEX_REAL (z);
6913 y = SCM_COMPLEX_IMAG (z);
6914 return scm_c_make_rectangular (cosh (x) * cos (y),
6915 sinh (x) * sin (y));
6916 }
6917 else
6918 SCM_WTA_DISPATCH_1 (g_scm_cosh, z, 1, s_scm_cosh);
6919}
6920#undef FUNC_NAME
6921
6922SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
6923 (SCM z),
6924 "Compute the hyperbolic tangent of @var{z}.")
6925#define FUNC_NAME s_scm_tanh
6926{
8deddc94
MW
6927 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6928 return z; /* tanh(exact0) = exact0 */
6929 else if (scm_is_real (z))
ad79736c
AW
6930 return scm_from_double (tanh (scm_to_double (z)));
6931 else if (SCM_COMPLEXP (z))
6932 { double x, y, w;
6933 x = 2.0 * SCM_COMPLEX_REAL (z);
6934 y = 2.0 * SCM_COMPLEX_IMAG (z);
6935 w = cosh (x) + cos (y);
6936#ifndef ALLOW_DIVIDE_BY_ZERO
6937 if (w == 0.0)
6938 scm_num_overflow (s_scm_tanh);
6939#endif
6940 return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
6941 }
6942 else
6943 SCM_WTA_DISPATCH_1 (g_scm_tanh, z, 1, s_scm_tanh);
6944}
6945#undef FUNC_NAME
6946
6947SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
6948 (SCM z),
6949 "Compute the arc sine of @var{z}.")
6950#define FUNC_NAME s_scm_asin
6951{
8deddc94
MW
6952 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6953 return z; /* asin(exact0) = exact0 */
6954 else if (scm_is_real (z))
ad79736c
AW
6955 {
6956 double w = scm_to_double (z);
6957 if (w >= -1.0 && w <= 1.0)
6958 return scm_from_double (asin (w));
6959 else
6960 return scm_product (scm_c_make_rectangular (0, -1),
6961 scm_sys_asinh (scm_c_make_rectangular (0, w)));
6962 }
6963 else if (SCM_COMPLEXP (z))
6964 { double x, y;
6965 x = SCM_COMPLEX_REAL (z);
6966 y = SCM_COMPLEX_IMAG (z);
6967 return scm_product (scm_c_make_rectangular (0, -1),
6968 scm_sys_asinh (scm_c_make_rectangular (-y, x)));
6969 }
6970 else
6971 SCM_WTA_DISPATCH_1 (g_scm_asin, z, 1, s_scm_asin);
6972}
6973#undef FUNC_NAME
6974
6975SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
6976 (SCM z),
6977 "Compute the arc cosine of @var{z}.")
6978#define FUNC_NAME s_scm_acos
6979{
8deddc94
MW
6980 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
6981 return SCM_INUM0; /* acos(exact1) = exact0 */
6982 else if (scm_is_real (z))
ad79736c
AW
6983 {
6984 double w = scm_to_double (z);
6985 if (w >= -1.0 && w <= 1.0)
6986 return scm_from_double (acos (w));
6987 else
6988 return scm_sum (scm_from_double (acos (0.0)),
6989 scm_product (scm_c_make_rectangular (0, 1),
6990 scm_sys_asinh (scm_c_make_rectangular (0, w))));
6991 }
6992 else if (SCM_COMPLEXP (z))
6993 { double x, y;
6994 x = SCM_COMPLEX_REAL (z);
6995 y = SCM_COMPLEX_IMAG (z);
6996 return scm_sum (scm_from_double (acos (0.0)),
6997 scm_product (scm_c_make_rectangular (0, 1),
6998 scm_sys_asinh (scm_c_make_rectangular (-y, x))));
6999 }
7000 else
7001 SCM_WTA_DISPATCH_1 (g_scm_acos, z, 1, s_scm_acos);
7002}
7003#undef FUNC_NAME
7004
7005SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
7006 (SCM z, SCM y),
7007 "With one argument, compute the arc tangent of @var{z}.\n"
7008 "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
7009 "using the sign of @var{z} and @var{y} to determine the quadrant.")
7010#define FUNC_NAME s_scm_atan
7011{
7012 if (SCM_UNBNDP (y))
7013 {
8deddc94
MW
7014 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
7015 return z; /* atan(exact0) = exact0 */
7016 else if (scm_is_real (z))
ad79736c
AW
7017 return scm_from_double (atan (scm_to_double (z)));
7018 else if (SCM_COMPLEXP (z))
7019 {
7020 double v, w;
7021 v = SCM_COMPLEX_REAL (z);
7022 w = SCM_COMPLEX_IMAG (z);
7023 return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
7024 scm_c_make_rectangular (v, w + 1.0))),
7025 scm_c_make_rectangular (0, 2));
7026 }
7027 else
7028 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
7029 }
7030 else if (scm_is_real (z))
7031 {
7032 if (scm_is_real (y))
7033 return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
7034 else
7035 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
7036 }
7037 else
7038 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
7039}
7040#undef FUNC_NAME
7041
7042SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
7043 (SCM z),
7044 "Compute the inverse hyperbolic sine of @var{z}.")
7045#define FUNC_NAME s_scm_sys_asinh
7046{
8deddc94
MW
7047 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
7048 return z; /* asinh(exact0) = exact0 */
7049 else if (scm_is_real (z))
ad79736c
AW
7050 return scm_from_double (asinh (scm_to_double (z)));
7051 else if (scm_is_number (z))
7052 return scm_log (scm_sum (z,
7053 scm_sqrt (scm_sum (scm_product (z, z),
cff5fa33 7054 SCM_INUM1))));
ad79736c
AW
7055 else
7056 SCM_WTA_DISPATCH_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
7057}
7058#undef FUNC_NAME
7059
7060SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
7061 (SCM z),
7062 "Compute the inverse hyperbolic cosine of @var{z}.")
7063#define FUNC_NAME s_scm_sys_acosh
7064{
8deddc94
MW
7065 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
7066 return SCM_INUM0; /* acosh(exact1) = exact0 */
7067 else if (scm_is_real (z) && scm_to_double (z) >= 1.0)
ad79736c
AW
7068 return scm_from_double (acosh (scm_to_double (z)));
7069 else if (scm_is_number (z))
7070 return scm_log (scm_sum (z,
7071 scm_sqrt (scm_difference (scm_product (z, z),
cff5fa33 7072 SCM_INUM1))));
ad79736c
AW
7073 else
7074 SCM_WTA_DISPATCH_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
7075}
7076#undef FUNC_NAME
7077
7078SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
7079 (SCM z),
7080 "Compute the inverse hyperbolic tangent of @var{z}.")
7081#define FUNC_NAME s_scm_sys_atanh
7082{
8deddc94
MW
7083 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
7084 return z; /* atanh(exact0) = exact0 */
7085 else if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
ad79736c
AW
7086 return scm_from_double (atanh (scm_to_double (z)));
7087 else if (scm_is_number (z))
cff5fa33
MW
7088 return scm_divide (scm_log (scm_divide (scm_sum (SCM_INUM1, z),
7089 scm_difference (SCM_INUM1, z))),
ad79736c
AW
7090 SCM_I_MAKINUM (2));
7091 else
7092 SCM_WTA_DISPATCH_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
0f2d19dd 7093}
1bbd0b84 7094#undef FUNC_NAME
0f2d19dd 7095
8507ec80
MV
7096SCM
7097scm_c_make_rectangular (double re, double im)
7098{
c7218482 7099 SCM z;
03604fcf 7100
c7218482
MW
7101 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
7102 "complex"));
7103 SCM_SET_CELL_TYPE (z, scm_tc16_complex);
7104 SCM_COMPLEX_REAL (z) = re;
7105 SCM_COMPLEX_IMAG (z) = im;
7106 return z;
8507ec80 7107}
0f2d19dd 7108
a1ec6916 7109SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
a2c25234
LC
7110 (SCM real_part, SCM imaginary_part),
7111 "Return a complex number constructed of the given @var{real-part} "
7112 "and @var{imaginary-part} parts.")
1bbd0b84 7113#define FUNC_NAME s_scm_make_rectangular
0f2d19dd 7114{
ad79736c
AW
7115 SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
7116 SCM_ARG1, FUNC_NAME, "real");
7117 SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
7118 SCM_ARG2, FUNC_NAME, "real");
c7218482
MW
7119
7120 /* Return a real if and only if the imaginary_part is an _exact_ 0 */
7121 if (scm_is_eq (imaginary_part, SCM_INUM0))
7122 return real_part;
7123 else
7124 return scm_c_make_rectangular (scm_to_double (real_part),
7125 scm_to_double (imaginary_part));
0f2d19dd 7126}
1bbd0b84 7127#undef FUNC_NAME
0f2d19dd 7128
8507ec80
MV
7129SCM
7130scm_c_make_polar (double mag, double ang)
7131{
7132 double s, c;
5e647d08
LC
7133
7134 /* The sincos(3) function is undocumented an broken on Tru64. Thus we only
7135 use it on Glibc-based systems that have it (it's a GNU extension). See
7136 http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
7137 details. */
7138#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
8507ec80
MV
7139 sincos (ang, &s, &c);
7140#else
7141 s = sin (ang);
7142 c = cos (ang);
7143#endif
9d427b2c
MW
7144
7145 /* If s and c are NaNs, this indicates that the angle is a NaN,
7146 infinite, or perhaps simply too large to determine its value
7147 mod 2*pi. However, we know something that the floating-point
7148 implementation doesn't know: We know that s and c are finite.
7149 Therefore, if the magnitude is zero, return a complex zero.
7150
7151 The reason we check for the NaNs instead of using this case
7152 whenever mag == 0.0 is because when the angle is known, we'd
7153 like to return the correct kind of non-real complex zero:
7154 +0.0+0.0i, -0.0+0.0i, -0.0-0.0i, or +0.0-0.0i, depending
7155 on which quadrant the angle is in.
7156 */
7157 if (SCM_UNLIKELY (isnan(s)) && isnan(c) && (mag == 0.0))
7158 return scm_c_make_rectangular (0.0, 0.0);
7159 else
7160 return scm_c_make_rectangular (mag * c, mag * s);
8507ec80 7161}
0f2d19dd 7162
a1ec6916 7163SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
c7218482
MW
7164 (SCM mag, SCM ang),
7165 "Return the complex number @var{mag} * e^(i * @var{ang}).")
1bbd0b84 7166#define FUNC_NAME s_scm_make_polar
0f2d19dd 7167{
c7218482
MW
7168 SCM_ASSERT_TYPE (scm_is_real (mag), mag, SCM_ARG1, FUNC_NAME, "real");
7169 SCM_ASSERT_TYPE (scm_is_real (ang), ang, SCM_ARG2, FUNC_NAME, "real");
7170
7171 /* If mag is exact0, return exact0 */
7172 if (scm_is_eq (mag, SCM_INUM0))
7173 return SCM_INUM0;
7174 /* Return a real if ang is exact0 */
7175 else if (scm_is_eq (ang, SCM_INUM0))
7176 return mag;
7177 else
7178 return scm_c_make_polar (scm_to_double (mag), scm_to_double (ang));
0f2d19dd 7179}
1bbd0b84 7180#undef FUNC_NAME
0f2d19dd
JB
7181
7182
2519490c
MW
7183SCM_PRIMITIVE_GENERIC (scm_real_part, "real-part", 1, 0, 0,
7184 (SCM z),
7185 "Return the real part of the number @var{z}.")
7186#define FUNC_NAME s_scm_real_part
0f2d19dd 7187{
2519490c 7188 if (SCM_COMPLEXP (z))
55f26379 7189 return scm_from_double (SCM_COMPLEX_REAL (z));
2519490c 7190 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_REALP (z) || SCM_FRACTIONP (z))
2fa2d879 7191 return z;
0aacf84e 7192 else
2519490c 7193 SCM_WTA_DISPATCH_1 (g_scm_real_part, z, SCM_ARG1, s_scm_real_part);
0f2d19dd 7194}
2519490c 7195#undef FUNC_NAME
0f2d19dd
JB
7196
7197
2519490c
MW
7198SCM_PRIMITIVE_GENERIC (scm_imag_part, "imag-part", 1, 0, 0,
7199 (SCM z),
7200 "Return the imaginary part of the number @var{z}.")
7201#define FUNC_NAME s_scm_imag_part
0f2d19dd 7202{
2519490c
MW
7203 if (SCM_COMPLEXP (z))
7204 return scm_from_double (SCM_COMPLEX_IMAG (z));
c7218482 7205 else if (SCM_I_INUMP (z) || SCM_REALP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f92e85f7 7206 return SCM_INUM0;
0aacf84e 7207 else
2519490c 7208 SCM_WTA_DISPATCH_1 (g_scm_imag_part, z, SCM_ARG1, s_scm_imag_part);
0f2d19dd 7209}
2519490c 7210#undef FUNC_NAME
0f2d19dd 7211
2519490c
MW
7212SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
7213 (SCM z),
7214 "Return the numerator of the number @var{z}.")
7215#define FUNC_NAME s_scm_numerator
f92e85f7 7216{
2519490c 7217 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f92e85f7
MV
7218 return z;
7219 else if (SCM_FRACTIONP (z))
e2bf3b19 7220 return SCM_FRACTION_NUMERATOR (z);
f92e85f7
MV
7221 else if (SCM_REALP (z))
7222 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
7223 else
2519490c 7224 SCM_WTA_DISPATCH_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
f92e85f7 7225}
2519490c 7226#undef FUNC_NAME
f92e85f7
MV
7227
7228
2519490c
MW
7229SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
7230 (SCM z),
7231 "Return the denominator of the number @var{z}.")
7232#define FUNC_NAME s_scm_denominator
f92e85f7 7233{
2519490c 7234 if (SCM_I_INUMP (z) || SCM_BIGP (z))
cff5fa33 7235 return SCM_INUM1;
f92e85f7 7236 else if (SCM_FRACTIONP (z))
e2bf3b19 7237 return SCM_FRACTION_DENOMINATOR (z);
f92e85f7
MV
7238 else if (SCM_REALP (z))
7239 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
7240 else
2519490c 7241 SCM_WTA_DISPATCH_1 (g_scm_denominator, z, SCM_ARG1, s_scm_denominator);
f92e85f7 7242}
2519490c 7243#undef FUNC_NAME
0f2d19dd 7244
2519490c
MW
7245
7246SCM_PRIMITIVE_GENERIC (scm_magnitude, "magnitude", 1, 0, 0,
7247 (SCM z),
7248 "Return the magnitude of the number @var{z}. This is the same as\n"
7249 "@code{abs} for real arguments, but also allows complex numbers.")
7250#define FUNC_NAME s_scm_magnitude
0f2d19dd 7251{
e11e83f3 7252 if (SCM_I_INUMP (z))
0aacf84e 7253 {
e25f3727 7254 scm_t_inum zz = SCM_I_INUM (z);
0aacf84e
MD
7255 if (zz >= 0)
7256 return z;
7257 else if (SCM_POSFIXABLE (-zz))
d956fa6f 7258 return SCM_I_MAKINUM (-zz);
0aacf84e 7259 else
e25f3727 7260 return scm_i_inum2big (-zz);
5986c47d 7261 }
0aacf84e
MD
7262 else if (SCM_BIGP (z))
7263 {
7264 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
7265 scm_remember_upto_here_1 (z);
7266 if (sgn < 0)
7267 return scm_i_clonebig (z, 0);
7268 else
7269 return z;
5986c47d 7270 }
0aacf84e 7271 else if (SCM_REALP (z))
55f26379 7272 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 7273 else if (SCM_COMPLEXP (z))
55f26379 7274 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
7275 else if (SCM_FRACTIONP (z))
7276 {
73e4de09 7277 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 7278 return z;
cba42c93 7279 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
7280 SCM_FRACTION_DENOMINATOR (z));
7281 }
0aacf84e 7282 else
2519490c 7283 SCM_WTA_DISPATCH_1 (g_scm_magnitude, z, SCM_ARG1, s_scm_magnitude);
0f2d19dd 7284}
2519490c 7285#undef FUNC_NAME
0f2d19dd
JB
7286
7287
2519490c
MW
7288SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
7289 (SCM z),
7290 "Return the angle of the complex number @var{z}.")
7291#define FUNC_NAME s_scm_angle
0f2d19dd 7292{
c8ae173e 7293 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
e7efe8e7 7294 flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
7295 But if atan2 follows the floating point rounding mode, then the value
7296 is not a constant. Maybe it'd be close enough though. */
e11e83f3 7297 if (SCM_I_INUMP (z))
0aacf84e 7298 {
e11e83f3 7299 if (SCM_I_INUM (z) >= 0)
e7efe8e7 7300 return flo0;
0aacf84e 7301 else
55f26379 7302 return scm_from_double (atan2 (0.0, -1.0));
f872b822 7303 }
0aacf84e
MD
7304 else if (SCM_BIGP (z))
7305 {
7306 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
7307 scm_remember_upto_here_1 (z);
7308 if (sgn < 0)
55f26379 7309 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 7310 else
e7efe8e7 7311 return flo0;
0f2d19dd 7312 }
0aacf84e 7313 else if (SCM_REALP (z))
c8ae173e
KR
7314 {
7315 if (SCM_REAL_VALUE (z) >= 0)
e7efe8e7 7316 return flo0;
c8ae173e 7317 else
55f26379 7318 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 7319 }
0aacf84e 7320 else if (SCM_COMPLEXP (z))
55f26379 7321 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
7322 else if (SCM_FRACTIONP (z))
7323 {
73e4de09 7324 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
e7efe8e7 7325 return flo0;
55f26379 7326 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 7327 }
0aacf84e 7328 else
2519490c 7329 SCM_WTA_DISPATCH_1 (g_scm_angle, z, SCM_ARG1, s_scm_angle);
0f2d19dd 7330}
2519490c 7331#undef FUNC_NAME
0f2d19dd
JB
7332
7333
2519490c
MW
7334SCM_PRIMITIVE_GENERIC (scm_exact_to_inexact, "exact->inexact", 1, 0, 0,
7335 (SCM z),
7336 "Convert the number @var{z} to its inexact representation.\n")
7337#define FUNC_NAME s_scm_exact_to_inexact
3c9a524f 7338{
e11e83f3 7339 if (SCM_I_INUMP (z))
55f26379 7340 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 7341 else if (SCM_BIGP (z))
55f26379 7342 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 7343 else if (SCM_FRACTIONP (z))
55f26379 7344 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
7345 else if (SCM_INEXACTP (z))
7346 return z;
7347 else
2519490c 7348 SCM_WTA_DISPATCH_1 (g_scm_exact_to_inexact, z, 1, s_scm_exact_to_inexact);
3c9a524f 7349}
2519490c 7350#undef FUNC_NAME
3c9a524f
DH
7351
7352
2519490c
MW
7353SCM_PRIMITIVE_GENERIC (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
7354 (SCM z),
7355 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 7356#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 7357{
c7218482 7358 if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f872b822 7359 return z;
c7218482 7360 else
0aacf84e 7361 {
c7218482
MW
7362 double val;
7363
7364 if (SCM_REALP (z))
7365 val = SCM_REAL_VALUE (z);
7366 else if (SCM_COMPLEXP (z) && SCM_COMPLEX_IMAG (z) == 0.0)
7367 val = SCM_COMPLEX_REAL (z);
7368 else
7369 SCM_WTA_DISPATCH_1 (g_scm_inexact_to_exact, z, 1, s_scm_inexact_to_exact);
7370
7371 if (!SCM_LIKELY (DOUBLE_IS_FINITE (val)))
f92e85f7 7372 SCM_OUT_OF_RANGE (1, z);
2be24db4 7373 else
f92e85f7
MV
7374 {
7375 mpq_t frac;
7376 SCM q;
7377
7378 mpq_init (frac);
c7218482 7379 mpq_set_d (frac, val);
cba42c93 7380 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
c7218482 7381 scm_i_mpz2num (mpq_denref (frac)));
f92e85f7 7382
cba42c93 7383 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
7384 for frac...
7385 */
7386 mpq_clear (frac);
7387 return q;
7388 }
c2ff8ab0 7389 }
0f2d19dd 7390}
1bbd0b84 7391#undef FUNC_NAME
0f2d19dd 7392
f92e85f7 7393SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
76dae881
NJ
7394 (SCM x, SCM eps),
7395 "Returns the @emph{simplest} rational number differing\n"
7396 "from @var{x} by no more than @var{eps}.\n"
7397 "\n"
7398 "As required by @acronym{R5RS}, @code{rationalize} only returns an\n"
7399 "exact result when both its arguments are exact. Thus, you might need\n"
7400 "to use @code{inexact->exact} on the arguments.\n"
7401 "\n"
7402 "@lisp\n"
7403 "(rationalize (inexact->exact 1.2) 1/100)\n"
7404 "@result{} 6/5\n"
7405 "@end lisp")
f92e85f7
MV
7406#define FUNC_NAME s_scm_rationalize
7407{
605f6980
MW
7408 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
7409 SCM_ASSERT_TYPE (scm_is_real (eps), eps, SCM_ARG2, FUNC_NAME, "real");
7410 eps = scm_abs (eps);
7411 if (scm_is_false (scm_positive_p (eps)))
7412 {
7413 /* eps is either zero or a NaN */
7414 if (scm_is_true (scm_nan_p (eps)))
7415 return scm_nan ();
7416 else if (SCM_INEXACTP (eps))
7417 return scm_exact_to_inexact (x);
7418 else
7419 return x;
7420 }
7421 else if (scm_is_false (scm_finite_p (eps)))
7422 {
7423 if (scm_is_true (scm_finite_p (x)))
7424 return flo0;
7425 else
7426 return scm_nan ();
7427 }
7428 else if (scm_is_false (scm_finite_p (x))) /* checks for both inf and nan */
f92e85f7 7429 return x;
605f6980
MW
7430 else if (scm_is_false (scm_less_p (scm_floor (scm_sum (x, eps)),
7431 scm_ceiling (scm_difference (x, eps)))))
7432 {
7433 /* There's an integer within range; we want the one closest to zero */
7434 if (scm_is_false (scm_less_p (eps, scm_abs (x))))
7435 {
7436 /* zero is within range */
7437 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
7438 return flo0;
7439 else
7440 return SCM_INUM0;
7441 }
7442 else if (scm_is_true (scm_positive_p (x)))
7443 return scm_ceiling (scm_difference (x, eps));
7444 else
7445 return scm_floor (scm_sum (x, eps));
7446 }
7447 else
f92e85f7
MV
7448 {
7449 /* Use continued fractions to find closest ratio. All
7450 arithmetic is done with exact numbers.
7451 */
7452
7453 SCM ex = scm_inexact_to_exact (x);
7454 SCM int_part = scm_floor (ex);
cff5fa33
MW
7455 SCM tt = SCM_INUM1;
7456 SCM a1 = SCM_INUM0, a2 = SCM_INUM1, a = SCM_INUM0;
7457 SCM b1 = SCM_INUM1, b2 = SCM_INUM0, b = SCM_INUM0;
f92e85f7
MV
7458 SCM rx;
7459 int i = 0;
7460
f92e85f7
MV
7461 ex = scm_difference (ex, int_part); /* x = x-int_part */
7462 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
7463
7464 /* We stop after a million iterations just to be absolutely sure
7465 that we don't go into an infinite loop. The process normally
7466 converges after less than a dozen iterations.
7467 */
7468
f92e85f7
MV
7469 while (++i < 1000000)
7470 {
7471 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
7472 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
7473 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
7474 scm_is_false
f92e85f7 7475 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
76dae881 7476 eps))) /* abs(x-a/b) <= eps */
02164269
MV
7477 {
7478 SCM res = scm_sum (int_part, scm_divide (a, b));
605f6980 7479 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
02164269
MV
7480 return scm_exact_to_inexact (res);
7481 else
7482 return res;
7483 }
f92e85f7
MV
7484 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
7485 SCM_UNDEFINED);
7486 tt = scm_floor (rx); /* tt = floor (rx) */
7487 a2 = a1;
7488 b2 = b1;
7489 a1 = a;
7490 b1 = b;
7491 }
7492 scm_num_overflow (s_scm_rationalize);
7493 }
f92e85f7
MV
7494}
7495#undef FUNC_NAME
7496
73e4de09
MV
7497/* conversion functions */
7498
7499int
7500scm_is_integer (SCM val)
7501{
7502 return scm_is_true (scm_integer_p (val));
7503}
7504
7505int
7506scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
7507{
e11e83f3 7508 if (SCM_I_INUMP (val))
73e4de09 7509 {
e11e83f3 7510 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
7511 return n >= min && n <= max;
7512 }
7513 else if (SCM_BIGP (val))
7514 {
7515 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
7516 return 0;
7517 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
7518 {
7519 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
7520 {
7521 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
7522 return n >= min && n <= max;
7523 }
7524 else
7525 return 0;
7526 }
73e4de09
MV
7527 else
7528 {
d956fa6f
MV
7529 scm_t_intmax n;
7530 size_t count;
73e4de09 7531
d956fa6f
MV
7532 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
7533 > CHAR_BIT*sizeof (scm_t_uintmax))
7534 return 0;
7535
7536 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
7537 SCM_I_BIG_MPZ (val));
73e4de09 7538
d956fa6f 7539 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 7540 {
d956fa6f
MV
7541 if (n < 0)
7542 return 0;
73e4de09 7543 }
73e4de09
MV
7544 else
7545 {
d956fa6f
MV
7546 n = -n;
7547 if (n >= 0)
7548 return 0;
73e4de09 7549 }
d956fa6f
MV
7550
7551 return n >= min && n <= max;
73e4de09
MV
7552 }
7553 }
73e4de09
MV
7554 else
7555 return 0;
7556}
7557
7558int
7559scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
7560{
e11e83f3 7561 if (SCM_I_INUMP (val))
73e4de09 7562 {
e11e83f3 7563 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
7564 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
7565 }
7566 else if (SCM_BIGP (val))
7567 {
7568 if (max <= SCM_MOST_POSITIVE_FIXNUM)
7569 return 0;
7570 else if (max <= ULONG_MAX)
d956fa6f
MV
7571 {
7572 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
7573 {
7574 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
7575 return n >= min && n <= max;
7576 }
7577 else
7578 return 0;
7579 }
73e4de09
MV
7580 else
7581 {
d956fa6f
MV
7582 scm_t_uintmax n;
7583 size_t count;
73e4de09 7584
d956fa6f
MV
7585 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
7586 return 0;
73e4de09 7587
d956fa6f
MV
7588 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
7589 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 7590 return 0;
d956fa6f
MV
7591
7592 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
7593 SCM_I_BIG_MPZ (val));
73e4de09 7594
d956fa6f 7595 return n >= min && n <= max;
73e4de09
MV
7596 }
7597 }
73e4de09
MV
7598 else
7599 return 0;
7600}
7601
1713d319
MV
7602static void
7603scm_i_range_error (SCM bad_val, SCM min, SCM max)
7604{
7605 scm_error (scm_out_of_range_key,
7606 NULL,
7607 "Value out of range ~S to ~S: ~S",
7608 scm_list_3 (min, max, bad_val),
7609 scm_list_1 (bad_val));
7610}
7611
bfd7932e
MV
7612#define TYPE scm_t_intmax
7613#define TYPE_MIN min
7614#define TYPE_MAX max
7615#define SIZEOF_TYPE 0
7616#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
7617#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
7618#include "libguile/conv-integer.i.c"
7619
7620#define TYPE scm_t_uintmax
7621#define TYPE_MIN min
7622#define TYPE_MAX max
7623#define SIZEOF_TYPE 0
7624#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
7625#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
7626#include "libguile/conv-uinteger.i.c"
7627
7628#define TYPE scm_t_int8
7629#define TYPE_MIN SCM_T_INT8_MIN
7630#define TYPE_MAX SCM_T_INT8_MAX
7631#define SIZEOF_TYPE 1
7632#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
7633#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
7634#include "libguile/conv-integer.i.c"
7635
7636#define TYPE scm_t_uint8
7637#define TYPE_MIN 0
7638#define TYPE_MAX SCM_T_UINT8_MAX
7639#define SIZEOF_TYPE 1
7640#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
7641#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
7642#include "libguile/conv-uinteger.i.c"
7643
7644#define TYPE scm_t_int16
7645#define TYPE_MIN SCM_T_INT16_MIN
7646#define TYPE_MAX SCM_T_INT16_MAX
7647#define SIZEOF_TYPE 2
7648#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
7649#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
7650#include "libguile/conv-integer.i.c"
7651
7652#define TYPE scm_t_uint16
7653#define TYPE_MIN 0
7654#define TYPE_MAX SCM_T_UINT16_MAX
7655#define SIZEOF_TYPE 2
7656#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
7657#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
7658#include "libguile/conv-uinteger.i.c"
7659
7660#define TYPE scm_t_int32
7661#define TYPE_MIN SCM_T_INT32_MIN
7662#define TYPE_MAX SCM_T_INT32_MAX
7663#define SIZEOF_TYPE 4
7664#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
7665#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
7666#include "libguile/conv-integer.i.c"
7667
7668#define TYPE scm_t_uint32
7669#define TYPE_MIN 0
7670#define TYPE_MAX SCM_T_UINT32_MAX
7671#define SIZEOF_TYPE 4
7672#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
7673#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
7674#include "libguile/conv-uinteger.i.c"
7675
904a78f1
MG
7676#define TYPE scm_t_wchar
7677#define TYPE_MIN (scm_t_int32)-1
7678#define TYPE_MAX (scm_t_int32)0x10ffff
7679#define SIZEOF_TYPE 4
7680#define SCM_TO_TYPE_PROTO(arg) scm_to_wchar (arg)
7681#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
7682#include "libguile/conv-integer.i.c"
7683
bfd7932e
MV
7684#define TYPE scm_t_int64
7685#define TYPE_MIN SCM_T_INT64_MIN
7686#define TYPE_MAX SCM_T_INT64_MAX
7687#define SIZEOF_TYPE 8
7688#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
7689#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
7690#include "libguile/conv-integer.i.c"
7691
7692#define TYPE scm_t_uint64
7693#define TYPE_MIN 0
7694#define TYPE_MAX SCM_T_UINT64_MAX
7695#define SIZEOF_TYPE 8
7696#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
7697#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
7698#include "libguile/conv-uinteger.i.c"
73e4de09 7699
cd036260
MV
7700void
7701scm_to_mpz (SCM val, mpz_t rop)
7702{
7703 if (SCM_I_INUMP (val))
7704 mpz_set_si (rop, SCM_I_INUM (val));
7705 else if (SCM_BIGP (val))
7706 mpz_set (rop, SCM_I_BIG_MPZ (val));
7707 else
7708 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
7709}
7710
7711SCM
7712scm_from_mpz (mpz_t val)
7713{
7714 return scm_i_mpz2num (val);
7715}
7716
73e4de09
MV
7717int
7718scm_is_real (SCM val)
7719{
7720 return scm_is_true (scm_real_p (val));
7721}
7722
55f26379
MV
7723int
7724scm_is_rational (SCM val)
7725{
7726 return scm_is_true (scm_rational_p (val));
7727}
7728
73e4de09
MV
7729double
7730scm_to_double (SCM val)
7731{
55f26379
MV
7732 if (SCM_I_INUMP (val))
7733 return SCM_I_INUM (val);
7734 else if (SCM_BIGP (val))
7735 return scm_i_big2dbl (val);
7736 else if (SCM_FRACTIONP (val))
7737 return scm_i_fraction2double (val);
7738 else if (SCM_REALP (val))
7739 return SCM_REAL_VALUE (val);
7740 else
7a1aba42 7741 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
7742}
7743
7744SCM
7745scm_from_double (double val)
7746{
978c52d1
LC
7747 SCM z;
7748
7749 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
7750
7751 SCM_SET_CELL_TYPE (z, scm_tc16_real);
55f26379 7752 SCM_REAL_VALUE (z) = val;
978c52d1 7753
55f26379 7754 return z;
73e4de09
MV
7755}
7756
220058a8 7757#if SCM_ENABLE_DEPRECATED == 1
55f26379
MV
7758
7759float
e25f3727 7760scm_num2float (SCM num, unsigned long pos, const char *s_caller)
55f26379 7761{
220058a8
AW
7762 scm_c_issue_deprecation_warning
7763 ("`scm_num2float' is deprecated. Use scm_to_double instead.");
7764
55f26379
MV
7765 if (SCM_BIGP (num))
7766 {
7767 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 7768 if (!isinf (res))
55f26379
MV
7769 return res;
7770 else
7771 scm_out_of_range (NULL, num);
7772 }
7773 else
7774 return scm_to_double (num);
7775}
7776
7777double
e25f3727 7778scm_num2double (SCM num, unsigned long pos, const char *s_caller)
55f26379 7779{
220058a8
AW
7780 scm_c_issue_deprecation_warning
7781 ("`scm_num2double' is deprecated. Use scm_to_double instead.");
7782
55f26379
MV
7783 if (SCM_BIGP (num))
7784 {
7785 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 7786 if (!isinf (res))
55f26379
MV
7787 return res;
7788 else
7789 scm_out_of_range (NULL, num);
7790 }
7791 else
7792 return scm_to_double (num);
7793}
7794
7795#endif
7796
8507ec80
MV
7797int
7798scm_is_complex (SCM val)
7799{
7800 return scm_is_true (scm_complex_p (val));
7801}
7802
7803double
7804scm_c_real_part (SCM z)
7805{
7806 if (SCM_COMPLEXP (z))
7807 return SCM_COMPLEX_REAL (z);
7808 else
7809 {
7810 /* Use the scm_real_part to get proper error checking and
7811 dispatching.
7812 */
7813 return scm_to_double (scm_real_part (z));
7814 }
7815}
7816
7817double
7818scm_c_imag_part (SCM z)
7819{
7820 if (SCM_COMPLEXP (z))
7821 return SCM_COMPLEX_IMAG (z);
7822 else
7823 {
7824 /* Use the scm_imag_part to get proper error checking and
7825 dispatching. The result will almost always be 0.0, but not
7826 always.
7827 */
7828 return scm_to_double (scm_imag_part (z));
7829 }
7830}
7831
7832double
7833scm_c_magnitude (SCM z)
7834{
7835 return scm_to_double (scm_magnitude (z));
7836}
7837
7838double
7839scm_c_angle (SCM z)
7840{
7841 return scm_to_double (scm_angle (z));
7842}
7843
7844int
7845scm_is_number (SCM z)
7846{
7847 return scm_is_true (scm_number_p (z));
7848}
7849
8ab3d8a0
KR
7850
7851/* In the following functions we dispatch to the real-arg funcs like log()
7852 when we know the arg is real, instead of just handing everything to
7853 clog() for instance. This is in case clog() doesn't optimize for a
7854 real-only case, and because we have to test SCM_COMPLEXP anyway so may as
7855 well use it to go straight to the applicable C func. */
7856
2519490c
MW
7857SCM_PRIMITIVE_GENERIC (scm_log, "log", 1, 0, 0,
7858 (SCM z),
7859 "Return the natural logarithm of @var{z}.")
8ab3d8a0
KR
7860#define FUNC_NAME s_scm_log
7861{
7862 if (SCM_COMPLEXP (z))
7863 {
4b26c03e 7864#if HAVE_COMPLEX_DOUBLE && HAVE_CLOG && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
7865 return scm_from_complex_double (clog (SCM_COMPLEX_VALUE (z)));
7866#else
7867 double re = SCM_COMPLEX_REAL (z);
7868 double im = SCM_COMPLEX_IMAG (z);
7869 return scm_c_make_rectangular (log (hypot (re, im)),
7870 atan2 (im, re));
7871#endif
7872 }
2519490c 7873 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7874 {
7875 /* ENHANCE-ME: When z is a bignum the logarithm will fit a double
7876 although the value itself overflows. */
7877 double re = scm_to_double (z);
7878 double l = log (fabs (re));
7879 if (re >= 0.0)
7880 return scm_from_double (l);
7881 else
7882 return scm_c_make_rectangular (l, M_PI);
7883 }
2519490c
MW
7884 else
7885 SCM_WTA_DISPATCH_1 (g_scm_log, z, 1, s_scm_log);
8ab3d8a0
KR
7886}
7887#undef FUNC_NAME
7888
7889
2519490c
MW
7890SCM_PRIMITIVE_GENERIC (scm_log10, "log10", 1, 0, 0,
7891 (SCM z),
7892 "Return the base 10 logarithm of @var{z}.")
8ab3d8a0
KR
7893#define FUNC_NAME s_scm_log10
7894{
7895 if (SCM_COMPLEXP (z))
7896 {
7897 /* Mingw has clog() but not clog10(). (Maybe it'd be worth using
7898 clog() and a multiply by M_LOG10E, rather than the fallback
7899 log10+hypot+atan2.) */
f328f862
LC
7900#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
7901 && defined SCM_COMPLEX_VALUE
8ab3d8a0
KR
7902 return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
7903#else
7904 double re = SCM_COMPLEX_REAL (z);
7905 double im = SCM_COMPLEX_IMAG (z);
7906 return scm_c_make_rectangular (log10 (hypot (re, im)),
7907 M_LOG10E * atan2 (im, re));
7908#endif
7909 }
2519490c 7910 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7911 {
7912 /* ENHANCE-ME: When z is a bignum the logarithm will fit a double
7913 although the value itself overflows. */
7914 double re = scm_to_double (z);
7915 double l = log10 (fabs (re));
7916 if (re >= 0.0)
7917 return scm_from_double (l);
7918 else
7919 return scm_c_make_rectangular (l, M_LOG10E * M_PI);
7920 }
2519490c
MW
7921 else
7922 SCM_WTA_DISPATCH_1 (g_scm_log10, z, 1, s_scm_log10);
8ab3d8a0
KR
7923}
7924#undef FUNC_NAME
7925
7926
2519490c
MW
7927SCM_PRIMITIVE_GENERIC (scm_exp, "exp", 1, 0, 0,
7928 (SCM z),
7929 "Return @math{e} to the power of @var{z}, where @math{e} is the\n"
7930 "base of natural logarithms (2.71828@dots{}).")
8ab3d8a0
KR
7931#define FUNC_NAME s_scm_exp
7932{
7933 if (SCM_COMPLEXP (z))
7934 {
4b26c03e 7935#if HAVE_COMPLEX_DOUBLE && HAVE_CEXP && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
7936 return scm_from_complex_double (cexp (SCM_COMPLEX_VALUE (z)));
7937#else
7938 return scm_c_make_polar (exp (SCM_COMPLEX_REAL (z)),
7939 SCM_COMPLEX_IMAG (z));
7940#endif
7941 }
2519490c 7942 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7943 {
7944 /* When z is a negative bignum the conversion to double overflows,
7945 giving -infinity, but that's ok, the exp is still 0.0. */
7946 return scm_from_double (exp (scm_to_double (z)));
7947 }
2519490c
MW
7948 else
7949 SCM_WTA_DISPATCH_1 (g_scm_exp, z, 1, s_scm_exp);
8ab3d8a0
KR
7950}
7951#undef FUNC_NAME
7952
7953
2519490c
MW
7954SCM_PRIMITIVE_GENERIC (scm_sqrt, "sqrt", 1, 0, 0,
7955 (SCM z),
7956 "Return the square root of @var{z}. Of the two possible roots\n"
7957 "(positive and negative), the one with the a positive real part\n"
7958 "is returned, or if that's zero then a positive imaginary part.\n"
7959 "Thus,\n"
7960 "\n"
7961 "@example\n"
7962 "(sqrt 9.0) @result{} 3.0\n"
7963 "(sqrt -9.0) @result{} 0.0+3.0i\n"
7964 "(sqrt 1.0+1.0i) @result{} 1.09868411346781+0.455089860562227i\n"
7965 "(sqrt -1.0-1.0i) @result{} 0.455089860562227-1.09868411346781i\n"
7966 "@end example")
8ab3d8a0
KR
7967#define FUNC_NAME s_scm_sqrt
7968{
2519490c 7969 if (SCM_COMPLEXP (z))
8ab3d8a0 7970 {
f328f862
LC
7971#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT \
7972 && defined SCM_COMPLEX_VALUE
2519490c 7973 return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (z)));
8ab3d8a0 7974#else
2519490c
MW
7975 double re = SCM_COMPLEX_REAL (z);
7976 double im = SCM_COMPLEX_IMAG (z);
8ab3d8a0
KR
7977 return scm_c_make_polar (sqrt (hypot (re, im)),
7978 0.5 * atan2 (im, re));
7979#endif
7980 }
2519490c 7981 else if (SCM_NUMBERP (z))
8ab3d8a0 7982 {
2519490c 7983 double xx = scm_to_double (z);
8ab3d8a0
KR
7984 if (xx < 0)
7985 return scm_c_make_rectangular (0.0, sqrt (-xx));
7986 else
7987 return scm_from_double (sqrt (xx));
7988 }
2519490c
MW
7989 else
7990 SCM_WTA_DISPATCH_1 (g_scm_sqrt, z, 1, s_scm_sqrt);
8ab3d8a0
KR
7991}
7992#undef FUNC_NAME
7993
7994
7995
0f2d19dd
JB
7996void
7997scm_init_numbers ()
0f2d19dd 7998{
0b799eea
MV
7999 int i;
8000
713a4259
KR
8001 mpz_init_set_si (z_negative_one, -1);
8002
a261c0e9
DH
8003 /* It may be possible to tune the performance of some algorithms by using
8004 * the following constants to avoid the creation of bignums. Please, before
8005 * using these values, remember the two rules of program optimization:
8006 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 8007 scm_c_define ("most-positive-fixnum",
d956fa6f 8008 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 8009 scm_c_define ("most-negative-fixnum",
d956fa6f 8010 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 8011
f3ae5d60
MD
8012 scm_add_feature ("complex");
8013 scm_add_feature ("inexact");
e7efe8e7 8014 flo0 = scm_from_double (0.0);
0b799eea
MV
8015
8016 /* determine floating point precision */
55f26379 8017 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
8018 {
8019 init_dblprec(&scm_dblprec[i-2],i);
8020 init_fx_radix(fx_per_radix[i-2],i);
8021 }
f872b822 8022#ifdef DBL_DIG
0b799eea 8023 /* hard code precision for base 10 if the preprocessor tells us to... */
f39448c5 8024 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
0b799eea 8025#endif
1be6b49c 8026
cff5fa33 8027 exactly_one_half = scm_divide (SCM_INUM1, SCM_I_MAKINUM (2));
a0599745 8028#include "libguile/numbers.x"
0f2d19dd 8029}
89e00824
ML
8030
8031/*
8032 Local Variables:
8033 c-file-style: "gnu"
8034 End:
8035*/