Add comment about handling of exactness specifiers
[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:
bc3d34f5 3837 *
3c9a524f
DH
3838 * * Each function keeps a local index variable 'idx' that points at the
3839 * current position within the parsed string. The global index is only
3840 * updated if the function could parse the corresponding syntactic unit
3841 * successfully.
bc3d34f5 3842 *
3c9a524f 3843 * * Similarly, the functions keep track of indicators of inexactness ('#',
bc3d34f5
MW
3844 * '.' or exponents) using local variables ('hash_seen', 'x').
3845 *
3c9a524f
DH
3846 * * Sequences of digits are parsed into temporary variables holding fixnums.
3847 * Only if these fixnums would overflow, the result variables are updated
3848 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
3849 * the temporary variables holding the fixnums are cleared, and the process
3850 * starts over again. If for example fixnums were able to store five decimal
3851 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
3852 * and the result was computed as 12345 * 100000 + 67890. In other words,
3853 * only every five digits two bignum operations were performed.
bc3d34f5
MW
3854 *
3855 * Notes on the handling of exactness specifiers:
3856 *
3857 * When parsing non-real complex numbers, we apply exactness specifiers on
3858 * per-component basis, as is done in PLT Scheme. For complex numbers
3859 * written in rectangular form, exactness specifiers are applied to the
3860 * real and imaginary parts before calling scm_make_rectangular. For
3861 * complex numbers written in polar form, exactness specifiers are applied
3862 * to the magnitude and angle before calling scm_make_polar.
3863 *
3864 * There are two kinds of exactness specifiers: forced and implicit. A
3865 * forced exactness specifier is a "#e" or "#i" prefix at the beginning of
3866 * the entire number, and applies to both components of a complex number.
3867 * "#e" causes each component to be made exact, and "#i" causes each
3868 * component to be made inexact. If no forced exactness specifier is
3869 * present, then the exactness of each component is determined
3870 * independently by the presence or absence of a decimal point or hash mark
3871 * within that component. If a decimal point or hash mark is present, the
3872 * component is made inexact, otherwise it is made exact.
3873 *
3874 * After the exactness specifiers have been applied to each component, they
3875 * are passed to either scm_make_rectangular or scm_make_polar to produce
3876 * the final result. Note that this will result in a real number if the
3877 * imaginary part, magnitude, or angle is an exact 0.
3878 *
3879 * For example, (string->number "#i5.0+0i") does the equivalent of:
3880 *
3881 * (make-rectangular (exact->inexact 5) (exact->inexact 0))
3c9a524f
DH
3882 */
3883
3884enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
3885
3886/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
3887
a6f3af16
AW
3888/* Caller is responsible for checking that the return value is in range
3889 for the given radix, which should be <= 36. */
3890static unsigned int
3891char_decimal_value (scm_t_uint32 c)
3892{
3893 /* uc_decimal_value returns -1 on error. When cast to an unsigned int,
3894 that's certainly above any valid decimal, so we take advantage of
3895 that to elide some tests. */
3896 unsigned int d = (unsigned int) uc_decimal_value (c);
3897
3898 /* If that failed, try extended hexadecimals, then. Only accept ascii
3899 hexadecimals. */
3900 if (d >= 10U)
3901 {
3902 c = uc_tolower (c);
3903 if (c >= (scm_t_uint32) 'a')
3904 d = c - (scm_t_uint32)'a' + 10U;
3905 }
3906 return d;
3907}
3c9a524f 3908
2a8fecee 3909static SCM
3f47e526 3910mem2uinteger (SCM mem, unsigned int *p_idx,
3c9a524f 3911 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 3912{
3c9a524f
DH
3913 unsigned int idx = *p_idx;
3914 unsigned int hash_seen = 0;
3915 scm_t_bits shift = 1;
3916 scm_t_bits add = 0;
3917 unsigned int digit_value;
3918 SCM result;
3919 char c;
3f47e526 3920 size_t len = scm_i_string_length (mem);
3c9a524f
DH
3921
3922 if (idx == len)
3923 return SCM_BOOL_F;
2a8fecee 3924
3f47e526 3925 c = scm_i_string_ref (mem, idx);
a6f3af16 3926 digit_value = char_decimal_value (c);
3c9a524f
DH
3927 if (digit_value >= radix)
3928 return SCM_BOOL_F;
3929
3930 idx++;
d956fa6f 3931 result = SCM_I_MAKINUM (digit_value);
3c9a524f 3932 while (idx != len)
f872b822 3933 {
3f47e526 3934 scm_t_wchar c = scm_i_string_ref (mem, idx);
a6f3af16 3935 if (c == '#')
3c9a524f
DH
3936 {
3937 hash_seen = 1;
3938 digit_value = 0;
3939 }
a6f3af16
AW
3940 else if (hash_seen)
3941 break;
3c9a524f 3942 else
a6f3af16
AW
3943 {
3944 digit_value = char_decimal_value (c);
3945 /* This check catches non-decimals in addition to out-of-range
3946 decimals. */
3947 if (digit_value >= radix)
3948 break;
3949 }
3c9a524f
DH
3950
3951 idx++;
3952 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
3953 {
d956fa6f 3954 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 3955 if (add > 0)
d956fa6f 3956 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
3957
3958 shift = radix;
3959 add = digit_value;
3960 }
3961 else
3962 {
3963 shift = shift * radix;
3964 add = add * radix + digit_value;
3965 }
3966 };
3967
3968 if (shift > 1)
d956fa6f 3969 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 3970 if (add > 0)
d956fa6f 3971 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
3972
3973 *p_idx = idx;
3974 if (hash_seen)
3975 *p_exactness = INEXACT;
3976
3977 return result;
2a8fecee
JB
3978}
3979
3980
3c9a524f
DH
3981/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
3982 * covers the parts of the rules that start at a potential point. The value
3983 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
3984 * in variable result. The content of *p_exactness indicates, whether a hash
3985 * has already been seen in the digits before the point.
3c9a524f 3986 */
1cc91f1b 3987
3f47e526 3988#define DIGIT2UINT(d) (uc_numeric_value(d).numerator)
3c9a524f
DH
3989
3990static SCM
3f47e526 3991mem2decimal_from_point (SCM result, SCM mem,
3c9a524f 3992 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 3993{
3c9a524f
DH
3994 unsigned int idx = *p_idx;
3995 enum t_exactness x = *p_exactness;
3f47e526 3996 size_t len = scm_i_string_length (mem);
3c9a524f
DH
3997
3998 if (idx == len)
79d34f68 3999 return result;
3c9a524f 4000
3f47e526 4001 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
4002 {
4003 scm_t_bits shift = 1;
4004 scm_t_bits add = 0;
4005 unsigned int digit_value;
cff5fa33 4006 SCM big_shift = SCM_INUM1;
3c9a524f
DH
4007
4008 idx++;
4009 while (idx != len)
4010 {
3f47e526
MG
4011 scm_t_wchar c = scm_i_string_ref (mem, idx);
4012 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
4013 {
4014 if (x == INEXACT)
4015 return SCM_BOOL_F;
4016 else
4017 digit_value = DIGIT2UINT (c);
4018 }
4019 else if (c == '#')
4020 {
4021 x = INEXACT;
4022 digit_value = 0;
4023 }
4024 else
4025 break;
4026
4027 idx++;
4028 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
4029 {
d956fa6f
MV
4030 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
4031 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 4032 if (add > 0)
d956fa6f 4033 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
4034
4035 shift = 10;
4036 add = digit_value;
4037 }
4038 else
4039 {
4040 shift = shift * 10;
4041 add = add * 10 + digit_value;
4042 }
4043 };
4044
4045 if (add > 0)
4046 {
d956fa6f
MV
4047 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
4048 result = scm_product (result, SCM_I_MAKINUM (shift));
4049 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
4050 }
4051
d8592269 4052 result = scm_divide (result, big_shift);
79d34f68 4053
3c9a524f
DH
4054 /* We've seen a decimal point, thus the value is implicitly inexact. */
4055 x = INEXACT;
f872b822 4056 }
3c9a524f 4057
3c9a524f 4058 if (idx != len)
f872b822 4059 {
3c9a524f
DH
4060 int sign = 1;
4061 unsigned int start;
3f47e526 4062 scm_t_wchar c;
3c9a524f
DH
4063 int exponent;
4064 SCM e;
4065
4066 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
4067
3f47e526 4068 switch (scm_i_string_ref (mem, idx))
f872b822 4069 {
3c9a524f
DH
4070 case 'd': case 'D':
4071 case 'e': case 'E':
4072 case 'f': case 'F':
4073 case 'l': case 'L':
4074 case 's': case 'S':
4075 idx++;
ee0ddd21
AW
4076 if (idx == len)
4077 return SCM_BOOL_F;
4078
3c9a524f 4079 start = idx;
3f47e526 4080 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4081 if (c == '-')
4082 {
4083 idx++;
ee0ddd21
AW
4084 if (idx == len)
4085 return SCM_BOOL_F;
4086
3c9a524f 4087 sign = -1;
3f47e526 4088 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4089 }
4090 else if (c == '+')
4091 {
4092 idx++;
ee0ddd21
AW
4093 if (idx == len)
4094 return SCM_BOOL_F;
4095
3c9a524f 4096 sign = 1;
3f47e526 4097 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4098 }
4099 else
4100 sign = 1;
4101
3f47e526 4102 if (!uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
4103 return SCM_BOOL_F;
4104
4105 idx++;
4106 exponent = DIGIT2UINT (c);
4107 while (idx != len)
f872b822 4108 {
3f47e526
MG
4109 scm_t_wchar c = scm_i_string_ref (mem, idx);
4110 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
4111 {
4112 idx++;
4113 if (exponent <= SCM_MAXEXP)
4114 exponent = exponent * 10 + DIGIT2UINT (c);
4115 }
4116 else
4117 break;
f872b822 4118 }
3c9a524f
DH
4119
4120 if (exponent > SCM_MAXEXP)
f872b822 4121 {
3c9a524f 4122 size_t exp_len = idx - start;
3f47e526 4123 SCM exp_string = scm_i_substring_copy (mem, start, start + exp_len);
3c9a524f
DH
4124 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
4125 scm_out_of_range ("string->number", exp_num);
f872b822 4126 }
3c9a524f 4127
d956fa6f 4128 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
4129 if (sign == 1)
4130 result = scm_product (result, e);
4131 else
f92e85f7 4132 result = scm_divide2real (result, e);
3c9a524f
DH
4133
4134 /* We've seen an exponent, thus the value is implicitly inexact. */
4135 x = INEXACT;
4136
f872b822 4137 break;
3c9a524f 4138
f872b822 4139 default:
3c9a524f 4140 break;
f872b822 4141 }
0f2d19dd 4142 }
3c9a524f
DH
4143
4144 *p_idx = idx;
4145 if (x == INEXACT)
4146 *p_exactness = x;
4147
4148 return result;
0f2d19dd 4149}
0f2d19dd 4150
3c9a524f
DH
4151
4152/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
4153
4154static SCM
3f47e526 4155mem2ureal (SCM mem, unsigned int *p_idx,
9d427b2c 4156 unsigned int radix, enum t_exactness forced_x)
0f2d19dd 4157{
3c9a524f 4158 unsigned int idx = *p_idx;
164d2481 4159 SCM result;
3f47e526 4160 size_t len = scm_i_string_length (mem);
3c9a524f 4161
40f89215
NJ
4162 /* Start off believing that the number will be exact. This changes
4163 to INEXACT if we see a decimal point or a hash. */
9d427b2c 4164 enum t_exactness implicit_x = EXACT;
40f89215 4165
3c9a524f
DH
4166 if (idx == len)
4167 return SCM_BOOL_F;
4168
3f47e526 4169 if (idx+5 <= len && !scm_i_string_strcmp (mem, idx, "inf.0"))
7351e207
MV
4170 {
4171 *p_idx = idx+5;
4172 return scm_inf ();
4173 }
4174
3f47e526 4175 if (idx+4 < len && !scm_i_string_strcmp (mem, idx, "nan."))
7351e207 4176 {
d8592269
MV
4177 /* Cobble up the fractional part. We might want to set the
4178 NaN's mantissa from it. */
7351e207 4179 idx += 4;
9d427b2c 4180 mem2uinteger (mem, &idx, 10, &implicit_x);
7351e207
MV
4181 *p_idx = idx;
4182 return scm_nan ();
4183 }
4184
3f47e526 4185 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
4186 {
4187 if (radix != 10)
4188 return SCM_BOOL_F;
4189 else if (idx + 1 == len)
4190 return SCM_BOOL_F;
3f47e526 4191 else if (!uc_is_property_decimal_digit ((scm_t_uint32) scm_i_string_ref (mem, idx+1)))
3c9a524f
DH
4192 return SCM_BOOL_F;
4193 else
cff5fa33 4194 result = mem2decimal_from_point (SCM_INUM0, mem,
9d427b2c 4195 p_idx, &implicit_x);
f872b822 4196 }
3c9a524f
DH
4197 else
4198 {
3c9a524f 4199 SCM uinteger;
3c9a524f 4200
9d427b2c 4201 uinteger = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 4202 if (scm_is_false (uinteger))
3c9a524f
DH
4203 return SCM_BOOL_F;
4204
4205 if (idx == len)
4206 result = uinteger;
3f47e526 4207 else if (scm_i_string_ref (mem, idx) == '/')
f872b822 4208 {
3c9a524f
DH
4209 SCM divisor;
4210
4211 idx++;
ee0ddd21
AW
4212 if (idx == len)
4213 return SCM_BOOL_F;
3c9a524f 4214
9d427b2c 4215 divisor = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 4216 if (scm_is_false (divisor))
3c9a524f
DH
4217 return SCM_BOOL_F;
4218
f92e85f7 4219 /* both are int/big here, I assume */
cba42c93 4220 result = scm_i_make_ratio (uinteger, divisor);
f872b822 4221 }
3c9a524f
DH
4222 else if (radix == 10)
4223 {
9d427b2c 4224 result = mem2decimal_from_point (uinteger, mem, &idx, &implicit_x);
73e4de09 4225 if (scm_is_false (result))
3c9a524f
DH
4226 return SCM_BOOL_F;
4227 }
4228 else
4229 result = uinteger;
4230
4231 *p_idx = idx;
f872b822 4232 }
164d2481 4233
9d427b2c
MW
4234 switch (forced_x)
4235 {
4236 case EXACT:
4237 if (SCM_INEXACTP (result))
4238 return scm_inexact_to_exact (result);
4239 else
4240 return result;
4241 case INEXACT:
4242 if (SCM_INEXACTP (result))
4243 return result;
4244 else
4245 return scm_exact_to_inexact (result);
4246 case NO_EXACTNESS:
4247 if (implicit_x == INEXACT)
4248 {
4249 if (SCM_INEXACTP (result))
4250 return result;
4251 else
4252 return scm_exact_to_inexact (result);
4253 }
4254 else
4255 return result;
4256 }
164d2481 4257
9d427b2c
MW
4258 /* We should never get here */
4259 scm_syserror ("mem2ureal");
3c9a524f 4260}
0f2d19dd 4261
0f2d19dd 4262
3c9a524f 4263/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 4264
3c9a524f 4265static SCM
3f47e526 4266mem2complex (SCM mem, unsigned int idx,
9d427b2c 4267 unsigned int radix, enum t_exactness forced_x)
3c9a524f 4268{
3f47e526 4269 scm_t_wchar c;
3c9a524f
DH
4270 int sign = 0;
4271 SCM ureal;
3f47e526 4272 size_t len = scm_i_string_length (mem);
3c9a524f
DH
4273
4274 if (idx == len)
4275 return SCM_BOOL_F;
4276
3f47e526 4277 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4278 if (c == '+')
4279 {
4280 idx++;
4281 sign = 1;
4282 }
4283 else if (c == '-')
4284 {
4285 idx++;
4286 sign = -1;
0f2d19dd 4287 }
0f2d19dd 4288
3c9a524f
DH
4289 if (idx == len)
4290 return SCM_BOOL_F;
4291
9d427b2c 4292 ureal = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 4293 if (scm_is_false (ureal))
f872b822 4294 {
3c9a524f
DH
4295 /* input must be either +i or -i */
4296
4297 if (sign == 0)
4298 return SCM_BOOL_F;
4299
3f47e526
MG
4300 if (scm_i_string_ref (mem, idx) == 'i'
4301 || scm_i_string_ref (mem, idx) == 'I')
f872b822 4302 {
3c9a524f
DH
4303 idx++;
4304 if (idx != len)
4305 return SCM_BOOL_F;
4306
cff5fa33 4307 return scm_make_rectangular (SCM_INUM0, SCM_I_MAKINUM (sign));
f872b822 4308 }
3c9a524f
DH
4309 else
4310 return SCM_BOOL_F;
0f2d19dd 4311 }
3c9a524f
DH
4312 else
4313 {
73e4de09 4314 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 4315 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 4316
3c9a524f
DH
4317 if (idx == len)
4318 return ureal;
4319
3f47e526 4320 c = scm_i_string_ref (mem, idx);
3c9a524f 4321 switch (c)
f872b822 4322 {
3c9a524f
DH
4323 case 'i': case 'I':
4324 /* either +<ureal>i or -<ureal>i */
4325
4326 idx++;
4327 if (sign == 0)
4328 return SCM_BOOL_F;
4329 if (idx != len)
4330 return SCM_BOOL_F;
cff5fa33 4331 return scm_make_rectangular (SCM_INUM0, ureal);
3c9a524f
DH
4332
4333 case '@':
4334 /* polar input: <real>@<real>. */
4335
4336 idx++;
4337 if (idx == len)
4338 return SCM_BOOL_F;
4339 else
f872b822 4340 {
3c9a524f
DH
4341 int sign;
4342 SCM angle;
4343 SCM result;
4344
3f47e526 4345 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
4346 if (c == '+')
4347 {
4348 idx++;
ee0ddd21
AW
4349 if (idx == len)
4350 return SCM_BOOL_F;
3c9a524f
DH
4351 sign = 1;
4352 }
4353 else if (c == '-')
4354 {
4355 idx++;
ee0ddd21
AW
4356 if (idx == len)
4357 return SCM_BOOL_F;
3c9a524f
DH
4358 sign = -1;
4359 }
4360 else
4361 sign = 1;
4362
9d427b2c 4363 angle = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 4364 if (scm_is_false (angle))
3c9a524f
DH
4365 return SCM_BOOL_F;
4366 if (idx != len)
4367 return SCM_BOOL_F;
4368
73e4de09 4369 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
4370 angle = scm_difference (angle, SCM_UNDEFINED);
4371
4372 result = scm_make_polar (ureal, angle);
4373 return result;
f872b822 4374 }
3c9a524f
DH
4375 case '+':
4376 case '-':
4377 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 4378
3c9a524f
DH
4379 idx++;
4380 if (idx == len)
4381 return SCM_BOOL_F;
4382 else
4383 {
4384 int sign = (c == '+') ? 1 : -1;
9d427b2c 4385 SCM imag = mem2ureal (mem, &idx, radix, forced_x);
0f2d19dd 4386
73e4de09 4387 if (scm_is_false (imag))
d956fa6f 4388 imag = SCM_I_MAKINUM (sign);
23295dc3 4389 else if (sign == -1 && scm_is_false (scm_nan_p (imag)))
1fe5e088 4390 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 4391
3c9a524f
DH
4392 if (idx == len)
4393 return SCM_BOOL_F;
3f47e526
MG
4394 if (scm_i_string_ref (mem, idx) != 'i'
4395 && scm_i_string_ref (mem, idx) != 'I')
3c9a524f 4396 return SCM_BOOL_F;
0f2d19dd 4397
3c9a524f
DH
4398 idx++;
4399 if (idx != len)
4400 return SCM_BOOL_F;
0f2d19dd 4401
1fe5e088 4402 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
4403 }
4404 default:
4405 return SCM_BOOL_F;
4406 }
4407 }
0f2d19dd 4408}
0f2d19dd
JB
4409
4410
3c9a524f
DH
4411/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
4412
4413enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 4414
0f2d19dd 4415SCM
3f47e526 4416scm_i_string_to_number (SCM mem, unsigned int default_radix)
0f2d19dd 4417{
3c9a524f
DH
4418 unsigned int idx = 0;
4419 unsigned int radix = NO_RADIX;
4420 enum t_exactness forced_x = NO_EXACTNESS;
3f47e526 4421 size_t len = scm_i_string_length (mem);
3c9a524f
DH
4422
4423 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
3f47e526 4424 while (idx + 2 < len && scm_i_string_ref (mem, idx) == '#')
3c9a524f 4425 {
3f47e526 4426 switch (scm_i_string_ref (mem, idx + 1))
3c9a524f
DH
4427 {
4428 case 'b': case 'B':
4429 if (radix != NO_RADIX)
4430 return SCM_BOOL_F;
4431 radix = DUAL;
4432 break;
4433 case 'd': case 'D':
4434 if (radix != NO_RADIX)
4435 return SCM_BOOL_F;
4436 radix = DEC;
4437 break;
4438 case 'i': case 'I':
4439 if (forced_x != NO_EXACTNESS)
4440 return SCM_BOOL_F;
4441 forced_x = INEXACT;
4442 break;
4443 case 'e': case 'E':
4444 if (forced_x != NO_EXACTNESS)
4445 return SCM_BOOL_F;
4446 forced_x = EXACT;
4447 break;
4448 case 'o': case 'O':
4449 if (radix != NO_RADIX)
4450 return SCM_BOOL_F;
4451 radix = OCT;
4452 break;
4453 case 'x': case 'X':
4454 if (radix != NO_RADIX)
4455 return SCM_BOOL_F;
4456 radix = HEX;
4457 break;
4458 default:
f872b822 4459 return SCM_BOOL_F;
3c9a524f
DH
4460 }
4461 idx += 2;
4462 }
4463
4464 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
4465 if (radix == NO_RADIX)
9d427b2c 4466 radix = default_radix;
f872b822 4467
9d427b2c 4468 return mem2complex (mem, idx, radix, forced_x);
0f2d19dd
JB
4469}
4470
3f47e526
MG
4471SCM
4472scm_c_locale_stringn_to_number (const char* mem, size_t len,
4473 unsigned int default_radix)
4474{
4475 SCM str = scm_from_locale_stringn (mem, len);
4476
4477 return scm_i_string_to_number (str, default_radix);
4478}
4479
0f2d19dd 4480
a1ec6916 4481SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 4482 (SCM string, SCM radix),
1e6808ea 4483 "Return a number of the maximally precise representation\n"
942e5b91 4484 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
4485 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
4486 "is a default radix that may be overridden by an explicit radix\n"
4487 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
4488 "supplied, then the default radix is 10. If string is not a\n"
4489 "syntactically valid notation for a number, then\n"
4490 "@code{string->number} returns @code{#f}.")
1bbd0b84 4491#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
4492{
4493 SCM answer;
5efd3c7d 4494 unsigned int base;
a6d9e5ab 4495 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
4496
4497 if (SCM_UNBNDP (radix))
4498 base = 10;
4499 else
4500 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
4501
3f47e526 4502 answer = scm_i_string_to_number (string, base);
8824ac88
MV
4503 scm_remember_upto_here_1 (string);
4504 return answer;
0f2d19dd 4505}
1bbd0b84 4506#undef FUNC_NAME
3c9a524f
DH
4507
4508
0f2d19dd
JB
4509/*** END strs->nums ***/
4510
5986c47d 4511
8507ec80
MV
4512SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
4513 (SCM x),
4514 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
4515 "otherwise.")
4516#define FUNC_NAME s_scm_number_p
4517{
4518 return scm_from_bool (SCM_NUMBERP (x));
4519}
4520#undef FUNC_NAME
4521
4522SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 4523 (SCM x),
942e5b91 4524 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 4525 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
4526 "values form subsets of the set of complex numbers, i. e. the\n"
4527 "predicate will also be fulfilled if @var{x} is a real,\n"
4528 "rational or integer number.")
8507ec80 4529#define FUNC_NAME s_scm_complex_p
0f2d19dd 4530{
8507ec80
MV
4531 /* all numbers are complex. */
4532 return scm_number_p (x);
0f2d19dd 4533}
1bbd0b84 4534#undef FUNC_NAME
0f2d19dd 4535
f92e85f7
MV
4536SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
4537 (SCM x),
4538 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
4539 "otherwise. Note that the set of integer values forms a subset of\n"
4540 "the set of real numbers, i. e. the predicate will also be\n"
4541 "fulfilled if @var{x} is an integer number.")
4542#define FUNC_NAME s_scm_real_p
4543{
c960e556
MW
4544 return scm_from_bool
4545 (SCM_I_INUMP (x) || SCM_REALP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x));
f92e85f7
MV
4546}
4547#undef FUNC_NAME
4548
4549SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 4550 (SCM x),
942e5b91 4551 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 4552 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 4553 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
4554 "fulfilled if @var{x} is an integer number.")
4555#define FUNC_NAME s_scm_rational_p
0f2d19dd 4556{
c960e556 4557 if (SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x))
f92e85f7
MV
4558 return SCM_BOOL_T;
4559 else if (SCM_REALP (x))
c960e556
MW
4560 /* due to their limited precision, finite floating point numbers are
4561 rational as well. (finite means neither infinity nor a NaN) */
4562 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
0aacf84e 4563 else
bb628794 4564 return SCM_BOOL_F;
0f2d19dd 4565}
1bbd0b84 4566#undef FUNC_NAME
0f2d19dd 4567
a1ec6916 4568SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 4569 (SCM x),
942e5b91
MG
4570 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
4571 "else.")
1bbd0b84 4572#define FUNC_NAME s_scm_integer_p
0f2d19dd 4573{
c960e556 4574 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f872b822 4575 return SCM_BOOL_T;
c960e556
MW
4576 else if (SCM_REALP (x))
4577 {
4578 double val = SCM_REAL_VALUE (x);
4579 return scm_from_bool (!isinf (val) && (val == floor (val)));
4580 }
4581 else
8e43ed5d 4582 return SCM_BOOL_F;
0f2d19dd 4583}
1bbd0b84 4584#undef FUNC_NAME
0f2d19dd
JB
4585
4586
8a1f4f98
AW
4587SCM scm_i_num_eq_p (SCM, SCM, SCM);
4588SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
4589 (SCM x, SCM y, SCM rest),
4590 "Return @code{#t} if all parameters are numerically equal.")
4591#define FUNC_NAME s_scm_i_num_eq_p
4592{
4593 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4594 return SCM_BOOL_T;
4595 while (!scm_is_null (rest))
4596 {
4597 if (scm_is_false (scm_num_eq_p (x, y)))
4598 return SCM_BOOL_F;
4599 x = y;
4600 y = scm_car (rest);
4601 rest = scm_cdr (rest);
4602 }
4603 return scm_num_eq_p (x, y);
4604}
4605#undef FUNC_NAME
0f2d19dd 4606SCM
6e8d25a6 4607scm_num_eq_p (SCM x, SCM y)
0f2d19dd 4608{
d8b95e27 4609 again:
e11e83f3 4610 if (SCM_I_INUMP (x))
0aacf84e 4611 {
e25f3727 4612 scm_t_signed_bits xx = SCM_I_INUM (x);
e11e83f3 4613 if (SCM_I_INUMP (y))
0aacf84e 4614 {
e25f3727 4615 scm_t_signed_bits yy = SCM_I_INUM (y);
73e4de09 4616 return scm_from_bool (xx == yy);
0aacf84e
MD
4617 }
4618 else if (SCM_BIGP (y))
4619 return SCM_BOOL_F;
4620 else if (SCM_REALP (y))
e8c5b1f2
KR
4621 {
4622 /* On a 32-bit system an inum fits a double, we can cast the inum
4623 to a double and compare.
4624
4625 But on a 64-bit system an inum is bigger than a double and
4626 casting it to a double (call that dxx) will round. dxx is at
4627 worst 1 bigger or smaller than xx, so if dxx==yy we know yy is
4628 an integer and fits a long. So we cast yy to a long and
4629 compare with plain xx.
4630
4631 An alternative (for any size system actually) would be to check
4632 yy is an integer (with floor) and is in range of an inum
4633 (compare against appropriate powers of 2) then test
e25f3727
AW
4634 xx==(scm_t_signed_bits)yy. It's just a matter of which
4635 casts/comparisons might be fastest or easiest for the cpu. */
e8c5b1f2
KR
4636
4637 double yy = SCM_REAL_VALUE (y);
3a1b45fd
MV
4638 return scm_from_bool ((double) xx == yy
4639 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 4640 || xx == (scm_t_signed_bits) yy));
e8c5b1f2 4641 }
0aacf84e 4642 else if (SCM_COMPLEXP (y))
73e4de09 4643 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 4644 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
4645 else if (SCM_FRACTIONP (y))
4646 return SCM_BOOL_F;
0aacf84e 4647 else
8a1f4f98 4648 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 4649 }
0aacf84e
MD
4650 else if (SCM_BIGP (x))
4651 {
e11e83f3 4652 if (SCM_I_INUMP (y))
0aacf84e
MD
4653 return SCM_BOOL_F;
4654 else if (SCM_BIGP (y))
4655 {
4656 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
4657 scm_remember_upto_here_2 (x, y);
73e4de09 4658 return scm_from_bool (0 == cmp);
0aacf84e
MD
4659 }
4660 else if (SCM_REALP (y))
4661 {
4662 int cmp;
2e65b52f 4663 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
4664 return SCM_BOOL_F;
4665 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
4666 scm_remember_upto_here_1 (x);
73e4de09 4667 return scm_from_bool (0 == cmp);
0aacf84e
MD
4668 }
4669 else if (SCM_COMPLEXP (y))
4670 {
4671 int cmp;
4672 if (0.0 != SCM_COMPLEX_IMAG (y))
4673 return SCM_BOOL_F;
2e65b52f 4674 if (isnan (SCM_COMPLEX_REAL (y)))
0aacf84e
MD
4675 return SCM_BOOL_F;
4676 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
4677 scm_remember_upto_here_1 (x);
73e4de09 4678 return scm_from_bool (0 == cmp);
0aacf84e 4679 }
f92e85f7
MV
4680 else if (SCM_FRACTIONP (y))
4681 return SCM_BOOL_F;
0aacf84e 4682 else
8a1f4f98 4683 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 4684 }
0aacf84e
MD
4685 else if (SCM_REALP (x))
4686 {
e8c5b1f2 4687 double xx = SCM_REAL_VALUE (x);
e11e83f3 4688 if (SCM_I_INUMP (y))
e8c5b1f2
KR
4689 {
4690 /* see comments with inum/real above */
e25f3727 4691 scm_t_signed_bits yy = SCM_I_INUM (y);
3a1b45fd
MV
4692 return scm_from_bool (xx == (double) yy
4693 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 4694 || (scm_t_signed_bits) xx == yy));
e8c5b1f2 4695 }
0aacf84e
MD
4696 else if (SCM_BIGP (y))
4697 {
4698 int cmp;
2e65b52f 4699 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
4700 return SCM_BOOL_F;
4701 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
4702 scm_remember_upto_here_1 (y);
73e4de09 4703 return scm_from_bool (0 == cmp);
0aacf84e
MD
4704 }
4705 else if (SCM_REALP (y))
73e4de09 4706 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 4707 else if (SCM_COMPLEXP (y))
73e4de09 4708 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 4709 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 4710 else if (SCM_FRACTIONP (y))
d8b95e27
KR
4711 {
4712 double xx = SCM_REAL_VALUE (x);
2e65b52f 4713 if (isnan (xx))
d8b95e27 4714 return SCM_BOOL_F;
2e65b52f 4715 if (isinf (xx))
73e4de09 4716 return scm_from_bool (xx < 0.0);
d8b95e27
KR
4717 x = scm_inexact_to_exact (x); /* with x as frac or int */
4718 goto again;
4719 }
0aacf84e 4720 else
8a1f4f98 4721 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 4722 }
0aacf84e
MD
4723 else if (SCM_COMPLEXP (x))
4724 {
e11e83f3
MV
4725 if (SCM_I_INUMP (y))
4726 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
4727 && (SCM_COMPLEX_IMAG (x) == 0.0));
4728 else if (SCM_BIGP (y))
4729 {
4730 int cmp;
4731 if (0.0 != SCM_COMPLEX_IMAG (x))
4732 return SCM_BOOL_F;
2e65b52f 4733 if (isnan (SCM_COMPLEX_REAL (x)))
0aacf84e
MD
4734 return SCM_BOOL_F;
4735 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
4736 scm_remember_upto_here_1 (y);
73e4de09 4737 return scm_from_bool (0 == cmp);
0aacf84e
MD
4738 }
4739 else if (SCM_REALP (y))
73e4de09 4740 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
4741 && (SCM_COMPLEX_IMAG (x) == 0.0));
4742 else if (SCM_COMPLEXP (y))
73e4de09 4743 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 4744 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 4745 else if (SCM_FRACTIONP (y))
d8b95e27
KR
4746 {
4747 double xx;
4748 if (SCM_COMPLEX_IMAG (x) != 0.0)
4749 return SCM_BOOL_F;
4750 xx = SCM_COMPLEX_REAL (x);
2e65b52f 4751 if (isnan (xx))
d8b95e27 4752 return SCM_BOOL_F;
2e65b52f 4753 if (isinf (xx))
73e4de09 4754 return scm_from_bool (xx < 0.0);
d8b95e27
KR
4755 x = scm_inexact_to_exact (x); /* with x as frac or int */
4756 goto again;
4757 }
f92e85f7 4758 else
8a1f4f98 4759 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f92e85f7
MV
4760 }
4761 else if (SCM_FRACTIONP (x))
4762 {
e11e83f3 4763 if (SCM_I_INUMP (y))
f92e85f7
MV
4764 return SCM_BOOL_F;
4765 else if (SCM_BIGP (y))
4766 return SCM_BOOL_F;
4767 else if (SCM_REALP (y))
d8b95e27
KR
4768 {
4769 double yy = SCM_REAL_VALUE (y);
2e65b52f 4770 if (isnan (yy))
d8b95e27 4771 return SCM_BOOL_F;
2e65b52f 4772 if (isinf (yy))
73e4de09 4773 return scm_from_bool (0.0 < yy);
d8b95e27
KR
4774 y = scm_inexact_to_exact (y); /* with y as frac or int */
4775 goto again;
4776 }
f92e85f7 4777 else if (SCM_COMPLEXP (y))
d8b95e27
KR
4778 {
4779 double yy;
4780 if (SCM_COMPLEX_IMAG (y) != 0.0)
4781 return SCM_BOOL_F;
4782 yy = SCM_COMPLEX_REAL (y);
2e65b52f 4783 if (isnan (yy))
d8b95e27 4784 return SCM_BOOL_F;
2e65b52f 4785 if (isinf (yy))
73e4de09 4786 return scm_from_bool (0.0 < yy);
d8b95e27
KR
4787 y = scm_inexact_to_exact (y); /* with y as frac or int */
4788 goto again;
4789 }
f92e85f7
MV
4790 else if (SCM_FRACTIONP (y))
4791 return scm_i_fraction_equalp (x, y);
0aacf84e 4792 else
8a1f4f98 4793 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 4794 }
0aacf84e 4795 else
8a1f4f98 4796 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARG1, s_scm_i_num_eq_p);
0f2d19dd
JB
4797}
4798
4799
a5f0b599
KR
4800/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
4801 done are good for inums, but for bignums an answer can almost always be
4802 had by just examining a few high bits of the operands, as done by GMP in
4803 mpq_cmp. flonum/frac compares likewise, but with the slight complication
4804 of the float exponent to take into account. */
4805
8c93b597 4806SCM_INTERNAL SCM scm_i_num_less_p (SCM, SCM, SCM);
8a1f4f98
AW
4807SCM_PRIMITIVE_GENERIC (scm_i_num_less_p, "<", 0, 2, 1,
4808 (SCM x, SCM y, SCM rest),
4809 "Return @code{#t} if the list of parameters is monotonically\n"
4810 "increasing.")
4811#define FUNC_NAME s_scm_i_num_less_p
4812{
4813 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4814 return SCM_BOOL_T;
4815 while (!scm_is_null (rest))
4816 {
4817 if (scm_is_false (scm_less_p (x, y)))
4818 return SCM_BOOL_F;
4819 x = y;
4820 y = scm_car (rest);
4821 rest = scm_cdr (rest);
4822 }
4823 return scm_less_p (x, y);
4824}
4825#undef FUNC_NAME
0f2d19dd 4826SCM
6e8d25a6 4827scm_less_p (SCM x, SCM y)
0f2d19dd 4828{
a5f0b599 4829 again:
e11e83f3 4830 if (SCM_I_INUMP (x))
0aacf84e 4831 {
e25f3727 4832 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 4833 if (SCM_I_INUMP (y))
0aacf84e 4834 {
e25f3727 4835 scm_t_inum yy = SCM_I_INUM (y);
73e4de09 4836 return scm_from_bool (xx < yy);
0aacf84e
MD
4837 }
4838 else if (SCM_BIGP (y))
4839 {
4840 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
4841 scm_remember_upto_here_1 (y);
73e4de09 4842 return scm_from_bool (sgn > 0);
0aacf84e
MD
4843 }
4844 else if (SCM_REALP (y))
73e4de09 4845 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 4846 else if (SCM_FRACTIONP (y))
a5f0b599
KR
4847 {
4848 /* "x < a/b" becomes "x*b < a" */
4849 int_frac:
4850 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
4851 y = SCM_FRACTION_NUMERATOR (y);
4852 goto again;
4853 }
0aacf84e 4854 else
8a1f4f98 4855 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 4856 }
0aacf84e
MD
4857 else if (SCM_BIGP (x))
4858 {
e11e83f3 4859 if (SCM_I_INUMP (y))
0aacf84e
MD
4860 {
4861 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4862 scm_remember_upto_here_1 (x);
73e4de09 4863 return scm_from_bool (sgn < 0);
0aacf84e
MD
4864 }
4865 else if (SCM_BIGP (y))
4866 {
4867 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
4868 scm_remember_upto_here_2 (x, y);
73e4de09 4869 return scm_from_bool (cmp < 0);
0aacf84e
MD
4870 }
4871 else if (SCM_REALP (y))
4872 {
4873 int cmp;
2e65b52f 4874 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
4875 return SCM_BOOL_F;
4876 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
4877 scm_remember_upto_here_1 (x);
73e4de09 4878 return scm_from_bool (cmp < 0);
0aacf84e 4879 }
f92e85f7 4880 else if (SCM_FRACTIONP (y))
a5f0b599 4881 goto int_frac;
0aacf84e 4882 else
8a1f4f98 4883 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f4c627b3 4884 }
0aacf84e
MD
4885 else if (SCM_REALP (x))
4886 {
e11e83f3
MV
4887 if (SCM_I_INUMP (y))
4888 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
4889 else if (SCM_BIGP (y))
4890 {
4891 int cmp;
2e65b52f 4892 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
4893 return SCM_BOOL_F;
4894 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
4895 scm_remember_upto_here_1 (y);
73e4de09 4896 return scm_from_bool (cmp > 0);
0aacf84e
MD
4897 }
4898 else if (SCM_REALP (y))
73e4de09 4899 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 4900 else if (SCM_FRACTIONP (y))
a5f0b599
KR
4901 {
4902 double xx = SCM_REAL_VALUE (x);
2e65b52f 4903 if (isnan (xx))
a5f0b599 4904 return SCM_BOOL_F;
2e65b52f 4905 if (isinf (xx))
73e4de09 4906 return scm_from_bool (xx < 0.0);
a5f0b599
KR
4907 x = scm_inexact_to_exact (x); /* with x as frac or int */
4908 goto again;
4909 }
f92e85f7 4910 else
8a1f4f98 4911 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f92e85f7
MV
4912 }
4913 else if (SCM_FRACTIONP (x))
4914 {
e11e83f3 4915 if (SCM_I_INUMP (y) || SCM_BIGP (y))
a5f0b599
KR
4916 {
4917 /* "a/b < y" becomes "a < y*b" */
4918 y = scm_product (y, SCM_FRACTION_DENOMINATOR (x));
4919 x = SCM_FRACTION_NUMERATOR (x);
4920 goto again;
4921 }
f92e85f7 4922 else if (SCM_REALP (y))
a5f0b599
KR
4923 {
4924 double yy = SCM_REAL_VALUE (y);
2e65b52f 4925 if (isnan (yy))
a5f0b599 4926 return SCM_BOOL_F;
2e65b52f 4927 if (isinf (yy))
73e4de09 4928 return scm_from_bool (0.0 < yy);
a5f0b599
KR
4929 y = scm_inexact_to_exact (y); /* with y as frac or int */
4930 goto again;
4931 }
f92e85f7 4932 else if (SCM_FRACTIONP (y))
a5f0b599
KR
4933 {
4934 /* "a/b < c/d" becomes "a*d < c*b" */
4935 SCM new_x = scm_product (SCM_FRACTION_NUMERATOR (x),
4936 SCM_FRACTION_DENOMINATOR (y));
4937 SCM new_y = scm_product (SCM_FRACTION_NUMERATOR (y),
4938 SCM_FRACTION_DENOMINATOR (x));
4939 x = new_x;
4940 y = new_y;
4941 goto again;
4942 }
0aacf84e 4943 else
8a1f4f98 4944 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 4945 }
0aacf84e 4946 else
8a1f4f98 4947 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARG1, s_scm_i_num_less_p);
0f2d19dd
JB
4948}
4949
4950
8a1f4f98
AW
4951SCM scm_i_num_gr_p (SCM, SCM, SCM);
4952SCM_PRIMITIVE_GENERIC (scm_i_num_gr_p, ">", 0, 2, 1,
4953 (SCM x, SCM y, SCM rest),
4954 "Return @code{#t} if the list of parameters is monotonically\n"
4955 "decreasing.")
4956#define FUNC_NAME s_scm_i_num_gr_p
4957{
4958 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4959 return SCM_BOOL_T;
4960 while (!scm_is_null (rest))
4961 {
4962 if (scm_is_false (scm_gr_p (x, y)))
4963 return SCM_BOOL_F;
4964 x = y;
4965 y = scm_car (rest);
4966 rest = scm_cdr (rest);
4967 }
4968 return scm_gr_p (x, y);
4969}
4970#undef FUNC_NAME
4971#define FUNC_NAME s_scm_i_num_gr_p
c76b1eaf
MD
4972SCM
4973scm_gr_p (SCM x, SCM y)
0f2d19dd 4974{
c76b1eaf 4975 if (!SCM_NUMBERP (x))
8a1f4f98 4976 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 4977 else if (!SCM_NUMBERP (y))
8a1f4f98 4978 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG2, FUNC_NAME);
c76b1eaf
MD
4979 else
4980 return scm_less_p (y, x);
0f2d19dd 4981}
1bbd0b84 4982#undef FUNC_NAME
0f2d19dd
JB
4983
4984
8a1f4f98
AW
4985SCM scm_i_num_leq_p (SCM, SCM, SCM);
4986SCM_PRIMITIVE_GENERIC (scm_i_num_leq_p, "<=", 0, 2, 1,
4987 (SCM x, SCM y, SCM rest),
4988 "Return @code{#t} if the list of parameters is monotonically\n"
4989 "non-decreasing.")
4990#define FUNC_NAME s_scm_i_num_leq_p
4991{
4992 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
4993 return SCM_BOOL_T;
4994 while (!scm_is_null (rest))
4995 {
4996 if (scm_is_false (scm_leq_p (x, y)))
4997 return SCM_BOOL_F;
4998 x = y;
4999 y = scm_car (rest);
5000 rest = scm_cdr (rest);
5001 }
5002 return scm_leq_p (x, y);
5003}
5004#undef FUNC_NAME
5005#define FUNC_NAME s_scm_i_num_leq_p
c76b1eaf
MD
5006SCM
5007scm_leq_p (SCM x, SCM y)
0f2d19dd 5008{
c76b1eaf 5009 if (!SCM_NUMBERP (x))
8a1f4f98 5010 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 5011 else if (!SCM_NUMBERP (y))
8a1f4f98 5012 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 5013 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 5014 return SCM_BOOL_F;
c76b1eaf 5015 else
73e4de09 5016 return scm_not (scm_less_p (y, x));
0f2d19dd 5017}
1bbd0b84 5018#undef FUNC_NAME
0f2d19dd
JB
5019
5020
8a1f4f98
AW
5021SCM scm_i_num_geq_p (SCM, SCM, SCM);
5022SCM_PRIMITIVE_GENERIC (scm_i_num_geq_p, ">=", 0, 2, 1,
5023 (SCM x, SCM y, SCM rest),
5024 "Return @code{#t} if the list of parameters is monotonically\n"
5025 "non-increasing.")
5026#define FUNC_NAME s_scm_i_num_geq_p
5027{
5028 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
5029 return SCM_BOOL_T;
5030 while (!scm_is_null (rest))
5031 {
5032 if (scm_is_false (scm_geq_p (x, y)))
5033 return SCM_BOOL_F;
5034 x = y;
5035 y = scm_car (rest);
5036 rest = scm_cdr (rest);
5037 }
5038 return scm_geq_p (x, y);
5039}
5040#undef FUNC_NAME
5041#define FUNC_NAME s_scm_i_num_geq_p
c76b1eaf
MD
5042SCM
5043scm_geq_p (SCM x, SCM y)
0f2d19dd 5044{
c76b1eaf 5045 if (!SCM_NUMBERP (x))
8a1f4f98 5046 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 5047 else if (!SCM_NUMBERP (y))
8a1f4f98 5048 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 5049 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 5050 return SCM_BOOL_F;
c76b1eaf 5051 else
73e4de09 5052 return scm_not (scm_less_p (x, y));
0f2d19dd 5053}
1bbd0b84 5054#undef FUNC_NAME
0f2d19dd
JB
5055
5056
2519490c
MW
5057SCM_PRIMITIVE_GENERIC (scm_zero_p, "zero?", 1, 0, 0,
5058 (SCM z),
5059 "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
5060 "zero.")
5061#define FUNC_NAME s_scm_zero_p
0f2d19dd 5062{
e11e83f3 5063 if (SCM_I_INUMP (z))
bc36d050 5064 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 5065 else if (SCM_BIGP (z))
c2ff8ab0 5066 return SCM_BOOL_F;
0aacf84e 5067 else if (SCM_REALP (z))
73e4de09 5068 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 5069 else if (SCM_COMPLEXP (z))
73e4de09 5070 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 5071 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
5072 else if (SCM_FRACTIONP (z))
5073 return SCM_BOOL_F;
0aacf84e 5074 else
2519490c 5075 SCM_WTA_DISPATCH_1 (g_scm_zero_p, z, SCM_ARG1, s_scm_zero_p);
0f2d19dd 5076}
2519490c 5077#undef FUNC_NAME
0f2d19dd
JB
5078
5079
2519490c
MW
5080SCM_PRIMITIVE_GENERIC (scm_positive_p, "positive?", 1, 0, 0,
5081 (SCM x),
5082 "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
5083 "zero.")
5084#define FUNC_NAME s_scm_positive_p
0f2d19dd 5085{
e11e83f3
MV
5086 if (SCM_I_INUMP (x))
5087 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
5088 else if (SCM_BIGP (x))
5089 {
5090 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5091 scm_remember_upto_here_1 (x);
73e4de09 5092 return scm_from_bool (sgn > 0);
0aacf84e
MD
5093 }
5094 else if (SCM_REALP (x))
73e4de09 5095 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
5096 else if (SCM_FRACTIONP (x))
5097 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 5098 else
2519490c 5099 SCM_WTA_DISPATCH_1 (g_scm_positive_p, x, SCM_ARG1, s_scm_positive_p);
0f2d19dd 5100}
2519490c 5101#undef FUNC_NAME
0f2d19dd
JB
5102
5103
2519490c
MW
5104SCM_PRIMITIVE_GENERIC (scm_negative_p, "negative?", 1, 0, 0,
5105 (SCM x),
5106 "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
5107 "zero.")
5108#define FUNC_NAME s_scm_negative_p
0f2d19dd 5109{
e11e83f3
MV
5110 if (SCM_I_INUMP (x))
5111 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
5112 else if (SCM_BIGP (x))
5113 {
5114 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5115 scm_remember_upto_here_1 (x);
73e4de09 5116 return scm_from_bool (sgn < 0);
0aacf84e
MD
5117 }
5118 else if (SCM_REALP (x))
73e4de09 5119 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
5120 else if (SCM_FRACTIONP (x))
5121 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 5122 else
2519490c 5123 SCM_WTA_DISPATCH_1 (g_scm_negative_p, x, SCM_ARG1, s_scm_negative_p);
0f2d19dd 5124}
2519490c 5125#undef FUNC_NAME
0f2d19dd
JB
5126
5127
2a06f791
KR
5128/* scm_min and scm_max return an inexact when either argument is inexact, as
5129 required by r5rs. On that basis, for exact/inexact combinations the
5130 exact is converted to inexact to compare and possibly return. This is
5131 unlike scm_less_p above which takes some trouble to preserve all bits in
5132 its test, such trouble is not required for min and max. */
5133
78d3deb1
AW
5134SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
5135 (SCM x, SCM y, SCM rest),
5136 "Return the maximum of all parameter values.")
5137#define FUNC_NAME s_scm_i_max
5138{
5139 while (!scm_is_null (rest))
5140 { x = scm_max (x, y);
5141 y = scm_car (rest);
5142 rest = scm_cdr (rest);
5143 }
5144 return scm_max (x, y);
5145}
5146#undef FUNC_NAME
5147
5148#define s_max s_scm_i_max
5149#define g_max g_scm_i_max
5150
0f2d19dd 5151SCM
6e8d25a6 5152scm_max (SCM x, SCM y)
0f2d19dd 5153{
0aacf84e
MD
5154 if (SCM_UNBNDP (y))
5155 {
5156 if (SCM_UNBNDP (x))
5157 SCM_WTA_DISPATCH_0 (g_max, s_max);
e11e83f3 5158 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
5159 return x;
5160 else
5161 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 5162 }
f4c627b3 5163
e11e83f3 5164 if (SCM_I_INUMP (x))
0aacf84e 5165 {
e25f3727 5166 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 5167 if (SCM_I_INUMP (y))
0aacf84e 5168 {
e25f3727 5169 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
5170 return (xx < yy) ? y : x;
5171 }
5172 else if (SCM_BIGP (y))
5173 {
5174 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
5175 scm_remember_upto_here_1 (y);
5176 return (sgn < 0) ? x : y;
5177 }
5178 else if (SCM_REALP (y))
5179 {
2e274311
MW
5180 double xxd = xx;
5181 double yyd = SCM_REAL_VALUE (y);
5182
5183 if (xxd > yyd)
5184 return scm_from_double (xxd);
5185 /* If y is a NaN, then "==" is false and we return the NaN */
5186 else if (SCM_LIKELY (!(xxd == yyd)))
5187 return y;
5188 /* Handle signed zeroes properly */
5189 else if (xx == 0)
5190 return flo0;
5191 else
5192 return y;
0aacf84e 5193 }
f92e85f7
MV
5194 else if (SCM_FRACTIONP (y))
5195 {
e4bc5d6c 5196 use_less:
73e4de09 5197 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 5198 }
0aacf84e
MD
5199 else
5200 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 5201 }
0aacf84e
MD
5202 else if (SCM_BIGP (x))
5203 {
e11e83f3 5204 if (SCM_I_INUMP (y))
0aacf84e
MD
5205 {
5206 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5207 scm_remember_upto_here_1 (x);
5208 return (sgn < 0) ? y : x;
5209 }
5210 else if (SCM_BIGP (y))
5211 {
5212 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
5213 scm_remember_upto_here_2 (x, y);
5214 return (cmp > 0) ? x : y;
5215 }
5216 else if (SCM_REALP (y))
5217 {
2a06f791
KR
5218 /* if y==NaN then xx>yy is false, so we return the NaN y */
5219 double xx, yy;
5220 big_real:
5221 xx = scm_i_big2dbl (x);
5222 yy = SCM_REAL_VALUE (y);
55f26379 5223 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 5224 }
f92e85f7
MV
5225 else if (SCM_FRACTIONP (y))
5226 {
e4bc5d6c 5227 goto use_less;
f92e85f7 5228 }
0aacf84e
MD
5229 else
5230 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 5231 }
0aacf84e
MD
5232 else if (SCM_REALP (x))
5233 {
e11e83f3 5234 if (SCM_I_INUMP (y))
0aacf84e 5235 {
2e274311
MW
5236 scm_t_inum yy = SCM_I_INUM (y);
5237 double xxd = SCM_REAL_VALUE (x);
5238 double yyd = yy;
5239
5240 if (yyd > xxd)
5241 return scm_from_double (yyd);
5242 /* If x is a NaN, then "==" is false and we return the NaN */
5243 else if (SCM_LIKELY (!(xxd == yyd)))
5244 return x;
5245 /* Handle signed zeroes properly */
5246 else if (yy == 0)
5247 return flo0;
5248 else
5249 return x;
0aacf84e
MD
5250 }
5251 else if (SCM_BIGP (y))
5252 {
b6f8f763 5253 SCM_SWAP (x, y);
2a06f791 5254 goto big_real;
0aacf84e
MD
5255 }
5256 else if (SCM_REALP (y))
5257 {
0aacf84e 5258 double xx = SCM_REAL_VALUE (x);
2e274311
MW
5259 double yy = SCM_REAL_VALUE (y);
5260
5261 /* For purposes of max: +inf.0 > nan > everything else, per R6RS */
5262 if (xx > yy)
5263 return x;
5264 else if (SCM_LIKELY (xx < yy))
5265 return y;
5266 /* If neither (xx > yy) nor (xx < yy), then
5267 either they're equal or one is a NaN */
5268 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 5269 return DOUBLE_IS_POSITIVE_INFINITY (yy) ? y : x;
2e274311 5270 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 5271 return DOUBLE_IS_POSITIVE_INFINITY (xx) ? x : y;
2e274311
MW
5272 /* xx == yy, but handle signed zeroes properly */
5273 else if (double_is_non_negative_zero (yy))
5274 return y;
5275 else
5276 return x;
0aacf84e 5277 }
f92e85f7
MV
5278 else if (SCM_FRACTIONP (y))
5279 {
5280 double yy = scm_i_fraction2double (y);
5281 double xx = SCM_REAL_VALUE (x);
55f26379 5282 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
5283 }
5284 else
5285 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
5286 }
5287 else if (SCM_FRACTIONP (x))
5288 {
e11e83f3 5289 if (SCM_I_INUMP (y))
f92e85f7 5290 {
e4bc5d6c 5291 goto use_less;
f92e85f7
MV
5292 }
5293 else if (SCM_BIGP (y))
5294 {
e4bc5d6c 5295 goto use_less;
f92e85f7
MV
5296 }
5297 else if (SCM_REALP (y))
5298 {
5299 double xx = scm_i_fraction2double (x);
2e274311
MW
5300 /* if y==NaN then ">" is false, so we return the NaN y */
5301 return (xx > SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
5302 }
5303 else if (SCM_FRACTIONP (y))
5304 {
e4bc5d6c 5305 goto use_less;
f92e85f7 5306 }
0aacf84e
MD
5307 else
5308 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 5309 }
0aacf84e 5310 else
f4c627b3 5311 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
5312}
5313
5314
78d3deb1
AW
5315SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
5316 (SCM x, SCM y, SCM rest),
5317 "Return the minimum of all parameter values.")
5318#define FUNC_NAME s_scm_i_min
5319{
5320 while (!scm_is_null (rest))
5321 { x = scm_min (x, y);
5322 y = scm_car (rest);
5323 rest = scm_cdr (rest);
5324 }
5325 return scm_min (x, y);
5326}
5327#undef FUNC_NAME
5328
5329#define s_min s_scm_i_min
5330#define g_min g_scm_i_min
5331
0f2d19dd 5332SCM
6e8d25a6 5333scm_min (SCM x, SCM y)
0f2d19dd 5334{
0aacf84e
MD
5335 if (SCM_UNBNDP (y))
5336 {
5337 if (SCM_UNBNDP (x))
5338 SCM_WTA_DISPATCH_0 (g_min, s_min);
e11e83f3 5339 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
5340 return x;
5341 else
5342 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 5343 }
f4c627b3 5344
e11e83f3 5345 if (SCM_I_INUMP (x))
0aacf84e 5346 {
e25f3727 5347 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 5348 if (SCM_I_INUMP (y))
0aacf84e 5349 {
e25f3727 5350 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
5351 return (xx < yy) ? x : y;
5352 }
5353 else if (SCM_BIGP (y))
5354 {
5355 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
5356 scm_remember_upto_here_1 (y);
5357 return (sgn < 0) ? y : x;
5358 }
5359 else if (SCM_REALP (y))
5360 {
5361 double z = xx;
5362 /* if y==NaN then "<" is false and we return NaN */
55f26379 5363 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 5364 }
f92e85f7
MV
5365 else if (SCM_FRACTIONP (y))
5366 {
e4bc5d6c 5367 use_less:
73e4de09 5368 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 5369 }
0aacf84e
MD
5370 else
5371 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 5372 }
0aacf84e
MD
5373 else if (SCM_BIGP (x))
5374 {
e11e83f3 5375 if (SCM_I_INUMP (y))
0aacf84e
MD
5376 {
5377 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5378 scm_remember_upto_here_1 (x);
5379 return (sgn < 0) ? x : y;
5380 }
5381 else if (SCM_BIGP (y))
5382 {
5383 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
5384 scm_remember_upto_here_2 (x, y);
5385 return (cmp > 0) ? y : x;
5386 }
5387 else if (SCM_REALP (y))
5388 {
2a06f791
KR
5389 /* if y==NaN then xx<yy is false, so we return the NaN y */
5390 double xx, yy;
5391 big_real:
5392 xx = scm_i_big2dbl (x);
5393 yy = SCM_REAL_VALUE (y);
55f26379 5394 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 5395 }
f92e85f7
MV
5396 else if (SCM_FRACTIONP (y))
5397 {
e4bc5d6c 5398 goto use_less;
f92e85f7 5399 }
0aacf84e
MD
5400 else
5401 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 5402 }
0aacf84e
MD
5403 else if (SCM_REALP (x))
5404 {
e11e83f3 5405 if (SCM_I_INUMP (y))
0aacf84e 5406 {
e11e83f3 5407 double z = SCM_I_INUM (y);
0aacf84e 5408 /* if x==NaN then "<" is false and we return NaN */
55f26379 5409 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
5410 }
5411 else if (SCM_BIGP (y))
5412 {
b6f8f763 5413 SCM_SWAP (x, y);
2a06f791 5414 goto big_real;
0aacf84e
MD
5415 }
5416 else if (SCM_REALP (y))
5417 {
0aacf84e 5418 double xx = SCM_REAL_VALUE (x);
2e274311
MW
5419 double yy = SCM_REAL_VALUE (y);
5420
5421 /* For purposes of min: -inf.0 < nan < everything else, per R6RS */
5422 if (xx < yy)
5423 return x;
5424 else if (SCM_LIKELY (xx > yy))
5425 return y;
5426 /* If neither (xx < yy) nor (xx > yy), then
5427 either they're equal or one is a NaN */
5428 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 5429 return DOUBLE_IS_NEGATIVE_INFINITY (yy) ? y : x;
2e274311 5430 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 5431 return DOUBLE_IS_NEGATIVE_INFINITY (xx) ? x : y;
2e274311
MW
5432 /* xx == yy, but handle signed zeroes properly */
5433 else if (double_is_non_negative_zero (xx))
5434 return y;
5435 else
5436 return x;
0aacf84e 5437 }
f92e85f7
MV
5438 else if (SCM_FRACTIONP (y))
5439 {
5440 double yy = scm_i_fraction2double (y);
5441 double xx = SCM_REAL_VALUE (x);
55f26379 5442 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 5443 }
0aacf84e
MD
5444 else
5445 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 5446 }
f92e85f7
MV
5447 else if (SCM_FRACTIONP (x))
5448 {
e11e83f3 5449 if (SCM_I_INUMP (y))
f92e85f7 5450 {
e4bc5d6c 5451 goto use_less;
f92e85f7
MV
5452 }
5453 else if (SCM_BIGP (y))
5454 {
e4bc5d6c 5455 goto use_less;
f92e85f7
MV
5456 }
5457 else if (SCM_REALP (y))
5458 {
5459 double xx = scm_i_fraction2double (x);
2e274311
MW
5460 /* if y==NaN then "<" is false, so we return the NaN y */
5461 return (xx < SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
5462 }
5463 else if (SCM_FRACTIONP (y))
5464 {
e4bc5d6c 5465 goto use_less;
f92e85f7
MV
5466 }
5467 else
78d3deb1 5468 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f92e85f7 5469 }
0aacf84e 5470 else
f4c627b3 5471 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
5472}
5473
5474
8ccd24f7
AW
5475SCM_PRIMITIVE_GENERIC (scm_i_sum, "+", 0, 2, 1,
5476 (SCM x, SCM y, SCM rest),
5477 "Return the sum of all parameter values. Return 0 if called without\n"
5478 "any parameters." )
5479#define FUNC_NAME s_scm_i_sum
5480{
5481 while (!scm_is_null (rest))
5482 { x = scm_sum (x, y);
5483 y = scm_car (rest);
5484 rest = scm_cdr (rest);
5485 }
5486 return scm_sum (x, y);
5487}
5488#undef FUNC_NAME
5489
5490#define s_sum s_scm_i_sum
5491#define g_sum g_scm_i_sum
5492
0f2d19dd 5493SCM
6e8d25a6 5494scm_sum (SCM x, SCM y)
0f2d19dd 5495{
9cc37597 5496 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
5497 {
5498 if (SCM_NUMBERP (x)) return x;
5499 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 5500 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 5501 }
c209c88e 5502
9cc37597 5503 if (SCM_LIKELY (SCM_I_INUMP (x)))
ca46fb90 5504 {
9cc37597 5505 if (SCM_LIKELY (SCM_I_INUMP (y)))
ca46fb90 5506 {
e25f3727
AW
5507 scm_t_inum xx = SCM_I_INUM (x);
5508 scm_t_inum yy = SCM_I_INUM (y);
5509 scm_t_inum z = xx + yy;
5510 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_inum2big (z);
ca46fb90
RB
5511 }
5512 else if (SCM_BIGP (y))
5513 {
5514 SCM_SWAP (x, y);
5515 goto add_big_inum;
5516 }
5517 else if (SCM_REALP (y))
5518 {
e25f3727 5519 scm_t_inum xx = SCM_I_INUM (x);
55f26379 5520 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
5521 }
5522 else if (SCM_COMPLEXP (y))
5523 {
e25f3727 5524 scm_t_inum xx = SCM_I_INUM (x);
8507ec80 5525 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
5526 SCM_COMPLEX_IMAG (y));
5527 }
f92e85f7 5528 else if (SCM_FRACTIONP (y))
cba42c93 5529 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
5530 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
5531 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
5532 else
5533 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
5534 } else if (SCM_BIGP (x))
5535 {
e11e83f3 5536 if (SCM_I_INUMP (y))
0aacf84e 5537 {
e25f3727 5538 scm_t_inum inum;
0aacf84e
MD
5539 int bigsgn;
5540 add_big_inum:
e11e83f3 5541 inum = SCM_I_INUM (y);
0aacf84e
MD
5542 if (inum == 0)
5543 return x;
5544 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
5545 if (inum < 0)
5546 {
5547 SCM result = scm_i_mkbig ();
5548 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
5549 scm_remember_upto_here_1 (x);
5550 /* we know the result will have to be a bignum */
5551 if (bigsgn == -1)
5552 return result;
5553 return scm_i_normbig (result);
5554 }
5555 else
5556 {
5557 SCM result = scm_i_mkbig ();
5558 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
5559 scm_remember_upto_here_1 (x);
5560 /* we know the result will have to be a bignum */
5561 if (bigsgn == 1)
5562 return result;
5563 return scm_i_normbig (result);
5564 }
5565 }
5566 else if (SCM_BIGP (y))
5567 {
5568 SCM result = scm_i_mkbig ();
5569 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
5570 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
5571 mpz_add (SCM_I_BIG_MPZ (result),
5572 SCM_I_BIG_MPZ (x),
5573 SCM_I_BIG_MPZ (y));
5574 scm_remember_upto_here_2 (x, y);
5575 /* we know the result will have to be a bignum */
5576 if (sgn_x == sgn_y)
5577 return result;
5578 return scm_i_normbig (result);
5579 }
5580 else if (SCM_REALP (y))
5581 {
5582 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
5583 scm_remember_upto_here_1 (x);
55f26379 5584 return scm_from_double (result);
0aacf84e
MD
5585 }
5586 else if (SCM_COMPLEXP (y))
5587 {
5588 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
5589 + SCM_COMPLEX_REAL (y));
5590 scm_remember_upto_here_1 (x);
8507ec80 5591 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 5592 }
f92e85f7 5593 else if (SCM_FRACTIONP (y))
cba42c93 5594 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
5595 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
5596 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
5597 else
5598 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 5599 }
0aacf84e
MD
5600 else if (SCM_REALP (x))
5601 {
e11e83f3 5602 if (SCM_I_INUMP (y))
55f26379 5603 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
5604 else if (SCM_BIGP (y))
5605 {
5606 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
5607 scm_remember_upto_here_1 (y);
55f26379 5608 return scm_from_double (result);
0aacf84e
MD
5609 }
5610 else if (SCM_REALP (y))
55f26379 5611 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 5612 else if (SCM_COMPLEXP (y))
8507ec80 5613 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 5614 SCM_COMPLEX_IMAG (y));
f92e85f7 5615 else if (SCM_FRACTIONP (y))
55f26379 5616 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
5617 else
5618 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 5619 }
0aacf84e
MD
5620 else if (SCM_COMPLEXP (x))
5621 {
e11e83f3 5622 if (SCM_I_INUMP (y))
8507ec80 5623 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
5624 SCM_COMPLEX_IMAG (x));
5625 else if (SCM_BIGP (y))
5626 {
5627 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
5628 + SCM_COMPLEX_REAL (x));
5629 scm_remember_upto_here_1 (y);
8507ec80 5630 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
5631 }
5632 else if (SCM_REALP (y))
8507ec80 5633 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
5634 SCM_COMPLEX_IMAG (x));
5635 else if (SCM_COMPLEXP (y))
8507ec80 5636 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 5637 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 5638 else if (SCM_FRACTIONP (y))
8507ec80 5639 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
5640 SCM_COMPLEX_IMAG (x));
5641 else
5642 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
5643 }
5644 else if (SCM_FRACTIONP (x))
5645 {
e11e83f3 5646 if (SCM_I_INUMP (y))
cba42c93 5647 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5648 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
5649 SCM_FRACTION_DENOMINATOR (x));
5650 else if (SCM_BIGP (y))
cba42c93 5651 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5652 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
5653 SCM_FRACTION_DENOMINATOR (x));
5654 else if (SCM_REALP (y))
55f26379 5655 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 5656 else if (SCM_COMPLEXP (y))
8507ec80 5657 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
5658 SCM_COMPLEX_IMAG (y));
5659 else if (SCM_FRACTIONP (y))
5660 /* a/b + c/d = (ad + bc) / bd */
cba42c93 5661 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5662 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
5663 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
5664 else
5665 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 5666 }
0aacf84e 5667 else
98cb6e75 5668 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
5669}
5670
5671
40882e3d
KR
5672SCM_DEFINE (scm_oneplus, "1+", 1, 0, 0,
5673 (SCM x),
5674 "Return @math{@var{x}+1}.")
5675#define FUNC_NAME s_scm_oneplus
5676{
cff5fa33 5677 return scm_sum (x, SCM_INUM1);
40882e3d
KR
5678}
5679#undef FUNC_NAME
5680
5681
78d3deb1
AW
5682SCM_PRIMITIVE_GENERIC (scm_i_difference, "-", 0, 2, 1,
5683 (SCM x, SCM y, SCM rest),
5684 "If called with one argument @var{z1}, -@var{z1} returned. Otherwise\n"
5685 "the sum of all but the first argument are subtracted from the first\n"
5686 "argument.")
5687#define FUNC_NAME s_scm_i_difference
5688{
5689 while (!scm_is_null (rest))
5690 { x = scm_difference (x, y);
5691 y = scm_car (rest);
5692 rest = scm_cdr (rest);
5693 }
5694 return scm_difference (x, y);
5695}
5696#undef FUNC_NAME
5697
5698#define s_difference s_scm_i_difference
5699#define g_difference g_scm_i_difference
5700
0f2d19dd 5701SCM
6e8d25a6 5702scm_difference (SCM x, SCM y)
78d3deb1 5703#define FUNC_NAME s_difference
0f2d19dd 5704{
9cc37597 5705 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
5706 {
5707 if (SCM_UNBNDP (x))
5708 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
5709 else
e11e83f3 5710 if (SCM_I_INUMP (x))
ca46fb90 5711 {
e25f3727 5712 scm_t_inum xx = -SCM_I_INUM (x);
ca46fb90 5713 if (SCM_FIXABLE (xx))
d956fa6f 5714 return SCM_I_MAKINUM (xx);
ca46fb90 5715 else
e25f3727 5716 return scm_i_inum2big (xx);
ca46fb90
RB
5717 }
5718 else if (SCM_BIGP (x))
a9ad4847
KR
5719 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
5720 bignum, but negating that gives a fixnum. */
ca46fb90
RB
5721 return scm_i_normbig (scm_i_clonebig (x, 0));
5722 else if (SCM_REALP (x))
55f26379 5723 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 5724 else if (SCM_COMPLEXP (x))
8507ec80 5725 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 5726 -SCM_COMPLEX_IMAG (x));
f92e85f7 5727 else if (SCM_FRACTIONP (x))
cba42c93 5728 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 5729 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
5730 else
5731 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 5732 }
ca46fb90 5733
9cc37597 5734 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 5735 {
9cc37597 5736 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 5737 {
e25f3727
AW
5738 scm_t_inum xx = SCM_I_INUM (x);
5739 scm_t_inum yy = SCM_I_INUM (y);
5740 scm_t_inum z = xx - yy;
0aacf84e 5741 if (SCM_FIXABLE (z))
d956fa6f 5742 return SCM_I_MAKINUM (z);
0aacf84e 5743 else
e25f3727 5744 return scm_i_inum2big (z);
0aacf84e
MD
5745 }
5746 else if (SCM_BIGP (y))
5747 {
5748 /* inum-x - big-y */
e25f3727 5749 scm_t_inum xx = SCM_I_INUM (x);
ca46fb90 5750
0aacf84e 5751 if (xx == 0)
b5c40589
MW
5752 {
5753 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
5754 bignum, but negating that gives a fixnum. */
5755 return scm_i_normbig (scm_i_clonebig (y, 0));
5756 }
0aacf84e
MD
5757 else
5758 {
5759 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
5760 SCM result = scm_i_mkbig ();
ca46fb90 5761
0aacf84e
MD
5762 if (xx >= 0)
5763 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
5764 else
5765 {
5766 /* x - y == -(y + -x) */
5767 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
5768 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
5769 }
5770 scm_remember_upto_here_1 (y);
ca46fb90 5771
0aacf84e
MD
5772 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
5773 /* we know the result will have to be a bignum */
5774 return result;
5775 else
5776 return scm_i_normbig (result);
5777 }
5778 }
5779 else if (SCM_REALP (y))
5780 {
e25f3727 5781 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
5782
5783 /*
5784 * We need to handle x == exact 0
5785 * specially because R6RS states that:
5786 * (- 0.0) ==> -0.0 and
5787 * (- 0.0 0.0) ==> 0.0
5788 * and the scheme compiler changes
5789 * (- 0.0) into (- 0 0.0)
5790 * So we need to treat (- 0 0.0) like (- 0.0).
5791 * At the C level, (-x) is different than (0.0 - x).
5792 * (0.0 - 0.0) ==> 0.0, but (- 0.0) ==> -0.0.
5793 */
5794 if (xx == 0)
5795 return scm_from_double (- SCM_REAL_VALUE (y));
5796 else
5797 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
5798 }
5799 else if (SCM_COMPLEXP (y))
5800 {
e25f3727 5801 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
5802
5803 /* We need to handle x == exact 0 specially.
5804 See the comment above (for SCM_REALP (y)) */
5805 if (xx == 0)
5806 return scm_c_make_rectangular (- SCM_COMPLEX_REAL (y),
5807 - SCM_COMPLEX_IMAG (y));
5808 else
5809 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
5810 - SCM_COMPLEX_IMAG (y));
0aacf84e 5811 }
f92e85f7
MV
5812 else if (SCM_FRACTIONP (y))
5813 /* a - b/c = (ac - b) / c */
cba42c93 5814 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5815 SCM_FRACTION_NUMERATOR (y)),
5816 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
5817 else
5818 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 5819 }
0aacf84e
MD
5820 else if (SCM_BIGP (x))
5821 {
e11e83f3 5822 if (SCM_I_INUMP (y))
0aacf84e
MD
5823 {
5824 /* big-x - inum-y */
e25f3727 5825 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e 5826 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 5827
0aacf84e
MD
5828 scm_remember_upto_here_1 (x);
5829 if (sgn_x == 0)
c71b0706 5830 return (SCM_FIXABLE (-yy) ?
e25f3727 5831 SCM_I_MAKINUM (-yy) : scm_from_inum (-yy));
0aacf84e
MD
5832 else
5833 {
5834 SCM result = scm_i_mkbig ();
ca46fb90 5835
708f22c6
KR
5836 if (yy >= 0)
5837 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
5838 else
5839 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 5840 scm_remember_upto_here_1 (x);
ca46fb90 5841
0aacf84e
MD
5842 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
5843 /* we know the result will have to be a bignum */
5844 return result;
5845 else
5846 return scm_i_normbig (result);
5847 }
5848 }
5849 else if (SCM_BIGP (y))
5850 {
5851 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
5852 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
5853 SCM result = scm_i_mkbig ();
5854 mpz_sub (SCM_I_BIG_MPZ (result),
5855 SCM_I_BIG_MPZ (x),
5856 SCM_I_BIG_MPZ (y));
5857 scm_remember_upto_here_2 (x, y);
5858 /* we know the result will have to be a bignum */
5859 if ((sgn_x == 1) && (sgn_y == -1))
5860 return result;
5861 if ((sgn_x == -1) && (sgn_y == 1))
5862 return result;
5863 return scm_i_normbig (result);
5864 }
5865 else if (SCM_REALP (y))
5866 {
5867 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
5868 scm_remember_upto_here_1 (x);
55f26379 5869 return scm_from_double (result);
0aacf84e
MD
5870 }
5871 else if (SCM_COMPLEXP (y))
5872 {
5873 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
5874 - SCM_COMPLEX_REAL (y));
5875 scm_remember_upto_here_1 (x);
8507ec80 5876 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 5877 }
f92e85f7 5878 else if (SCM_FRACTIONP (y))
cba42c93 5879 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5880 SCM_FRACTION_NUMERATOR (y)),
5881 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 5882 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 5883 }
0aacf84e
MD
5884 else if (SCM_REALP (x))
5885 {
e11e83f3 5886 if (SCM_I_INUMP (y))
55f26379 5887 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
5888 else if (SCM_BIGP (y))
5889 {
5890 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
5891 scm_remember_upto_here_1 (x);
55f26379 5892 return scm_from_double (result);
0aacf84e
MD
5893 }
5894 else if (SCM_REALP (y))
55f26379 5895 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 5896 else if (SCM_COMPLEXP (y))
8507ec80 5897 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 5898 -SCM_COMPLEX_IMAG (y));
f92e85f7 5899 else if (SCM_FRACTIONP (y))
55f26379 5900 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
5901 else
5902 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 5903 }
0aacf84e
MD
5904 else if (SCM_COMPLEXP (x))
5905 {
e11e83f3 5906 if (SCM_I_INUMP (y))
8507ec80 5907 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
5908 SCM_COMPLEX_IMAG (x));
5909 else if (SCM_BIGP (y))
5910 {
5911 double real_part = (SCM_COMPLEX_REAL (x)
5912 - mpz_get_d (SCM_I_BIG_MPZ (y)));
5913 scm_remember_upto_here_1 (x);
8507ec80 5914 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
5915 }
5916 else if (SCM_REALP (y))
8507ec80 5917 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
5918 SCM_COMPLEX_IMAG (x));
5919 else if (SCM_COMPLEXP (y))
8507ec80 5920 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 5921 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 5922 else if (SCM_FRACTIONP (y))
8507ec80 5923 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
5924 SCM_COMPLEX_IMAG (x));
5925 else
5926 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
5927 }
5928 else if (SCM_FRACTIONP (x))
5929 {
e11e83f3 5930 if (SCM_I_INUMP (y))
f92e85f7 5931 /* a/b - c = (a - cb) / b */
cba42c93 5932 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5933 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
5934 SCM_FRACTION_DENOMINATOR (x));
5935 else if (SCM_BIGP (y))
cba42c93 5936 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
5937 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
5938 SCM_FRACTION_DENOMINATOR (x));
5939 else if (SCM_REALP (y))
55f26379 5940 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 5941 else if (SCM_COMPLEXP (y))
8507ec80 5942 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
5943 -SCM_COMPLEX_IMAG (y));
5944 else if (SCM_FRACTIONP (y))
5945 /* a/b - c/d = (ad - bc) / bd */
cba42c93 5946 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
5947 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
5948 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
5949 else
5950 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 5951 }
0aacf84e 5952 else
98cb6e75 5953 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 5954}
c05e97b7 5955#undef FUNC_NAME
0f2d19dd 5956
ca46fb90 5957
40882e3d
KR
5958SCM_DEFINE (scm_oneminus, "1-", 1, 0, 0,
5959 (SCM x),
5960 "Return @math{@var{x}-1}.")
5961#define FUNC_NAME s_scm_oneminus
5962{
cff5fa33 5963 return scm_difference (x, SCM_INUM1);
40882e3d
KR
5964}
5965#undef FUNC_NAME
5966
5967
78d3deb1
AW
5968SCM_PRIMITIVE_GENERIC (scm_i_product, "*", 0, 2, 1,
5969 (SCM x, SCM y, SCM rest),
5970 "Return the product of all arguments. If called without arguments,\n"
5971 "1 is returned.")
5972#define FUNC_NAME s_scm_i_product
5973{
5974 while (!scm_is_null (rest))
5975 { x = scm_product (x, y);
5976 y = scm_car (rest);
5977 rest = scm_cdr (rest);
5978 }
5979 return scm_product (x, y);
5980}
5981#undef FUNC_NAME
5982
5983#define s_product s_scm_i_product
5984#define g_product g_scm_i_product
5985
0f2d19dd 5986SCM
6e8d25a6 5987scm_product (SCM x, SCM y)
0f2d19dd 5988{
9cc37597 5989 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
5990 {
5991 if (SCM_UNBNDP (x))
d956fa6f 5992 return SCM_I_MAKINUM (1L);
0aacf84e
MD
5993 else if (SCM_NUMBERP (x))
5994 return x;
5995 else
5996 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 5997 }
ca46fb90 5998
9cc37597 5999 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 6000 {
e25f3727 6001 scm_t_inum xx;
f4c627b3 6002
5e791807 6003 xinum:
e11e83f3 6004 xx = SCM_I_INUM (x);
f4c627b3 6005
0aacf84e
MD
6006 switch (xx)
6007 {
5e791807
MW
6008 case 1:
6009 /* exact1 is the universal multiplicative identity */
6010 return y;
6011 break;
6012 case 0:
6013 /* exact0 times a fixnum is exact0: optimize this case */
6014 if (SCM_LIKELY (SCM_I_INUMP (y)))
6015 return SCM_INUM0;
6016 /* if the other argument is inexact, the result is inexact,
6017 and we must do the multiplication in order to handle
6018 infinities and NaNs properly. */
6019 else if (SCM_REALP (y))
6020 return scm_from_double (0.0 * SCM_REAL_VALUE (y));
6021 else if (SCM_COMPLEXP (y))
6022 return scm_c_make_rectangular (0.0 * SCM_COMPLEX_REAL (y),
6023 0.0 * SCM_COMPLEX_IMAG (y));
6024 /* we've already handled inexact numbers,
6025 so y must be exact, and we return exact0 */
6026 else if (SCM_NUMP (y))
6027 return SCM_INUM0;
6028 else
6029 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
6030 break;
6031 case -1:
b5c40589 6032 /*
5e791807
MW
6033 * This case is important for more than just optimization.
6034 * It handles the case of negating
b5c40589
MW
6035 * (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
6036 * which is a bignum that must be changed back into a fixnum.
6037 * Failure to do so will cause the following to return #f:
6038 * (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
6039 */
b5c40589
MW
6040 return scm_difference(y, SCM_UNDEFINED);
6041 break;
0aacf84e 6042 }
f4c627b3 6043
9cc37597 6044 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 6045 {
e25f3727
AW
6046 scm_t_inum yy = SCM_I_INUM (y);
6047 scm_t_inum kk = xx * yy;
d956fa6f 6048 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 6049 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
6050 return k;
6051 else
6052 {
e25f3727 6053 SCM result = scm_i_inum2big (xx);
0aacf84e
MD
6054 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
6055 return scm_i_normbig (result);
6056 }
6057 }
6058 else if (SCM_BIGP (y))
6059 {
6060 SCM result = scm_i_mkbig ();
6061 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
6062 scm_remember_upto_here_1 (y);
6063 return result;
6064 }
6065 else if (SCM_REALP (y))
55f26379 6066 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 6067 else if (SCM_COMPLEXP (y))
8507ec80 6068 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 6069 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 6070 else if (SCM_FRACTIONP (y))
cba42c93 6071 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 6072 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
6073 else
6074 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6075 }
0aacf84e
MD
6076 else if (SCM_BIGP (x))
6077 {
e11e83f3 6078 if (SCM_I_INUMP (y))
0aacf84e
MD
6079 {
6080 SCM_SWAP (x, y);
5e791807 6081 goto xinum;
0aacf84e
MD
6082 }
6083 else if (SCM_BIGP (y))
6084 {
6085 SCM result = scm_i_mkbig ();
6086 mpz_mul (SCM_I_BIG_MPZ (result),
6087 SCM_I_BIG_MPZ (x),
6088 SCM_I_BIG_MPZ (y));
6089 scm_remember_upto_here_2 (x, y);
6090 return result;
6091 }
6092 else if (SCM_REALP (y))
6093 {
6094 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
6095 scm_remember_upto_here_1 (x);
55f26379 6096 return scm_from_double (result);
0aacf84e
MD
6097 }
6098 else if (SCM_COMPLEXP (y))
6099 {
6100 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
6101 scm_remember_upto_here_1 (x);
8507ec80 6102 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
6103 z * SCM_COMPLEX_IMAG (y));
6104 }
f92e85f7 6105 else if (SCM_FRACTIONP (y))
cba42c93 6106 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 6107 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
6108 else
6109 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6110 }
0aacf84e
MD
6111 else if (SCM_REALP (x))
6112 {
e11e83f3 6113 if (SCM_I_INUMP (y))
5e791807
MW
6114 {
6115 SCM_SWAP (x, y);
6116 goto xinum;
6117 }
0aacf84e
MD
6118 else if (SCM_BIGP (y))
6119 {
6120 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
6121 scm_remember_upto_here_1 (y);
55f26379 6122 return scm_from_double (result);
0aacf84e
MD
6123 }
6124 else if (SCM_REALP (y))
55f26379 6125 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 6126 else if (SCM_COMPLEXP (y))
8507ec80 6127 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 6128 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 6129 else if (SCM_FRACTIONP (y))
55f26379 6130 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
6131 else
6132 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6133 }
0aacf84e
MD
6134 else if (SCM_COMPLEXP (x))
6135 {
e11e83f3 6136 if (SCM_I_INUMP (y))
5e791807
MW
6137 {
6138 SCM_SWAP (x, y);
6139 goto xinum;
6140 }
0aacf84e
MD
6141 else if (SCM_BIGP (y))
6142 {
6143 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
6144 scm_remember_upto_here_1 (y);
8507ec80 6145 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 6146 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
6147 }
6148 else if (SCM_REALP (y))
8507ec80 6149 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
6150 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
6151 else if (SCM_COMPLEXP (y))
6152 {
8507ec80 6153 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
6154 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
6155 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
6156 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
6157 }
f92e85f7
MV
6158 else if (SCM_FRACTIONP (y))
6159 {
6160 double yy = scm_i_fraction2double (y);
8507ec80 6161 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
6162 yy * SCM_COMPLEX_IMAG (x));
6163 }
6164 else
6165 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
6166 }
6167 else if (SCM_FRACTIONP (x))
6168 {
e11e83f3 6169 if (SCM_I_INUMP (y))
cba42c93 6170 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
6171 SCM_FRACTION_DENOMINATOR (x));
6172 else if (SCM_BIGP (y))
cba42c93 6173 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
6174 SCM_FRACTION_DENOMINATOR (x));
6175 else if (SCM_REALP (y))
55f26379 6176 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
6177 else if (SCM_COMPLEXP (y))
6178 {
6179 double xx = scm_i_fraction2double (x);
8507ec80 6180 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
6181 xx * SCM_COMPLEX_IMAG (y));
6182 }
6183 else if (SCM_FRACTIONP (y))
6184 /* a/b * c/d = ac / bd */
cba42c93 6185 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6186 SCM_FRACTION_NUMERATOR (y)),
6187 scm_product (SCM_FRACTION_DENOMINATOR (x),
6188 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
6189 else
6190 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6191 }
0aacf84e 6192 else
f4c627b3 6193 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
6194}
6195
7351e207
MV
6196#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
6197 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
6198#define ALLOW_DIVIDE_BY_ZERO
6199/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
6200#endif
0f2d19dd 6201
ba74ef4e
MV
6202/* The code below for complex division is adapted from the GNU
6203 libstdc++, which adapted it from f2c's libF77, and is subject to
6204 this copyright: */
6205
6206/****************************************************************
6207Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
6208
6209Permission to use, copy, modify, and distribute this software
6210and its documentation for any purpose and without fee is hereby
6211granted, provided that the above copyright notice appear in all
6212copies and that both that the copyright notice and this
6213permission notice and warranty disclaimer appear in supporting
6214documentation, and that the names of AT&T Bell Laboratories or
6215Bellcore or any of their entities not be used in advertising or
6216publicity pertaining to distribution of the software without
6217specific, written prior permission.
6218
6219AT&T and Bellcore disclaim all warranties with regard to this
6220software, including all implied warranties of merchantability
6221and fitness. In no event shall AT&T or Bellcore be liable for
6222any special, indirect or consequential damages or any damages
6223whatsoever resulting from loss of use, data or profits, whether
6224in an action of contract, negligence or other tortious action,
6225arising out of or in connection with the use or performance of
6226this software.
6227****************************************************************/
6228
78d3deb1
AW
6229SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
6230 (SCM x, SCM y, SCM rest),
6231 "Divide the first argument by the product of the remaining\n"
6232 "arguments. If called with one argument @var{z1}, 1/@var{z1} is\n"
6233 "returned.")
6234#define FUNC_NAME s_scm_i_divide
6235{
6236 while (!scm_is_null (rest))
6237 { x = scm_divide (x, y);
6238 y = scm_car (rest);
6239 rest = scm_cdr (rest);
6240 }
6241 return scm_divide (x, y);
6242}
6243#undef FUNC_NAME
6244
6245#define s_divide s_scm_i_divide
6246#define g_divide g_scm_i_divide
6247
f92e85f7 6248static SCM
78d3deb1
AW
6249do_divide (SCM x, SCM y, int inexact)
6250#define FUNC_NAME s_divide
0f2d19dd 6251{
f8de44c1
DH
6252 double a;
6253
9cc37597 6254 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
6255 {
6256 if (SCM_UNBNDP (x))
6257 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 6258 else if (SCM_I_INUMP (x))
0aacf84e 6259 {
e25f3727 6260 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
6261 if (xx == 1 || xx == -1)
6262 return x;
7351e207 6263#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6264 else if (xx == 0)
6265 scm_num_overflow (s_divide);
7351e207 6266#endif
0aacf84e 6267 else
f92e85f7
MV
6268 {
6269 if (inexact)
55f26379 6270 return scm_from_double (1.0 / (double) xx);
cff5fa33 6271 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 6272 }
0aacf84e
MD
6273 }
6274 else if (SCM_BIGP (x))
f92e85f7
MV
6275 {
6276 if (inexact)
55f26379 6277 return scm_from_double (1.0 / scm_i_big2dbl (x));
cff5fa33 6278 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 6279 }
0aacf84e
MD
6280 else if (SCM_REALP (x))
6281 {
6282 double xx = SCM_REAL_VALUE (x);
7351e207 6283#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6284 if (xx == 0.0)
6285 scm_num_overflow (s_divide);
6286 else
7351e207 6287#endif
55f26379 6288 return scm_from_double (1.0 / xx);
0aacf84e
MD
6289 }
6290 else if (SCM_COMPLEXP (x))
6291 {
6292 double r = SCM_COMPLEX_REAL (x);
6293 double i = SCM_COMPLEX_IMAG (x);
4c6e36a6 6294 if (fabs(r) <= fabs(i))
0aacf84e
MD
6295 {
6296 double t = r / i;
6297 double d = i * (1.0 + t * t);
8507ec80 6298 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
6299 }
6300 else
6301 {
6302 double t = i / r;
6303 double d = r * (1.0 + t * t);
8507ec80 6304 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
6305 }
6306 }
f92e85f7 6307 else if (SCM_FRACTIONP (x))
cba42c93 6308 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 6309 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
6310 else
6311 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 6312 }
f8de44c1 6313
9cc37597 6314 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 6315 {
e25f3727 6316 scm_t_inum xx = SCM_I_INUM (x);
9cc37597 6317 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 6318 {
e25f3727 6319 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6320 if (yy == 0)
6321 {
7351e207 6322#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 6323 scm_num_overflow (s_divide);
7351e207 6324#else
55f26379 6325 return scm_from_double ((double) xx / (double) yy);
7351e207 6326#endif
0aacf84e
MD
6327 }
6328 else if (xx % yy != 0)
f92e85f7
MV
6329 {
6330 if (inexact)
55f26379 6331 return scm_from_double ((double) xx / (double) yy);
cba42c93 6332 else return scm_i_make_ratio (x, y);
f92e85f7 6333 }
0aacf84e
MD
6334 else
6335 {
e25f3727 6336 scm_t_inum z = xx / yy;
0aacf84e 6337 if (SCM_FIXABLE (z))
d956fa6f 6338 return SCM_I_MAKINUM (z);
0aacf84e 6339 else
e25f3727 6340 return scm_i_inum2big (z);
0aacf84e 6341 }
f872b822 6342 }
0aacf84e 6343 else if (SCM_BIGP (y))
f92e85f7
MV
6344 {
6345 if (inexact)
55f26379 6346 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 6347 else return scm_i_make_ratio (x, y);
f92e85f7 6348 }
0aacf84e
MD
6349 else if (SCM_REALP (y))
6350 {
6351 double yy = SCM_REAL_VALUE (y);
7351e207 6352#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6353 if (yy == 0.0)
6354 scm_num_overflow (s_divide);
6355 else
7351e207 6356#endif
55f26379 6357 return scm_from_double ((double) xx / yy);
ba74ef4e 6358 }
0aacf84e
MD
6359 else if (SCM_COMPLEXP (y))
6360 {
6361 a = xx;
6362 complex_div: /* y _must_ be a complex number */
6363 {
6364 double r = SCM_COMPLEX_REAL (y);
6365 double i = SCM_COMPLEX_IMAG (y);
4c6e36a6 6366 if (fabs(r) <= fabs(i))
0aacf84e
MD
6367 {
6368 double t = r / i;
6369 double d = i * (1.0 + t * t);
8507ec80 6370 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
6371 }
6372 else
6373 {
6374 double t = i / r;
6375 double d = r * (1.0 + t * t);
8507ec80 6376 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
6377 }
6378 }
6379 }
f92e85f7
MV
6380 else if (SCM_FRACTIONP (y))
6381 /* a / b/c = ac / b */
cba42c93 6382 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 6383 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
6384 else
6385 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 6386 }
0aacf84e
MD
6387 else if (SCM_BIGP (x))
6388 {
e11e83f3 6389 if (SCM_I_INUMP (y))
0aacf84e 6390 {
e25f3727 6391 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6392 if (yy == 0)
6393 {
7351e207 6394#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 6395 scm_num_overflow (s_divide);
7351e207 6396#else
0aacf84e
MD
6397 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6398 scm_remember_upto_here_1 (x);
6399 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 6400#endif
0aacf84e
MD
6401 }
6402 else if (yy == 1)
6403 return x;
6404 else
6405 {
6406 /* FIXME: HMM, what are the relative performance issues here?
6407 We need to test. Is it faster on average to test
6408 divisible_p, then perform whichever operation, or is it
6409 faster to perform the integer div opportunistically and
6410 switch to real if there's a remainder? For now we take the
6411 middle ground: test, then if divisible, use the faster div
6412 func. */
6413
e25f3727 6414 scm_t_inum abs_yy = yy < 0 ? -yy : yy;
0aacf84e
MD
6415 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
6416
6417 if (divisible_p)
6418 {
6419 SCM result = scm_i_mkbig ();
6420 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
6421 scm_remember_upto_here_1 (x);
6422 if (yy < 0)
6423 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
6424 return scm_i_normbig (result);
6425 }
6426 else
f92e85f7
MV
6427 {
6428 if (inexact)
55f26379 6429 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 6430 else return scm_i_make_ratio (x, y);
f92e85f7 6431 }
0aacf84e
MD
6432 }
6433 }
6434 else if (SCM_BIGP (y))
6435 {
a4955a04
MW
6436 /* big_x / big_y */
6437 if (inexact)
0aacf84e 6438 {
a4955a04
MW
6439 /* It's easily possible for the ratio x/y to fit a double
6440 but one or both x and y be too big to fit a double,
6441 hence the use of mpq_get_d rather than converting and
6442 dividing. */
6443 mpq_t q;
6444 *mpq_numref(q) = *SCM_I_BIG_MPZ (x);
6445 *mpq_denref(q) = *SCM_I_BIG_MPZ (y);
6446 return scm_from_double (mpq_get_d (q));
0aacf84e
MD
6447 }
6448 else
6449 {
a4955a04
MW
6450 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
6451 SCM_I_BIG_MPZ (y));
6452 if (divisible_p)
6453 {
6454 SCM result = scm_i_mkbig ();
6455 mpz_divexact (SCM_I_BIG_MPZ (result),
6456 SCM_I_BIG_MPZ (x),
6457 SCM_I_BIG_MPZ (y));
6458 scm_remember_upto_here_2 (x, y);
6459 return scm_i_normbig (result);
6460 }
6461 else
6462 return scm_i_make_ratio (x, y);
0aacf84e
MD
6463 }
6464 }
6465 else if (SCM_REALP (y))
6466 {
6467 double yy = SCM_REAL_VALUE (y);
7351e207 6468#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6469 if (yy == 0.0)
6470 scm_num_overflow (s_divide);
6471 else
7351e207 6472#endif
55f26379 6473 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
6474 }
6475 else if (SCM_COMPLEXP (y))
6476 {
6477 a = scm_i_big2dbl (x);
6478 goto complex_div;
6479 }
f92e85f7 6480 else if (SCM_FRACTIONP (y))
cba42c93 6481 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 6482 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
6483 else
6484 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 6485 }
0aacf84e
MD
6486 else if (SCM_REALP (x))
6487 {
6488 double rx = SCM_REAL_VALUE (x);
e11e83f3 6489 if (SCM_I_INUMP (y))
0aacf84e 6490 {
e25f3727 6491 scm_t_inum yy = SCM_I_INUM (y);
7351e207 6492#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6493 if (yy == 0)
6494 scm_num_overflow (s_divide);
6495 else
7351e207 6496#endif
55f26379 6497 return scm_from_double (rx / (double) yy);
0aacf84e
MD
6498 }
6499 else if (SCM_BIGP (y))
6500 {
6501 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
6502 scm_remember_upto_here_1 (y);
55f26379 6503 return scm_from_double (rx / dby);
0aacf84e
MD
6504 }
6505 else if (SCM_REALP (y))
6506 {
6507 double yy = SCM_REAL_VALUE (y);
7351e207 6508#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6509 if (yy == 0.0)
6510 scm_num_overflow (s_divide);
6511 else
7351e207 6512#endif
55f26379 6513 return scm_from_double (rx / yy);
0aacf84e
MD
6514 }
6515 else if (SCM_COMPLEXP (y))
6516 {
6517 a = rx;
6518 goto complex_div;
6519 }
f92e85f7 6520 else if (SCM_FRACTIONP (y))
55f26379 6521 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
6522 else
6523 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 6524 }
0aacf84e
MD
6525 else if (SCM_COMPLEXP (x))
6526 {
6527 double rx = SCM_COMPLEX_REAL (x);
6528 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 6529 if (SCM_I_INUMP (y))
0aacf84e 6530 {
e25f3727 6531 scm_t_inum yy = SCM_I_INUM (y);
7351e207 6532#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6533 if (yy == 0)
6534 scm_num_overflow (s_divide);
6535 else
7351e207 6536#endif
0aacf84e
MD
6537 {
6538 double d = yy;
8507ec80 6539 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
6540 }
6541 }
6542 else if (SCM_BIGP (y))
6543 {
6544 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
6545 scm_remember_upto_here_1 (y);
8507ec80 6546 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
6547 }
6548 else if (SCM_REALP (y))
6549 {
6550 double yy = SCM_REAL_VALUE (y);
7351e207 6551#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6552 if (yy == 0.0)
6553 scm_num_overflow (s_divide);
6554 else
7351e207 6555#endif
8507ec80 6556 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
6557 }
6558 else if (SCM_COMPLEXP (y))
6559 {
6560 double ry = SCM_COMPLEX_REAL (y);
6561 double iy = SCM_COMPLEX_IMAG (y);
4c6e36a6 6562 if (fabs(ry) <= fabs(iy))
0aacf84e
MD
6563 {
6564 double t = ry / iy;
6565 double d = iy * (1.0 + t * t);
8507ec80 6566 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
6567 }
6568 else
6569 {
6570 double t = iy / ry;
6571 double d = ry * (1.0 + t * t);
8507ec80 6572 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
6573 }
6574 }
f92e85f7
MV
6575 else if (SCM_FRACTIONP (y))
6576 {
6577 double yy = scm_i_fraction2double (y);
8507ec80 6578 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 6579 }
0aacf84e
MD
6580 else
6581 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 6582 }
f92e85f7
MV
6583 else if (SCM_FRACTIONP (x))
6584 {
e11e83f3 6585 if (SCM_I_INUMP (y))
f92e85f7 6586 {
e25f3727 6587 scm_t_inum yy = SCM_I_INUM (y);
f92e85f7
MV
6588#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
6589 if (yy == 0)
6590 scm_num_overflow (s_divide);
6591 else
6592#endif
cba42c93 6593 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6594 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
6595 }
6596 else if (SCM_BIGP (y))
6597 {
cba42c93 6598 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6599 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
6600 }
6601 else if (SCM_REALP (y))
6602 {
6603 double yy = SCM_REAL_VALUE (y);
6604#ifndef ALLOW_DIVIDE_BY_ZERO
6605 if (yy == 0.0)
6606 scm_num_overflow (s_divide);
6607 else
6608#endif
55f26379 6609 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
6610 }
6611 else if (SCM_COMPLEXP (y))
6612 {
6613 a = scm_i_fraction2double (x);
6614 goto complex_div;
6615 }
6616 else if (SCM_FRACTIONP (y))
cba42c93 6617 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
6618 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
6619 else
6620 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
6621 }
0aacf84e 6622 else
f8de44c1 6623 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 6624}
f92e85f7
MV
6625
6626SCM
6627scm_divide (SCM x, SCM y)
6628{
78d3deb1 6629 return do_divide (x, y, 0);
f92e85f7
MV
6630}
6631
6632static SCM scm_divide2real (SCM x, SCM y)
6633{
78d3deb1 6634 return do_divide (x, y, 1);
f92e85f7 6635}
c05e97b7 6636#undef FUNC_NAME
0f2d19dd 6637
fa605590 6638
0f2d19dd 6639double
3101f40f 6640scm_c_truncate (double x)
0f2d19dd 6641{
fa605590
KR
6642#if HAVE_TRUNC
6643 return trunc (x);
6644#else
f872b822
MD
6645 if (x < 0.0)
6646 return -floor (-x);
6647 return floor (x);
fa605590 6648#endif
0f2d19dd 6649}
0f2d19dd 6650
3101f40f
MV
6651/* scm_c_round is done using floor(x+0.5) to round to nearest and with
6652 half-way case (ie. when x is an integer plus 0.5) going upwards.
6653 Then half-way cases are identified and adjusted down if the
6654 round-upwards didn't give the desired even integer.
6187f48b
KR
6655
6656 "plus_half == result" identifies a half-way case. If plus_half, which is
6657 x + 0.5, is an integer then x must be an integer plus 0.5.
6658
6659 An odd "result" value is identified with result/2 != floor(result/2).
6660 This is done with plus_half, since that value is ready for use sooner in
6661 a pipelined cpu, and we're already requiring plus_half == result.
6662
6663 Note however that we need to be careful when x is big and already an
6664 integer. In that case "x+0.5" may round to an adjacent integer, causing
6665 us to return such a value, incorrectly. For instance if the hardware is
6666 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
6667 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
6668 returned. Or if the hardware is in round-upwards mode, then other bigger
6669 values like say x == 2^128 will see x+0.5 rounding up to the next higher
6670 representable value, 2^128+2^76 (or whatever), again incorrect.
6671
6672 These bad roundings of x+0.5 are avoided by testing at the start whether
6673 x is already an integer. If it is then clearly that's the desired result
6674 already. And if it's not then the exponent must be small enough to allow
6675 an 0.5 to be represented, and hence added without a bad rounding. */
6676
0f2d19dd 6677double
3101f40f 6678scm_c_round (double x)
0f2d19dd 6679{
6187f48b
KR
6680 double plus_half, result;
6681
6682 if (x == floor (x))
6683 return x;
6684
6685 plus_half = x + 0.5;
6686 result = floor (plus_half);
3101f40f 6687 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
6688 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
6689 ? result - 1
6690 : result);
0f2d19dd
JB
6691}
6692
f92e85f7
MV
6693SCM_DEFINE (scm_truncate_number, "truncate", 1, 0, 0,
6694 (SCM x),
6695 "Round the number @var{x} towards zero.")
6696#define FUNC_NAME s_scm_truncate_number
6697{
73e4de09 6698 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
6699 return scm_floor (x);
6700 else
6701 return scm_ceiling (x);
6702}
6703#undef FUNC_NAME
6704
f92e85f7
MV
6705SCM_DEFINE (scm_round_number, "round", 1, 0, 0,
6706 (SCM x),
6707 "Round the number @var{x} towards the nearest integer. "
6708 "When it is exactly halfway between two integers, "
6709 "round towards the even one.")
6710#define FUNC_NAME s_scm_round_number
6711{
e11e83f3 6712 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
6713 return x;
6714 else if (SCM_REALP (x))
3101f40f 6715 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
f92e85f7 6716 else
bae30667
KR
6717 {
6718 /* OPTIMIZE-ME: Fraction case could be done more efficiently by a
6719 single quotient+remainder division then examining to see which way
6720 the rounding should go. */
6721 SCM plus_half = scm_sum (x, exactly_one_half);
6722 SCM result = scm_floor (plus_half);
3101f40f 6723 /* Adjust so that the rounding is towards even. */
73e4de09
MV
6724 if (scm_is_true (scm_num_eq_p (plus_half, result))
6725 && scm_is_true (scm_odd_p (result)))
cff5fa33 6726 return scm_difference (result, SCM_INUM1);
bae30667
KR
6727 else
6728 return result;
6729 }
f92e85f7
MV
6730}
6731#undef FUNC_NAME
6732
6733SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
6734 (SCM x),
6735 "Round the number @var{x} towards minus infinity.")
6736#define FUNC_NAME s_scm_floor
6737{
e11e83f3 6738 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
6739 return x;
6740 else if (SCM_REALP (x))
55f26379 6741 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7
MV
6742 else if (SCM_FRACTIONP (x))
6743 {
6744 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
6745 SCM_FRACTION_DENOMINATOR (x));
73e4de09 6746 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
6747 {
6748 /* For positive x, rounding towards zero is correct. */
6749 return q;
6750 }
6751 else
6752 {
6753 /* For negative x, we need to return q-1 unless x is an
6754 integer. But fractions are never integer, per our
6755 assumptions. */
cff5fa33 6756 return scm_difference (q, SCM_INUM1);
f92e85f7
MV
6757 }
6758 }
6759 else
6760 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
6761}
6762#undef FUNC_NAME
6763
6764SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
6765 (SCM x),
6766 "Round the number @var{x} towards infinity.")
6767#define FUNC_NAME s_scm_ceiling
6768{
e11e83f3 6769 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
6770 return x;
6771 else if (SCM_REALP (x))
55f26379 6772 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7
MV
6773 else if (SCM_FRACTIONP (x))
6774 {
6775 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
6776 SCM_FRACTION_DENOMINATOR (x));
73e4de09 6777 if (scm_is_false (scm_positive_p (x)))
f92e85f7
MV
6778 {
6779 /* For negative x, rounding towards zero is correct. */
6780 return q;
6781 }
6782 else
6783 {
6784 /* For positive x, we need to return q+1 unless x is an
6785 integer. But fractions are never integer, per our
6786 assumptions. */
cff5fa33 6787 return scm_sum (q, SCM_INUM1);
f92e85f7
MV
6788 }
6789 }
6790 else
6791 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
6792}
6793#undef FUNC_NAME
0f2d19dd 6794
2519490c
MW
6795SCM_PRIMITIVE_GENERIC (scm_expt, "expt", 2, 0, 0,
6796 (SCM x, SCM y),
6797 "Return @var{x} raised to the power of @var{y}.")
6fc4d012 6798#define FUNC_NAME s_scm_expt
0f2d19dd 6799{
01c7284a
MW
6800 if (scm_is_integer (y))
6801 {
6802 if (scm_is_true (scm_exact_p (y)))
6803 return scm_integer_expt (x, y);
6804 else
6805 {
6806 /* Here we handle the case where the exponent is an inexact
6807 integer. We make the exponent exact in order to use
6808 scm_integer_expt, and thus avoid the spurious imaginary
6809 parts that may result from round-off errors in the general
6810 e^(y log x) method below (for example when squaring a large
6811 negative number). In this case, we must return an inexact
6812 result for correctness. We also make the base inexact so
6813 that scm_integer_expt will use fast inexact arithmetic
6814 internally. Note that making the base inexact is not
6815 sufficient to guarantee an inexact result, because
6816 scm_integer_expt will return an exact 1 when the exponent
6817 is 0, even if the base is inexact. */
6818 return scm_exact_to_inexact
6819 (scm_integer_expt (scm_exact_to_inexact (x),
6820 scm_inexact_to_exact (y)));
6821 }
6822 }
6fc4d012
AW
6823 else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
6824 {
6825 return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
6826 }
2519490c 6827 else if (scm_is_complex (x) && scm_is_complex (y))
6fc4d012 6828 return scm_exp (scm_product (scm_log (x), y));
2519490c
MW
6829 else if (scm_is_complex (x))
6830 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG2, s_scm_expt);
6831 else
6832 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG1, s_scm_expt);
0f2d19dd 6833}
1bbd0b84 6834#undef FUNC_NAME
0f2d19dd 6835
7f41099e
MW
6836/* sin/cos/tan/asin/acos/atan
6837 sinh/cosh/tanh/asinh/acosh/atanh
6838 Derived from "Transcen.scm", Complex trancendental functions for SCM.
6839 Written by Jerry D. Hedden, (C) FSF.
6840 See the file `COPYING' for terms applying to this program. */
6841
ad79736c
AW
6842SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
6843 (SCM z),
6844 "Compute the sine of @var{z}.")
6845#define FUNC_NAME s_scm_sin
6846{
8deddc94
MW
6847 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6848 return z; /* sin(exact0) = exact0 */
6849 else if (scm_is_real (z))
ad79736c
AW
6850 return scm_from_double (sin (scm_to_double (z)));
6851 else if (SCM_COMPLEXP (z))
6852 { double x, y;
6853 x = SCM_COMPLEX_REAL (z);
6854 y = SCM_COMPLEX_IMAG (z);
6855 return scm_c_make_rectangular (sin (x) * cosh (y),
6856 cos (x) * sinh (y));
6857 }
6858 else
6859 SCM_WTA_DISPATCH_1 (g_scm_sin, z, 1, s_scm_sin);
6860}
6861#undef FUNC_NAME
0f2d19dd 6862
ad79736c
AW
6863SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
6864 (SCM z),
6865 "Compute the cosine of @var{z}.")
6866#define FUNC_NAME s_scm_cos
6867{
8deddc94
MW
6868 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6869 return SCM_INUM1; /* cos(exact0) = exact1 */
6870 else if (scm_is_real (z))
ad79736c
AW
6871 return scm_from_double (cos (scm_to_double (z)));
6872 else if (SCM_COMPLEXP (z))
6873 { double x, y;
6874 x = SCM_COMPLEX_REAL (z);
6875 y = SCM_COMPLEX_IMAG (z);
6876 return scm_c_make_rectangular (cos (x) * cosh (y),
6877 -sin (x) * sinh (y));
6878 }
6879 else
6880 SCM_WTA_DISPATCH_1 (g_scm_cos, z, 1, s_scm_cos);
6881}
6882#undef FUNC_NAME
6883
6884SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
6885 (SCM z),
6886 "Compute the tangent of @var{z}.")
6887#define FUNC_NAME s_scm_tan
0f2d19dd 6888{
8deddc94
MW
6889 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6890 return z; /* tan(exact0) = exact0 */
6891 else if (scm_is_real (z))
ad79736c
AW
6892 return scm_from_double (tan (scm_to_double (z)));
6893 else if (SCM_COMPLEXP (z))
6894 { double x, y, w;
6895 x = 2.0 * SCM_COMPLEX_REAL (z);
6896 y = 2.0 * SCM_COMPLEX_IMAG (z);
6897 w = cos (x) + cosh (y);
6898#ifndef ALLOW_DIVIDE_BY_ZERO
6899 if (w == 0.0)
6900 scm_num_overflow (s_scm_tan);
6901#endif
6902 return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
6903 }
6904 else
6905 SCM_WTA_DISPATCH_1 (g_scm_tan, z, 1, s_scm_tan);
6906}
6907#undef FUNC_NAME
6908
6909SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
6910 (SCM z),
6911 "Compute the hyperbolic sine of @var{z}.")
6912#define FUNC_NAME s_scm_sinh
6913{
8deddc94
MW
6914 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6915 return z; /* sinh(exact0) = exact0 */
6916 else if (scm_is_real (z))
ad79736c
AW
6917 return scm_from_double (sinh (scm_to_double (z)));
6918 else if (SCM_COMPLEXP (z))
6919 { double x, y;
6920 x = SCM_COMPLEX_REAL (z);
6921 y = SCM_COMPLEX_IMAG (z);
6922 return scm_c_make_rectangular (sinh (x) * cos (y),
6923 cosh (x) * sin (y));
6924 }
6925 else
6926 SCM_WTA_DISPATCH_1 (g_scm_sinh, z, 1, s_scm_sinh);
6927}
6928#undef FUNC_NAME
6929
6930SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
6931 (SCM z),
6932 "Compute the hyperbolic cosine of @var{z}.")
6933#define FUNC_NAME s_scm_cosh
6934{
8deddc94
MW
6935 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6936 return SCM_INUM1; /* cosh(exact0) = exact1 */
6937 else if (scm_is_real (z))
ad79736c
AW
6938 return scm_from_double (cosh (scm_to_double (z)));
6939 else if (SCM_COMPLEXP (z))
6940 { double x, y;
6941 x = SCM_COMPLEX_REAL (z);
6942 y = SCM_COMPLEX_IMAG (z);
6943 return scm_c_make_rectangular (cosh (x) * cos (y),
6944 sinh (x) * sin (y));
6945 }
6946 else
6947 SCM_WTA_DISPATCH_1 (g_scm_cosh, z, 1, s_scm_cosh);
6948}
6949#undef FUNC_NAME
6950
6951SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
6952 (SCM z),
6953 "Compute the hyperbolic tangent of @var{z}.")
6954#define FUNC_NAME s_scm_tanh
6955{
8deddc94
MW
6956 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6957 return z; /* tanh(exact0) = exact0 */
6958 else if (scm_is_real (z))
ad79736c
AW
6959 return scm_from_double (tanh (scm_to_double (z)));
6960 else if (SCM_COMPLEXP (z))
6961 { double x, y, w;
6962 x = 2.0 * SCM_COMPLEX_REAL (z);
6963 y = 2.0 * SCM_COMPLEX_IMAG (z);
6964 w = cosh (x) + cos (y);
6965#ifndef ALLOW_DIVIDE_BY_ZERO
6966 if (w == 0.0)
6967 scm_num_overflow (s_scm_tanh);
6968#endif
6969 return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
6970 }
6971 else
6972 SCM_WTA_DISPATCH_1 (g_scm_tanh, z, 1, s_scm_tanh);
6973}
6974#undef FUNC_NAME
6975
6976SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
6977 (SCM z),
6978 "Compute the arc sine of @var{z}.")
6979#define FUNC_NAME s_scm_asin
6980{
8deddc94
MW
6981 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
6982 return z; /* asin(exact0) = exact0 */
6983 else if (scm_is_real (z))
ad79736c
AW
6984 {
6985 double w = scm_to_double (z);
6986 if (w >= -1.0 && w <= 1.0)
6987 return scm_from_double (asin (w));
6988 else
6989 return 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_product (scm_c_make_rectangular (0, -1),
6997 scm_sys_asinh (scm_c_make_rectangular (-y, x)));
6998 }
6999 else
7000 SCM_WTA_DISPATCH_1 (g_scm_asin, z, 1, s_scm_asin);
7001}
7002#undef FUNC_NAME
7003
7004SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
7005 (SCM z),
7006 "Compute the arc cosine of @var{z}.")
7007#define FUNC_NAME s_scm_acos
7008{
8deddc94
MW
7009 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
7010 return SCM_INUM0; /* acos(exact1) = exact0 */
7011 else if (scm_is_real (z))
ad79736c
AW
7012 {
7013 double w = scm_to_double (z);
7014 if (w >= -1.0 && w <= 1.0)
7015 return scm_from_double (acos (w));
7016 else
7017 return scm_sum (scm_from_double (acos (0.0)),
7018 scm_product (scm_c_make_rectangular (0, 1),
7019 scm_sys_asinh (scm_c_make_rectangular (0, w))));
7020 }
7021 else if (SCM_COMPLEXP (z))
7022 { double x, y;
7023 x = SCM_COMPLEX_REAL (z);
7024 y = SCM_COMPLEX_IMAG (z);
7025 return scm_sum (scm_from_double (acos (0.0)),
7026 scm_product (scm_c_make_rectangular (0, 1),
7027 scm_sys_asinh (scm_c_make_rectangular (-y, x))));
7028 }
7029 else
7030 SCM_WTA_DISPATCH_1 (g_scm_acos, z, 1, s_scm_acos);
7031}
7032#undef FUNC_NAME
7033
7034SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
7035 (SCM z, SCM y),
7036 "With one argument, compute the arc tangent of @var{z}.\n"
7037 "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
7038 "using the sign of @var{z} and @var{y} to determine the quadrant.")
7039#define FUNC_NAME s_scm_atan
7040{
7041 if (SCM_UNBNDP (y))
7042 {
8deddc94
MW
7043 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
7044 return z; /* atan(exact0) = exact0 */
7045 else if (scm_is_real (z))
ad79736c
AW
7046 return scm_from_double (atan (scm_to_double (z)));
7047 else if (SCM_COMPLEXP (z))
7048 {
7049 double v, w;
7050 v = SCM_COMPLEX_REAL (z);
7051 w = SCM_COMPLEX_IMAG (z);
7052 return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
7053 scm_c_make_rectangular (v, w + 1.0))),
7054 scm_c_make_rectangular (0, 2));
7055 }
7056 else
18104cac 7057 SCM_WTA_DISPATCH_1 (g_scm_atan, z, SCM_ARG1, s_scm_atan);
ad79736c
AW
7058 }
7059 else if (scm_is_real (z))
7060 {
7061 if (scm_is_real (y))
7062 return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
7063 else
7064 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
7065 }
7066 else
7067 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
7068}
7069#undef FUNC_NAME
7070
7071SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
7072 (SCM z),
7073 "Compute the inverse hyperbolic sine of @var{z}.")
7074#define FUNC_NAME s_scm_sys_asinh
7075{
8deddc94
MW
7076 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
7077 return z; /* asinh(exact0) = exact0 */
7078 else if (scm_is_real (z))
ad79736c
AW
7079 return scm_from_double (asinh (scm_to_double (z)));
7080 else if (scm_is_number (z))
7081 return scm_log (scm_sum (z,
7082 scm_sqrt (scm_sum (scm_product (z, z),
cff5fa33 7083 SCM_INUM1))));
ad79736c
AW
7084 else
7085 SCM_WTA_DISPATCH_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
7086}
7087#undef FUNC_NAME
7088
7089SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
7090 (SCM z),
7091 "Compute the inverse hyperbolic cosine of @var{z}.")
7092#define FUNC_NAME s_scm_sys_acosh
7093{
8deddc94
MW
7094 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
7095 return SCM_INUM0; /* acosh(exact1) = exact0 */
7096 else if (scm_is_real (z) && scm_to_double (z) >= 1.0)
ad79736c
AW
7097 return scm_from_double (acosh (scm_to_double (z)));
7098 else if (scm_is_number (z))
7099 return scm_log (scm_sum (z,
7100 scm_sqrt (scm_difference (scm_product (z, z),
cff5fa33 7101 SCM_INUM1))));
ad79736c
AW
7102 else
7103 SCM_WTA_DISPATCH_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
7104}
7105#undef FUNC_NAME
7106
7107SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
7108 (SCM z),
7109 "Compute the inverse hyperbolic tangent of @var{z}.")
7110#define FUNC_NAME s_scm_sys_atanh
7111{
8deddc94
MW
7112 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
7113 return z; /* atanh(exact0) = exact0 */
7114 else if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
ad79736c
AW
7115 return scm_from_double (atanh (scm_to_double (z)));
7116 else if (scm_is_number (z))
cff5fa33
MW
7117 return scm_divide (scm_log (scm_divide (scm_sum (SCM_INUM1, z),
7118 scm_difference (SCM_INUM1, z))),
ad79736c
AW
7119 SCM_I_MAKINUM (2));
7120 else
7121 SCM_WTA_DISPATCH_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
0f2d19dd 7122}
1bbd0b84 7123#undef FUNC_NAME
0f2d19dd 7124
8507ec80
MV
7125SCM
7126scm_c_make_rectangular (double re, double im)
7127{
c7218482 7128 SCM z;
03604fcf 7129
c7218482
MW
7130 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
7131 "complex"));
7132 SCM_SET_CELL_TYPE (z, scm_tc16_complex);
7133 SCM_COMPLEX_REAL (z) = re;
7134 SCM_COMPLEX_IMAG (z) = im;
7135 return z;
8507ec80 7136}
0f2d19dd 7137
a1ec6916 7138SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
a2c25234
LC
7139 (SCM real_part, SCM imaginary_part),
7140 "Return a complex number constructed of the given @var{real-part} "
7141 "and @var{imaginary-part} parts.")
1bbd0b84 7142#define FUNC_NAME s_scm_make_rectangular
0f2d19dd 7143{
ad79736c
AW
7144 SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
7145 SCM_ARG1, FUNC_NAME, "real");
7146 SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
7147 SCM_ARG2, FUNC_NAME, "real");
c7218482
MW
7148
7149 /* Return a real if and only if the imaginary_part is an _exact_ 0 */
7150 if (scm_is_eq (imaginary_part, SCM_INUM0))
7151 return real_part;
7152 else
7153 return scm_c_make_rectangular (scm_to_double (real_part),
7154 scm_to_double (imaginary_part));
0f2d19dd 7155}
1bbd0b84 7156#undef FUNC_NAME
0f2d19dd 7157
8507ec80
MV
7158SCM
7159scm_c_make_polar (double mag, double ang)
7160{
7161 double s, c;
5e647d08
LC
7162
7163 /* The sincos(3) function is undocumented an broken on Tru64. Thus we only
7164 use it on Glibc-based systems that have it (it's a GNU extension). See
7165 http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
7166 details. */
7167#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
8507ec80
MV
7168 sincos (ang, &s, &c);
7169#else
7170 s = sin (ang);
7171 c = cos (ang);
7172#endif
9d427b2c
MW
7173
7174 /* If s and c are NaNs, this indicates that the angle is a NaN,
7175 infinite, or perhaps simply too large to determine its value
7176 mod 2*pi. However, we know something that the floating-point
7177 implementation doesn't know: We know that s and c are finite.
7178 Therefore, if the magnitude is zero, return a complex zero.
7179
7180 The reason we check for the NaNs instead of using this case
7181 whenever mag == 0.0 is because when the angle is known, we'd
7182 like to return the correct kind of non-real complex zero:
7183 +0.0+0.0i, -0.0+0.0i, -0.0-0.0i, or +0.0-0.0i, depending
7184 on which quadrant the angle is in.
7185 */
7186 if (SCM_UNLIKELY (isnan(s)) && isnan(c) && (mag == 0.0))
7187 return scm_c_make_rectangular (0.0, 0.0);
7188 else
7189 return scm_c_make_rectangular (mag * c, mag * s);
8507ec80 7190}
0f2d19dd 7191
a1ec6916 7192SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
c7218482
MW
7193 (SCM mag, SCM ang),
7194 "Return the complex number @var{mag} * e^(i * @var{ang}).")
1bbd0b84 7195#define FUNC_NAME s_scm_make_polar
0f2d19dd 7196{
c7218482
MW
7197 SCM_ASSERT_TYPE (scm_is_real (mag), mag, SCM_ARG1, FUNC_NAME, "real");
7198 SCM_ASSERT_TYPE (scm_is_real (ang), ang, SCM_ARG2, FUNC_NAME, "real");
7199
7200 /* If mag is exact0, return exact0 */
7201 if (scm_is_eq (mag, SCM_INUM0))
7202 return SCM_INUM0;
7203 /* Return a real if ang is exact0 */
7204 else if (scm_is_eq (ang, SCM_INUM0))
7205 return mag;
7206 else
7207 return scm_c_make_polar (scm_to_double (mag), scm_to_double (ang));
0f2d19dd 7208}
1bbd0b84 7209#undef FUNC_NAME
0f2d19dd
JB
7210
7211
2519490c
MW
7212SCM_PRIMITIVE_GENERIC (scm_real_part, "real-part", 1, 0, 0,
7213 (SCM z),
7214 "Return the real part of the number @var{z}.")
7215#define FUNC_NAME s_scm_real_part
0f2d19dd 7216{
2519490c 7217 if (SCM_COMPLEXP (z))
55f26379 7218 return scm_from_double (SCM_COMPLEX_REAL (z));
2519490c 7219 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_REALP (z) || SCM_FRACTIONP (z))
2fa2d879 7220 return z;
0aacf84e 7221 else
2519490c 7222 SCM_WTA_DISPATCH_1 (g_scm_real_part, z, SCM_ARG1, s_scm_real_part);
0f2d19dd 7223}
2519490c 7224#undef FUNC_NAME
0f2d19dd
JB
7225
7226
2519490c
MW
7227SCM_PRIMITIVE_GENERIC (scm_imag_part, "imag-part", 1, 0, 0,
7228 (SCM z),
7229 "Return the imaginary part of the number @var{z}.")
7230#define FUNC_NAME s_scm_imag_part
0f2d19dd 7231{
2519490c
MW
7232 if (SCM_COMPLEXP (z))
7233 return scm_from_double (SCM_COMPLEX_IMAG (z));
c7218482 7234 else if (SCM_I_INUMP (z) || SCM_REALP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f92e85f7 7235 return SCM_INUM0;
0aacf84e 7236 else
2519490c 7237 SCM_WTA_DISPATCH_1 (g_scm_imag_part, z, SCM_ARG1, s_scm_imag_part);
0f2d19dd 7238}
2519490c 7239#undef FUNC_NAME
0f2d19dd 7240
2519490c
MW
7241SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
7242 (SCM z),
7243 "Return the numerator of the number @var{z}.")
7244#define FUNC_NAME s_scm_numerator
f92e85f7 7245{
2519490c 7246 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f92e85f7
MV
7247 return z;
7248 else if (SCM_FRACTIONP (z))
e2bf3b19 7249 return SCM_FRACTION_NUMERATOR (z);
f92e85f7
MV
7250 else if (SCM_REALP (z))
7251 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
7252 else
2519490c 7253 SCM_WTA_DISPATCH_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
f92e85f7 7254}
2519490c 7255#undef FUNC_NAME
f92e85f7
MV
7256
7257
2519490c
MW
7258SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
7259 (SCM z),
7260 "Return the denominator of the number @var{z}.")
7261#define FUNC_NAME s_scm_denominator
f92e85f7 7262{
2519490c 7263 if (SCM_I_INUMP (z) || SCM_BIGP (z))
cff5fa33 7264 return SCM_INUM1;
f92e85f7 7265 else if (SCM_FRACTIONP (z))
e2bf3b19 7266 return SCM_FRACTION_DENOMINATOR (z);
f92e85f7
MV
7267 else if (SCM_REALP (z))
7268 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
7269 else
2519490c 7270 SCM_WTA_DISPATCH_1 (g_scm_denominator, z, SCM_ARG1, s_scm_denominator);
f92e85f7 7271}
2519490c 7272#undef FUNC_NAME
0f2d19dd 7273
2519490c
MW
7274
7275SCM_PRIMITIVE_GENERIC (scm_magnitude, "magnitude", 1, 0, 0,
7276 (SCM z),
7277 "Return the magnitude of the number @var{z}. This is the same as\n"
7278 "@code{abs} for real arguments, but also allows complex numbers.")
7279#define FUNC_NAME s_scm_magnitude
0f2d19dd 7280{
e11e83f3 7281 if (SCM_I_INUMP (z))
0aacf84e 7282 {
e25f3727 7283 scm_t_inum zz = SCM_I_INUM (z);
0aacf84e
MD
7284 if (zz >= 0)
7285 return z;
7286 else if (SCM_POSFIXABLE (-zz))
d956fa6f 7287 return SCM_I_MAKINUM (-zz);
0aacf84e 7288 else
e25f3727 7289 return scm_i_inum2big (-zz);
5986c47d 7290 }
0aacf84e
MD
7291 else if (SCM_BIGP (z))
7292 {
7293 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
7294 scm_remember_upto_here_1 (z);
7295 if (sgn < 0)
7296 return scm_i_clonebig (z, 0);
7297 else
7298 return z;
5986c47d 7299 }
0aacf84e 7300 else if (SCM_REALP (z))
55f26379 7301 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 7302 else if (SCM_COMPLEXP (z))
55f26379 7303 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
7304 else if (SCM_FRACTIONP (z))
7305 {
73e4de09 7306 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 7307 return z;
cba42c93 7308 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
7309 SCM_FRACTION_DENOMINATOR (z));
7310 }
0aacf84e 7311 else
2519490c 7312 SCM_WTA_DISPATCH_1 (g_scm_magnitude, z, SCM_ARG1, s_scm_magnitude);
0f2d19dd 7313}
2519490c 7314#undef FUNC_NAME
0f2d19dd
JB
7315
7316
2519490c
MW
7317SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
7318 (SCM z),
7319 "Return the angle of the complex number @var{z}.")
7320#define FUNC_NAME s_scm_angle
0f2d19dd 7321{
c8ae173e 7322 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
e7efe8e7 7323 flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
7324 But if atan2 follows the floating point rounding mode, then the value
7325 is not a constant. Maybe it'd be close enough though. */
e11e83f3 7326 if (SCM_I_INUMP (z))
0aacf84e 7327 {
e11e83f3 7328 if (SCM_I_INUM (z) >= 0)
e7efe8e7 7329 return flo0;
0aacf84e 7330 else
55f26379 7331 return scm_from_double (atan2 (0.0, -1.0));
f872b822 7332 }
0aacf84e
MD
7333 else if (SCM_BIGP (z))
7334 {
7335 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
7336 scm_remember_upto_here_1 (z);
7337 if (sgn < 0)
55f26379 7338 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 7339 else
e7efe8e7 7340 return flo0;
0f2d19dd 7341 }
0aacf84e 7342 else if (SCM_REALP (z))
c8ae173e
KR
7343 {
7344 if (SCM_REAL_VALUE (z) >= 0)
e7efe8e7 7345 return flo0;
c8ae173e 7346 else
55f26379 7347 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 7348 }
0aacf84e 7349 else if (SCM_COMPLEXP (z))
55f26379 7350 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
7351 else if (SCM_FRACTIONP (z))
7352 {
73e4de09 7353 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
e7efe8e7 7354 return flo0;
55f26379 7355 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 7356 }
0aacf84e 7357 else
2519490c 7358 SCM_WTA_DISPATCH_1 (g_scm_angle, z, SCM_ARG1, s_scm_angle);
0f2d19dd 7359}
2519490c 7360#undef FUNC_NAME
0f2d19dd
JB
7361
7362
2519490c
MW
7363SCM_PRIMITIVE_GENERIC (scm_exact_to_inexact, "exact->inexact", 1, 0, 0,
7364 (SCM z),
7365 "Convert the number @var{z} to its inexact representation.\n")
7366#define FUNC_NAME s_scm_exact_to_inexact
3c9a524f 7367{
e11e83f3 7368 if (SCM_I_INUMP (z))
55f26379 7369 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 7370 else if (SCM_BIGP (z))
55f26379 7371 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 7372 else if (SCM_FRACTIONP (z))
55f26379 7373 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
7374 else if (SCM_INEXACTP (z))
7375 return z;
7376 else
2519490c 7377 SCM_WTA_DISPATCH_1 (g_scm_exact_to_inexact, z, 1, s_scm_exact_to_inexact);
3c9a524f 7378}
2519490c 7379#undef FUNC_NAME
3c9a524f
DH
7380
7381
2519490c
MW
7382SCM_PRIMITIVE_GENERIC (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
7383 (SCM z),
7384 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 7385#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 7386{
c7218482 7387 if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f872b822 7388 return z;
c7218482 7389 else
0aacf84e 7390 {
c7218482
MW
7391 double val;
7392
7393 if (SCM_REALP (z))
7394 val = SCM_REAL_VALUE (z);
7395 else if (SCM_COMPLEXP (z) && SCM_COMPLEX_IMAG (z) == 0.0)
7396 val = SCM_COMPLEX_REAL (z);
7397 else
7398 SCM_WTA_DISPATCH_1 (g_scm_inexact_to_exact, z, 1, s_scm_inexact_to_exact);
7399
7400 if (!SCM_LIKELY (DOUBLE_IS_FINITE (val)))
f92e85f7 7401 SCM_OUT_OF_RANGE (1, z);
2be24db4 7402 else
f92e85f7
MV
7403 {
7404 mpq_t frac;
7405 SCM q;
7406
7407 mpq_init (frac);
c7218482 7408 mpq_set_d (frac, val);
cba42c93 7409 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
c7218482 7410 scm_i_mpz2num (mpq_denref (frac)));
f92e85f7 7411
cba42c93 7412 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
7413 for frac...
7414 */
7415 mpq_clear (frac);
7416 return q;
7417 }
c2ff8ab0 7418 }
0f2d19dd 7419}
1bbd0b84 7420#undef FUNC_NAME
0f2d19dd 7421
f92e85f7 7422SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
76dae881
NJ
7423 (SCM x, SCM eps),
7424 "Returns the @emph{simplest} rational number differing\n"
7425 "from @var{x} by no more than @var{eps}.\n"
7426 "\n"
7427 "As required by @acronym{R5RS}, @code{rationalize} only returns an\n"
7428 "exact result when both its arguments are exact. Thus, you might need\n"
7429 "to use @code{inexact->exact} on the arguments.\n"
7430 "\n"
7431 "@lisp\n"
7432 "(rationalize (inexact->exact 1.2) 1/100)\n"
7433 "@result{} 6/5\n"
7434 "@end lisp")
f92e85f7
MV
7435#define FUNC_NAME s_scm_rationalize
7436{
605f6980
MW
7437 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
7438 SCM_ASSERT_TYPE (scm_is_real (eps), eps, SCM_ARG2, FUNC_NAME, "real");
7439 eps = scm_abs (eps);
7440 if (scm_is_false (scm_positive_p (eps)))
7441 {
7442 /* eps is either zero or a NaN */
7443 if (scm_is_true (scm_nan_p (eps)))
7444 return scm_nan ();
7445 else if (SCM_INEXACTP (eps))
7446 return scm_exact_to_inexact (x);
7447 else
7448 return x;
7449 }
7450 else if (scm_is_false (scm_finite_p (eps)))
7451 {
7452 if (scm_is_true (scm_finite_p (x)))
7453 return flo0;
7454 else
7455 return scm_nan ();
7456 }
7457 else if (scm_is_false (scm_finite_p (x))) /* checks for both inf and nan */
f92e85f7 7458 return x;
605f6980
MW
7459 else if (scm_is_false (scm_less_p (scm_floor (scm_sum (x, eps)),
7460 scm_ceiling (scm_difference (x, eps)))))
7461 {
7462 /* There's an integer within range; we want the one closest to zero */
7463 if (scm_is_false (scm_less_p (eps, scm_abs (x))))
7464 {
7465 /* zero is within range */
7466 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
7467 return flo0;
7468 else
7469 return SCM_INUM0;
7470 }
7471 else if (scm_is_true (scm_positive_p (x)))
7472 return scm_ceiling (scm_difference (x, eps));
7473 else
7474 return scm_floor (scm_sum (x, eps));
7475 }
7476 else
f92e85f7
MV
7477 {
7478 /* Use continued fractions to find closest ratio. All
7479 arithmetic is done with exact numbers.
7480 */
7481
7482 SCM ex = scm_inexact_to_exact (x);
7483 SCM int_part = scm_floor (ex);
cff5fa33
MW
7484 SCM tt = SCM_INUM1;
7485 SCM a1 = SCM_INUM0, a2 = SCM_INUM1, a = SCM_INUM0;
7486 SCM b1 = SCM_INUM1, b2 = SCM_INUM0, b = SCM_INUM0;
f92e85f7
MV
7487 SCM rx;
7488 int i = 0;
7489
f92e85f7
MV
7490 ex = scm_difference (ex, int_part); /* x = x-int_part */
7491 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
7492
7493 /* We stop after a million iterations just to be absolutely sure
7494 that we don't go into an infinite loop. The process normally
7495 converges after less than a dozen iterations.
7496 */
7497
f92e85f7
MV
7498 while (++i < 1000000)
7499 {
7500 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
7501 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
7502 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
7503 scm_is_false
f92e85f7 7504 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
76dae881 7505 eps))) /* abs(x-a/b) <= eps */
02164269
MV
7506 {
7507 SCM res = scm_sum (int_part, scm_divide (a, b));
605f6980 7508 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
02164269
MV
7509 return scm_exact_to_inexact (res);
7510 else
7511 return res;
7512 }
f92e85f7
MV
7513 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
7514 SCM_UNDEFINED);
7515 tt = scm_floor (rx); /* tt = floor (rx) */
7516 a2 = a1;
7517 b2 = b1;
7518 a1 = a;
7519 b1 = b;
7520 }
7521 scm_num_overflow (s_scm_rationalize);
7522 }
f92e85f7
MV
7523}
7524#undef FUNC_NAME
7525
73e4de09
MV
7526/* conversion functions */
7527
7528int
7529scm_is_integer (SCM val)
7530{
7531 return scm_is_true (scm_integer_p (val));
7532}
7533
7534int
7535scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
7536{
e11e83f3 7537 if (SCM_I_INUMP (val))
73e4de09 7538 {
e11e83f3 7539 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
7540 return n >= min && n <= max;
7541 }
7542 else if (SCM_BIGP (val))
7543 {
7544 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
7545 return 0;
7546 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
7547 {
7548 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
7549 {
7550 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
7551 return n >= min && n <= max;
7552 }
7553 else
7554 return 0;
7555 }
73e4de09
MV
7556 else
7557 {
d956fa6f
MV
7558 scm_t_intmax n;
7559 size_t count;
73e4de09 7560
d956fa6f
MV
7561 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
7562 > CHAR_BIT*sizeof (scm_t_uintmax))
7563 return 0;
7564
7565 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
7566 SCM_I_BIG_MPZ (val));
73e4de09 7567
d956fa6f 7568 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 7569 {
d956fa6f
MV
7570 if (n < 0)
7571 return 0;
73e4de09 7572 }
73e4de09
MV
7573 else
7574 {
d956fa6f
MV
7575 n = -n;
7576 if (n >= 0)
7577 return 0;
73e4de09 7578 }
d956fa6f
MV
7579
7580 return n >= min && n <= max;
73e4de09
MV
7581 }
7582 }
73e4de09
MV
7583 else
7584 return 0;
7585}
7586
7587int
7588scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
7589{
e11e83f3 7590 if (SCM_I_INUMP (val))
73e4de09 7591 {
e11e83f3 7592 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
7593 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
7594 }
7595 else if (SCM_BIGP (val))
7596 {
7597 if (max <= SCM_MOST_POSITIVE_FIXNUM)
7598 return 0;
7599 else if (max <= ULONG_MAX)
d956fa6f
MV
7600 {
7601 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
7602 {
7603 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
7604 return n >= min && n <= max;
7605 }
7606 else
7607 return 0;
7608 }
73e4de09
MV
7609 else
7610 {
d956fa6f
MV
7611 scm_t_uintmax n;
7612 size_t count;
73e4de09 7613
d956fa6f
MV
7614 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
7615 return 0;
73e4de09 7616
d956fa6f
MV
7617 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
7618 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 7619 return 0;
d956fa6f
MV
7620
7621 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
7622 SCM_I_BIG_MPZ (val));
73e4de09 7623
d956fa6f 7624 return n >= min && n <= max;
73e4de09
MV
7625 }
7626 }
73e4de09
MV
7627 else
7628 return 0;
7629}
7630
1713d319
MV
7631static void
7632scm_i_range_error (SCM bad_val, SCM min, SCM max)
7633{
7634 scm_error (scm_out_of_range_key,
7635 NULL,
7636 "Value out of range ~S to ~S: ~S",
7637 scm_list_3 (min, max, bad_val),
7638 scm_list_1 (bad_val));
7639}
7640
bfd7932e
MV
7641#define TYPE scm_t_intmax
7642#define TYPE_MIN min
7643#define TYPE_MAX max
7644#define SIZEOF_TYPE 0
7645#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
7646#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
7647#include "libguile/conv-integer.i.c"
7648
7649#define TYPE scm_t_uintmax
7650#define TYPE_MIN min
7651#define TYPE_MAX max
7652#define SIZEOF_TYPE 0
7653#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
7654#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
7655#include "libguile/conv-uinteger.i.c"
7656
7657#define TYPE scm_t_int8
7658#define TYPE_MIN SCM_T_INT8_MIN
7659#define TYPE_MAX SCM_T_INT8_MAX
7660#define SIZEOF_TYPE 1
7661#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
7662#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
7663#include "libguile/conv-integer.i.c"
7664
7665#define TYPE scm_t_uint8
7666#define TYPE_MIN 0
7667#define TYPE_MAX SCM_T_UINT8_MAX
7668#define SIZEOF_TYPE 1
7669#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
7670#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
7671#include "libguile/conv-uinteger.i.c"
7672
7673#define TYPE scm_t_int16
7674#define TYPE_MIN SCM_T_INT16_MIN
7675#define TYPE_MAX SCM_T_INT16_MAX
7676#define SIZEOF_TYPE 2
7677#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
7678#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
7679#include "libguile/conv-integer.i.c"
7680
7681#define TYPE scm_t_uint16
7682#define TYPE_MIN 0
7683#define TYPE_MAX SCM_T_UINT16_MAX
7684#define SIZEOF_TYPE 2
7685#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
7686#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
7687#include "libguile/conv-uinteger.i.c"
7688
7689#define TYPE scm_t_int32
7690#define TYPE_MIN SCM_T_INT32_MIN
7691#define TYPE_MAX SCM_T_INT32_MAX
7692#define SIZEOF_TYPE 4
7693#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
7694#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
7695#include "libguile/conv-integer.i.c"
7696
7697#define TYPE scm_t_uint32
7698#define TYPE_MIN 0
7699#define TYPE_MAX SCM_T_UINT32_MAX
7700#define SIZEOF_TYPE 4
7701#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
7702#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
7703#include "libguile/conv-uinteger.i.c"
7704
904a78f1
MG
7705#define TYPE scm_t_wchar
7706#define TYPE_MIN (scm_t_int32)-1
7707#define TYPE_MAX (scm_t_int32)0x10ffff
7708#define SIZEOF_TYPE 4
7709#define SCM_TO_TYPE_PROTO(arg) scm_to_wchar (arg)
7710#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
7711#include "libguile/conv-integer.i.c"
7712
bfd7932e
MV
7713#define TYPE scm_t_int64
7714#define TYPE_MIN SCM_T_INT64_MIN
7715#define TYPE_MAX SCM_T_INT64_MAX
7716#define SIZEOF_TYPE 8
7717#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
7718#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
7719#include "libguile/conv-integer.i.c"
7720
7721#define TYPE scm_t_uint64
7722#define TYPE_MIN 0
7723#define TYPE_MAX SCM_T_UINT64_MAX
7724#define SIZEOF_TYPE 8
7725#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
7726#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
7727#include "libguile/conv-uinteger.i.c"
73e4de09 7728
cd036260
MV
7729void
7730scm_to_mpz (SCM val, mpz_t rop)
7731{
7732 if (SCM_I_INUMP (val))
7733 mpz_set_si (rop, SCM_I_INUM (val));
7734 else if (SCM_BIGP (val))
7735 mpz_set (rop, SCM_I_BIG_MPZ (val));
7736 else
7737 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
7738}
7739
7740SCM
7741scm_from_mpz (mpz_t val)
7742{
7743 return scm_i_mpz2num (val);
7744}
7745
73e4de09
MV
7746int
7747scm_is_real (SCM val)
7748{
7749 return scm_is_true (scm_real_p (val));
7750}
7751
55f26379
MV
7752int
7753scm_is_rational (SCM val)
7754{
7755 return scm_is_true (scm_rational_p (val));
7756}
7757
73e4de09
MV
7758double
7759scm_to_double (SCM val)
7760{
55f26379
MV
7761 if (SCM_I_INUMP (val))
7762 return SCM_I_INUM (val);
7763 else if (SCM_BIGP (val))
7764 return scm_i_big2dbl (val);
7765 else if (SCM_FRACTIONP (val))
7766 return scm_i_fraction2double (val);
7767 else if (SCM_REALP (val))
7768 return SCM_REAL_VALUE (val);
7769 else
7a1aba42 7770 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
7771}
7772
7773SCM
7774scm_from_double (double val)
7775{
978c52d1
LC
7776 SCM z;
7777
7778 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
7779
7780 SCM_SET_CELL_TYPE (z, scm_tc16_real);
55f26379 7781 SCM_REAL_VALUE (z) = val;
978c52d1 7782
55f26379 7783 return z;
73e4de09
MV
7784}
7785
220058a8 7786#if SCM_ENABLE_DEPRECATED == 1
55f26379
MV
7787
7788float
e25f3727 7789scm_num2float (SCM num, unsigned long pos, const char *s_caller)
55f26379 7790{
220058a8
AW
7791 scm_c_issue_deprecation_warning
7792 ("`scm_num2float' is deprecated. Use scm_to_double instead.");
7793
55f26379
MV
7794 if (SCM_BIGP (num))
7795 {
7796 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 7797 if (!isinf (res))
55f26379
MV
7798 return res;
7799 else
7800 scm_out_of_range (NULL, num);
7801 }
7802 else
7803 return scm_to_double (num);
7804}
7805
7806double
e25f3727 7807scm_num2double (SCM num, unsigned long pos, const char *s_caller)
55f26379 7808{
220058a8
AW
7809 scm_c_issue_deprecation_warning
7810 ("`scm_num2double' is deprecated. Use scm_to_double instead.");
7811
55f26379
MV
7812 if (SCM_BIGP (num))
7813 {
7814 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 7815 if (!isinf (res))
55f26379
MV
7816 return res;
7817 else
7818 scm_out_of_range (NULL, num);
7819 }
7820 else
7821 return scm_to_double (num);
7822}
7823
7824#endif
7825
8507ec80
MV
7826int
7827scm_is_complex (SCM val)
7828{
7829 return scm_is_true (scm_complex_p (val));
7830}
7831
7832double
7833scm_c_real_part (SCM z)
7834{
7835 if (SCM_COMPLEXP (z))
7836 return SCM_COMPLEX_REAL (z);
7837 else
7838 {
7839 /* Use the scm_real_part to get proper error checking and
7840 dispatching.
7841 */
7842 return scm_to_double (scm_real_part (z));
7843 }
7844}
7845
7846double
7847scm_c_imag_part (SCM z)
7848{
7849 if (SCM_COMPLEXP (z))
7850 return SCM_COMPLEX_IMAG (z);
7851 else
7852 {
7853 /* Use the scm_imag_part to get proper error checking and
7854 dispatching. The result will almost always be 0.0, but not
7855 always.
7856 */
7857 return scm_to_double (scm_imag_part (z));
7858 }
7859}
7860
7861double
7862scm_c_magnitude (SCM z)
7863{
7864 return scm_to_double (scm_magnitude (z));
7865}
7866
7867double
7868scm_c_angle (SCM z)
7869{
7870 return scm_to_double (scm_angle (z));
7871}
7872
7873int
7874scm_is_number (SCM z)
7875{
7876 return scm_is_true (scm_number_p (z));
7877}
7878
8ab3d8a0
KR
7879
7880/* In the following functions we dispatch to the real-arg funcs like log()
7881 when we know the arg is real, instead of just handing everything to
7882 clog() for instance. This is in case clog() doesn't optimize for a
7883 real-only case, and because we have to test SCM_COMPLEXP anyway so may as
7884 well use it to go straight to the applicable C func. */
7885
2519490c
MW
7886SCM_PRIMITIVE_GENERIC (scm_log, "log", 1, 0, 0,
7887 (SCM z),
7888 "Return the natural logarithm of @var{z}.")
8ab3d8a0
KR
7889#define FUNC_NAME s_scm_log
7890{
7891 if (SCM_COMPLEXP (z))
7892 {
4b26c03e 7893#if HAVE_COMPLEX_DOUBLE && HAVE_CLOG && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
7894 return scm_from_complex_double (clog (SCM_COMPLEX_VALUE (z)));
7895#else
7896 double re = SCM_COMPLEX_REAL (z);
7897 double im = SCM_COMPLEX_IMAG (z);
7898 return scm_c_make_rectangular (log (hypot (re, im)),
7899 atan2 (im, re));
7900#endif
7901 }
2519490c 7902 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7903 {
7904 /* ENHANCE-ME: When z is a bignum the logarithm will fit a double
7905 although the value itself overflows. */
7906 double re = scm_to_double (z);
7907 double l = log (fabs (re));
7908 if (re >= 0.0)
7909 return scm_from_double (l);
7910 else
7911 return scm_c_make_rectangular (l, M_PI);
7912 }
2519490c
MW
7913 else
7914 SCM_WTA_DISPATCH_1 (g_scm_log, z, 1, s_scm_log);
8ab3d8a0
KR
7915}
7916#undef FUNC_NAME
7917
7918
2519490c
MW
7919SCM_PRIMITIVE_GENERIC (scm_log10, "log10", 1, 0, 0,
7920 (SCM z),
7921 "Return the base 10 logarithm of @var{z}.")
8ab3d8a0
KR
7922#define FUNC_NAME s_scm_log10
7923{
7924 if (SCM_COMPLEXP (z))
7925 {
7926 /* Mingw has clog() but not clog10(). (Maybe it'd be worth using
7927 clog() and a multiply by M_LOG10E, rather than the fallback
7928 log10+hypot+atan2.) */
f328f862
LC
7929#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
7930 && defined SCM_COMPLEX_VALUE
8ab3d8a0
KR
7931 return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
7932#else
7933 double re = SCM_COMPLEX_REAL (z);
7934 double im = SCM_COMPLEX_IMAG (z);
7935 return scm_c_make_rectangular (log10 (hypot (re, im)),
7936 M_LOG10E * atan2 (im, re));
7937#endif
7938 }
2519490c 7939 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7940 {
7941 /* ENHANCE-ME: When z is a bignum the logarithm will fit a double
7942 although the value itself overflows. */
7943 double re = scm_to_double (z);
7944 double l = log10 (fabs (re));
7945 if (re >= 0.0)
7946 return scm_from_double (l);
7947 else
7948 return scm_c_make_rectangular (l, M_LOG10E * M_PI);
7949 }
2519490c
MW
7950 else
7951 SCM_WTA_DISPATCH_1 (g_scm_log10, z, 1, s_scm_log10);
8ab3d8a0
KR
7952}
7953#undef FUNC_NAME
7954
7955
2519490c
MW
7956SCM_PRIMITIVE_GENERIC (scm_exp, "exp", 1, 0, 0,
7957 (SCM z),
7958 "Return @math{e} to the power of @var{z}, where @math{e} is the\n"
7959 "base of natural logarithms (2.71828@dots{}).")
8ab3d8a0
KR
7960#define FUNC_NAME s_scm_exp
7961{
7962 if (SCM_COMPLEXP (z))
7963 {
4b26c03e 7964#if HAVE_COMPLEX_DOUBLE && HAVE_CEXP && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
7965 return scm_from_complex_double (cexp (SCM_COMPLEX_VALUE (z)));
7966#else
7967 return scm_c_make_polar (exp (SCM_COMPLEX_REAL (z)),
7968 SCM_COMPLEX_IMAG (z));
7969#endif
7970 }
2519490c 7971 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7972 {
7973 /* When z is a negative bignum the conversion to double overflows,
7974 giving -infinity, but that's ok, the exp is still 0.0. */
7975 return scm_from_double (exp (scm_to_double (z)));
7976 }
2519490c
MW
7977 else
7978 SCM_WTA_DISPATCH_1 (g_scm_exp, z, 1, s_scm_exp);
8ab3d8a0
KR
7979}
7980#undef FUNC_NAME
7981
7982
2519490c
MW
7983SCM_PRIMITIVE_GENERIC (scm_sqrt, "sqrt", 1, 0, 0,
7984 (SCM z),
7985 "Return the square root of @var{z}. Of the two possible roots\n"
ffb62a43 7986 "(positive and negative), the one with positive real part\n"
2519490c
MW
7987 "is returned, or if that's zero then a positive imaginary part.\n"
7988 "Thus,\n"
7989 "\n"
7990 "@example\n"
7991 "(sqrt 9.0) @result{} 3.0\n"
7992 "(sqrt -9.0) @result{} 0.0+3.0i\n"
7993 "(sqrt 1.0+1.0i) @result{} 1.09868411346781+0.455089860562227i\n"
7994 "(sqrt -1.0-1.0i) @result{} 0.455089860562227-1.09868411346781i\n"
7995 "@end example")
8ab3d8a0
KR
7996#define FUNC_NAME s_scm_sqrt
7997{
2519490c 7998 if (SCM_COMPLEXP (z))
8ab3d8a0 7999 {
f328f862
LC
8000#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT \
8001 && defined SCM_COMPLEX_VALUE
2519490c 8002 return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (z)));
8ab3d8a0 8003#else
2519490c
MW
8004 double re = SCM_COMPLEX_REAL (z);
8005 double im = SCM_COMPLEX_IMAG (z);
8ab3d8a0
KR
8006 return scm_c_make_polar (sqrt (hypot (re, im)),
8007 0.5 * atan2 (im, re));
8008#endif
8009 }
2519490c 8010 else if (SCM_NUMBERP (z))
8ab3d8a0 8011 {
2519490c 8012 double xx = scm_to_double (z);
8ab3d8a0
KR
8013 if (xx < 0)
8014 return scm_c_make_rectangular (0.0, sqrt (-xx));
8015 else
8016 return scm_from_double (sqrt (xx));
8017 }
2519490c
MW
8018 else
8019 SCM_WTA_DISPATCH_1 (g_scm_sqrt, z, 1, s_scm_sqrt);
8ab3d8a0
KR
8020}
8021#undef FUNC_NAME
8022
8023
8024
0f2d19dd
JB
8025void
8026scm_init_numbers ()
0f2d19dd 8027{
0b799eea
MV
8028 int i;
8029
713a4259
KR
8030 mpz_init_set_si (z_negative_one, -1);
8031
a261c0e9
DH
8032 /* It may be possible to tune the performance of some algorithms by using
8033 * the following constants to avoid the creation of bignums. Please, before
8034 * using these values, remember the two rules of program optimization:
8035 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 8036 scm_c_define ("most-positive-fixnum",
d956fa6f 8037 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 8038 scm_c_define ("most-negative-fixnum",
d956fa6f 8039 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 8040
f3ae5d60
MD
8041 scm_add_feature ("complex");
8042 scm_add_feature ("inexact");
e7efe8e7 8043 flo0 = scm_from_double (0.0);
0b799eea
MV
8044
8045 /* determine floating point precision */
55f26379 8046 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
8047 {
8048 init_dblprec(&scm_dblprec[i-2],i);
8049 init_fx_radix(fx_per_radix[i-2],i);
8050 }
f872b822 8051#ifdef DBL_DIG
0b799eea 8052 /* hard code precision for base 10 if the preprocessor tells us to... */
f39448c5 8053 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
0b799eea 8054#endif
1be6b49c 8055
cff5fa33 8056 exactly_one_half = scm_divide (SCM_INUM1, SCM_I_MAKINUM (2));
a0599745 8057#include "libguile/numbers.x"
0f2d19dd 8058}
89e00824
ML
8059
8060/*
8061 Local Variables:
8062 c-file-style: "gnu"
8063 End:
8064*/