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