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