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