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