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