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