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