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