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