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