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