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