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