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