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