fix deadlock in before-gc-hook on certain 7.2alpha gc versions
[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
181 bignum = PTR2SCM (ptr);
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
2519490c 535 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
2519490c 556 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 }
2519490c 595 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 }
2519490c 629 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
2519490c 644 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
2519490c 659 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
2519490c 674 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
a48d60b1 801 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
2519490c 816 SCM_WTA_DISPATCH_2 (g_scm_quotient, x, y, SCM_ARG2, s_scm_quotient);
f872b822 817 }
0aacf84e 818 else
2519490c 819 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
2519490c 837 SCM_WTA_DISPATCH_2 (g_scm_remainder, x, y, SCM_ARG2, s_scm_remainder);
f872b822 838 }
0aacf84e 839 else
2519490c 840 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
2519490c 859 SCM_WTA_DISPATCH_2 (g_scm_modulo, x, y, SCM_ARG2, s_scm_modulo);
828865c3 860 }
0aacf84e 861 else
2519490c 862 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{
883 if (SCM_UNPACK (gf))
884 scm_i_extract_values_2 (scm_call_generic_2 (gf, a1, a2), rp1, rp2);
885 else
886 scm_wrong_type_arg (subr, pos, (pos == SCM_ARG1) ? a1 : a2);
887}
888
a8da6d93
MW
889SCM_DEFINE (scm_euclidean_quotient, "euclidean-quotient", 2, 0, 0,
890 (SCM x, SCM y),
891 "Return the integer @var{q} such that\n"
892 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
893 "where @math{0 <= @var{r} < abs(@var{y})}.\n"
894 "@lisp\n"
895 "(euclidean-quotient 123 10) @result{} 12\n"
896 "(euclidean-quotient 123 -10) @result{} -12\n"
897 "(euclidean-quotient -123 10) @result{} -13\n"
898 "(euclidean-quotient -123 -10) @result{} 13\n"
899 "(euclidean-quotient -123.2 -63.5) @result{} 2.0\n"
900 "(euclidean-quotient 16/3 -10/7) @result{} -3\n"
901 "@end lisp")
ff62c168
MW
902#define FUNC_NAME s_scm_euclidean_quotient
903{
a8da6d93
MW
904 if (scm_is_false (scm_negative_p (y)))
905 return scm_floor_quotient (x, y);
ff62c168 906 else
a8da6d93 907 return scm_ceiling_quotient (x, y);
ff62c168
MW
908}
909#undef FUNC_NAME
910
a8da6d93
MW
911SCM_DEFINE (scm_euclidean_remainder, "euclidean-remainder", 2, 0, 0,
912 (SCM x, SCM y),
913 "Return the real number @var{r} such that\n"
914 "@math{0 <= @var{r} < abs(@var{y})} and\n"
915 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
916 "for some integer @var{q}.\n"
917 "@lisp\n"
918 "(euclidean-remainder 123 10) @result{} 3\n"
919 "(euclidean-remainder 123 -10) @result{} 3\n"
920 "(euclidean-remainder -123 10) @result{} 7\n"
921 "(euclidean-remainder -123 -10) @result{} 7\n"
922 "(euclidean-remainder -123.2 -63.5) @result{} 3.8\n"
923 "(euclidean-remainder 16/3 -10/7) @result{} 22/21\n"
924 "@end lisp")
ff62c168
MW
925#define FUNC_NAME s_scm_euclidean_remainder
926{
a8da6d93
MW
927 if (scm_is_false (scm_negative_p (y)))
928 return scm_floor_remainder (x, y);
ff62c168 929 else
a8da6d93 930 return scm_ceiling_remainder (x, y);
ff62c168
MW
931}
932#undef FUNC_NAME
933
a8da6d93
MW
934SCM_DEFINE (scm_i_euclidean_divide, "euclidean/", 2, 0, 0,
935 (SCM x, SCM y),
936 "Return the integer @var{q} and the real number @var{r}\n"
937 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
938 "and @math{0 <= @var{r} < abs(@var{y})}.\n"
939 "@lisp\n"
940 "(euclidean/ 123 10) @result{} 12 and 3\n"
941 "(euclidean/ 123 -10) @result{} -12 and 3\n"
942 "(euclidean/ -123 10) @result{} -13 and 7\n"
943 "(euclidean/ -123 -10) @result{} 13 and 7\n"
944 "(euclidean/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
945 "(euclidean/ 16/3 -10/7) @result{} -3 and 22/21\n"
946 "@end lisp")
5fbf680b
MW
947#define FUNC_NAME s_scm_i_euclidean_divide
948{
a8da6d93
MW
949 if (scm_is_false (scm_negative_p (y)))
950 return scm_i_floor_divide (x, y);
951 else
952 return scm_i_ceiling_divide (x, y);
5fbf680b
MW
953}
954#undef FUNC_NAME
955
5fbf680b
MW
956void
957scm_euclidean_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 958{
a8da6d93
MW
959 if (scm_is_false (scm_negative_p (y)))
960 return scm_floor_divide (x, y, qp, rp);
ff62c168 961 else
a8da6d93 962 return scm_ceiling_divide (x, y, qp, rp);
ff62c168
MW
963}
964
8f9da340
MW
965static SCM scm_i_inexact_floor_quotient (double x, double y);
966static SCM scm_i_exact_rational_floor_quotient (SCM x, SCM y);
967
968SCM_PRIMITIVE_GENERIC (scm_floor_quotient, "floor-quotient", 2, 0, 0,
969 (SCM x, SCM y),
970 "Return the floor of @math{@var{x} / @var{y}}.\n"
971 "@lisp\n"
972 "(floor-quotient 123 10) @result{} 12\n"
973 "(floor-quotient 123 -10) @result{} -13\n"
974 "(floor-quotient -123 10) @result{} -13\n"
975 "(floor-quotient -123 -10) @result{} 12\n"
976 "(floor-quotient -123.2 -63.5) @result{} 1.0\n"
977 "(floor-quotient 16/3 -10/7) @result{} -4\n"
978 "@end lisp")
979#define FUNC_NAME s_scm_floor_quotient
980{
981 if (SCM_LIKELY (SCM_I_INUMP (x)))
982 {
983 scm_t_inum xx = SCM_I_INUM (x);
984 if (SCM_LIKELY (SCM_I_INUMP (y)))
985 {
986 scm_t_inum yy = SCM_I_INUM (y);
987 scm_t_inum xx1 = xx;
988 scm_t_inum qq;
989 if (SCM_LIKELY (yy > 0))
990 {
991 if (SCM_UNLIKELY (xx < 0))
992 xx1 = xx - yy + 1;
993 }
994 else if (SCM_UNLIKELY (yy == 0))
995 scm_num_overflow (s_scm_floor_quotient);
996 else if (xx > 0)
997 xx1 = xx - yy - 1;
998 qq = xx1 / yy;
999 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1000 return SCM_I_MAKINUM (qq);
1001 else
1002 return scm_i_inum2big (qq);
1003 }
1004 else if (SCM_BIGP (y))
1005 {
1006 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1007 scm_remember_upto_here_1 (y);
1008 if (sign > 0)
1009 return SCM_I_MAKINUM ((xx < 0) ? -1 : 0);
1010 else
1011 return SCM_I_MAKINUM ((xx > 0) ? -1 : 0);
1012 }
1013 else if (SCM_REALP (y))
1014 return scm_i_inexact_floor_quotient (xx, SCM_REAL_VALUE (y));
1015 else if (SCM_FRACTIONP (y))
1016 return scm_i_exact_rational_floor_quotient (x, y);
1017 else
1018 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1019 s_scm_floor_quotient);
1020 }
1021 else if (SCM_BIGP (x))
1022 {
1023 if (SCM_LIKELY (SCM_I_INUMP (y)))
1024 {
1025 scm_t_inum yy = SCM_I_INUM (y);
1026 if (SCM_UNLIKELY (yy == 0))
1027 scm_num_overflow (s_scm_floor_quotient);
1028 else if (SCM_UNLIKELY (yy == 1))
1029 return x;
1030 else
1031 {
1032 SCM q = scm_i_mkbig ();
1033 if (yy > 0)
1034 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1035 else
1036 {
1037 mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1038 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1039 }
1040 scm_remember_upto_here_1 (x);
1041 return scm_i_normbig (q);
1042 }
1043 }
1044 else if (SCM_BIGP (y))
1045 {
1046 SCM q = scm_i_mkbig ();
1047 mpz_fdiv_q (SCM_I_BIG_MPZ (q),
1048 SCM_I_BIG_MPZ (x),
1049 SCM_I_BIG_MPZ (y));
1050 scm_remember_upto_here_2 (x, y);
1051 return scm_i_normbig (q);
1052 }
1053 else if (SCM_REALP (y))
1054 return scm_i_inexact_floor_quotient
1055 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1056 else if (SCM_FRACTIONP (y))
1057 return scm_i_exact_rational_floor_quotient (x, y);
1058 else
1059 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1060 s_scm_floor_quotient);
1061 }
1062 else if (SCM_REALP (x))
1063 {
1064 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1065 SCM_BIGP (y) || SCM_FRACTIONP (y))
1066 return scm_i_inexact_floor_quotient
1067 (SCM_REAL_VALUE (x), scm_to_double (y));
1068 else
1069 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1070 s_scm_floor_quotient);
1071 }
1072 else if (SCM_FRACTIONP (x))
1073 {
1074 if (SCM_REALP (y))
1075 return scm_i_inexact_floor_quotient
1076 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1077 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1078 return scm_i_exact_rational_floor_quotient (x, y);
1079 else
1080 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1081 s_scm_floor_quotient);
1082 }
1083 else
1084 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG1,
1085 s_scm_floor_quotient);
1086}
1087#undef FUNC_NAME
1088
1089static SCM
1090scm_i_inexact_floor_quotient (double x, double y)
1091{
1092 if (SCM_UNLIKELY (y == 0))
1093 scm_num_overflow (s_scm_floor_quotient); /* or return a NaN? */
1094 else
1095 return scm_from_double (floor (x / y));
1096}
1097
1098static SCM
1099scm_i_exact_rational_floor_quotient (SCM x, SCM y)
1100{
1101 return scm_floor_quotient
1102 (scm_product (scm_numerator (x), scm_denominator (y)),
1103 scm_product (scm_numerator (y), scm_denominator (x)));
1104}
1105
1106static SCM scm_i_inexact_floor_remainder (double x, double y);
1107static SCM scm_i_exact_rational_floor_remainder (SCM x, SCM y);
1108
1109SCM_PRIMITIVE_GENERIC (scm_floor_remainder, "floor-remainder", 2, 0, 0,
1110 (SCM x, SCM y),
1111 "Return the real number @var{r} such that\n"
1112 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1113 "where @math{@var{q} = floor(@var{x} / @var{y})}.\n"
1114 "@lisp\n"
1115 "(floor-remainder 123 10) @result{} 3\n"
1116 "(floor-remainder 123 -10) @result{} -7\n"
1117 "(floor-remainder -123 10) @result{} 7\n"
1118 "(floor-remainder -123 -10) @result{} -3\n"
1119 "(floor-remainder -123.2 -63.5) @result{} -59.7\n"
1120 "(floor-remainder 16/3 -10/7) @result{} -8/21\n"
1121 "@end lisp")
1122#define FUNC_NAME s_scm_floor_remainder
1123{
1124 if (SCM_LIKELY (SCM_I_INUMP (x)))
1125 {
1126 scm_t_inum xx = SCM_I_INUM (x);
1127 if (SCM_LIKELY (SCM_I_INUMP (y)))
1128 {
1129 scm_t_inum yy = SCM_I_INUM (y);
1130 if (SCM_UNLIKELY (yy == 0))
1131 scm_num_overflow (s_scm_floor_remainder);
1132 else
1133 {
1134 scm_t_inum rr = xx % yy;
1135 int needs_adjustment;
1136
1137 if (SCM_LIKELY (yy > 0))
1138 needs_adjustment = (rr < 0);
1139 else
1140 needs_adjustment = (rr > 0);
1141
1142 if (needs_adjustment)
1143 rr += yy;
1144 return SCM_I_MAKINUM (rr);
1145 }
1146 }
1147 else if (SCM_BIGP (y))
1148 {
1149 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1150 scm_remember_upto_here_1 (y);
1151 if (sign > 0)
1152 {
1153 if (xx < 0)
1154 {
1155 SCM r = scm_i_mkbig ();
1156 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1157 scm_remember_upto_here_1 (y);
1158 return scm_i_normbig (r);
1159 }
1160 else
1161 return x;
1162 }
1163 else if (xx <= 0)
1164 return x;
1165 else
1166 {
1167 SCM r = scm_i_mkbig ();
1168 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1169 scm_remember_upto_here_1 (y);
1170 return scm_i_normbig (r);
1171 }
1172 }
1173 else if (SCM_REALP (y))
1174 return scm_i_inexact_floor_remainder (xx, SCM_REAL_VALUE (y));
1175 else if (SCM_FRACTIONP (y))
1176 return scm_i_exact_rational_floor_remainder (x, y);
1177 else
1178 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1179 s_scm_floor_remainder);
1180 }
1181 else if (SCM_BIGP (x))
1182 {
1183 if (SCM_LIKELY (SCM_I_INUMP (y)))
1184 {
1185 scm_t_inum yy = SCM_I_INUM (y);
1186 if (SCM_UNLIKELY (yy == 0))
1187 scm_num_overflow (s_scm_floor_remainder);
1188 else
1189 {
1190 scm_t_inum rr;
1191 if (yy > 0)
1192 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), yy);
1193 else
1194 rr = -mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1195 scm_remember_upto_here_1 (x);
1196 return SCM_I_MAKINUM (rr);
1197 }
1198 }
1199 else if (SCM_BIGP (y))
1200 {
1201 SCM r = scm_i_mkbig ();
1202 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
1203 SCM_I_BIG_MPZ (x),
1204 SCM_I_BIG_MPZ (y));
1205 scm_remember_upto_here_2 (x, y);
1206 return scm_i_normbig (r);
1207 }
1208 else if (SCM_REALP (y))
1209 return scm_i_inexact_floor_remainder
1210 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1211 else if (SCM_FRACTIONP (y))
1212 return scm_i_exact_rational_floor_remainder (x, y);
1213 else
1214 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1215 s_scm_floor_remainder);
1216 }
1217 else if (SCM_REALP (x))
1218 {
1219 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1220 SCM_BIGP (y) || SCM_FRACTIONP (y))
1221 return scm_i_inexact_floor_remainder
1222 (SCM_REAL_VALUE (x), scm_to_double (y));
1223 else
1224 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1225 s_scm_floor_remainder);
1226 }
1227 else if (SCM_FRACTIONP (x))
1228 {
1229 if (SCM_REALP (y))
1230 return scm_i_inexact_floor_remainder
1231 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1232 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1233 return scm_i_exact_rational_floor_remainder (x, y);
1234 else
1235 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1236 s_scm_floor_remainder);
1237 }
1238 else
1239 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG1,
1240 s_scm_floor_remainder);
1241}
1242#undef FUNC_NAME
1243
1244static SCM
1245scm_i_inexact_floor_remainder (double x, double y)
1246{
1247 /* Although it would be more efficient to use fmod here, we can't
1248 because it would in some cases produce results inconsistent with
1249 scm_i_inexact_floor_quotient, such that x != q * y + r (not even
1250 close). In particular, when x is very close to a multiple of y,
1251 then r might be either 0.0 or y, but those two cases must
1252 correspond to different choices of q. If r = 0.0 then q must be
1253 x/y, and if r = y then q must be x/y-1. If quotient chooses one
1254 and remainder chooses the other, it would be bad. */
1255 if (SCM_UNLIKELY (y == 0))
1256 scm_num_overflow (s_scm_floor_remainder); /* or return a NaN? */
1257 else
1258 return scm_from_double (x - y * floor (x / y));
1259}
1260
1261static SCM
1262scm_i_exact_rational_floor_remainder (SCM x, SCM y)
1263{
1264 SCM xd = scm_denominator (x);
1265 SCM yd = scm_denominator (y);
1266 SCM r1 = scm_floor_remainder (scm_product (scm_numerator (x), yd),
1267 scm_product (scm_numerator (y), xd));
1268 return scm_divide (r1, scm_product (xd, yd));
1269}
1270
1271
1272static void scm_i_inexact_floor_divide (double x, double y,
1273 SCM *qp, SCM *rp);
1274static void scm_i_exact_rational_floor_divide (SCM x, SCM y,
1275 SCM *qp, SCM *rp);
1276
1277SCM_PRIMITIVE_GENERIC (scm_i_floor_divide, "floor/", 2, 0, 0,
1278 (SCM x, SCM y),
1279 "Return the integer @var{q} and the real number @var{r}\n"
1280 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1281 "and @math{@var{q} = floor(@var{x} / @var{y})}.\n"
1282 "@lisp\n"
1283 "(floor/ 123 10) @result{} 12 and 3\n"
1284 "(floor/ 123 -10) @result{} -13 and -7\n"
1285 "(floor/ -123 10) @result{} -13 and 7\n"
1286 "(floor/ -123 -10) @result{} 12 and -3\n"
1287 "(floor/ -123.2 -63.5) @result{} 1.0 and -59.7\n"
1288 "(floor/ 16/3 -10/7) @result{} -4 and -8/21\n"
1289 "@end lisp")
1290#define FUNC_NAME s_scm_i_floor_divide
1291{
1292 SCM q, r;
1293
1294 scm_floor_divide(x, y, &q, &r);
1295 return scm_values (scm_list_2 (q, r));
1296}
1297#undef FUNC_NAME
1298
1299#define s_scm_floor_divide s_scm_i_floor_divide
1300#define g_scm_floor_divide g_scm_i_floor_divide
1301
1302void
1303scm_floor_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1304{
1305 if (SCM_LIKELY (SCM_I_INUMP (x)))
1306 {
1307 scm_t_inum xx = SCM_I_INUM (x);
1308 if (SCM_LIKELY (SCM_I_INUMP (y)))
1309 {
1310 scm_t_inum yy = SCM_I_INUM (y);
1311 if (SCM_UNLIKELY (yy == 0))
1312 scm_num_overflow (s_scm_floor_divide);
1313 else
1314 {
1315 scm_t_inum qq = xx / yy;
1316 scm_t_inum rr = xx % yy;
1317 int needs_adjustment;
1318
1319 if (SCM_LIKELY (yy > 0))
1320 needs_adjustment = (rr < 0);
1321 else
1322 needs_adjustment = (rr > 0);
1323
1324 if (needs_adjustment)
1325 {
1326 rr += yy;
1327 qq--;
1328 }
1329
1330 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1331 *qp = SCM_I_MAKINUM (qq);
1332 else
1333 *qp = scm_i_inum2big (qq);
1334 *rp = SCM_I_MAKINUM (rr);
1335 }
1336 return;
1337 }
1338 else if (SCM_BIGP (y))
1339 {
1340 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1341 scm_remember_upto_here_1 (y);
1342 if (sign > 0)
1343 {
1344 if (xx < 0)
1345 {
1346 SCM r = scm_i_mkbig ();
1347 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1348 scm_remember_upto_here_1 (y);
1349 *qp = SCM_I_MAKINUM (-1);
1350 *rp = scm_i_normbig (r);
1351 }
1352 else
1353 {
1354 *qp = SCM_INUM0;
1355 *rp = x;
1356 }
1357 }
1358 else if (xx <= 0)
1359 {
1360 *qp = SCM_INUM0;
1361 *rp = x;
1362 }
1363 else
1364 {
1365 SCM r = scm_i_mkbig ();
1366 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1367 scm_remember_upto_here_1 (y);
1368 *qp = SCM_I_MAKINUM (-1);
1369 *rp = scm_i_normbig (r);
1370 }
1371 return;
1372 }
1373 else if (SCM_REALP (y))
1374 return scm_i_inexact_floor_divide (xx, SCM_REAL_VALUE (y), qp, rp);
1375 else if (SCM_FRACTIONP (y))
1376 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1377 else
1378 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1379 s_scm_floor_divide, qp, rp);
1380 }
1381 else if (SCM_BIGP (x))
1382 {
1383 if (SCM_LIKELY (SCM_I_INUMP (y)))
1384 {
1385 scm_t_inum yy = SCM_I_INUM (y);
1386 if (SCM_UNLIKELY (yy == 0))
1387 scm_num_overflow (s_scm_floor_divide);
1388 else
1389 {
1390 SCM q = scm_i_mkbig ();
1391 SCM r = scm_i_mkbig ();
1392 if (yy > 0)
1393 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1394 SCM_I_BIG_MPZ (x), yy);
1395 else
1396 {
1397 mpz_cdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1398 SCM_I_BIG_MPZ (x), -yy);
1399 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1400 }
1401 scm_remember_upto_here_1 (x);
1402 *qp = scm_i_normbig (q);
1403 *rp = scm_i_normbig (r);
1404 }
1405 return;
1406 }
1407 else if (SCM_BIGP (y))
1408 {
1409 SCM q = scm_i_mkbig ();
1410 SCM r = scm_i_mkbig ();
1411 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1412 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1413 scm_remember_upto_here_2 (x, y);
1414 *qp = scm_i_normbig (q);
1415 *rp = scm_i_normbig (r);
1416 return;
1417 }
1418 else if (SCM_REALP (y))
1419 return scm_i_inexact_floor_divide
1420 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
1421 else if (SCM_FRACTIONP (y))
1422 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1423 else
1424 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1425 s_scm_floor_divide, qp, rp);
1426 }
1427 else if (SCM_REALP (x))
1428 {
1429 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1430 SCM_BIGP (y) || SCM_FRACTIONP (y))
1431 return scm_i_inexact_floor_divide
1432 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
1433 else
1434 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1435 s_scm_floor_divide, qp, rp);
1436 }
1437 else if (SCM_FRACTIONP (x))
1438 {
1439 if (SCM_REALP (y))
1440 return scm_i_inexact_floor_divide
1441 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
1442 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1443 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1444 else
1445 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1446 s_scm_floor_divide, qp, rp);
1447 }
1448 else
1449 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG1,
1450 s_scm_floor_divide, qp, rp);
1451}
1452
1453static void
1454scm_i_inexact_floor_divide (double x, double y, SCM *qp, SCM *rp)
1455{
1456 if (SCM_UNLIKELY (y == 0))
1457 scm_num_overflow (s_scm_floor_divide); /* or return a NaN? */
1458 else
1459 {
1460 double q = floor (x / y);
1461 double r = x - q * y;
1462 *qp = scm_from_double (q);
1463 *rp = scm_from_double (r);
1464 }
1465}
1466
1467static void
1468scm_i_exact_rational_floor_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1469{
1470 SCM r1;
1471 SCM xd = scm_denominator (x);
1472 SCM yd = scm_denominator (y);
1473
1474 scm_floor_divide (scm_product (scm_numerator (x), yd),
1475 scm_product (scm_numerator (y), xd),
1476 qp, &r1);
1477 *rp = scm_divide (r1, scm_product (xd, yd));
1478}
1479
1480static SCM scm_i_inexact_ceiling_quotient (double x, double y);
1481static SCM scm_i_exact_rational_ceiling_quotient (SCM x, SCM y);
1482
1483SCM_PRIMITIVE_GENERIC (scm_ceiling_quotient, "ceiling-quotient", 2, 0, 0,
1484 (SCM x, SCM y),
1485 "Return the ceiling of @math{@var{x} / @var{y}}.\n"
1486 "@lisp\n"
1487 "(ceiling-quotient 123 10) @result{} 13\n"
1488 "(ceiling-quotient 123 -10) @result{} -12\n"
1489 "(ceiling-quotient -123 10) @result{} -12\n"
1490 "(ceiling-quotient -123 -10) @result{} 13\n"
1491 "(ceiling-quotient -123.2 -63.5) @result{} 2.0\n"
1492 "(ceiling-quotient 16/3 -10/7) @result{} -3\n"
1493 "@end lisp")
1494#define FUNC_NAME s_scm_ceiling_quotient
1495{
1496 if (SCM_LIKELY (SCM_I_INUMP (x)))
1497 {
1498 scm_t_inum xx = SCM_I_INUM (x);
1499 if (SCM_LIKELY (SCM_I_INUMP (y)))
1500 {
1501 scm_t_inum yy = SCM_I_INUM (y);
1502 if (SCM_UNLIKELY (yy == 0))
1503 scm_num_overflow (s_scm_ceiling_quotient);
1504 else
1505 {
1506 scm_t_inum xx1 = xx;
1507 scm_t_inum qq;
1508 if (SCM_LIKELY (yy > 0))
1509 {
1510 if (SCM_LIKELY (xx >= 0))
1511 xx1 = xx + yy - 1;
1512 }
8f9da340
MW
1513 else if (xx < 0)
1514 xx1 = xx + yy + 1;
1515 qq = xx1 / yy;
1516 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1517 return SCM_I_MAKINUM (qq);
1518 else
1519 return scm_i_inum2big (qq);
1520 }
1521 }
1522 else if (SCM_BIGP (y))
1523 {
1524 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1525 scm_remember_upto_here_1 (y);
1526 if (SCM_LIKELY (sign > 0))
1527 {
1528 if (SCM_LIKELY (xx > 0))
1529 return SCM_INUM1;
1530 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1531 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1532 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1533 {
1534 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1535 scm_remember_upto_here_1 (y);
1536 return SCM_I_MAKINUM (-1);
1537 }
1538 else
1539 return SCM_INUM0;
1540 }
1541 else if (xx >= 0)
1542 return SCM_INUM0;
1543 else
1544 return SCM_INUM1;
1545 }
1546 else if (SCM_REALP (y))
1547 return scm_i_inexact_ceiling_quotient (xx, SCM_REAL_VALUE (y));
1548 else if (SCM_FRACTIONP (y))
1549 return scm_i_exact_rational_ceiling_quotient (x, y);
1550 else
1551 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1552 s_scm_ceiling_quotient);
1553 }
1554 else if (SCM_BIGP (x))
1555 {
1556 if (SCM_LIKELY (SCM_I_INUMP (y)))
1557 {
1558 scm_t_inum yy = SCM_I_INUM (y);
1559 if (SCM_UNLIKELY (yy == 0))
1560 scm_num_overflow (s_scm_ceiling_quotient);
1561 else if (SCM_UNLIKELY (yy == 1))
1562 return x;
1563 else
1564 {
1565 SCM q = scm_i_mkbig ();
1566 if (yy > 0)
1567 mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1568 else
1569 {
1570 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1571 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1572 }
1573 scm_remember_upto_here_1 (x);
1574 return scm_i_normbig (q);
1575 }
1576 }
1577 else if (SCM_BIGP (y))
1578 {
1579 SCM q = scm_i_mkbig ();
1580 mpz_cdiv_q (SCM_I_BIG_MPZ (q),
1581 SCM_I_BIG_MPZ (x),
1582 SCM_I_BIG_MPZ (y));
1583 scm_remember_upto_here_2 (x, y);
1584 return scm_i_normbig (q);
1585 }
1586 else if (SCM_REALP (y))
1587 return scm_i_inexact_ceiling_quotient
1588 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1589 else if (SCM_FRACTIONP (y))
1590 return scm_i_exact_rational_ceiling_quotient (x, y);
1591 else
1592 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1593 s_scm_ceiling_quotient);
1594 }
1595 else if (SCM_REALP (x))
1596 {
1597 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1598 SCM_BIGP (y) || SCM_FRACTIONP (y))
1599 return scm_i_inexact_ceiling_quotient
1600 (SCM_REAL_VALUE (x), scm_to_double (y));
1601 else
1602 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1603 s_scm_ceiling_quotient);
1604 }
1605 else if (SCM_FRACTIONP (x))
1606 {
1607 if (SCM_REALP (y))
1608 return scm_i_inexact_ceiling_quotient
1609 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1610 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1611 return scm_i_exact_rational_ceiling_quotient (x, y);
1612 else
1613 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1614 s_scm_ceiling_quotient);
1615 }
1616 else
1617 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG1,
1618 s_scm_ceiling_quotient);
1619}
1620#undef FUNC_NAME
1621
1622static SCM
1623scm_i_inexact_ceiling_quotient (double x, double y)
1624{
1625 if (SCM_UNLIKELY (y == 0))
1626 scm_num_overflow (s_scm_ceiling_quotient); /* or return a NaN? */
1627 else
1628 return scm_from_double (ceil (x / y));
1629}
1630
1631static SCM
1632scm_i_exact_rational_ceiling_quotient (SCM x, SCM y)
1633{
1634 return scm_ceiling_quotient
1635 (scm_product (scm_numerator (x), scm_denominator (y)),
1636 scm_product (scm_numerator (y), scm_denominator (x)));
1637}
1638
1639static SCM scm_i_inexact_ceiling_remainder (double x, double y);
1640static SCM scm_i_exact_rational_ceiling_remainder (SCM x, SCM y);
1641
1642SCM_PRIMITIVE_GENERIC (scm_ceiling_remainder, "ceiling-remainder", 2, 0, 0,
1643 (SCM x, SCM y),
1644 "Return the real number @var{r} such that\n"
1645 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1646 "where @math{@var{q} = ceiling(@var{x} / @var{y})}.\n"
1647 "@lisp\n"
1648 "(ceiling-remainder 123 10) @result{} -7\n"
1649 "(ceiling-remainder 123 -10) @result{} 3\n"
1650 "(ceiling-remainder -123 10) @result{} -3\n"
1651 "(ceiling-remainder -123 -10) @result{} 7\n"
1652 "(ceiling-remainder -123.2 -63.5) @result{} 3.8\n"
1653 "(ceiling-remainder 16/3 -10/7) @result{} 22/21\n"
1654 "@end lisp")
1655#define FUNC_NAME s_scm_ceiling_remainder
1656{
1657 if (SCM_LIKELY (SCM_I_INUMP (x)))
1658 {
1659 scm_t_inum xx = SCM_I_INUM (x);
1660 if (SCM_LIKELY (SCM_I_INUMP (y)))
1661 {
1662 scm_t_inum yy = SCM_I_INUM (y);
1663 if (SCM_UNLIKELY (yy == 0))
1664 scm_num_overflow (s_scm_ceiling_remainder);
1665 else
1666 {
1667 scm_t_inum rr = xx % yy;
1668 int needs_adjustment;
1669
1670 if (SCM_LIKELY (yy > 0))
1671 needs_adjustment = (rr > 0);
1672 else
1673 needs_adjustment = (rr < 0);
1674
1675 if (needs_adjustment)
1676 rr -= yy;
1677 return SCM_I_MAKINUM (rr);
1678 }
1679 }
1680 else if (SCM_BIGP (y))
1681 {
1682 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1683 scm_remember_upto_here_1 (y);
1684 if (SCM_LIKELY (sign > 0))
1685 {
1686 if (SCM_LIKELY (xx > 0))
1687 {
1688 SCM r = scm_i_mkbig ();
1689 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1690 scm_remember_upto_here_1 (y);
1691 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1692 return scm_i_normbig (r);
1693 }
1694 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1695 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1696 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1697 {
1698 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1699 scm_remember_upto_here_1 (y);
1700 return SCM_INUM0;
1701 }
1702 else
1703 return x;
1704 }
1705 else if (xx >= 0)
1706 return x;
1707 else
1708 {
1709 SCM r = scm_i_mkbig ();
1710 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1711 scm_remember_upto_here_1 (y);
1712 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1713 return scm_i_normbig (r);
1714 }
1715 }
1716 else if (SCM_REALP (y))
1717 return scm_i_inexact_ceiling_remainder (xx, SCM_REAL_VALUE (y));
1718 else if (SCM_FRACTIONP (y))
1719 return scm_i_exact_rational_ceiling_remainder (x, y);
1720 else
1721 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1722 s_scm_ceiling_remainder);
1723 }
1724 else if (SCM_BIGP (x))
1725 {
1726 if (SCM_LIKELY (SCM_I_INUMP (y)))
1727 {
1728 scm_t_inum yy = SCM_I_INUM (y);
1729 if (SCM_UNLIKELY (yy == 0))
1730 scm_num_overflow (s_scm_ceiling_remainder);
1731 else
1732 {
1733 scm_t_inum rr;
1734 if (yy > 0)
1735 rr = -mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
1736 else
1737 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1738 scm_remember_upto_here_1 (x);
1739 return SCM_I_MAKINUM (rr);
1740 }
1741 }
1742 else if (SCM_BIGP (y))
1743 {
1744 SCM r = scm_i_mkbig ();
1745 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
1746 SCM_I_BIG_MPZ (x),
1747 SCM_I_BIG_MPZ (y));
1748 scm_remember_upto_here_2 (x, y);
1749 return scm_i_normbig (r);
1750 }
1751 else if (SCM_REALP (y))
1752 return scm_i_inexact_ceiling_remainder
1753 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1754 else if (SCM_FRACTIONP (y))
1755 return scm_i_exact_rational_ceiling_remainder (x, y);
1756 else
1757 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1758 s_scm_ceiling_remainder);
1759 }
1760 else if (SCM_REALP (x))
1761 {
1762 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1763 SCM_BIGP (y) || SCM_FRACTIONP (y))
1764 return scm_i_inexact_ceiling_remainder
1765 (SCM_REAL_VALUE (x), scm_to_double (y));
1766 else
1767 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1768 s_scm_ceiling_remainder);
1769 }
1770 else if (SCM_FRACTIONP (x))
1771 {
1772 if (SCM_REALP (y))
1773 return scm_i_inexact_ceiling_remainder
1774 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1775 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1776 return scm_i_exact_rational_ceiling_remainder (x, y);
1777 else
1778 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1779 s_scm_ceiling_remainder);
1780 }
1781 else
1782 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG1,
1783 s_scm_ceiling_remainder);
1784}
1785#undef FUNC_NAME
1786
1787static SCM
1788scm_i_inexact_ceiling_remainder (double x, double y)
1789{
1790 /* Although it would be more efficient to use fmod here, we can't
1791 because it would in some cases produce results inconsistent with
1792 scm_i_inexact_ceiling_quotient, such that x != q * y + r (not even
1793 close). In particular, when x is very close to a multiple of y,
1794 then r might be either 0.0 or -y, but those two cases must
1795 correspond to different choices of q. If r = 0.0 then q must be
1796 x/y, and if r = -y then q must be x/y+1. If quotient chooses one
1797 and remainder chooses the other, it would be bad. */
1798 if (SCM_UNLIKELY (y == 0))
1799 scm_num_overflow (s_scm_ceiling_remainder); /* or return a NaN? */
1800 else
1801 return scm_from_double (x - y * ceil (x / y));
1802}
1803
1804static SCM
1805scm_i_exact_rational_ceiling_remainder (SCM x, SCM y)
1806{
1807 SCM xd = scm_denominator (x);
1808 SCM yd = scm_denominator (y);
1809 SCM r1 = scm_ceiling_remainder (scm_product (scm_numerator (x), yd),
1810 scm_product (scm_numerator (y), xd));
1811 return scm_divide (r1, scm_product (xd, yd));
1812}
1813
1814static void scm_i_inexact_ceiling_divide (double x, double y,
1815 SCM *qp, SCM *rp);
1816static void scm_i_exact_rational_ceiling_divide (SCM x, SCM y,
1817 SCM *qp, SCM *rp);
1818
1819SCM_PRIMITIVE_GENERIC (scm_i_ceiling_divide, "ceiling/", 2, 0, 0,
1820 (SCM x, SCM y),
1821 "Return the integer @var{q} and the real number @var{r}\n"
1822 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1823 "and @math{@var{q} = ceiling(@var{x} / @var{y})}.\n"
1824 "@lisp\n"
1825 "(ceiling/ 123 10) @result{} 13 and -7\n"
1826 "(ceiling/ 123 -10) @result{} -12 and 3\n"
1827 "(ceiling/ -123 10) @result{} -12 and -3\n"
1828 "(ceiling/ -123 -10) @result{} 13 and 7\n"
1829 "(ceiling/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
1830 "(ceiling/ 16/3 -10/7) @result{} -3 and 22/21\n"
1831 "@end lisp")
1832#define FUNC_NAME s_scm_i_ceiling_divide
1833{
1834 SCM q, r;
1835
1836 scm_ceiling_divide(x, y, &q, &r);
1837 return scm_values (scm_list_2 (q, r));
1838}
1839#undef FUNC_NAME
1840
1841#define s_scm_ceiling_divide s_scm_i_ceiling_divide
1842#define g_scm_ceiling_divide g_scm_i_ceiling_divide
1843
1844void
1845scm_ceiling_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1846{
1847 if (SCM_LIKELY (SCM_I_INUMP (x)))
1848 {
1849 scm_t_inum xx = SCM_I_INUM (x);
1850 if (SCM_LIKELY (SCM_I_INUMP (y)))
1851 {
1852 scm_t_inum yy = SCM_I_INUM (y);
1853 if (SCM_UNLIKELY (yy == 0))
1854 scm_num_overflow (s_scm_ceiling_divide);
1855 else
1856 {
1857 scm_t_inum qq = xx / yy;
1858 scm_t_inum rr = xx % yy;
1859 int needs_adjustment;
1860
1861 if (SCM_LIKELY (yy > 0))
1862 needs_adjustment = (rr > 0);
1863 else
1864 needs_adjustment = (rr < 0);
1865
1866 if (needs_adjustment)
1867 {
1868 rr -= yy;
1869 qq++;
1870 }
1871 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1872 *qp = SCM_I_MAKINUM (qq);
1873 else
1874 *qp = scm_i_inum2big (qq);
1875 *rp = SCM_I_MAKINUM (rr);
1876 }
1877 return;
1878 }
1879 else if (SCM_BIGP (y))
1880 {
1881 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1882 scm_remember_upto_here_1 (y);
1883 if (SCM_LIKELY (sign > 0))
1884 {
1885 if (SCM_LIKELY (xx > 0))
1886 {
1887 SCM r = scm_i_mkbig ();
1888 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1889 scm_remember_upto_here_1 (y);
1890 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1891 *qp = SCM_INUM1;
1892 *rp = scm_i_normbig (r);
1893 }
1894 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1895 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1896 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1897 {
1898 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1899 scm_remember_upto_here_1 (y);
1900 *qp = SCM_I_MAKINUM (-1);
1901 *rp = SCM_INUM0;
1902 }
1903 else
1904 {
1905 *qp = SCM_INUM0;
1906 *rp = x;
1907 }
1908 }
1909 else if (xx >= 0)
1910 {
1911 *qp = SCM_INUM0;
1912 *rp = x;
1913 }
1914 else
1915 {
1916 SCM r = scm_i_mkbig ();
1917 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1918 scm_remember_upto_here_1 (y);
1919 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1920 *qp = SCM_INUM1;
1921 *rp = scm_i_normbig (r);
1922 }
1923 return;
1924 }
1925 else if (SCM_REALP (y))
1926 return scm_i_inexact_ceiling_divide (xx, SCM_REAL_VALUE (y), qp, rp);
1927 else if (SCM_FRACTIONP (y))
1928 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1929 else
1930 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1931 s_scm_ceiling_divide, qp, rp);
1932 }
1933 else if (SCM_BIGP (x))
1934 {
1935 if (SCM_LIKELY (SCM_I_INUMP (y)))
1936 {
1937 scm_t_inum yy = SCM_I_INUM (y);
1938 if (SCM_UNLIKELY (yy == 0))
1939 scm_num_overflow (s_scm_ceiling_divide);
1940 else
1941 {
1942 SCM q = scm_i_mkbig ();
1943 SCM r = scm_i_mkbig ();
1944 if (yy > 0)
1945 mpz_cdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1946 SCM_I_BIG_MPZ (x), yy);
1947 else
1948 {
1949 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1950 SCM_I_BIG_MPZ (x), -yy);
1951 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1952 }
1953 scm_remember_upto_here_1 (x);
1954 *qp = scm_i_normbig (q);
1955 *rp = scm_i_normbig (r);
1956 }
1957 return;
1958 }
1959 else if (SCM_BIGP (y))
1960 {
1961 SCM q = scm_i_mkbig ();
1962 SCM r = scm_i_mkbig ();
1963 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1964 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1965 scm_remember_upto_here_2 (x, y);
1966 *qp = scm_i_normbig (q);
1967 *rp = scm_i_normbig (r);
1968 return;
1969 }
1970 else if (SCM_REALP (y))
1971 return scm_i_inexact_ceiling_divide
1972 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
1973 else if (SCM_FRACTIONP (y))
1974 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1975 else
1976 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1977 s_scm_ceiling_divide, qp, rp);
1978 }
1979 else if (SCM_REALP (x))
1980 {
1981 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1982 SCM_BIGP (y) || SCM_FRACTIONP (y))
1983 return scm_i_inexact_ceiling_divide
1984 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
1985 else
1986 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1987 s_scm_ceiling_divide, qp, rp);
1988 }
1989 else if (SCM_FRACTIONP (x))
1990 {
1991 if (SCM_REALP (y))
1992 return scm_i_inexact_ceiling_divide
1993 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
1994 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1995 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1996 else
1997 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1998 s_scm_ceiling_divide, qp, rp);
1999 }
2000 else
2001 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG1,
2002 s_scm_ceiling_divide, qp, rp);
2003}
2004
2005static void
2006scm_i_inexact_ceiling_divide (double x, double y, SCM *qp, SCM *rp)
2007{
2008 if (SCM_UNLIKELY (y == 0))
2009 scm_num_overflow (s_scm_ceiling_divide); /* or return a NaN? */
2010 else
2011 {
2012 double q = ceil (x / y);
2013 double r = x - q * y;
2014 *qp = scm_from_double (q);
2015 *rp = scm_from_double (r);
2016 }
2017}
2018
2019static void
2020scm_i_exact_rational_ceiling_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2021{
2022 SCM r1;
2023 SCM xd = scm_denominator (x);
2024 SCM yd = scm_denominator (y);
2025
2026 scm_ceiling_divide (scm_product (scm_numerator (x), yd),
2027 scm_product (scm_numerator (y), xd),
2028 qp, &r1);
2029 *rp = scm_divide (r1, scm_product (xd, yd));
2030}
2031
2032static SCM scm_i_inexact_truncate_quotient (double x, double y);
2033static SCM scm_i_exact_rational_truncate_quotient (SCM x, SCM y);
2034
2035SCM_PRIMITIVE_GENERIC (scm_truncate_quotient, "truncate-quotient", 2, 0, 0,
2036 (SCM x, SCM y),
2037 "Return @math{@var{x} / @var{y}} rounded toward zero.\n"
2038 "@lisp\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 -10) @result{} 12\n"
2043 "(truncate-quotient -123.2 -63.5) @result{} 1.0\n"
2044 "(truncate-quotient 16/3 -10/7) @result{} -3\n"
2045 "@end lisp")
2046#define FUNC_NAME s_scm_truncate_quotient
2047{
2048 if (SCM_LIKELY (SCM_I_INUMP (x)))
2049 {
2050 scm_t_inum xx = SCM_I_INUM (x);
2051 if (SCM_LIKELY (SCM_I_INUMP (y)))
2052 {
2053 scm_t_inum yy = SCM_I_INUM (y);
2054 if (SCM_UNLIKELY (yy == 0))
2055 scm_num_overflow (s_scm_truncate_quotient);
2056 else
2057 {
2058 scm_t_inum qq = xx / yy;
2059 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2060 return SCM_I_MAKINUM (qq);
2061 else
2062 return scm_i_inum2big (qq);
2063 }
2064 }
2065 else if (SCM_BIGP (y))
2066 {
2067 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2068 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2069 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2070 {
2071 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2072 scm_remember_upto_here_1 (y);
2073 return SCM_I_MAKINUM (-1);
2074 }
2075 else
2076 return SCM_INUM0;
2077 }
2078 else if (SCM_REALP (y))
2079 return scm_i_inexact_truncate_quotient (xx, SCM_REAL_VALUE (y));
2080 else if (SCM_FRACTIONP (y))
2081 return scm_i_exact_rational_truncate_quotient (x, y);
2082 else
2083 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2084 s_scm_truncate_quotient);
2085 }
2086 else if (SCM_BIGP (x))
2087 {
2088 if (SCM_LIKELY (SCM_I_INUMP (y)))
2089 {
2090 scm_t_inum yy = SCM_I_INUM (y);
2091 if (SCM_UNLIKELY (yy == 0))
2092 scm_num_overflow (s_scm_truncate_quotient);
2093 else if (SCM_UNLIKELY (yy == 1))
2094 return x;
2095 else
2096 {
2097 SCM q = scm_i_mkbig ();
2098 if (yy > 0)
2099 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
2100 else
2101 {
2102 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
2103 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2104 }
2105 scm_remember_upto_here_1 (x);
2106 return scm_i_normbig (q);
2107 }
2108 }
2109 else if (SCM_BIGP (y))
2110 {
2111 SCM q = scm_i_mkbig ();
2112 mpz_tdiv_q (SCM_I_BIG_MPZ (q),
2113 SCM_I_BIG_MPZ (x),
2114 SCM_I_BIG_MPZ (y));
2115 scm_remember_upto_here_2 (x, y);
2116 return scm_i_normbig (q);
2117 }
2118 else if (SCM_REALP (y))
2119 return scm_i_inexact_truncate_quotient
2120 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2121 else if (SCM_FRACTIONP (y))
2122 return scm_i_exact_rational_truncate_quotient (x, y);
2123 else
2124 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2125 s_scm_truncate_quotient);
2126 }
2127 else if (SCM_REALP (x))
2128 {
2129 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2130 SCM_BIGP (y) || SCM_FRACTIONP (y))
2131 return scm_i_inexact_truncate_quotient
2132 (SCM_REAL_VALUE (x), scm_to_double (y));
2133 else
2134 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2135 s_scm_truncate_quotient);
2136 }
2137 else if (SCM_FRACTIONP (x))
2138 {
2139 if (SCM_REALP (y))
2140 return scm_i_inexact_truncate_quotient
2141 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2142 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2143 return scm_i_exact_rational_truncate_quotient (x, y);
2144 else
2145 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2146 s_scm_truncate_quotient);
2147 }
2148 else
2149 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG1,
2150 s_scm_truncate_quotient);
2151}
2152#undef FUNC_NAME
2153
2154static SCM
2155scm_i_inexact_truncate_quotient (double x, double y)
2156{
2157 if (SCM_UNLIKELY (y == 0))
2158 scm_num_overflow (s_scm_truncate_quotient); /* or return a NaN? */
2159 else
c251ab63 2160 return scm_from_double (trunc (x / y));
8f9da340
MW
2161}
2162
2163static SCM
2164scm_i_exact_rational_truncate_quotient (SCM x, SCM y)
2165{
2166 return scm_truncate_quotient
2167 (scm_product (scm_numerator (x), scm_denominator (y)),
2168 scm_product (scm_numerator (y), scm_denominator (x)));
2169}
2170
2171static SCM scm_i_inexact_truncate_remainder (double x, double y);
2172static SCM scm_i_exact_rational_truncate_remainder (SCM x, SCM y);
2173
2174SCM_PRIMITIVE_GENERIC (scm_truncate_remainder, "truncate-remainder", 2, 0, 0,
2175 (SCM x, SCM y),
2176 "Return the real number @var{r} such that\n"
2177 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2178 "where @math{@var{q} = truncate(@var{x} / @var{y})}.\n"
2179 "@lisp\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 -10) @result{} -3\n"
2184 "(truncate-remainder -123.2 -63.5) @result{} -59.7\n"
2185 "(truncate-remainder 16/3 -10/7) @result{} 22/21\n"
2186 "@end lisp")
2187#define FUNC_NAME s_scm_truncate_remainder
2188{
2189 if (SCM_LIKELY (SCM_I_INUMP (x)))
2190 {
2191 scm_t_inum xx = SCM_I_INUM (x);
2192 if (SCM_LIKELY (SCM_I_INUMP (y)))
2193 {
2194 scm_t_inum yy = SCM_I_INUM (y);
2195 if (SCM_UNLIKELY (yy == 0))
2196 scm_num_overflow (s_scm_truncate_remainder);
2197 else
2198 return SCM_I_MAKINUM (xx % yy);
2199 }
2200 else if (SCM_BIGP (y))
2201 {
2202 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2203 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2204 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2205 {
2206 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2207 scm_remember_upto_here_1 (y);
2208 return SCM_INUM0;
2209 }
2210 else
2211 return x;
2212 }
2213 else if (SCM_REALP (y))
2214 return scm_i_inexact_truncate_remainder (xx, SCM_REAL_VALUE (y));
2215 else if (SCM_FRACTIONP (y))
2216 return scm_i_exact_rational_truncate_remainder (x, y);
2217 else
2218 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2219 s_scm_truncate_remainder);
2220 }
2221 else if (SCM_BIGP (x))
2222 {
2223 if (SCM_LIKELY (SCM_I_INUMP (y)))
2224 {
2225 scm_t_inum yy = SCM_I_INUM (y);
2226 if (SCM_UNLIKELY (yy == 0))
2227 scm_num_overflow (s_scm_truncate_remainder);
2228 else
2229 {
2230 scm_t_inum rr = (mpz_tdiv_ui (SCM_I_BIG_MPZ (x),
2231 (yy > 0) ? yy : -yy)
2232 * mpz_sgn (SCM_I_BIG_MPZ (x)));
2233 scm_remember_upto_here_1 (x);
2234 return SCM_I_MAKINUM (rr);
2235 }
2236 }
2237 else if (SCM_BIGP (y))
2238 {
2239 SCM r = scm_i_mkbig ();
2240 mpz_tdiv_r (SCM_I_BIG_MPZ (r),
2241 SCM_I_BIG_MPZ (x),
2242 SCM_I_BIG_MPZ (y));
2243 scm_remember_upto_here_2 (x, y);
2244 return scm_i_normbig (r);
2245 }
2246 else if (SCM_REALP (y))
2247 return scm_i_inexact_truncate_remainder
2248 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2249 else if (SCM_FRACTIONP (y))
2250 return scm_i_exact_rational_truncate_remainder (x, y);
2251 else
2252 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2253 s_scm_truncate_remainder);
2254 }
2255 else if (SCM_REALP (x))
2256 {
2257 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2258 SCM_BIGP (y) || SCM_FRACTIONP (y))
2259 return scm_i_inexact_truncate_remainder
2260 (SCM_REAL_VALUE (x), scm_to_double (y));
2261 else
2262 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2263 s_scm_truncate_remainder);
2264 }
2265 else if (SCM_FRACTIONP (x))
2266 {
2267 if (SCM_REALP (y))
2268 return scm_i_inexact_truncate_remainder
2269 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2270 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2271 return scm_i_exact_rational_truncate_remainder (x, y);
2272 else
2273 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2274 s_scm_truncate_remainder);
2275 }
2276 else
2277 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG1,
2278 s_scm_truncate_remainder);
2279}
2280#undef FUNC_NAME
2281
2282static SCM
2283scm_i_inexact_truncate_remainder (double x, double y)
2284{
2285 /* Although it would be more efficient to use fmod here, we can't
2286 because it would in some cases produce results inconsistent with
2287 scm_i_inexact_truncate_quotient, such that x != q * y + r (not even
2288 close). In particular, when x is very close to a multiple of y,
2289 then r might be either 0.0 or sgn(x)*|y|, but those two cases must
2290 correspond to different choices of q. If quotient chooses one and
2291 remainder chooses the other, it would be bad. */
2292 if (SCM_UNLIKELY (y == 0))
2293 scm_num_overflow (s_scm_truncate_remainder); /* or return a NaN? */
2294 else
c251ab63 2295 return scm_from_double (x - y * trunc (x / y));
8f9da340
MW
2296}
2297
2298static SCM
2299scm_i_exact_rational_truncate_remainder (SCM x, SCM y)
2300{
2301 SCM xd = scm_denominator (x);
2302 SCM yd = scm_denominator (y);
2303 SCM r1 = scm_truncate_remainder (scm_product (scm_numerator (x), yd),
2304 scm_product (scm_numerator (y), xd));
2305 return scm_divide (r1, scm_product (xd, yd));
2306}
2307
2308
2309static void scm_i_inexact_truncate_divide (double x, double y,
2310 SCM *qp, SCM *rp);
2311static void scm_i_exact_rational_truncate_divide (SCM x, SCM y,
2312 SCM *qp, SCM *rp);
2313
2314SCM_PRIMITIVE_GENERIC (scm_i_truncate_divide, "truncate/", 2, 0, 0,
2315 (SCM x, SCM y),
2316 "Return the integer @var{q} and the real number @var{r}\n"
2317 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2318 "and @math{@var{q} = truncate(@var{x} / @var{y})}.\n"
2319 "@lisp\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 -10) @result{} 12 and -3\n"
2324 "(truncate/ -123.2 -63.5) @result{} 1.0 and -59.7\n"
2325 "(truncate/ 16/3 -10/7) @result{} -3 and 22/21\n"
2326 "@end lisp")
2327#define FUNC_NAME s_scm_i_truncate_divide
2328{
2329 SCM q, r;
2330
2331 scm_truncate_divide(x, y, &q, &r);
2332 return scm_values (scm_list_2 (q, r));
2333}
2334#undef FUNC_NAME
2335
2336#define s_scm_truncate_divide s_scm_i_truncate_divide
2337#define g_scm_truncate_divide g_scm_i_truncate_divide
2338
2339void
2340scm_truncate_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2341{
2342 if (SCM_LIKELY (SCM_I_INUMP (x)))
2343 {
2344 scm_t_inum xx = SCM_I_INUM (x);
2345 if (SCM_LIKELY (SCM_I_INUMP (y)))
2346 {
2347 scm_t_inum yy = SCM_I_INUM (y);
2348 if (SCM_UNLIKELY (yy == 0))
2349 scm_num_overflow (s_scm_truncate_divide);
2350 else
2351 {
2352 scm_t_inum qq = xx / yy;
2353 scm_t_inum rr = xx % yy;
2354 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2355 *qp = SCM_I_MAKINUM (qq);
2356 else
2357 *qp = scm_i_inum2big (qq);
2358 *rp = SCM_I_MAKINUM (rr);
2359 }
2360 return;
2361 }
2362 else if (SCM_BIGP (y))
2363 {
2364 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2365 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2366 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2367 {
2368 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2369 scm_remember_upto_here_1 (y);
2370 *qp = SCM_I_MAKINUM (-1);
2371 *rp = SCM_INUM0;
2372 }
2373 else
2374 {
2375 *qp = SCM_INUM0;
2376 *rp = x;
2377 }
2378 return;
2379 }
2380 else if (SCM_REALP (y))
2381 return scm_i_inexact_truncate_divide (xx, SCM_REAL_VALUE (y), qp, rp);
2382 else if (SCM_FRACTIONP (y))
2383 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2384 else
2385 return two_valued_wta_dispatch_2
2386 (g_scm_truncate_divide, x, y, SCM_ARG2,
2387 s_scm_truncate_divide, qp, rp);
2388 }
2389 else if (SCM_BIGP (x))
2390 {
2391 if (SCM_LIKELY (SCM_I_INUMP (y)))
2392 {
2393 scm_t_inum yy = SCM_I_INUM (y);
2394 if (SCM_UNLIKELY (yy == 0))
2395 scm_num_overflow (s_scm_truncate_divide);
2396 else
2397 {
2398 SCM q = scm_i_mkbig ();
2399 scm_t_inum rr;
2400 if (yy > 0)
2401 rr = mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q),
2402 SCM_I_BIG_MPZ (x), yy);
2403 else
2404 {
2405 rr = mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q),
2406 SCM_I_BIG_MPZ (x), -yy);
2407 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2408 }
2409 rr *= mpz_sgn (SCM_I_BIG_MPZ (x));
2410 scm_remember_upto_here_1 (x);
2411 *qp = scm_i_normbig (q);
2412 *rp = SCM_I_MAKINUM (rr);
2413 }
2414 return;
2415 }
2416 else if (SCM_BIGP (y))
2417 {
2418 SCM q = scm_i_mkbig ();
2419 SCM r = scm_i_mkbig ();
2420 mpz_tdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2421 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2422 scm_remember_upto_here_2 (x, y);
2423 *qp = scm_i_normbig (q);
2424 *rp = scm_i_normbig (r);
2425 }
2426 else if (SCM_REALP (y))
2427 return scm_i_inexact_truncate_divide
2428 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
2429 else if (SCM_FRACTIONP (y))
2430 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2431 else
2432 return two_valued_wta_dispatch_2
2433 (g_scm_truncate_divide, x, y, SCM_ARG2,
2434 s_scm_truncate_divide, qp, rp);
2435 }
2436 else if (SCM_REALP (x))
2437 {
2438 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2439 SCM_BIGP (y) || SCM_FRACTIONP (y))
2440 return scm_i_inexact_truncate_divide
2441 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
2442 else
2443 return two_valued_wta_dispatch_2
2444 (g_scm_truncate_divide, x, y, SCM_ARG2,
2445 s_scm_truncate_divide, qp, rp);
2446 }
2447 else if (SCM_FRACTIONP (x))
2448 {
2449 if (SCM_REALP (y))
2450 return scm_i_inexact_truncate_divide
2451 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
2452 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2453 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2454 else
2455 return two_valued_wta_dispatch_2
2456 (g_scm_truncate_divide, x, y, SCM_ARG2,
2457 s_scm_truncate_divide, qp, rp);
2458 }
2459 else
2460 return two_valued_wta_dispatch_2 (g_scm_truncate_divide, x, y, SCM_ARG1,
2461 s_scm_truncate_divide, qp, rp);
2462}
2463
2464static void
2465scm_i_inexact_truncate_divide (double x, double y, SCM *qp, SCM *rp)
2466{
2467 if (SCM_UNLIKELY (y == 0))
2468 scm_num_overflow (s_scm_truncate_divide); /* or return a NaN? */
2469 else
2470 {
c15fe499
MW
2471 double q = trunc (x / y);
2472 double r = x - q * y;
8f9da340
MW
2473 *qp = scm_from_double (q);
2474 *rp = scm_from_double (r);
2475 }
2476}
2477
2478static void
2479scm_i_exact_rational_truncate_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2480{
2481 SCM r1;
2482 SCM xd = scm_denominator (x);
2483 SCM yd = scm_denominator (y);
2484
2485 scm_truncate_divide (scm_product (scm_numerator (x), yd),
2486 scm_product (scm_numerator (y), xd),
2487 qp, &r1);
2488 *rp = scm_divide (r1, scm_product (xd, yd));
2489}
2490
ff62c168
MW
2491static SCM scm_i_inexact_centered_quotient (double x, double y);
2492static SCM scm_i_bigint_centered_quotient (SCM x, SCM y);
03ddd15b 2493static SCM scm_i_exact_rational_centered_quotient (SCM x, SCM y);
ff62c168 2494
8f9da340
MW
2495SCM_PRIMITIVE_GENERIC (scm_centered_quotient, "centered-quotient", 2, 0, 0,
2496 (SCM x, SCM y),
2497 "Return the integer @var{q} such that\n"
2498 "@math{@var{x} = @var{q}*@var{y} + @var{r}} where\n"
2499 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2500 "@lisp\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 -10) @result{} 12\n"
2505 "(centered-quotient -123.2 -63.5) @result{} 2.0\n"
2506 "(centered-quotient 16/3 -10/7) @result{} -4\n"
2507 "@end lisp")
2508#define FUNC_NAME s_scm_centered_quotient
2509{
2510 if (SCM_LIKELY (SCM_I_INUMP (x)))
2511 {
2512 scm_t_inum xx = SCM_I_INUM (x);
2513 if (SCM_LIKELY (SCM_I_INUMP (y)))
2514 {
2515 scm_t_inum yy = SCM_I_INUM (y);
2516 if (SCM_UNLIKELY (yy == 0))
2517 scm_num_overflow (s_scm_centered_quotient);
2518 else
2519 {
2520 scm_t_inum qq = xx / yy;
2521 scm_t_inum rr = xx % yy;
2522 if (SCM_LIKELY (xx > 0))
2523 {
2524 if (SCM_LIKELY (yy > 0))
2525 {
2526 if (rr >= (yy + 1) / 2)
2527 qq++;
2528 }
2529 else
2530 {
2531 if (rr >= (1 - yy) / 2)
2532 qq--;
2533 }
2534 }
2535 else
2536 {
2537 if (SCM_LIKELY (yy > 0))
2538 {
2539 if (rr < -yy / 2)
2540 qq--;
2541 }
2542 else
2543 {
2544 if (rr < yy / 2)
2545 qq++;
2546 }
2547 }
2548 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2549 return SCM_I_MAKINUM (qq);
2550 else
2551 return scm_i_inum2big (qq);
2552 }
2553 }
2554 else if (SCM_BIGP (y))
2555 {
2556 /* Pass a denormalized bignum version of x (even though it
2557 can fit in a fixnum) to scm_i_bigint_centered_quotient */
2558 return scm_i_bigint_centered_quotient (scm_i_long2big (xx), y);
2559 }
2560 else if (SCM_REALP (y))
2561 return scm_i_inexact_centered_quotient (xx, SCM_REAL_VALUE (y));
2562 else if (SCM_FRACTIONP (y))
2563 return scm_i_exact_rational_centered_quotient (x, y);
2564 else
2565 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2566 s_scm_centered_quotient);
2567 }
2568 else if (SCM_BIGP (x))
2569 {
2570 if (SCM_LIKELY (SCM_I_INUMP (y)))
2571 {
2572 scm_t_inum yy = SCM_I_INUM (y);
2573 if (SCM_UNLIKELY (yy == 0))
2574 scm_num_overflow (s_scm_centered_quotient);
2575 else if (SCM_UNLIKELY (yy == 1))
2576 return x;
2577 else
2578 {
2579 SCM q = scm_i_mkbig ();
2580 scm_t_inum rr;
2581 /* Arrange for rr to initially be non-positive,
2582 because that simplifies the test to see
2583 if it is within the needed bounds. */
2584 if (yy > 0)
2585 {
2586 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2587 SCM_I_BIG_MPZ (x), yy);
2588 scm_remember_upto_here_1 (x);
2589 if (rr < -yy / 2)
2590 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2591 SCM_I_BIG_MPZ (q), 1);
2592 }
2593 else
2594 {
2595 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2596 SCM_I_BIG_MPZ (x), -yy);
2597 scm_remember_upto_here_1 (x);
2598 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2599 if (rr < yy / 2)
2600 mpz_add_ui (SCM_I_BIG_MPZ (q),
2601 SCM_I_BIG_MPZ (q), 1);
2602 }
2603 return scm_i_normbig (q);
2604 }
2605 }
2606 else if (SCM_BIGP (y))
2607 return scm_i_bigint_centered_quotient (x, y);
2608 else if (SCM_REALP (y))
2609 return scm_i_inexact_centered_quotient
2610 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2611 else if (SCM_FRACTIONP (y))
2612 return scm_i_exact_rational_centered_quotient (x, y);
2613 else
2614 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2615 s_scm_centered_quotient);
2616 }
2617 else if (SCM_REALP (x))
2618 {
2619 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2620 SCM_BIGP (y) || SCM_FRACTIONP (y))
2621 return scm_i_inexact_centered_quotient
2622 (SCM_REAL_VALUE (x), scm_to_double (y));
2623 else
2624 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2625 s_scm_centered_quotient);
2626 }
2627 else if (SCM_FRACTIONP (x))
2628 {
2629 if (SCM_REALP (y))
2630 return scm_i_inexact_centered_quotient
2631 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2632 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2633 return scm_i_exact_rational_centered_quotient (x, y);
2634 else
2635 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2636 s_scm_centered_quotient);
2637 }
2638 else
2639 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG1,
2640 s_scm_centered_quotient);
2641}
2642#undef FUNC_NAME
2643
2644static SCM
2645scm_i_inexact_centered_quotient (double x, double y)
2646{
2647 if (SCM_LIKELY (y > 0))
2648 return scm_from_double (floor (x/y + 0.5));
2649 else if (SCM_LIKELY (y < 0))
2650 return scm_from_double (ceil (x/y - 0.5));
2651 else if (y == 0)
2652 scm_num_overflow (s_scm_centered_quotient); /* or return a NaN? */
2653 else
2654 return scm_nan ();
2655}
2656
2657/* Assumes that both x and y are bigints, though
2658 x might be able to fit into a fixnum. */
2659static SCM
2660scm_i_bigint_centered_quotient (SCM x, SCM y)
2661{
2662 SCM q, r, min_r;
2663
2664 /* Note that x might be small enough to fit into a
2665 fixnum, so we must not let it escape into the wild */
2666 q = scm_i_mkbig ();
2667 r = scm_i_mkbig ();
2668
2669 /* min_r will eventually become -abs(y)/2 */
2670 min_r = scm_i_mkbig ();
2671 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2672 SCM_I_BIG_MPZ (y), 1);
2673
2674 /* Arrange for rr to initially be non-positive,
2675 because that simplifies the test to see
2676 if it is within the needed bounds. */
2677 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2678 {
2679 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2680 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2681 scm_remember_upto_here_2 (x, y);
2682 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2683 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2684 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2685 SCM_I_BIG_MPZ (q), 1);
2686 }
2687 else
2688 {
2689 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2690 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2691 scm_remember_upto_here_2 (x, y);
2692 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2693 mpz_add_ui (SCM_I_BIG_MPZ (q),
2694 SCM_I_BIG_MPZ (q), 1);
2695 }
2696 scm_remember_upto_here_2 (r, min_r);
2697 return scm_i_normbig (q);
2698}
2699
2700static SCM
2701scm_i_exact_rational_centered_quotient (SCM x, SCM y)
2702{
2703 return scm_centered_quotient
2704 (scm_product (scm_numerator (x), scm_denominator (y)),
2705 scm_product (scm_numerator (y), scm_denominator (x)));
2706}
2707
2708static SCM scm_i_inexact_centered_remainder (double x, double y);
2709static SCM scm_i_bigint_centered_remainder (SCM x, SCM y);
2710static SCM scm_i_exact_rational_centered_remainder (SCM x, SCM y);
2711
2712SCM_PRIMITIVE_GENERIC (scm_centered_remainder, "centered-remainder", 2, 0, 0,
2713 (SCM x, SCM y),
2714 "Return the real number @var{r} such that\n"
2715 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}\n"
2716 "and @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2717 "for some integer @var{q}.\n"
2718 "@lisp\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 -10) @result{} -3\n"
2723 "(centered-remainder -123.2 -63.5) @result{} 3.8\n"
2724 "(centered-remainder 16/3 -10/7) @result{} -8/21\n"
2725 "@end lisp")
2726#define FUNC_NAME s_scm_centered_remainder
2727{
2728 if (SCM_LIKELY (SCM_I_INUMP (x)))
2729 {
2730 scm_t_inum xx = SCM_I_INUM (x);
2731 if (SCM_LIKELY (SCM_I_INUMP (y)))
2732 {
2733 scm_t_inum yy = SCM_I_INUM (y);
2734 if (SCM_UNLIKELY (yy == 0))
2735 scm_num_overflow (s_scm_centered_remainder);
2736 else
2737 {
2738 scm_t_inum rr = xx % yy;
2739 if (SCM_LIKELY (xx > 0))
2740 {
2741 if (SCM_LIKELY (yy > 0))
2742 {
2743 if (rr >= (yy + 1) / 2)
2744 rr -= yy;
2745 }
2746 else
2747 {
2748 if (rr >= (1 - yy) / 2)
2749 rr += yy;
2750 }
2751 }
2752 else
2753 {
2754 if (SCM_LIKELY (yy > 0))
2755 {
2756 if (rr < -yy / 2)
2757 rr += yy;
2758 }
2759 else
2760 {
2761 if (rr < yy / 2)
2762 rr -= yy;
2763 }
2764 }
2765 return SCM_I_MAKINUM (rr);
2766 }
2767 }
2768 else if (SCM_BIGP (y))
2769 {
2770 /* Pass a denormalized bignum version of x (even though it
2771 can fit in a fixnum) to scm_i_bigint_centered_remainder */
2772 return scm_i_bigint_centered_remainder (scm_i_long2big (xx), y);
2773 }
2774 else if (SCM_REALP (y))
2775 return scm_i_inexact_centered_remainder (xx, SCM_REAL_VALUE (y));
2776 else if (SCM_FRACTIONP (y))
2777 return scm_i_exact_rational_centered_remainder (x, y);
2778 else
2779 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2780 s_scm_centered_remainder);
2781 }
2782 else if (SCM_BIGP (x))
2783 {
2784 if (SCM_LIKELY (SCM_I_INUMP (y)))
2785 {
2786 scm_t_inum yy = SCM_I_INUM (y);
2787 if (SCM_UNLIKELY (yy == 0))
2788 scm_num_overflow (s_scm_centered_remainder);
2789 else
2790 {
2791 scm_t_inum rr;
2792 /* Arrange for rr to initially be non-positive,
2793 because that simplifies the test to see
2794 if it is within the needed bounds. */
2795 if (yy > 0)
2796 {
2797 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
2798 scm_remember_upto_here_1 (x);
2799 if (rr < -yy / 2)
2800 rr += yy;
2801 }
2802 else
2803 {
2804 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
2805 scm_remember_upto_here_1 (x);
2806 if (rr < yy / 2)
2807 rr -= yy;
2808 }
2809 return SCM_I_MAKINUM (rr);
2810 }
2811 }
2812 else if (SCM_BIGP (y))
2813 return scm_i_bigint_centered_remainder (x, y);
2814 else if (SCM_REALP (y))
2815 return scm_i_inexact_centered_remainder
2816 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2817 else if (SCM_FRACTIONP (y))
2818 return scm_i_exact_rational_centered_remainder (x, y);
2819 else
2820 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2821 s_scm_centered_remainder);
2822 }
2823 else if (SCM_REALP (x))
2824 {
2825 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2826 SCM_BIGP (y) || SCM_FRACTIONP (y))
2827 return scm_i_inexact_centered_remainder
2828 (SCM_REAL_VALUE (x), scm_to_double (y));
2829 else
2830 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2831 s_scm_centered_remainder);
2832 }
2833 else if (SCM_FRACTIONP (x))
2834 {
2835 if (SCM_REALP (y))
2836 return scm_i_inexact_centered_remainder
2837 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2838 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2839 return scm_i_exact_rational_centered_remainder (x, y);
2840 else
2841 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2842 s_scm_centered_remainder);
2843 }
2844 else
2845 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG1,
2846 s_scm_centered_remainder);
2847}
2848#undef FUNC_NAME
2849
2850static SCM
2851scm_i_inexact_centered_remainder (double x, double y)
2852{
2853 double q;
2854
2855 /* Although it would be more efficient to use fmod here, we can't
2856 because it would in some cases produce results inconsistent with
2857 scm_i_inexact_centered_quotient, such that x != r + q * y (not even
2858 close). In particular, when x-y/2 is very close to a multiple of
2859 y, then r might be either -abs(y/2) or abs(y/2)-epsilon, but those
2860 two cases must correspond to different choices of q. If quotient
2861 chooses one and remainder chooses the other, it would be bad. */
2862 if (SCM_LIKELY (y > 0))
2863 q = floor (x/y + 0.5);
2864 else if (SCM_LIKELY (y < 0))
2865 q = ceil (x/y - 0.5);
2866 else if (y == 0)
2867 scm_num_overflow (s_scm_centered_remainder); /* or return a NaN? */
2868 else
2869 return scm_nan ();
2870 return scm_from_double (x - q * y);
2871}
2872
2873/* Assumes that both x and y are bigints, though
2874 x might be able to fit into a fixnum. */
2875static SCM
2876scm_i_bigint_centered_remainder (SCM x, SCM y)
2877{
2878 SCM r, min_r;
2879
2880 /* Note that x might be small enough to fit into a
2881 fixnum, so we must not let it escape into the wild */
2882 r = scm_i_mkbig ();
2883
2884 /* min_r will eventually become -abs(y)/2 */
2885 min_r = scm_i_mkbig ();
2886 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2887 SCM_I_BIG_MPZ (y), 1);
2888
2889 /* Arrange for rr to initially be non-positive,
2890 because that simplifies the test to see
2891 if it is within the needed bounds. */
2892 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2893 {
2894 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
2895 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2896 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2897 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2898 mpz_add (SCM_I_BIG_MPZ (r),
2899 SCM_I_BIG_MPZ (r),
2900 SCM_I_BIG_MPZ (y));
2901 }
2902 else
2903 {
2904 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
2905 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2906 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2907 mpz_sub (SCM_I_BIG_MPZ (r),
2908 SCM_I_BIG_MPZ (r),
2909 SCM_I_BIG_MPZ (y));
2910 }
2911 scm_remember_upto_here_2 (x, y);
2912 return scm_i_normbig (r);
2913}
2914
2915static SCM
2916scm_i_exact_rational_centered_remainder (SCM x, SCM y)
2917{
2918 SCM xd = scm_denominator (x);
2919 SCM yd = scm_denominator (y);
2920 SCM r1 = scm_centered_remainder (scm_product (scm_numerator (x), yd),
2921 scm_product (scm_numerator (y), xd));
2922 return scm_divide (r1, scm_product (xd, yd));
2923}
2924
2925
2926static void scm_i_inexact_centered_divide (double x, double y,
2927 SCM *qp, SCM *rp);
2928static void scm_i_bigint_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp);
2929static void scm_i_exact_rational_centered_divide (SCM x, SCM y,
2930 SCM *qp, SCM *rp);
2931
2932SCM_PRIMITIVE_GENERIC (scm_i_centered_divide, "centered/", 2, 0, 0,
2933 (SCM x, SCM y),
2934 "Return the integer @var{q} and the real number @var{r}\n"
2935 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2936 "and @math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2937 "@lisp\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 -10) @result{} 12 and -3\n"
2942 "(centered/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
2943 "(centered/ 16/3 -10/7) @result{} -4 and -8/21\n"
2944 "@end lisp")
2945#define FUNC_NAME s_scm_i_centered_divide
2946{
2947 SCM q, r;
2948
2949 scm_centered_divide(x, y, &q, &r);
2950 return scm_values (scm_list_2 (q, r));
2951}
2952#undef FUNC_NAME
2953
2954#define s_scm_centered_divide s_scm_i_centered_divide
2955#define g_scm_centered_divide g_scm_i_centered_divide
2956
2957void
2958scm_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2959{
2960 if (SCM_LIKELY (SCM_I_INUMP (x)))
2961 {
2962 scm_t_inum xx = SCM_I_INUM (x);
2963 if (SCM_LIKELY (SCM_I_INUMP (y)))
2964 {
2965 scm_t_inum yy = SCM_I_INUM (y);
2966 if (SCM_UNLIKELY (yy == 0))
2967 scm_num_overflow (s_scm_centered_divide);
2968 else
2969 {
2970 scm_t_inum qq = xx / yy;
2971 scm_t_inum rr = xx % yy;
2972 if (SCM_LIKELY (xx > 0))
2973 {
2974 if (SCM_LIKELY (yy > 0))
2975 {
2976 if (rr >= (yy + 1) / 2)
2977 { qq++; rr -= yy; }
2978 }
2979 else
2980 {
2981 if (rr >= (1 - yy) / 2)
2982 { qq--; rr += yy; }
2983 }
2984 }
2985 else
2986 {
2987 if (SCM_LIKELY (yy > 0))
2988 {
2989 if (rr < -yy / 2)
2990 { qq--; rr += yy; }
2991 }
2992 else
2993 {
2994 if (rr < yy / 2)
2995 { qq++; rr -= yy; }
2996 }
2997 }
2998 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2999 *qp = SCM_I_MAKINUM (qq);
3000 else
3001 *qp = scm_i_inum2big (qq);
3002 *rp = SCM_I_MAKINUM (rr);
3003 }
3004 return;
3005 }
3006 else if (SCM_BIGP (y))
3007 {
3008 /* Pass a denormalized bignum version of x (even though it
3009 can fit in a fixnum) to scm_i_bigint_centered_divide */
3010 return scm_i_bigint_centered_divide (scm_i_long2big (xx), y, qp, rp);
3011 }
3012 else if (SCM_REALP (y))
3013 return scm_i_inexact_centered_divide (xx, SCM_REAL_VALUE (y), qp, rp);
3014 else if (SCM_FRACTIONP (y))
3015 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3016 else
3017 return two_valued_wta_dispatch_2
3018 (g_scm_centered_divide, x, y, SCM_ARG2,
3019 s_scm_centered_divide, qp, rp);
3020 }
3021 else if (SCM_BIGP (x))
3022 {
3023 if (SCM_LIKELY (SCM_I_INUMP (y)))
3024 {
3025 scm_t_inum yy = SCM_I_INUM (y);
3026 if (SCM_UNLIKELY (yy == 0))
3027 scm_num_overflow (s_scm_centered_divide);
3028 else
3029 {
3030 SCM q = scm_i_mkbig ();
3031 scm_t_inum rr;
3032 /* Arrange for rr to initially be non-positive,
3033 because that simplifies the test to see
3034 if it is within the needed bounds. */
3035 if (yy > 0)
3036 {
3037 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3038 SCM_I_BIG_MPZ (x), yy);
3039 scm_remember_upto_here_1 (x);
3040 if (rr < -yy / 2)
3041 {
3042 mpz_sub_ui (SCM_I_BIG_MPZ (q),
3043 SCM_I_BIG_MPZ (q), 1);
3044 rr += yy;
3045 }
3046 }
3047 else
3048 {
3049 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3050 SCM_I_BIG_MPZ (x), -yy);
3051 scm_remember_upto_here_1 (x);
3052 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
3053 if (rr < yy / 2)
3054 {
3055 mpz_add_ui (SCM_I_BIG_MPZ (q),
3056 SCM_I_BIG_MPZ (q), 1);
3057 rr -= yy;
3058 }
3059 }
3060 *qp = scm_i_normbig (q);
3061 *rp = SCM_I_MAKINUM (rr);
3062 }
3063 return;
3064 }
3065 else if (SCM_BIGP (y))
3066 return scm_i_bigint_centered_divide (x, y, qp, rp);
3067 else if (SCM_REALP (y))
3068 return scm_i_inexact_centered_divide
3069 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
3070 else if (SCM_FRACTIONP (y))
3071 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3072 else
3073 return two_valued_wta_dispatch_2
3074 (g_scm_centered_divide, x, y, SCM_ARG2,
3075 s_scm_centered_divide, qp, rp);
3076 }
3077 else if (SCM_REALP (x))
3078 {
3079 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3080 SCM_BIGP (y) || SCM_FRACTIONP (y))
3081 return scm_i_inexact_centered_divide
3082 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
3083 else
3084 return two_valued_wta_dispatch_2
3085 (g_scm_centered_divide, x, y, SCM_ARG2,
3086 s_scm_centered_divide, qp, rp);
3087 }
3088 else if (SCM_FRACTIONP (x))
3089 {
3090 if (SCM_REALP (y))
3091 return scm_i_inexact_centered_divide
3092 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
3093 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
3094 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3095 else
3096 return two_valued_wta_dispatch_2
3097 (g_scm_centered_divide, x, y, SCM_ARG2,
3098 s_scm_centered_divide, qp, rp);
3099 }
3100 else
3101 return two_valued_wta_dispatch_2 (g_scm_centered_divide, x, y, SCM_ARG1,
3102 s_scm_centered_divide, qp, rp);
3103}
3104
3105static void
3106scm_i_inexact_centered_divide (double x, double y, SCM *qp, SCM *rp)
3107{
3108 double q, r;
3109
3110 if (SCM_LIKELY (y > 0))
3111 q = floor (x/y + 0.5);
3112 else if (SCM_LIKELY (y < 0))
3113 q = ceil (x/y - 0.5);
3114 else if (y == 0)
3115 scm_num_overflow (s_scm_centered_divide); /* or return a NaN? */
3116 else
3117 q = guile_NaN;
3118 r = x - q * y;
3119 *qp = scm_from_double (q);
3120 *rp = scm_from_double (r);
3121}
3122
3123/* Assumes that both x and y are bigints, though
3124 x might be able to fit into a fixnum. */
3125static void
3126scm_i_bigint_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
3127{
3128 SCM q, r, min_r;
3129
3130 /* Note that x might be small enough to fit into a
3131 fixnum, so we must not let it escape into the wild */
3132 q = scm_i_mkbig ();
3133 r = scm_i_mkbig ();
3134
3135 /* min_r will eventually become -abs(y/2) */
3136 min_r = scm_i_mkbig ();
3137 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
3138 SCM_I_BIG_MPZ (y), 1);
3139
3140 /* Arrange for rr to initially be non-positive,
3141 because that simplifies the test to see
3142 if it is within the needed bounds. */
3143 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
3144 {
3145 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3146 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3147 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
3148 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
3149 {
3150 mpz_sub_ui (SCM_I_BIG_MPZ (q),
3151 SCM_I_BIG_MPZ (q), 1);
3152 mpz_add (SCM_I_BIG_MPZ (r),
3153 SCM_I_BIG_MPZ (r),
3154 SCM_I_BIG_MPZ (y));
3155 }
3156 }
3157 else
3158 {
3159 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3160 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3161 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
3162 {
3163 mpz_add_ui (SCM_I_BIG_MPZ (q),
3164 SCM_I_BIG_MPZ (q), 1);
3165 mpz_sub (SCM_I_BIG_MPZ (r),
3166 SCM_I_BIG_MPZ (r),
3167 SCM_I_BIG_MPZ (y));
3168 }
3169 }
3170 scm_remember_upto_here_2 (x, y);
3171 *qp = scm_i_normbig (q);
3172 *rp = scm_i_normbig (r);
3173}
3174
3175static void
3176scm_i_exact_rational_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
3177{
3178 SCM r1;
3179 SCM xd = scm_denominator (x);
3180 SCM yd = scm_denominator (y);
3181
3182 scm_centered_divide (scm_product (scm_numerator (x), yd),
3183 scm_product (scm_numerator (y), xd),
3184 qp, &r1);
3185 *rp = scm_divide (r1, scm_product (xd, yd));
3186}
3187
3188static SCM scm_i_inexact_round_quotient (double x, double y);
3189static SCM scm_i_bigint_round_quotient (SCM x, SCM y);
3190static SCM scm_i_exact_rational_round_quotient (SCM x, SCM y);
3191
3192SCM_PRIMITIVE_GENERIC (scm_round_quotient, "round-quotient", 2, 0, 0,
ff62c168 3193 (SCM x, SCM y),
8f9da340
MW
3194 "Return @math{@var{x} / @var{y}} to the nearest integer,\n"
3195 "with ties going to the nearest even integer.\n"
ff62c168 3196 "@lisp\n"
8f9da340
MW
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 -123 -10) @result{} 12\n"
3201 "(round-quotient 125 10) @result{} 12\n"
3202 "(round-quotient 127 10) @result{} 13\n"
3203 "(round-quotient 135 10) @result{} 14\n"
3204 "(round-quotient -123.2 -63.5) @result{} 2.0\n"
3205 "(round-quotient 16/3 -10/7) @result{} -4\n"
ff62c168 3206 "@end lisp")
8f9da340 3207#define FUNC_NAME s_scm_round_quotient
ff62c168
MW
3208{
3209 if (SCM_LIKELY (SCM_I_INUMP (x)))
3210 {
4a46bc2a 3211 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3212 if (SCM_LIKELY (SCM_I_INUMP (y)))
3213 {
3214 scm_t_inum yy = SCM_I_INUM (y);
3215 if (SCM_UNLIKELY (yy == 0))
8f9da340 3216 scm_num_overflow (s_scm_round_quotient);
ff62c168
MW
3217 else
3218 {
ff62c168 3219 scm_t_inum qq = xx / yy;
4a46bc2a 3220 scm_t_inum rr = xx % yy;
8f9da340
MW
3221 scm_t_inum ay = yy;
3222 scm_t_inum r2 = 2 * rr;
3223
3224 if (SCM_LIKELY (yy < 0))
ff62c168 3225 {
8f9da340
MW
3226 ay = -ay;
3227 r2 = -r2;
3228 }
3229
3230 if (qq & 1L)
3231 {
3232 if (r2 >= ay)
3233 qq++;
3234 else if (r2 <= -ay)
3235 qq--;
ff62c168
MW
3236 }
3237 else
3238 {
8f9da340
MW
3239 if (r2 > ay)
3240 qq++;
3241 else if (r2 < -ay)
3242 qq--;
ff62c168 3243 }
4a46bc2a
MW
3244 if (SCM_LIKELY (SCM_FIXABLE (qq)))
3245 return SCM_I_MAKINUM (qq);
3246 else
3247 return scm_i_inum2big (qq);
ff62c168
MW
3248 }
3249 }
3250 else if (SCM_BIGP (y))
3251 {
3252 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3253 can fit in a fixnum) to scm_i_bigint_round_quotient */
3254 return scm_i_bigint_round_quotient (scm_i_long2big (xx), y);
ff62c168
MW
3255 }
3256 else if (SCM_REALP (y))
8f9da340 3257 return scm_i_inexact_round_quotient (xx, SCM_REAL_VALUE (y));
ff62c168 3258 else if (SCM_FRACTIONP (y))
8f9da340 3259 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3260 else
8f9da340
MW
3261 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3262 s_scm_round_quotient);
ff62c168
MW
3263 }
3264 else if (SCM_BIGP (x))
3265 {
3266 if (SCM_LIKELY (SCM_I_INUMP (y)))
3267 {
3268 scm_t_inum yy = SCM_I_INUM (y);
3269 if (SCM_UNLIKELY (yy == 0))
8f9da340 3270 scm_num_overflow (s_scm_round_quotient);
4a46bc2a
MW
3271 else if (SCM_UNLIKELY (yy == 1))
3272 return x;
ff62c168
MW
3273 else
3274 {
3275 SCM q = scm_i_mkbig ();
3276 scm_t_inum rr;
8f9da340
MW
3277 int needs_adjustment;
3278
ff62c168
MW
3279 if (yy > 0)
3280 {
8f9da340
MW
3281 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3282 SCM_I_BIG_MPZ (x), yy);
3283 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3284 needs_adjustment = (2*rr >= yy);
3285 else
3286 needs_adjustment = (2*rr > yy);
ff62c168
MW
3287 }
3288 else
3289 {
3290 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3291 SCM_I_BIG_MPZ (x), -yy);
ff62c168 3292 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
8f9da340
MW
3293 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3294 needs_adjustment = (2*rr <= yy);
3295 else
3296 needs_adjustment = (2*rr < yy);
ff62c168 3297 }
8f9da340
MW
3298 scm_remember_upto_here_1 (x);
3299 if (needs_adjustment)
3300 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
ff62c168
MW
3301 return scm_i_normbig (q);
3302 }
3303 }
3304 else if (SCM_BIGP (y))
8f9da340 3305 return scm_i_bigint_round_quotient (x, y);
ff62c168 3306 else if (SCM_REALP (y))
8f9da340 3307 return scm_i_inexact_round_quotient
ff62c168
MW
3308 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
3309 else if (SCM_FRACTIONP (y))
8f9da340 3310 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3311 else
8f9da340
MW
3312 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3313 s_scm_round_quotient);
ff62c168
MW
3314 }
3315 else if (SCM_REALP (x))
3316 {
3317 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3318 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3319 return scm_i_inexact_round_quotient
ff62c168
MW
3320 (SCM_REAL_VALUE (x), scm_to_double (y));
3321 else
8f9da340
MW
3322 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3323 s_scm_round_quotient);
ff62c168
MW
3324 }
3325 else if (SCM_FRACTIONP (x))
3326 {
3327 if (SCM_REALP (y))
8f9da340 3328 return scm_i_inexact_round_quotient
ff62c168 3329 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
03ddd15b 3330 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3331 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3332 else
8f9da340
MW
3333 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3334 s_scm_round_quotient);
ff62c168
MW
3335 }
3336 else
8f9da340
MW
3337 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG1,
3338 s_scm_round_quotient);
ff62c168
MW
3339}
3340#undef FUNC_NAME
3341
3342static SCM
8f9da340 3343scm_i_inexact_round_quotient (double x, double y)
ff62c168 3344{
8f9da340
MW
3345 if (SCM_UNLIKELY (y == 0))
3346 scm_num_overflow (s_scm_round_quotient); /* or return a NaN? */
ff62c168 3347 else
8f9da340 3348 return scm_from_double (scm_c_round (x / y));
ff62c168
MW
3349}
3350
3351/* Assumes that both x and y are bigints, though
3352 x might be able to fit into a fixnum. */
3353static SCM
8f9da340 3354scm_i_bigint_round_quotient (SCM x, SCM y)
ff62c168 3355{
8f9da340
MW
3356 SCM q, r, r2;
3357 int cmp, needs_adjustment;
ff62c168
MW
3358
3359 /* Note that x might be small enough to fit into a
3360 fixnum, so we must not let it escape into the wild */
3361 q = scm_i_mkbig ();
3362 r = scm_i_mkbig ();
8f9da340 3363 r2 = scm_i_mkbig ();
ff62c168 3364
8f9da340
MW
3365 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3366 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3367 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
3368 scm_remember_upto_here_2 (x, r);
ff62c168 3369
8f9da340
MW
3370 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3371 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3372 needs_adjustment = (cmp >= 0);
ff62c168 3373 else
8f9da340
MW
3374 needs_adjustment = (cmp > 0);
3375 scm_remember_upto_here_2 (r2, y);
3376
3377 if (needs_adjustment)
3378 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3379
ff62c168
MW
3380 return scm_i_normbig (q);
3381}
3382
ff62c168 3383static SCM
8f9da340 3384scm_i_exact_rational_round_quotient (SCM x, SCM y)
ff62c168 3385{
8f9da340 3386 return scm_round_quotient
03ddd15b
MW
3387 (scm_product (scm_numerator (x), scm_denominator (y)),
3388 scm_product (scm_numerator (y), scm_denominator (x)));
ff62c168
MW
3389}
3390
8f9da340
MW
3391static SCM scm_i_inexact_round_remainder (double x, double y);
3392static SCM scm_i_bigint_round_remainder (SCM x, SCM y);
3393static SCM scm_i_exact_rational_round_remainder (SCM x, SCM y);
ff62c168 3394
8f9da340 3395SCM_PRIMITIVE_GENERIC (scm_round_remainder, "round-remainder", 2, 0, 0,
ff62c168
MW
3396 (SCM x, SCM y),
3397 "Return the real number @var{r} such that\n"
8f9da340
MW
3398 "@math{@var{x} = @var{q}*@var{y} + @var{r}}, where\n"
3399 "@var{q} is @math{@var{x} / @var{y}} rounded to the\n"
3400 "nearest integer, with ties going to the nearest\n"
3401 "even integer.\n"
ff62c168 3402 "@lisp\n"
8f9da340
MW
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 -123 -10) @result{} -3\n"
3407 "(round-remainder 125 10) @result{} 5\n"
3408 "(round-remainder 127 10) @result{} -3\n"
3409 "(round-remainder 135 10) @result{} -5\n"
3410 "(round-remainder -123.2 -63.5) @result{} 3.8\n"
3411 "(round-remainder 16/3 -10/7) @result{} -8/21\n"
ff62c168 3412 "@end lisp")
8f9da340 3413#define FUNC_NAME s_scm_round_remainder
ff62c168
MW
3414{
3415 if (SCM_LIKELY (SCM_I_INUMP (x)))
3416 {
4a46bc2a 3417 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3418 if (SCM_LIKELY (SCM_I_INUMP (y)))
3419 {
3420 scm_t_inum yy = SCM_I_INUM (y);
3421 if (SCM_UNLIKELY (yy == 0))
8f9da340 3422 scm_num_overflow (s_scm_round_remainder);
ff62c168
MW
3423 else
3424 {
8f9da340 3425 scm_t_inum qq = xx / yy;
ff62c168 3426 scm_t_inum rr = xx % yy;
8f9da340
MW
3427 scm_t_inum ay = yy;
3428 scm_t_inum r2 = 2 * rr;
3429
3430 if (SCM_LIKELY (yy < 0))
ff62c168 3431 {
8f9da340
MW
3432 ay = -ay;
3433 r2 = -r2;
3434 }
3435
3436 if (qq & 1L)
3437 {
3438 if (r2 >= ay)
3439 rr -= yy;
3440 else if (r2 <= -ay)
3441 rr += yy;
ff62c168
MW
3442 }
3443 else
3444 {
8f9da340
MW
3445 if (r2 > ay)
3446 rr -= yy;
3447 else if (r2 < -ay)
3448 rr += yy;
ff62c168
MW
3449 }
3450 return SCM_I_MAKINUM (rr);
3451 }
3452 }
3453 else if (SCM_BIGP (y))
3454 {
3455 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3456 can fit in a fixnum) to scm_i_bigint_round_remainder */
3457 return scm_i_bigint_round_remainder
3458 (scm_i_long2big (xx), y);
ff62c168
MW
3459 }
3460 else if (SCM_REALP (y))
8f9da340 3461 return scm_i_inexact_round_remainder (xx, SCM_REAL_VALUE (y));
ff62c168 3462 else if (SCM_FRACTIONP (y))
8f9da340 3463 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3464 else
8f9da340
MW
3465 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3466 s_scm_round_remainder);
ff62c168
MW
3467 }
3468 else if (SCM_BIGP (x))
3469 {
3470 if (SCM_LIKELY (SCM_I_INUMP (y)))
3471 {
3472 scm_t_inum yy = SCM_I_INUM (y);
3473 if (SCM_UNLIKELY (yy == 0))
8f9da340 3474 scm_num_overflow (s_scm_round_remainder);
ff62c168
MW
3475 else
3476 {
8f9da340 3477 SCM q = scm_i_mkbig ();
ff62c168 3478 scm_t_inum rr;
8f9da340
MW
3479 int needs_adjustment;
3480
ff62c168
MW
3481 if (yy > 0)
3482 {
8f9da340
MW
3483 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3484 SCM_I_BIG_MPZ (x), yy);
3485 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3486 needs_adjustment = (2*rr >= yy);
3487 else
3488 needs_adjustment = (2*rr > yy);
ff62c168
MW
3489 }
3490 else
3491 {
8f9da340
MW
3492 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3493 SCM_I_BIG_MPZ (x), -yy);
3494 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3495 needs_adjustment = (2*rr <= yy);
3496 else
3497 needs_adjustment = (2*rr < yy);
ff62c168 3498 }
8f9da340
MW
3499 scm_remember_upto_here_2 (x, q);
3500 if (needs_adjustment)
3501 rr -= yy;
ff62c168
MW
3502 return SCM_I_MAKINUM (rr);
3503 }
3504 }
3505 else if (SCM_BIGP (y))
8f9da340 3506 return scm_i_bigint_round_remainder (x, y);
ff62c168 3507 else if (SCM_REALP (y))
8f9da340 3508 return scm_i_inexact_round_remainder
ff62c168
MW
3509 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
3510 else if (SCM_FRACTIONP (y))
8f9da340 3511 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3512 else
8f9da340
MW
3513 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3514 s_scm_round_remainder);
ff62c168
MW
3515 }
3516 else if (SCM_REALP (x))
3517 {
3518 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3519 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3520 return scm_i_inexact_round_remainder
ff62c168
MW
3521 (SCM_REAL_VALUE (x), scm_to_double (y));
3522 else
8f9da340
MW
3523 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3524 s_scm_round_remainder);
ff62c168
MW
3525 }
3526 else if (SCM_FRACTIONP (x))
3527 {
3528 if (SCM_REALP (y))
8f9da340 3529 return scm_i_inexact_round_remainder
ff62c168 3530 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
03ddd15b 3531 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3532 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3533 else
8f9da340
MW
3534 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3535 s_scm_round_remainder);
ff62c168
MW
3536 }
3537 else
8f9da340
MW
3538 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG1,
3539 s_scm_round_remainder);
ff62c168
MW
3540}
3541#undef FUNC_NAME
3542
3543static SCM
8f9da340 3544scm_i_inexact_round_remainder (double x, double y)
ff62c168 3545{
ff62c168
MW
3546 /* Although it would be more efficient to use fmod here, we can't
3547 because it would in some cases produce results inconsistent with
8f9da340 3548 scm_i_inexact_round_quotient, such that x != r + q * y (not even
ff62c168 3549 close). In particular, when x-y/2 is very close to a multiple of
8f9da340
MW
3550 y, then r might be either -abs(y/2) or abs(y/2), but those two
3551 cases must correspond to different choices of q. If quotient
ff62c168 3552 chooses one and remainder chooses the other, it would be bad. */
8f9da340
MW
3553
3554 if (SCM_UNLIKELY (y == 0))
3555 scm_num_overflow (s_scm_round_remainder); /* or return a NaN? */
ff62c168 3556 else
8f9da340
MW
3557 {
3558 double q = scm_c_round (x / y);
3559 return scm_from_double (x - q * y);
3560 }
ff62c168
MW
3561}
3562
3563/* Assumes that both x and y are bigints, though
3564 x might be able to fit into a fixnum. */
3565static SCM
8f9da340 3566scm_i_bigint_round_remainder (SCM x, SCM y)
ff62c168 3567{
8f9da340
MW
3568 SCM q, r, r2;
3569 int cmp, needs_adjustment;
ff62c168
MW
3570
3571 /* Note that x might be small enough to fit into a
3572 fixnum, so we must not let it escape into the wild */
8f9da340 3573 q = scm_i_mkbig ();
ff62c168 3574 r = scm_i_mkbig ();
8f9da340 3575 r2 = scm_i_mkbig ();
ff62c168 3576
8f9da340
MW
3577 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3578 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3579 scm_remember_upto_here_1 (x);
3580 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
ff62c168 3581
8f9da340
MW
3582 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3583 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3584 needs_adjustment = (cmp >= 0);
ff62c168 3585 else
8f9da340
MW
3586 needs_adjustment = (cmp > 0);
3587 scm_remember_upto_here_2 (q, r2);
3588
3589 if (needs_adjustment)
3590 mpz_sub (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y));
3591
3592 scm_remember_upto_here_1 (y);
ff62c168
MW
3593 return scm_i_normbig (r);
3594}
3595
ff62c168 3596static SCM
8f9da340 3597scm_i_exact_rational_round_remainder (SCM x, SCM y)
ff62c168 3598{
03ddd15b
MW
3599 SCM xd = scm_denominator (x);
3600 SCM yd = scm_denominator (y);
8f9da340
MW
3601 SCM r1 = scm_round_remainder (scm_product (scm_numerator (x), yd),
3602 scm_product (scm_numerator (y), xd));
03ddd15b 3603 return scm_divide (r1, scm_product (xd, yd));
ff62c168
MW
3604}
3605
3606
8f9da340
MW
3607static void scm_i_inexact_round_divide (double x, double y, SCM *qp, SCM *rp);
3608static void scm_i_bigint_round_divide (SCM x, SCM y, SCM *qp, SCM *rp);
3609static void scm_i_exact_rational_round_divide (SCM x, SCM y, SCM *qp, SCM *rp);
ff62c168 3610
8f9da340 3611SCM_PRIMITIVE_GENERIC (scm_i_round_divide, "round/", 2, 0, 0,
ff62c168
MW
3612 (SCM x, SCM y),
3613 "Return the integer @var{q} and the real number @var{r}\n"
3614 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
8f9da340
MW
3615 "and @var{q} is @math{@var{x} / @var{y}} rounded to the\n"
3616 "nearest integer, with ties going to the nearest even integer.\n"
ff62c168 3617 "@lisp\n"
8f9da340
MW
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/ -123 -10) @result{} 12 and -3\n"
3622 "(round/ 125 10) @result{} 12 and 5\n"
3623 "(round/ 127 10) @result{} 13 and -3\n"
3624 "(round/ 135 10) @result{} 14 and -5\n"
3625 "(round/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
3626 "(round/ 16/3 -10/7) @result{} -4 and -8/21\n"
ff62c168 3627 "@end lisp")
8f9da340 3628#define FUNC_NAME s_scm_i_round_divide
5fbf680b
MW
3629{
3630 SCM q, r;
3631
8f9da340 3632 scm_round_divide(x, y, &q, &r);
5fbf680b
MW
3633 return scm_values (scm_list_2 (q, r));
3634}
3635#undef FUNC_NAME
3636
8f9da340
MW
3637#define s_scm_round_divide s_scm_i_round_divide
3638#define g_scm_round_divide g_scm_i_round_divide
5fbf680b
MW
3639
3640void
8f9da340 3641scm_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168
MW
3642{
3643 if (SCM_LIKELY (SCM_I_INUMP (x)))
3644 {
4a46bc2a 3645 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3646 if (SCM_LIKELY (SCM_I_INUMP (y)))
3647 {
3648 scm_t_inum yy = SCM_I_INUM (y);
3649 if (SCM_UNLIKELY (yy == 0))
8f9da340 3650 scm_num_overflow (s_scm_round_divide);
ff62c168
MW
3651 else
3652 {
ff62c168 3653 scm_t_inum qq = xx / yy;
4a46bc2a 3654 scm_t_inum rr = xx % yy;
8f9da340
MW
3655 scm_t_inum ay = yy;
3656 scm_t_inum r2 = 2 * rr;
3657
3658 if (SCM_LIKELY (yy < 0))
ff62c168 3659 {
8f9da340
MW
3660 ay = -ay;
3661 r2 = -r2;
3662 }
3663
3664 if (qq & 1L)
3665 {
3666 if (r2 >= ay)
3667 { qq++; rr -= yy; }
3668 else if (r2 <= -ay)
3669 { qq--; rr += yy; }
ff62c168
MW
3670 }
3671 else
3672 {
8f9da340
MW
3673 if (r2 > ay)
3674 { qq++; rr -= yy; }
3675 else if (r2 < -ay)
3676 { qq--; rr += yy; }
ff62c168 3677 }
4a46bc2a 3678 if (SCM_LIKELY (SCM_FIXABLE (qq)))
5fbf680b 3679 *qp = SCM_I_MAKINUM (qq);
4a46bc2a 3680 else
5fbf680b
MW
3681 *qp = scm_i_inum2big (qq);
3682 *rp = SCM_I_MAKINUM (rr);
ff62c168 3683 }
5fbf680b 3684 return;
ff62c168
MW
3685 }
3686 else if (SCM_BIGP (y))
3687 {
3688 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3689 can fit in a fixnum) to scm_i_bigint_round_divide */
3690 return scm_i_bigint_round_divide
3691 (scm_i_long2big (SCM_I_INUM (x)), y, qp, rp);
ff62c168
MW
3692 }
3693 else if (SCM_REALP (y))
8f9da340 3694 return scm_i_inexact_round_divide (xx, SCM_REAL_VALUE (y), qp, rp);
ff62c168 3695 else if (SCM_FRACTIONP (y))
8f9da340 3696 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3697 else
8f9da340
MW
3698 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3699 s_scm_round_divide, qp, rp);
ff62c168
MW
3700 }
3701 else if (SCM_BIGP (x))
3702 {
3703 if (SCM_LIKELY (SCM_I_INUMP (y)))
3704 {
3705 scm_t_inum yy = SCM_I_INUM (y);
3706 if (SCM_UNLIKELY (yy == 0))
8f9da340 3707 scm_num_overflow (s_scm_round_divide);
ff62c168
MW
3708 else
3709 {
3710 SCM q = scm_i_mkbig ();
3711 scm_t_inum rr;
8f9da340
MW
3712 int needs_adjustment;
3713
ff62c168
MW
3714 if (yy > 0)
3715 {
8f9da340
MW
3716 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3717 SCM_I_BIG_MPZ (x), yy);
3718 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3719 needs_adjustment = (2*rr >= yy);
3720 else
3721 needs_adjustment = (2*rr > yy);
ff62c168
MW
3722 }
3723 else
3724 {
3725 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3726 SCM_I_BIG_MPZ (x), -yy);
ff62c168 3727 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
8f9da340
MW
3728 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3729 needs_adjustment = (2*rr <= yy);
3730 else
3731 needs_adjustment = (2*rr < yy);
3732 }
3733 scm_remember_upto_here_1 (x);
3734 if (needs_adjustment)
3735 {
3736 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3737 rr -= yy;
ff62c168 3738 }
5fbf680b
MW
3739 *qp = scm_i_normbig (q);
3740 *rp = SCM_I_MAKINUM (rr);
ff62c168 3741 }
5fbf680b 3742 return;
ff62c168
MW
3743 }
3744 else if (SCM_BIGP (y))
8f9da340 3745 return scm_i_bigint_round_divide (x, y, qp, rp);
ff62c168 3746 else if (SCM_REALP (y))
8f9da340 3747 return scm_i_inexact_round_divide
5fbf680b 3748 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
ff62c168 3749 else if (SCM_FRACTIONP (y))
8f9da340 3750 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3751 else
8f9da340
MW
3752 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3753 s_scm_round_divide, qp, rp);
ff62c168
MW
3754 }
3755 else if (SCM_REALP (x))
3756 {
3757 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3758 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3759 return scm_i_inexact_round_divide
5fbf680b 3760 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
03ddd15b 3761 else
8f9da340
MW
3762 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3763 s_scm_round_divide, qp, rp);
ff62c168
MW
3764 }
3765 else if (SCM_FRACTIONP (x))
3766 {
3767 if (SCM_REALP (y))
8f9da340 3768 return scm_i_inexact_round_divide
5fbf680b 3769 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
03ddd15b 3770 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3771 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3772 else
8f9da340
MW
3773 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3774 s_scm_round_divide, qp, rp);
ff62c168
MW
3775 }
3776 else
8f9da340
MW
3777 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG1,
3778 s_scm_round_divide, qp, rp);
ff62c168 3779}
ff62c168 3780
5fbf680b 3781static void
8f9da340 3782scm_i_inexact_round_divide (double x, double y, SCM *qp, SCM *rp)
ff62c168 3783{
8f9da340
MW
3784 if (SCM_UNLIKELY (y == 0))
3785 scm_num_overflow (s_scm_round_divide); /* or return a NaN? */
ff62c168 3786 else
8f9da340
MW
3787 {
3788 double q = scm_c_round (x / y);
3789 double r = x - q * y;
3790 *qp = scm_from_double (q);
3791 *rp = scm_from_double (r);
3792 }
ff62c168
MW
3793}
3794
3795/* Assumes that both x and y are bigints, though
3796 x might be able to fit into a fixnum. */
5fbf680b 3797static void
8f9da340 3798scm_i_bigint_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 3799{
8f9da340
MW
3800 SCM q, r, r2;
3801 int cmp, needs_adjustment;
ff62c168
MW
3802
3803 /* Note that x might be small enough to fit into a
3804 fixnum, so we must not let it escape into the wild */
3805 q = scm_i_mkbig ();
3806 r = scm_i_mkbig ();
8f9da340 3807 r2 = scm_i_mkbig ();
ff62c168 3808
8f9da340
MW
3809 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3810 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3811 scm_remember_upto_here_1 (x);
3812 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
ff62c168 3813
8f9da340
MW
3814 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3815 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3816 needs_adjustment = (cmp >= 0);
ff62c168 3817 else
8f9da340
MW
3818 needs_adjustment = (cmp > 0);
3819
3820 if (needs_adjustment)
ff62c168 3821 {
8f9da340
MW
3822 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3823 mpz_sub (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y));
ff62c168 3824 }
8f9da340
MW
3825
3826 scm_remember_upto_here_2 (r2, y);
5fbf680b
MW
3827 *qp = scm_i_normbig (q);
3828 *rp = scm_i_normbig (r);
ff62c168
MW
3829}
3830
5fbf680b 3831static void
8f9da340 3832scm_i_exact_rational_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 3833{
03ddd15b
MW
3834 SCM r1;
3835 SCM xd = scm_denominator (x);
3836 SCM yd = scm_denominator (y);
3837
8f9da340
MW
3838 scm_round_divide (scm_product (scm_numerator (x), yd),
3839 scm_product (scm_numerator (y), xd),
3840 qp, &r1);
03ddd15b 3841 *rp = scm_divide (r1, scm_product (xd, yd));
ff62c168
MW
3842}
3843
3844
78d3deb1
AW
3845SCM_PRIMITIVE_GENERIC (scm_i_gcd, "gcd", 0, 2, 1,
3846 (SCM x, SCM y, SCM rest),
3847 "Return the greatest common divisor of all parameter values.\n"
3848 "If called without arguments, 0 is returned.")
3849#define FUNC_NAME s_scm_i_gcd
3850{
3851 while (!scm_is_null (rest))
3852 { x = scm_gcd (x, y);
3853 y = scm_car (rest);
3854 rest = scm_cdr (rest);
3855 }
3856 return scm_gcd (x, y);
3857}
3858#undef FUNC_NAME
3859
3860#define s_gcd s_scm_i_gcd
3861#define g_gcd g_scm_i_gcd
3862
0f2d19dd 3863SCM
6e8d25a6 3864scm_gcd (SCM x, SCM y)
0f2d19dd 3865{
ca46fb90 3866 if (SCM_UNBNDP (y))
1dd79792 3867 return SCM_UNBNDP (x) ? SCM_INUM0 : scm_abs (x);
ca46fb90 3868
e11e83f3 3869 if (SCM_I_INUMP (x))
ca46fb90 3870 {
e11e83f3 3871 if (SCM_I_INUMP (y))
ca46fb90 3872 {
e25f3727
AW
3873 scm_t_inum xx = SCM_I_INUM (x);
3874 scm_t_inum yy = SCM_I_INUM (y);
3875 scm_t_inum u = xx < 0 ? -xx : xx;
3876 scm_t_inum v = yy < 0 ? -yy : yy;
3877 scm_t_inum result;
0aacf84e
MD
3878 if (xx == 0)
3879 result = v;
3880 else if (yy == 0)
3881 result = u;
3882 else
3883 {
e25f3727
AW
3884 scm_t_inum k = 1;
3885 scm_t_inum t;
0aacf84e
MD
3886 /* Determine a common factor 2^k */
3887 while (!(1 & (u | v)))
3888 {
3889 k <<= 1;
3890 u >>= 1;
3891 v >>= 1;
3892 }
3893 /* Now, any factor 2^n can be eliminated */
3894 if (u & 1)
3895 t = -v;
3896 else
3897 {
3898 t = u;
3899 b3:
3900 t = SCM_SRS (t, 1);
3901 }
3902 if (!(1 & t))
3903 goto b3;
3904 if (t > 0)
3905 u = t;
3906 else
3907 v = -t;
3908 t = u - v;
3909 if (t != 0)
3910 goto b3;
3911 result = u * k;
3912 }
3913 return (SCM_POSFIXABLE (result)
d956fa6f 3914 ? SCM_I_MAKINUM (result)
e25f3727 3915 : scm_i_inum2big (result));
ca46fb90
RB
3916 }
3917 else if (SCM_BIGP (y))
3918 {
0bff4dce
KR
3919 SCM_SWAP (x, y);
3920 goto big_inum;
ca46fb90
RB
3921 }
3922 else
3923 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 3924 }
ca46fb90
RB
3925 else if (SCM_BIGP (x))
3926 {
e11e83f3 3927 if (SCM_I_INUMP (y))
ca46fb90 3928 {
e25f3727
AW
3929 scm_t_bits result;
3930 scm_t_inum yy;
0bff4dce 3931 big_inum:
e11e83f3 3932 yy = SCM_I_INUM (y);
8c5b0afc
KR
3933 if (yy == 0)
3934 return scm_abs (x);
0aacf84e
MD
3935 if (yy < 0)
3936 yy = -yy;
ca46fb90
RB
3937 result = mpz_gcd_ui (NULL, SCM_I_BIG_MPZ (x), yy);
3938 scm_remember_upto_here_1 (x);
0aacf84e 3939 return (SCM_POSFIXABLE (result)
d956fa6f 3940 ? SCM_I_MAKINUM (result)
e25f3727 3941 : scm_from_unsigned_integer (result));
ca46fb90
RB
3942 }
3943 else if (SCM_BIGP (y))
3944 {
3945 SCM result = scm_i_mkbig ();
0aacf84e
MD
3946 mpz_gcd (SCM_I_BIG_MPZ (result),
3947 SCM_I_BIG_MPZ (x),
3948 SCM_I_BIG_MPZ (y));
3949 scm_remember_upto_here_2 (x, y);
ca46fb90
RB
3950 return scm_i_normbig (result);
3951 }
3952 else
3953 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
09fb7599 3954 }
ca46fb90 3955 else
09fb7599 3956 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
0f2d19dd
JB
3957}
3958
78d3deb1
AW
3959SCM_PRIMITIVE_GENERIC (scm_i_lcm, "lcm", 0, 2, 1,
3960 (SCM x, SCM y, SCM rest),
3961 "Return the least common multiple of the arguments.\n"
3962 "If called without arguments, 1 is returned.")
3963#define FUNC_NAME s_scm_i_lcm
3964{
3965 while (!scm_is_null (rest))
3966 { x = scm_lcm (x, y);
3967 y = scm_car (rest);
3968 rest = scm_cdr (rest);
3969 }
3970 return scm_lcm (x, y);
3971}
3972#undef FUNC_NAME
3973
3974#define s_lcm s_scm_i_lcm
3975#define g_lcm g_scm_i_lcm
3976
0f2d19dd 3977SCM
6e8d25a6 3978scm_lcm (SCM n1, SCM n2)
0f2d19dd 3979{
ca46fb90
RB
3980 if (SCM_UNBNDP (n2))
3981 {
3982 if (SCM_UNBNDP (n1))
d956fa6f
MV
3983 return SCM_I_MAKINUM (1L);
3984 n2 = SCM_I_MAKINUM (1L);
09fb7599 3985 }
09fb7599 3986
e11e83f3 3987 SCM_GASSERT2 (SCM_I_INUMP (n1) || SCM_BIGP (n1),
ca46fb90 3988 g_lcm, n1, n2, SCM_ARG1, s_lcm);
e11e83f3 3989 SCM_GASSERT2 (SCM_I_INUMP (n2) || SCM_BIGP (n2),
ca46fb90 3990 g_lcm, n1, n2, SCM_ARGn, 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:
0b799eea
MV
5120#ifdef ENGNOT
5121 /* adding 9999 makes this equivalent to abs(x) % 3 */
f872b822 5122 dpt = (exp + 9999) % 3;
0f2d19dd
JB
5123 exp -= dpt++;
5124 efmt = 1;
f872b822
MD
5125#else
5126 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 5127 if (!efmt)
cda139a7
MD
5128 {
5129 if (exp < 0)
5130 {
5131 a[ch++] = '0';
5132 a[ch++] = '.';
5133 dpt = exp;
f872b822
MD
5134 while (++dpt)
5135 a[ch++] = '0';
cda139a7
MD
5136 }
5137 else
f872b822 5138 dpt = exp + 1;
cda139a7 5139 }
0f2d19dd
JB
5140 else
5141 dpt = 1;
f872b822
MD
5142#endif
5143
5144 do
5145 {
5146 d = f;
5147 f -= d;
0b799eea 5148 a[ch++] = number_chars[d];
f872b822
MD
5149 if (f < fx[wp])
5150 break;
5151 if (f + fx[wp] >= 1.0)
5152 {
0b799eea 5153 a[ch - 1] = number_chars[d+1];
f872b822
MD
5154 break;
5155 }
0b799eea 5156 f *= radix;
f872b822
MD
5157 if (!(--dpt))
5158 a[ch++] = '.';
0f2d19dd 5159 }
f872b822 5160 while (wp--);
0f2d19dd
JB
5161
5162 if (dpt > 0)
cda139a7 5163 {
f872b822 5164#ifndef ENGNOT
cda139a7
MD
5165 if ((dpt > 4) && (exp > 6))
5166 {
f872b822 5167 d = (a[0] == '-' ? 2 : 1);
cda139a7 5168 for (i = ch++; i > d; i--)
f872b822 5169 a[i] = a[i - 1];
cda139a7
MD
5170 a[d] = '.';
5171 efmt = 1;
5172 }
5173 else
f872b822 5174#endif
cda139a7 5175 {
f872b822
MD
5176 while (--dpt)
5177 a[ch++] = '0';
cda139a7
MD
5178 a[ch++] = '.';
5179 }
5180 }
f872b822
MD
5181 if (a[ch - 1] == '.')
5182 a[ch++] = '0'; /* trailing zero */
5183 if (efmt && exp)
5184 {
5185 a[ch++] = 'e';
5186 if (exp < 0)
5187 {
5188 exp = -exp;
5189 a[ch++] = '-';
5190 }
0b799eea
MV
5191 for (i = radix; i <= exp; i *= radix);
5192 for (i /= radix; i; i /= radix)
f872b822 5193 {
0b799eea 5194 a[ch++] = number_chars[exp / i];
f872b822
MD
5195 exp %= i;
5196 }
0f2d19dd 5197 }
0f2d19dd
JB
5198 return ch;
5199}
5200
7a1aba42
MV
5201
5202static size_t
5203icmplx2str (double real, double imag, char *str, int radix)
5204{
5205 size_t i;
c7218482 5206 double sgn;
7a1aba42
MV
5207
5208 i = idbl2str (real, str, radix);
c7218482
MW
5209#ifdef HAVE_COPYSIGN
5210 sgn = copysign (1.0, imag);
5211#else
5212 sgn = imag;
5213#endif
5214 /* Don't output a '+' for negative numbers or for Inf and
5215 NaN. They will provide their own sign. */
5216 if (sgn >= 0 && DOUBLE_IS_FINITE (imag))
5217 str[i++] = '+';
5218 i += idbl2str (imag, &str[i], radix);
5219 str[i++] = 'i';
7a1aba42
MV
5220 return i;
5221}
5222
1be6b49c 5223static size_t
0b799eea 5224iflo2str (SCM flt, char *str, int radix)
0f2d19dd 5225{
1be6b49c 5226 size_t i;
3c9a524f 5227 if (SCM_REALP (flt))
0b799eea 5228 i = idbl2str (SCM_REAL_VALUE (flt), str, radix);
0f2d19dd 5229 else
7a1aba42
MV
5230 i = icmplx2str (SCM_COMPLEX_REAL (flt), SCM_COMPLEX_IMAG (flt),
5231 str, radix);
0f2d19dd
JB
5232 return i;
5233}
0f2d19dd 5234
2881e77b 5235/* convert a scm_t_intmax to a string (unterminated). returns the number of
1bbd0b84
GB
5236 characters in the result.
5237 rad is output base
5238 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 5239size_t
2881e77b
MV
5240scm_iint2str (scm_t_intmax num, int rad, char *p)
5241{
5242 if (num < 0)
5243 {
5244 *p++ = '-';
5245 return scm_iuint2str (-num, rad, p) + 1;
5246 }
5247 else
5248 return scm_iuint2str (num, rad, p);
5249}
5250
5251/* convert a scm_t_intmax to a string (unterminated). returns the number of
5252 characters in the result.
5253 rad is output base
5254 p is destination: worst case (base 2) is SCM_INTBUFLEN */
5255size_t
5256scm_iuint2str (scm_t_uintmax num, int rad, char *p)
0f2d19dd 5257{
1be6b49c
ML
5258 size_t j = 1;
5259 size_t i;
2881e77b 5260 scm_t_uintmax n = num;
5c11cc9d 5261
a6f3af16
AW
5262 if (rad < 2 || rad > 36)
5263 scm_out_of_range ("scm_iuint2str", scm_from_int (rad));
5264
f872b822 5265 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
5266 j++;
5267
5268 i = j;
2881e77b 5269 n = num;
f872b822
MD
5270 while (i--)
5271 {
5c11cc9d
GH
5272 int d = n % rad;
5273
f872b822 5274 n /= rad;
a6f3af16 5275 p[i] = number_chars[d];
f872b822 5276 }
0f2d19dd
JB
5277 return j;
5278}
5279
a1ec6916 5280SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
5281 (SCM n, SCM radix),
5282 "Return a string holding the external representation of the\n"
942e5b91
MG
5283 "number @var{n} in the given @var{radix}. If @var{n} is\n"
5284 "inexact, a radix of 10 will be used.")
1bbd0b84 5285#define FUNC_NAME s_scm_number_to_string
0f2d19dd 5286{
1bbd0b84 5287 int base;
98cb6e75 5288
0aacf84e 5289 if (SCM_UNBNDP (radix))
98cb6e75 5290 base = 10;
0aacf84e 5291 else
5efd3c7d 5292 base = scm_to_signed_integer (radix, 2, 36);
98cb6e75 5293
e11e83f3 5294 if (SCM_I_INUMP (n))
0aacf84e
MD
5295 {
5296 char num_buf [SCM_INTBUFLEN];
e11e83f3 5297 size_t length = scm_iint2str (SCM_I_INUM (n), base, num_buf);
cc95e00a 5298 return scm_from_locale_stringn (num_buf, length);
0aacf84e
MD
5299 }
5300 else if (SCM_BIGP (n))
5301 {
5302 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
5303 scm_remember_upto_here_1 (n);
cc95e00a 5304 return scm_take_locale_string (str);
0aacf84e 5305 }
f92e85f7
MV
5306 else if (SCM_FRACTIONP (n))
5307 {
f92e85f7 5308 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
cc95e00a 5309 scm_from_locale_string ("/"),
f92e85f7
MV
5310 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
5311 }
0aacf84e
MD
5312 else if (SCM_INEXACTP (n))
5313 {
5314 char num_buf [FLOBUFLEN];
cc95e00a 5315 return scm_from_locale_stringn (num_buf, iflo2str (n, num_buf, base));
0aacf84e
MD
5316 }
5317 else
bb628794 5318 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 5319}
1bbd0b84 5320#undef FUNC_NAME
0f2d19dd
JB
5321
5322
ca46fb90
RB
5323/* These print routines used to be stubbed here so that scm_repl.c
5324 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 5325
0f2d19dd 5326int
e81d98ec 5327scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 5328{
56e55ac7 5329 char num_buf[FLOBUFLEN];
0b799eea 5330 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
0f2d19dd
JB
5331 return !0;
5332}
5333
b479fe9a
MV
5334void
5335scm_i_print_double (double val, SCM port)
5336{
5337 char num_buf[FLOBUFLEN];
5338 scm_lfwrite (num_buf, idbl2str (val, num_buf, 10), port);
5339}
5340
f3ae5d60 5341int
e81d98ec 5342scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 5343
f3ae5d60 5344{
56e55ac7 5345 char num_buf[FLOBUFLEN];
0b799eea 5346 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
f3ae5d60
MD
5347 return !0;
5348}
1cc91f1b 5349
7a1aba42
MV
5350void
5351scm_i_print_complex (double real, double imag, SCM port)
5352{
5353 char num_buf[FLOBUFLEN];
5354 scm_lfwrite (num_buf, icmplx2str (real, imag, num_buf, 10), port);
5355}
5356
f92e85f7
MV
5357int
5358scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
5359{
5360 SCM str;
f92e85f7 5361 str = scm_number_to_string (sexp, SCM_UNDEFINED);
a9178715 5362 scm_display (str, port);
f92e85f7
MV
5363 scm_remember_upto_here_1 (str);
5364 return !0;
5365}
5366
0f2d19dd 5367int
e81d98ec 5368scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 5369{
ca46fb90
RB
5370 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
5371 scm_remember_upto_here_1 (exp);
5372 scm_lfwrite (str, (size_t) strlen (str), port);
5373 free (str);
0f2d19dd
JB
5374 return !0;
5375}
5376/*** END nums->strs ***/
5377
3c9a524f 5378
0f2d19dd 5379/*** STRINGS -> NUMBERS ***/
2a8fecee 5380
3c9a524f
DH
5381/* The following functions implement the conversion from strings to numbers.
5382 * The implementation somehow follows the grammar for numbers as it is given
5383 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
5384 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
5385 * points should be noted about the implementation:
bc3d34f5 5386 *
3c9a524f
DH
5387 * * Each function keeps a local index variable 'idx' that points at the
5388 * current position within the parsed string. The global index is only
5389 * updated if the function could parse the corresponding syntactic unit
5390 * successfully.
bc3d34f5 5391 *
3c9a524f 5392 * * Similarly, the functions keep track of indicators of inexactness ('#',
bc3d34f5
MW
5393 * '.' or exponents) using local variables ('hash_seen', 'x').
5394 *
3c9a524f
DH
5395 * * Sequences of digits are parsed into temporary variables holding fixnums.
5396 * Only if these fixnums would overflow, the result variables are updated
5397 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
5398 * the temporary variables holding the fixnums are cleared, and the process
5399 * starts over again. If for example fixnums were able to store five decimal
5400 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
5401 * and the result was computed as 12345 * 100000 + 67890. In other words,
5402 * only every five digits two bignum operations were performed.
bc3d34f5
MW
5403 *
5404 * Notes on the handling of exactness specifiers:
5405 *
5406 * When parsing non-real complex numbers, we apply exactness specifiers on
5407 * per-component basis, as is done in PLT Scheme. For complex numbers
5408 * written in rectangular form, exactness specifiers are applied to the
5409 * real and imaginary parts before calling scm_make_rectangular. For
5410 * complex numbers written in polar form, exactness specifiers are applied
5411 * to the magnitude and angle before calling scm_make_polar.
5412 *
5413 * There are two kinds of exactness specifiers: forced and implicit. A
5414 * forced exactness specifier is a "#e" or "#i" prefix at the beginning of
5415 * the entire number, and applies to both components of a complex number.
5416 * "#e" causes each component to be made exact, and "#i" causes each
5417 * component to be made inexact. If no forced exactness specifier is
5418 * present, then the exactness of each component is determined
5419 * independently by the presence or absence of a decimal point or hash mark
5420 * within that component. If a decimal point or hash mark is present, the
5421 * component is made inexact, otherwise it is made exact.
5422 *
5423 * After the exactness specifiers have been applied to each component, they
5424 * are passed to either scm_make_rectangular or scm_make_polar to produce
5425 * the final result. Note that this will result in a real number if the
5426 * imaginary part, magnitude, or angle is an exact 0.
5427 *
5428 * For example, (string->number "#i5.0+0i") does the equivalent of:
5429 *
5430 * (make-rectangular (exact->inexact 5) (exact->inexact 0))
3c9a524f
DH
5431 */
5432
5433enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
5434
5435/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
5436
a6f3af16
AW
5437/* Caller is responsible for checking that the return value is in range
5438 for the given radix, which should be <= 36. */
5439static unsigned int
5440char_decimal_value (scm_t_uint32 c)
5441{
5442 /* uc_decimal_value returns -1 on error. When cast to an unsigned int,
5443 that's certainly above any valid decimal, so we take advantage of
5444 that to elide some tests. */
5445 unsigned int d = (unsigned int) uc_decimal_value (c);
5446
5447 /* If that failed, try extended hexadecimals, then. Only accept ascii
5448 hexadecimals. */
5449 if (d >= 10U)
5450 {
5451 c = uc_tolower (c);
5452 if (c >= (scm_t_uint32) 'a')
5453 d = c - (scm_t_uint32)'a' + 10U;
5454 }
5455 return d;
5456}
3c9a524f 5457
91db4a37
LC
5458/* Parse the substring of MEM starting at *P_IDX for an unsigned integer
5459 in base RADIX. Upon success, return the unsigned integer and update
5460 *P_IDX and *P_EXACTNESS accordingly. Return #f on failure. */
2a8fecee 5461static SCM
3f47e526 5462mem2uinteger (SCM mem, unsigned int *p_idx,
3c9a524f 5463 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 5464{
3c9a524f
DH
5465 unsigned int idx = *p_idx;
5466 unsigned int hash_seen = 0;
5467 scm_t_bits shift = 1;
5468 scm_t_bits add = 0;
5469 unsigned int digit_value;
5470 SCM result;
5471 char c;
3f47e526 5472 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5473
5474 if (idx == len)
5475 return SCM_BOOL_F;
2a8fecee 5476
3f47e526 5477 c = scm_i_string_ref (mem, idx);
a6f3af16 5478 digit_value = char_decimal_value (c);
3c9a524f
DH
5479 if (digit_value >= radix)
5480 return SCM_BOOL_F;
5481
5482 idx++;
d956fa6f 5483 result = SCM_I_MAKINUM (digit_value);
3c9a524f 5484 while (idx != len)
f872b822 5485 {
3f47e526 5486 scm_t_wchar c = scm_i_string_ref (mem, idx);
a6f3af16 5487 if (c == '#')
3c9a524f
DH
5488 {
5489 hash_seen = 1;
5490 digit_value = 0;
5491 }
a6f3af16
AW
5492 else if (hash_seen)
5493 break;
3c9a524f 5494 else
a6f3af16
AW
5495 {
5496 digit_value = char_decimal_value (c);
5497 /* This check catches non-decimals in addition to out-of-range
5498 decimals. */
5499 if (digit_value >= radix)
5500 break;
5501 }
3c9a524f
DH
5502
5503 idx++;
5504 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
5505 {
d956fa6f 5506 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5507 if (add > 0)
d956fa6f 5508 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5509
5510 shift = radix;
5511 add = digit_value;
5512 }
5513 else
5514 {
5515 shift = shift * radix;
5516 add = add * radix + digit_value;
5517 }
5518 };
5519
5520 if (shift > 1)
d956fa6f 5521 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5522 if (add > 0)
d956fa6f 5523 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5524
5525 *p_idx = idx;
5526 if (hash_seen)
5527 *p_exactness = INEXACT;
5528
5529 return result;
2a8fecee
JB
5530}
5531
5532
3c9a524f
DH
5533/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
5534 * covers the parts of the rules that start at a potential point. The value
5535 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
5536 * in variable result. The content of *p_exactness indicates, whether a hash
5537 * has already been seen in the digits before the point.
3c9a524f 5538 */
1cc91f1b 5539
3f47e526 5540#define DIGIT2UINT(d) (uc_numeric_value(d).numerator)
3c9a524f
DH
5541
5542static SCM
3f47e526 5543mem2decimal_from_point (SCM result, SCM mem,
3c9a524f 5544 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 5545{
3c9a524f
DH
5546 unsigned int idx = *p_idx;
5547 enum t_exactness x = *p_exactness;
3f47e526 5548 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5549
5550 if (idx == len)
79d34f68 5551 return result;
3c9a524f 5552
3f47e526 5553 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
5554 {
5555 scm_t_bits shift = 1;
5556 scm_t_bits add = 0;
5557 unsigned int digit_value;
cff5fa33 5558 SCM big_shift = SCM_INUM1;
3c9a524f
DH
5559
5560 idx++;
5561 while (idx != len)
5562 {
3f47e526
MG
5563 scm_t_wchar c = scm_i_string_ref (mem, idx);
5564 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5565 {
5566 if (x == INEXACT)
5567 return SCM_BOOL_F;
5568 else
5569 digit_value = DIGIT2UINT (c);
5570 }
5571 else if (c == '#')
5572 {
5573 x = INEXACT;
5574 digit_value = 0;
5575 }
5576 else
5577 break;
5578
5579 idx++;
5580 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
5581 {
d956fa6f
MV
5582 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
5583 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5584 if (add > 0)
d956fa6f 5585 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5586
5587 shift = 10;
5588 add = digit_value;
5589 }
5590 else
5591 {
5592 shift = shift * 10;
5593 add = add * 10 + digit_value;
5594 }
5595 };
5596
5597 if (add > 0)
5598 {
d956fa6f
MV
5599 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
5600 result = scm_product (result, SCM_I_MAKINUM (shift));
5601 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5602 }
5603
d8592269 5604 result = scm_divide (result, big_shift);
79d34f68 5605
3c9a524f
DH
5606 /* We've seen a decimal point, thus the value is implicitly inexact. */
5607 x = INEXACT;
f872b822 5608 }
3c9a524f 5609
3c9a524f 5610 if (idx != len)
f872b822 5611 {
3c9a524f
DH
5612 int sign = 1;
5613 unsigned int start;
3f47e526 5614 scm_t_wchar c;
3c9a524f
DH
5615 int exponent;
5616 SCM e;
5617
5618 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
5619
3f47e526 5620 switch (scm_i_string_ref (mem, idx))
f872b822 5621 {
3c9a524f
DH
5622 case 'd': case 'D':
5623 case 'e': case 'E':
5624 case 'f': case 'F':
5625 case 'l': case 'L':
5626 case 's': case 'S':
5627 idx++;
ee0ddd21
AW
5628 if (idx == len)
5629 return SCM_BOOL_F;
5630
3c9a524f 5631 start = idx;
3f47e526 5632 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5633 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 if (c == '+')
5643 {
5644 idx++;
ee0ddd21
AW
5645 if (idx == len)
5646 return SCM_BOOL_F;
5647
3c9a524f 5648 sign = 1;
3f47e526 5649 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5650 }
5651 else
5652 sign = 1;
5653
3f47e526 5654 if (!uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5655 return SCM_BOOL_F;
5656
5657 idx++;
5658 exponent = DIGIT2UINT (c);
5659 while (idx != len)
f872b822 5660 {
3f47e526
MG
5661 scm_t_wchar c = scm_i_string_ref (mem, idx);
5662 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5663 {
5664 idx++;
5665 if (exponent <= SCM_MAXEXP)
5666 exponent = exponent * 10 + DIGIT2UINT (c);
5667 }
5668 else
5669 break;
f872b822 5670 }
3c9a524f
DH
5671
5672 if (exponent > SCM_MAXEXP)
f872b822 5673 {
3c9a524f 5674 size_t exp_len = idx - start;
3f47e526 5675 SCM exp_string = scm_i_substring_copy (mem, start, start + exp_len);
3c9a524f
DH
5676 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
5677 scm_out_of_range ("string->number", exp_num);
f872b822 5678 }
3c9a524f 5679
d956fa6f 5680 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
5681 if (sign == 1)
5682 result = scm_product (result, e);
5683 else
6ebecdeb 5684 result = scm_divide (result, e);
3c9a524f
DH
5685
5686 /* We've seen an exponent, thus the value is implicitly inexact. */
5687 x = INEXACT;
5688
f872b822 5689 break;
3c9a524f 5690
f872b822 5691 default:
3c9a524f 5692 break;
f872b822 5693 }
0f2d19dd 5694 }
3c9a524f
DH
5695
5696 *p_idx = idx;
5697 if (x == INEXACT)
5698 *p_exactness = x;
5699
5700 return result;
0f2d19dd 5701}
0f2d19dd 5702
3c9a524f
DH
5703
5704/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
5705
5706static SCM
3f47e526 5707mem2ureal (SCM mem, unsigned int *p_idx,
9d427b2c 5708 unsigned int radix, enum t_exactness forced_x)
0f2d19dd 5709{
3c9a524f 5710 unsigned int idx = *p_idx;
164d2481 5711 SCM result;
3f47e526 5712 size_t len = scm_i_string_length (mem);
3c9a524f 5713
40f89215
NJ
5714 /* Start off believing that the number will be exact. This changes
5715 to INEXACT if we see a decimal point or a hash. */
9d427b2c 5716 enum t_exactness implicit_x = EXACT;
40f89215 5717
3c9a524f
DH
5718 if (idx == len)
5719 return SCM_BOOL_F;
5720
3f47e526 5721 if (idx+5 <= len && !scm_i_string_strcmp (mem, idx, "inf.0"))
7351e207
MV
5722 {
5723 *p_idx = idx+5;
5724 return scm_inf ();
5725 }
5726
3f47e526 5727 if (idx+4 < len && !scm_i_string_strcmp (mem, idx, "nan."))
7351e207 5728 {
d8592269
MV
5729 /* Cobble up the fractional part. We might want to set the
5730 NaN's mantissa from it. */
7351e207 5731 idx += 4;
91db4a37 5732 if (!scm_is_eq (mem2uinteger (mem, &idx, 10, &implicit_x), SCM_INUM0))
5f237d6e
AW
5733 {
5734#if SCM_ENABLE_DEPRECATED == 1
5735 scm_c_issue_deprecation_warning
5736 ("Non-zero suffixes to `+nan.' are deprecated. Use `+nan.0'.");
5737#else
5738 return SCM_BOOL_F;
5739#endif
5740 }
5741
7351e207
MV
5742 *p_idx = idx;
5743 return scm_nan ();
5744 }
5745
3f47e526 5746 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
5747 {
5748 if (radix != 10)
5749 return SCM_BOOL_F;
5750 else if (idx + 1 == len)
5751 return SCM_BOOL_F;
3f47e526 5752 else if (!uc_is_property_decimal_digit ((scm_t_uint32) scm_i_string_ref (mem, idx+1)))
3c9a524f
DH
5753 return SCM_BOOL_F;
5754 else
cff5fa33 5755 result = mem2decimal_from_point (SCM_INUM0, mem,
9d427b2c 5756 p_idx, &implicit_x);
f872b822 5757 }
3c9a524f
DH
5758 else
5759 {
3c9a524f 5760 SCM uinteger;
3c9a524f 5761
9d427b2c 5762 uinteger = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 5763 if (scm_is_false (uinteger))
3c9a524f
DH
5764 return SCM_BOOL_F;
5765
5766 if (idx == len)
5767 result = uinteger;
3f47e526 5768 else if (scm_i_string_ref (mem, idx) == '/')
f872b822 5769 {
3c9a524f
DH
5770 SCM divisor;
5771
5772 idx++;
ee0ddd21
AW
5773 if (idx == len)
5774 return SCM_BOOL_F;
3c9a524f 5775
9d427b2c 5776 divisor = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 5777 if (scm_is_false (divisor))
3c9a524f
DH
5778 return SCM_BOOL_F;
5779
f92e85f7 5780 /* both are int/big here, I assume */
cba42c93 5781 result = scm_i_make_ratio (uinteger, divisor);
f872b822 5782 }
3c9a524f
DH
5783 else if (radix == 10)
5784 {
9d427b2c 5785 result = mem2decimal_from_point (uinteger, mem, &idx, &implicit_x);
73e4de09 5786 if (scm_is_false (result))
3c9a524f
DH
5787 return SCM_BOOL_F;
5788 }
5789 else
5790 result = uinteger;
5791
5792 *p_idx = idx;
f872b822 5793 }
164d2481 5794
9d427b2c
MW
5795 switch (forced_x)
5796 {
5797 case EXACT:
5798 if (SCM_INEXACTP (result))
5799 return scm_inexact_to_exact (result);
5800 else
5801 return result;
5802 case INEXACT:
5803 if (SCM_INEXACTP (result))
5804 return result;
5805 else
5806 return scm_exact_to_inexact (result);
5807 case NO_EXACTNESS:
5808 if (implicit_x == INEXACT)
5809 {
5810 if (SCM_INEXACTP (result))
5811 return result;
5812 else
5813 return scm_exact_to_inexact (result);
5814 }
5815 else
5816 return result;
5817 }
164d2481 5818
9d427b2c
MW
5819 /* We should never get here */
5820 scm_syserror ("mem2ureal");
3c9a524f 5821}
0f2d19dd 5822
0f2d19dd 5823
3c9a524f 5824/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 5825
3c9a524f 5826static SCM
3f47e526 5827mem2complex (SCM mem, unsigned int idx,
9d427b2c 5828 unsigned int radix, enum t_exactness forced_x)
3c9a524f 5829{
3f47e526 5830 scm_t_wchar c;
3c9a524f
DH
5831 int sign = 0;
5832 SCM ureal;
3f47e526 5833 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5834
5835 if (idx == len)
5836 return SCM_BOOL_F;
5837
3f47e526 5838 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5839 if (c == '+')
5840 {
5841 idx++;
5842 sign = 1;
5843 }
5844 else if (c == '-')
5845 {
5846 idx++;
5847 sign = -1;
0f2d19dd 5848 }
0f2d19dd 5849
3c9a524f
DH
5850 if (idx == len)
5851 return SCM_BOOL_F;
5852
9d427b2c 5853 ureal = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 5854 if (scm_is_false (ureal))
f872b822 5855 {
3c9a524f
DH
5856 /* input must be either +i or -i */
5857
5858 if (sign == 0)
5859 return SCM_BOOL_F;
5860
3f47e526
MG
5861 if (scm_i_string_ref (mem, idx) == 'i'
5862 || scm_i_string_ref (mem, idx) == 'I')
f872b822 5863 {
3c9a524f
DH
5864 idx++;
5865 if (idx != len)
5866 return SCM_BOOL_F;
5867
cff5fa33 5868 return scm_make_rectangular (SCM_INUM0, SCM_I_MAKINUM (sign));
f872b822 5869 }
3c9a524f
DH
5870 else
5871 return SCM_BOOL_F;
0f2d19dd 5872 }
3c9a524f
DH
5873 else
5874 {
73e4de09 5875 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 5876 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 5877
3c9a524f
DH
5878 if (idx == len)
5879 return ureal;
5880
3f47e526 5881 c = scm_i_string_ref (mem, idx);
3c9a524f 5882 switch (c)
f872b822 5883 {
3c9a524f
DH
5884 case 'i': case 'I':
5885 /* either +<ureal>i or -<ureal>i */
5886
5887 idx++;
5888 if (sign == 0)
5889 return SCM_BOOL_F;
5890 if (idx != len)
5891 return SCM_BOOL_F;
cff5fa33 5892 return scm_make_rectangular (SCM_INUM0, ureal);
3c9a524f
DH
5893
5894 case '@':
5895 /* polar input: <real>@<real>. */
5896
5897 idx++;
5898 if (idx == len)
5899 return SCM_BOOL_F;
5900 else
f872b822 5901 {
3c9a524f
DH
5902 int sign;
5903 SCM angle;
5904 SCM result;
5905
3f47e526 5906 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5907 if (c == '+')
5908 {
5909 idx++;
ee0ddd21
AW
5910 if (idx == len)
5911 return SCM_BOOL_F;
3c9a524f
DH
5912 sign = 1;
5913 }
5914 else if (c == '-')
5915 {
5916 idx++;
ee0ddd21
AW
5917 if (idx == len)
5918 return SCM_BOOL_F;
3c9a524f
DH
5919 sign = -1;
5920 }
5921 else
5922 sign = 1;
5923
9d427b2c 5924 angle = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 5925 if (scm_is_false (angle))
3c9a524f
DH
5926 return SCM_BOOL_F;
5927 if (idx != len)
5928 return SCM_BOOL_F;
5929
73e4de09 5930 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
5931 angle = scm_difference (angle, SCM_UNDEFINED);
5932
5933 result = scm_make_polar (ureal, angle);
5934 return result;
f872b822 5935 }
3c9a524f
DH
5936 case '+':
5937 case '-':
5938 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 5939
3c9a524f
DH
5940 idx++;
5941 if (idx == len)
5942 return SCM_BOOL_F;
5943 else
5944 {
5945 int sign = (c == '+') ? 1 : -1;
9d427b2c 5946 SCM imag = mem2ureal (mem, &idx, radix, forced_x);
0f2d19dd 5947
73e4de09 5948 if (scm_is_false (imag))
d956fa6f 5949 imag = SCM_I_MAKINUM (sign);
23295dc3 5950 else if (sign == -1 && scm_is_false (scm_nan_p (imag)))
1fe5e088 5951 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 5952
3c9a524f
DH
5953 if (idx == len)
5954 return SCM_BOOL_F;
3f47e526
MG
5955 if (scm_i_string_ref (mem, idx) != 'i'
5956 && scm_i_string_ref (mem, idx) != 'I')
3c9a524f 5957 return SCM_BOOL_F;
0f2d19dd 5958
3c9a524f
DH
5959 idx++;
5960 if (idx != len)
5961 return SCM_BOOL_F;
0f2d19dd 5962
1fe5e088 5963 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
5964 }
5965 default:
5966 return SCM_BOOL_F;
5967 }
5968 }
0f2d19dd 5969}
0f2d19dd
JB
5970
5971
3c9a524f
DH
5972/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
5973
5974enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 5975
0f2d19dd 5976SCM
3f47e526 5977scm_i_string_to_number (SCM mem, unsigned int default_radix)
0f2d19dd 5978{
3c9a524f
DH
5979 unsigned int idx = 0;
5980 unsigned int radix = NO_RADIX;
5981 enum t_exactness forced_x = NO_EXACTNESS;
3f47e526 5982 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5983
5984 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
3f47e526 5985 while (idx + 2 < len && scm_i_string_ref (mem, idx) == '#')
3c9a524f 5986 {
3f47e526 5987 switch (scm_i_string_ref (mem, idx + 1))
3c9a524f
DH
5988 {
5989 case 'b': case 'B':
5990 if (radix != NO_RADIX)
5991 return SCM_BOOL_F;
5992 radix = DUAL;
5993 break;
5994 case 'd': case 'D':
5995 if (radix != NO_RADIX)
5996 return SCM_BOOL_F;
5997 radix = DEC;
5998 break;
5999 case 'i': case 'I':
6000 if (forced_x != NO_EXACTNESS)
6001 return SCM_BOOL_F;
6002 forced_x = INEXACT;
6003 break;
6004 case 'e': case 'E':
6005 if (forced_x != NO_EXACTNESS)
6006 return SCM_BOOL_F;
6007 forced_x = EXACT;
6008 break;
6009 case 'o': case 'O':
6010 if (radix != NO_RADIX)
6011 return SCM_BOOL_F;
6012 radix = OCT;
6013 break;
6014 case 'x': case 'X':
6015 if (radix != NO_RADIX)
6016 return SCM_BOOL_F;
6017 radix = HEX;
6018 break;
6019 default:
f872b822 6020 return SCM_BOOL_F;
3c9a524f
DH
6021 }
6022 idx += 2;
6023 }
6024
6025 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
6026 if (radix == NO_RADIX)
9d427b2c 6027 radix = default_radix;
f872b822 6028
9d427b2c 6029 return mem2complex (mem, idx, radix, forced_x);
0f2d19dd
JB
6030}
6031
3f47e526
MG
6032SCM
6033scm_c_locale_stringn_to_number (const char* mem, size_t len,
6034 unsigned int default_radix)
6035{
6036 SCM str = scm_from_locale_stringn (mem, len);
6037
6038 return scm_i_string_to_number (str, default_radix);
6039}
6040
0f2d19dd 6041
a1ec6916 6042SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 6043 (SCM string, SCM radix),
1e6808ea 6044 "Return a number of the maximally precise representation\n"
942e5b91 6045 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
6046 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
6047 "is a default radix that may be overridden by an explicit radix\n"
6048 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
6049 "supplied, then the default radix is 10. If string is not a\n"
6050 "syntactically valid notation for a number, then\n"
6051 "@code{string->number} returns @code{#f}.")
1bbd0b84 6052#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
6053{
6054 SCM answer;
5efd3c7d 6055 unsigned int base;
a6d9e5ab 6056 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
6057
6058 if (SCM_UNBNDP (radix))
6059 base = 10;
6060 else
6061 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
6062
3f47e526 6063 answer = scm_i_string_to_number (string, base);
8824ac88
MV
6064 scm_remember_upto_here_1 (string);
6065 return answer;
0f2d19dd 6066}
1bbd0b84 6067#undef FUNC_NAME
3c9a524f
DH
6068
6069
0f2d19dd
JB
6070/*** END strs->nums ***/
6071
5986c47d 6072
8507ec80
MV
6073SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
6074 (SCM x),
6075 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
6076 "otherwise.")
6077#define FUNC_NAME s_scm_number_p
6078{
6079 return scm_from_bool (SCM_NUMBERP (x));
6080}
6081#undef FUNC_NAME
6082
6083SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 6084 (SCM x),
942e5b91 6085 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 6086 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
6087 "values form subsets of the set of complex numbers, i. e. the\n"
6088 "predicate will also be fulfilled if @var{x} is a real,\n"
6089 "rational or integer number.")
8507ec80 6090#define FUNC_NAME s_scm_complex_p
0f2d19dd 6091{
8507ec80
MV
6092 /* all numbers are complex. */
6093 return scm_number_p (x);
0f2d19dd 6094}
1bbd0b84 6095#undef FUNC_NAME
0f2d19dd 6096
f92e85f7
MV
6097SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
6098 (SCM x),
6099 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
6100 "otherwise. Note that the set of integer values forms a subset of\n"
6101 "the set of real numbers, i. e. the predicate will also be\n"
6102 "fulfilled if @var{x} is an integer number.")
6103#define FUNC_NAME s_scm_real_p
6104{
c960e556
MW
6105 return scm_from_bool
6106 (SCM_I_INUMP (x) || SCM_REALP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x));
f92e85f7
MV
6107}
6108#undef FUNC_NAME
6109
6110SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 6111 (SCM x),
942e5b91 6112 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 6113 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 6114 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
6115 "fulfilled if @var{x} is an integer number.")
6116#define FUNC_NAME s_scm_rational_p
0f2d19dd 6117{
c960e556 6118 if (SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x))
f92e85f7
MV
6119 return SCM_BOOL_T;
6120 else if (SCM_REALP (x))
c960e556
MW
6121 /* due to their limited precision, finite floating point numbers are
6122 rational as well. (finite means neither infinity nor a NaN) */
6123 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
0aacf84e 6124 else
bb628794 6125 return SCM_BOOL_F;
0f2d19dd 6126}
1bbd0b84 6127#undef FUNC_NAME
0f2d19dd 6128
a1ec6916 6129SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 6130 (SCM x),
942e5b91
MG
6131 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
6132 "else.")
1bbd0b84 6133#define FUNC_NAME s_scm_integer_p
0f2d19dd 6134{
c960e556 6135 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f872b822 6136 return SCM_BOOL_T;
c960e556
MW
6137 else if (SCM_REALP (x))
6138 {
6139 double val = SCM_REAL_VALUE (x);
6140 return scm_from_bool (!isinf (val) && (val == floor (val)));
6141 }
6142 else
8e43ed5d 6143 return SCM_BOOL_F;
0f2d19dd 6144}
1bbd0b84 6145#undef FUNC_NAME
0f2d19dd
JB
6146
6147
8a1f4f98
AW
6148SCM scm_i_num_eq_p (SCM, SCM, SCM);
6149SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
6150 (SCM x, SCM y, SCM rest),
6151 "Return @code{#t} if all parameters are numerically equal.")
6152#define FUNC_NAME s_scm_i_num_eq_p
6153{
6154 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6155 return SCM_BOOL_T;
6156 while (!scm_is_null (rest))
6157 {
6158 if (scm_is_false (scm_num_eq_p (x, y)))
6159 return SCM_BOOL_F;
6160 x = y;
6161 y = scm_car (rest);
6162 rest = scm_cdr (rest);
6163 }
6164 return scm_num_eq_p (x, y);
6165}
6166#undef FUNC_NAME
0f2d19dd 6167SCM
6e8d25a6 6168scm_num_eq_p (SCM x, SCM y)
0f2d19dd 6169{
d8b95e27 6170 again:
e11e83f3 6171 if (SCM_I_INUMP (x))
0aacf84e 6172 {
e25f3727 6173 scm_t_signed_bits xx = SCM_I_INUM (x);
e11e83f3 6174 if (SCM_I_INUMP (y))
0aacf84e 6175 {
e25f3727 6176 scm_t_signed_bits yy = SCM_I_INUM (y);
73e4de09 6177 return scm_from_bool (xx == yy);
0aacf84e
MD
6178 }
6179 else if (SCM_BIGP (y))
6180 return SCM_BOOL_F;
6181 else if (SCM_REALP (y))
e8c5b1f2
KR
6182 {
6183 /* On a 32-bit system an inum fits a double, we can cast the inum
6184 to a double and compare.
6185
6186 But on a 64-bit system an inum is bigger than a double and
6187 casting it to a double (call that dxx) will round. dxx is at
6188 worst 1 bigger or smaller than xx, so if dxx==yy we know yy is
6189 an integer and fits a long. So we cast yy to a long and
6190 compare with plain xx.
6191
6192 An alternative (for any size system actually) would be to check
6193 yy is an integer (with floor) and is in range of an inum
6194 (compare against appropriate powers of 2) then test
e25f3727
AW
6195 xx==(scm_t_signed_bits)yy. It's just a matter of which
6196 casts/comparisons might be fastest or easiest for the cpu. */
e8c5b1f2
KR
6197
6198 double yy = SCM_REAL_VALUE (y);
3a1b45fd
MV
6199 return scm_from_bool ((double) xx == yy
6200 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 6201 || xx == (scm_t_signed_bits) yy));
e8c5b1f2 6202 }
0aacf84e 6203 else if (SCM_COMPLEXP (y))
73e4de09 6204 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 6205 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
6206 else if (SCM_FRACTIONP (y))
6207 return SCM_BOOL_F;
0aacf84e 6208 else
8a1f4f98 6209 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 6210 }
0aacf84e
MD
6211 else if (SCM_BIGP (x))
6212 {
e11e83f3 6213 if (SCM_I_INUMP (y))
0aacf84e
MD
6214 return SCM_BOOL_F;
6215 else if (SCM_BIGP (y))
6216 {
6217 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6218 scm_remember_upto_here_2 (x, y);
73e4de09 6219 return scm_from_bool (0 == cmp);
0aacf84e
MD
6220 }
6221 else if (SCM_REALP (y))
6222 {
6223 int cmp;
2e65b52f 6224 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
6225 return SCM_BOOL_F;
6226 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
6227 scm_remember_upto_here_1 (x);
73e4de09 6228 return scm_from_bool (0 == cmp);
0aacf84e
MD
6229 }
6230 else if (SCM_COMPLEXP (y))
6231 {
6232 int cmp;
6233 if (0.0 != SCM_COMPLEX_IMAG (y))
6234 return SCM_BOOL_F;
2e65b52f 6235 if (isnan (SCM_COMPLEX_REAL (y)))
0aacf84e
MD
6236 return SCM_BOOL_F;
6237 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
6238 scm_remember_upto_here_1 (x);
73e4de09 6239 return scm_from_bool (0 == cmp);
0aacf84e 6240 }
f92e85f7
MV
6241 else if (SCM_FRACTIONP (y))
6242 return SCM_BOOL_F;
0aacf84e 6243 else
8a1f4f98 6244 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 6245 }
0aacf84e
MD
6246 else if (SCM_REALP (x))
6247 {
e8c5b1f2 6248 double xx = SCM_REAL_VALUE (x);
e11e83f3 6249 if (SCM_I_INUMP (y))
e8c5b1f2
KR
6250 {
6251 /* see comments with inum/real above */
e25f3727 6252 scm_t_signed_bits yy = SCM_I_INUM (y);
3a1b45fd
MV
6253 return scm_from_bool (xx == (double) yy
6254 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 6255 || (scm_t_signed_bits) xx == yy));
e8c5b1f2 6256 }
0aacf84e
MD
6257 else if (SCM_BIGP (y))
6258 {
6259 int cmp;
2e65b52f 6260 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
6261 return SCM_BOOL_F;
6262 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
6263 scm_remember_upto_here_1 (y);
73e4de09 6264 return scm_from_bool (0 == cmp);
0aacf84e
MD
6265 }
6266 else if (SCM_REALP (y))
73e4de09 6267 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 6268 else if (SCM_COMPLEXP (y))
73e4de09 6269 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 6270 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 6271 else if (SCM_FRACTIONP (y))
d8b95e27
KR
6272 {
6273 double xx = SCM_REAL_VALUE (x);
2e65b52f 6274 if (isnan (xx))
d8b95e27 6275 return SCM_BOOL_F;
2e65b52f 6276 if (isinf (xx))
73e4de09 6277 return scm_from_bool (xx < 0.0);
d8b95e27
KR
6278 x = scm_inexact_to_exact (x); /* with x as frac or int */
6279 goto again;
6280 }
0aacf84e 6281 else
8a1f4f98 6282 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 6283 }
0aacf84e
MD
6284 else if (SCM_COMPLEXP (x))
6285 {
e11e83f3
MV
6286 if (SCM_I_INUMP (y))
6287 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
6288 && (SCM_COMPLEX_IMAG (x) == 0.0));
6289 else if (SCM_BIGP (y))
6290 {
6291 int cmp;
6292 if (0.0 != SCM_COMPLEX_IMAG (x))
6293 return SCM_BOOL_F;
2e65b52f 6294 if (isnan (SCM_COMPLEX_REAL (x)))
0aacf84e
MD
6295 return SCM_BOOL_F;
6296 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
6297 scm_remember_upto_here_1 (y);
73e4de09 6298 return scm_from_bool (0 == cmp);
0aacf84e
MD
6299 }
6300 else if (SCM_REALP (y))
73e4de09 6301 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
6302 && (SCM_COMPLEX_IMAG (x) == 0.0));
6303 else if (SCM_COMPLEXP (y))
73e4de09 6304 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 6305 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 6306 else if (SCM_FRACTIONP (y))
d8b95e27
KR
6307 {
6308 double xx;
6309 if (SCM_COMPLEX_IMAG (x) != 0.0)
6310 return SCM_BOOL_F;
6311 xx = SCM_COMPLEX_REAL (x);
2e65b52f 6312 if (isnan (xx))
d8b95e27 6313 return SCM_BOOL_F;
2e65b52f 6314 if (isinf (xx))
73e4de09 6315 return scm_from_bool (xx < 0.0);
d8b95e27
KR
6316 x = scm_inexact_to_exact (x); /* with x as frac or int */
6317 goto again;
6318 }
f92e85f7 6319 else
8a1f4f98 6320 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f92e85f7
MV
6321 }
6322 else if (SCM_FRACTIONP (x))
6323 {
e11e83f3 6324 if (SCM_I_INUMP (y))
f92e85f7
MV
6325 return SCM_BOOL_F;
6326 else if (SCM_BIGP (y))
6327 return SCM_BOOL_F;
6328 else if (SCM_REALP (y))
d8b95e27
KR
6329 {
6330 double yy = SCM_REAL_VALUE (y);
2e65b52f 6331 if (isnan (yy))
d8b95e27 6332 return SCM_BOOL_F;
2e65b52f 6333 if (isinf (yy))
73e4de09 6334 return scm_from_bool (0.0 < yy);
d8b95e27
KR
6335 y = scm_inexact_to_exact (y); /* with y as frac or int */
6336 goto again;
6337 }
f92e85f7 6338 else if (SCM_COMPLEXP (y))
d8b95e27
KR
6339 {
6340 double yy;
6341 if (SCM_COMPLEX_IMAG (y) != 0.0)
6342 return SCM_BOOL_F;
6343 yy = SCM_COMPLEX_REAL (y);
2e65b52f 6344 if (isnan (yy))
d8b95e27 6345 return SCM_BOOL_F;
2e65b52f 6346 if (isinf (yy))
73e4de09 6347 return scm_from_bool (0.0 < yy);
d8b95e27
KR
6348 y = scm_inexact_to_exact (y); /* with y as frac or int */
6349 goto again;
6350 }
f92e85f7
MV
6351 else if (SCM_FRACTIONP (y))
6352 return scm_i_fraction_equalp (x, y);
0aacf84e 6353 else
8a1f4f98 6354 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 6355 }
0aacf84e 6356 else
8a1f4f98 6357 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARG1, s_scm_i_num_eq_p);
0f2d19dd
JB
6358}
6359
6360
a5f0b599
KR
6361/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
6362 done are good for inums, but for bignums an answer can almost always be
6363 had by just examining a few high bits of the operands, as done by GMP in
6364 mpq_cmp. flonum/frac compares likewise, but with the slight complication
6365 of the float exponent to take into account. */
6366
8c93b597 6367SCM_INTERNAL SCM scm_i_num_less_p (SCM, SCM, SCM);
8a1f4f98
AW
6368SCM_PRIMITIVE_GENERIC (scm_i_num_less_p, "<", 0, 2, 1,
6369 (SCM x, SCM y, SCM rest),
6370 "Return @code{#t} if the list of parameters is monotonically\n"
6371 "increasing.")
6372#define FUNC_NAME s_scm_i_num_less_p
6373{
6374 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6375 return SCM_BOOL_T;
6376 while (!scm_is_null (rest))
6377 {
6378 if (scm_is_false (scm_less_p (x, y)))
6379 return SCM_BOOL_F;
6380 x = y;
6381 y = scm_car (rest);
6382 rest = scm_cdr (rest);
6383 }
6384 return scm_less_p (x, y);
6385}
6386#undef FUNC_NAME
0f2d19dd 6387SCM
6e8d25a6 6388scm_less_p (SCM x, SCM y)
0f2d19dd 6389{
a5f0b599 6390 again:
e11e83f3 6391 if (SCM_I_INUMP (x))
0aacf84e 6392 {
e25f3727 6393 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6394 if (SCM_I_INUMP (y))
0aacf84e 6395 {
e25f3727 6396 scm_t_inum yy = SCM_I_INUM (y);
73e4de09 6397 return scm_from_bool (xx < yy);
0aacf84e
MD
6398 }
6399 else if (SCM_BIGP (y))
6400 {
6401 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6402 scm_remember_upto_here_1 (y);
73e4de09 6403 return scm_from_bool (sgn > 0);
0aacf84e
MD
6404 }
6405 else if (SCM_REALP (y))
73e4de09 6406 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 6407 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6408 {
6409 /* "x < a/b" becomes "x*b < a" */
6410 int_frac:
6411 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
6412 y = SCM_FRACTION_NUMERATOR (y);
6413 goto again;
6414 }
0aacf84e 6415 else
8a1f4f98 6416 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 6417 }
0aacf84e
MD
6418 else if (SCM_BIGP (x))
6419 {
e11e83f3 6420 if (SCM_I_INUMP (y))
0aacf84e
MD
6421 {
6422 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6423 scm_remember_upto_here_1 (x);
73e4de09 6424 return scm_from_bool (sgn < 0);
0aacf84e
MD
6425 }
6426 else if (SCM_BIGP (y))
6427 {
6428 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6429 scm_remember_upto_here_2 (x, y);
73e4de09 6430 return scm_from_bool (cmp < 0);
0aacf84e
MD
6431 }
6432 else if (SCM_REALP (y))
6433 {
6434 int cmp;
2e65b52f 6435 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
6436 return SCM_BOOL_F;
6437 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
6438 scm_remember_upto_here_1 (x);
73e4de09 6439 return scm_from_bool (cmp < 0);
0aacf84e 6440 }
f92e85f7 6441 else if (SCM_FRACTIONP (y))
a5f0b599 6442 goto int_frac;
0aacf84e 6443 else
8a1f4f98 6444 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f4c627b3 6445 }
0aacf84e
MD
6446 else if (SCM_REALP (x))
6447 {
e11e83f3
MV
6448 if (SCM_I_INUMP (y))
6449 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
6450 else if (SCM_BIGP (y))
6451 {
6452 int cmp;
2e65b52f 6453 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
6454 return SCM_BOOL_F;
6455 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
6456 scm_remember_upto_here_1 (y);
73e4de09 6457 return scm_from_bool (cmp > 0);
0aacf84e
MD
6458 }
6459 else if (SCM_REALP (y))
73e4de09 6460 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 6461 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6462 {
6463 double xx = SCM_REAL_VALUE (x);
2e65b52f 6464 if (isnan (xx))
a5f0b599 6465 return SCM_BOOL_F;
2e65b52f 6466 if (isinf (xx))
73e4de09 6467 return scm_from_bool (xx < 0.0);
a5f0b599
KR
6468 x = scm_inexact_to_exact (x); /* with x as frac or int */
6469 goto again;
6470 }
f92e85f7 6471 else
8a1f4f98 6472 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, 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
8a1f4f98 6505 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 6506 }
0aacf84e 6507 else
8a1f4f98 6508 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARG1, s_scm_i_num_less_p);
0f2d19dd
JB
6509}
6510
6511
8a1f4f98
AW
6512SCM scm_i_num_gr_p (SCM, SCM, SCM);
6513SCM_PRIMITIVE_GENERIC (scm_i_num_gr_p, ">", 0, 2, 1,
6514 (SCM x, SCM y, SCM rest),
6515 "Return @code{#t} if the list of parameters is monotonically\n"
6516 "decreasing.")
6517#define FUNC_NAME s_scm_i_num_gr_p
6518{
6519 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6520 return SCM_BOOL_T;
6521 while (!scm_is_null (rest))
6522 {
6523 if (scm_is_false (scm_gr_p (x, y)))
6524 return SCM_BOOL_F;
6525 x = y;
6526 y = scm_car (rest);
6527 rest = scm_cdr (rest);
6528 }
6529 return scm_gr_p (x, y);
6530}
6531#undef FUNC_NAME
6532#define FUNC_NAME s_scm_i_num_gr_p
c76b1eaf
MD
6533SCM
6534scm_gr_p (SCM x, SCM y)
0f2d19dd 6535{
c76b1eaf 6536 if (!SCM_NUMBERP (x))
8a1f4f98 6537 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6538 else if (!SCM_NUMBERP (y))
8a1f4f98 6539 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG2, FUNC_NAME);
c76b1eaf
MD
6540 else
6541 return scm_less_p (y, x);
0f2d19dd 6542}
1bbd0b84 6543#undef FUNC_NAME
0f2d19dd
JB
6544
6545
8a1f4f98
AW
6546SCM scm_i_num_leq_p (SCM, SCM, SCM);
6547SCM_PRIMITIVE_GENERIC (scm_i_num_leq_p, "<=", 0, 2, 1,
6548 (SCM x, SCM y, SCM rest),
6549 "Return @code{#t} if the list of parameters is monotonically\n"
6550 "non-decreasing.")
6551#define FUNC_NAME s_scm_i_num_leq_p
6552{
6553 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6554 return SCM_BOOL_T;
6555 while (!scm_is_null (rest))
6556 {
6557 if (scm_is_false (scm_leq_p (x, y)))
6558 return SCM_BOOL_F;
6559 x = y;
6560 y = scm_car (rest);
6561 rest = scm_cdr (rest);
6562 }
6563 return scm_leq_p (x, y);
6564}
6565#undef FUNC_NAME
6566#define FUNC_NAME s_scm_i_num_leq_p
c76b1eaf
MD
6567SCM
6568scm_leq_p (SCM x, SCM y)
0f2d19dd 6569{
c76b1eaf 6570 if (!SCM_NUMBERP (x))
8a1f4f98 6571 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6572 else if (!SCM_NUMBERP (y))
8a1f4f98 6573 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 6574 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 6575 return SCM_BOOL_F;
c76b1eaf 6576 else
73e4de09 6577 return scm_not (scm_less_p (y, x));
0f2d19dd 6578}
1bbd0b84 6579#undef FUNC_NAME
0f2d19dd
JB
6580
6581
8a1f4f98
AW
6582SCM scm_i_num_geq_p (SCM, SCM, SCM);
6583SCM_PRIMITIVE_GENERIC (scm_i_num_geq_p, ">=", 0, 2, 1,
6584 (SCM x, SCM y, SCM rest),
6585 "Return @code{#t} if the list of parameters is monotonically\n"
6586 "non-increasing.")
6587#define FUNC_NAME s_scm_i_num_geq_p
6588{
6589 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6590 return SCM_BOOL_T;
6591 while (!scm_is_null (rest))
6592 {
6593 if (scm_is_false (scm_geq_p (x, y)))
6594 return SCM_BOOL_F;
6595 x = y;
6596 y = scm_car (rest);
6597 rest = scm_cdr (rest);
6598 }
6599 return scm_geq_p (x, y);
6600}
6601#undef FUNC_NAME
6602#define FUNC_NAME s_scm_i_num_geq_p
c76b1eaf
MD
6603SCM
6604scm_geq_p (SCM x, SCM y)
0f2d19dd 6605{
c76b1eaf 6606 if (!SCM_NUMBERP (x))
8a1f4f98 6607 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6608 else if (!SCM_NUMBERP (y))
8a1f4f98 6609 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 6610 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 6611 return SCM_BOOL_F;
c76b1eaf 6612 else
73e4de09 6613 return scm_not (scm_less_p (x, y));
0f2d19dd 6614}
1bbd0b84 6615#undef FUNC_NAME
0f2d19dd
JB
6616
6617
2519490c
MW
6618SCM_PRIMITIVE_GENERIC (scm_zero_p, "zero?", 1, 0, 0,
6619 (SCM z),
6620 "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
6621 "zero.")
6622#define FUNC_NAME s_scm_zero_p
0f2d19dd 6623{
e11e83f3 6624 if (SCM_I_INUMP (z))
bc36d050 6625 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 6626 else if (SCM_BIGP (z))
c2ff8ab0 6627 return SCM_BOOL_F;
0aacf84e 6628 else if (SCM_REALP (z))
73e4de09 6629 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 6630 else if (SCM_COMPLEXP (z))
73e4de09 6631 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 6632 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
6633 else if (SCM_FRACTIONP (z))
6634 return SCM_BOOL_F;
0aacf84e 6635 else
2519490c 6636 SCM_WTA_DISPATCH_1 (g_scm_zero_p, z, SCM_ARG1, s_scm_zero_p);
0f2d19dd 6637}
2519490c 6638#undef FUNC_NAME
0f2d19dd
JB
6639
6640
2519490c
MW
6641SCM_PRIMITIVE_GENERIC (scm_positive_p, "positive?", 1, 0, 0,
6642 (SCM x),
6643 "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
6644 "zero.")
6645#define FUNC_NAME s_scm_positive_p
0f2d19dd 6646{
e11e83f3
MV
6647 if (SCM_I_INUMP (x))
6648 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
6649 else if (SCM_BIGP (x))
6650 {
6651 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6652 scm_remember_upto_here_1 (x);
73e4de09 6653 return scm_from_bool (sgn > 0);
0aacf84e
MD
6654 }
6655 else if (SCM_REALP (x))
73e4de09 6656 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
6657 else if (SCM_FRACTIONP (x))
6658 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 6659 else
2519490c 6660 SCM_WTA_DISPATCH_1 (g_scm_positive_p, x, SCM_ARG1, s_scm_positive_p);
0f2d19dd 6661}
2519490c 6662#undef FUNC_NAME
0f2d19dd
JB
6663
6664
2519490c
MW
6665SCM_PRIMITIVE_GENERIC (scm_negative_p, "negative?", 1, 0, 0,
6666 (SCM x),
6667 "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
6668 "zero.")
6669#define FUNC_NAME s_scm_negative_p
0f2d19dd 6670{
e11e83f3
MV
6671 if (SCM_I_INUMP (x))
6672 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
6673 else if (SCM_BIGP (x))
6674 {
6675 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6676 scm_remember_upto_here_1 (x);
73e4de09 6677 return scm_from_bool (sgn < 0);
0aacf84e
MD
6678 }
6679 else if (SCM_REALP (x))
73e4de09 6680 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
6681 else if (SCM_FRACTIONP (x))
6682 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 6683 else
2519490c 6684 SCM_WTA_DISPATCH_1 (g_scm_negative_p, x, SCM_ARG1, s_scm_negative_p);
0f2d19dd 6685}
2519490c 6686#undef FUNC_NAME
0f2d19dd
JB
6687
6688
2a06f791
KR
6689/* scm_min and scm_max return an inexact when either argument is inexact, as
6690 required by r5rs. On that basis, for exact/inexact combinations the
6691 exact is converted to inexact to compare and possibly return. This is
6692 unlike scm_less_p above which takes some trouble to preserve all bits in
6693 its test, such trouble is not required for min and max. */
6694
78d3deb1
AW
6695SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
6696 (SCM x, SCM y, SCM rest),
6697 "Return the maximum of all parameter values.")
6698#define FUNC_NAME s_scm_i_max
6699{
6700 while (!scm_is_null (rest))
6701 { x = scm_max (x, y);
6702 y = scm_car (rest);
6703 rest = scm_cdr (rest);
6704 }
6705 return scm_max (x, y);
6706}
6707#undef FUNC_NAME
6708
6709#define s_max s_scm_i_max
6710#define g_max g_scm_i_max
6711
0f2d19dd 6712SCM
6e8d25a6 6713scm_max (SCM x, SCM y)
0f2d19dd 6714{
0aacf84e
MD
6715 if (SCM_UNBNDP (y))
6716 {
6717 if (SCM_UNBNDP (x))
6718 SCM_WTA_DISPATCH_0 (g_max, s_max);
e11e83f3 6719 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
6720 return x;
6721 else
6722 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 6723 }
f4c627b3 6724
e11e83f3 6725 if (SCM_I_INUMP (x))
0aacf84e 6726 {
e25f3727 6727 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6728 if (SCM_I_INUMP (y))
0aacf84e 6729 {
e25f3727 6730 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6731 return (xx < yy) ? y : x;
6732 }
6733 else if (SCM_BIGP (y))
6734 {
6735 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6736 scm_remember_upto_here_1 (y);
6737 return (sgn < 0) ? x : y;
6738 }
6739 else if (SCM_REALP (y))
6740 {
2e274311
MW
6741 double xxd = xx;
6742 double yyd = SCM_REAL_VALUE (y);
6743
6744 if (xxd > yyd)
6745 return scm_from_double (xxd);
6746 /* If y is a NaN, then "==" is false and we return the NaN */
6747 else if (SCM_LIKELY (!(xxd == yyd)))
6748 return y;
6749 /* Handle signed zeroes properly */
6750 else if (xx == 0)
6751 return flo0;
6752 else
6753 return y;
0aacf84e 6754 }
f92e85f7
MV
6755 else if (SCM_FRACTIONP (y))
6756 {
e4bc5d6c 6757 use_less:
73e4de09 6758 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 6759 }
0aacf84e
MD
6760 else
6761 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 6762 }
0aacf84e
MD
6763 else if (SCM_BIGP (x))
6764 {
e11e83f3 6765 if (SCM_I_INUMP (y))
0aacf84e
MD
6766 {
6767 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6768 scm_remember_upto_here_1 (x);
6769 return (sgn < 0) ? y : x;
6770 }
6771 else if (SCM_BIGP (y))
6772 {
6773 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6774 scm_remember_upto_here_2 (x, y);
6775 return (cmp > 0) ? x : y;
6776 }
6777 else if (SCM_REALP (y))
6778 {
2a06f791
KR
6779 /* if y==NaN then xx>yy is false, so we return the NaN y */
6780 double xx, yy;
6781 big_real:
6782 xx = scm_i_big2dbl (x);
6783 yy = SCM_REAL_VALUE (y);
55f26379 6784 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 6785 }
f92e85f7
MV
6786 else if (SCM_FRACTIONP (y))
6787 {
e4bc5d6c 6788 goto use_less;
f92e85f7 6789 }
0aacf84e
MD
6790 else
6791 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 6792 }
0aacf84e
MD
6793 else if (SCM_REALP (x))
6794 {
e11e83f3 6795 if (SCM_I_INUMP (y))
0aacf84e 6796 {
2e274311
MW
6797 scm_t_inum yy = SCM_I_INUM (y);
6798 double xxd = SCM_REAL_VALUE (x);
6799 double yyd = yy;
6800
6801 if (yyd > xxd)
6802 return scm_from_double (yyd);
6803 /* If x is a NaN, then "==" is false and we return the NaN */
6804 else if (SCM_LIKELY (!(xxd == yyd)))
6805 return x;
6806 /* Handle signed zeroes properly */
6807 else if (yy == 0)
6808 return flo0;
6809 else
6810 return x;
0aacf84e
MD
6811 }
6812 else if (SCM_BIGP (y))
6813 {
b6f8f763 6814 SCM_SWAP (x, y);
2a06f791 6815 goto big_real;
0aacf84e
MD
6816 }
6817 else if (SCM_REALP (y))
6818 {
0aacf84e 6819 double xx = SCM_REAL_VALUE (x);
2e274311
MW
6820 double yy = SCM_REAL_VALUE (y);
6821
6822 /* For purposes of max: +inf.0 > nan > everything else, per R6RS */
6823 if (xx > yy)
6824 return x;
6825 else if (SCM_LIKELY (xx < yy))
6826 return y;
6827 /* If neither (xx > yy) nor (xx < yy), then
6828 either they're equal or one is a NaN */
6829 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 6830 return DOUBLE_IS_POSITIVE_INFINITY (yy) ? y : x;
2e274311 6831 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 6832 return DOUBLE_IS_POSITIVE_INFINITY (xx) ? x : y;
2e274311
MW
6833 /* xx == yy, but handle signed zeroes properly */
6834 else if (double_is_non_negative_zero (yy))
6835 return y;
6836 else
6837 return x;
0aacf84e 6838 }
f92e85f7
MV
6839 else if (SCM_FRACTIONP (y))
6840 {
6841 double yy = scm_i_fraction2double (y);
6842 double xx = SCM_REAL_VALUE (x);
55f26379 6843 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
6844 }
6845 else
6846 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
6847 }
6848 else if (SCM_FRACTIONP (x))
6849 {
e11e83f3 6850 if (SCM_I_INUMP (y))
f92e85f7 6851 {
e4bc5d6c 6852 goto use_less;
f92e85f7
MV
6853 }
6854 else if (SCM_BIGP (y))
6855 {
e4bc5d6c 6856 goto use_less;
f92e85f7
MV
6857 }
6858 else if (SCM_REALP (y))
6859 {
6860 double xx = scm_i_fraction2double (x);
2e274311
MW
6861 /* if y==NaN then ">" is false, so we return the NaN y */
6862 return (xx > SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
6863 }
6864 else if (SCM_FRACTIONP (y))
6865 {
e4bc5d6c 6866 goto use_less;
f92e85f7 6867 }
0aacf84e
MD
6868 else
6869 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 6870 }
0aacf84e 6871 else
f4c627b3 6872 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
6873}
6874
6875
78d3deb1
AW
6876SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
6877 (SCM x, SCM y, SCM rest),
6878 "Return the minimum of all parameter values.")
6879#define FUNC_NAME s_scm_i_min
6880{
6881 while (!scm_is_null (rest))
6882 { x = scm_min (x, y);
6883 y = scm_car (rest);
6884 rest = scm_cdr (rest);
6885 }
6886 return scm_min (x, y);
6887}
6888#undef FUNC_NAME
6889
6890#define s_min s_scm_i_min
6891#define g_min g_scm_i_min
6892
0f2d19dd 6893SCM
6e8d25a6 6894scm_min (SCM x, SCM y)
0f2d19dd 6895{
0aacf84e
MD
6896 if (SCM_UNBNDP (y))
6897 {
6898 if (SCM_UNBNDP (x))
6899 SCM_WTA_DISPATCH_0 (g_min, s_min);
e11e83f3 6900 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
6901 return x;
6902 else
6903 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 6904 }
f4c627b3 6905
e11e83f3 6906 if (SCM_I_INUMP (x))
0aacf84e 6907 {
e25f3727 6908 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6909 if (SCM_I_INUMP (y))
0aacf84e 6910 {
e25f3727 6911 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6912 return (xx < yy) ? x : y;
6913 }
6914 else if (SCM_BIGP (y))
6915 {
6916 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6917 scm_remember_upto_here_1 (y);
6918 return (sgn < 0) ? y : x;
6919 }
6920 else if (SCM_REALP (y))
6921 {
6922 double z = xx;
6923 /* if y==NaN then "<" is false and we return NaN */
55f26379 6924 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 6925 }
f92e85f7
MV
6926 else if (SCM_FRACTIONP (y))
6927 {
e4bc5d6c 6928 use_less:
73e4de09 6929 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 6930 }
0aacf84e
MD
6931 else
6932 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 6933 }
0aacf84e
MD
6934 else if (SCM_BIGP (x))
6935 {
e11e83f3 6936 if (SCM_I_INUMP (y))
0aacf84e
MD
6937 {
6938 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6939 scm_remember_upto_here_1 (x);
6940 return (sgn < 0) ? x : y;
6941 }
6942 else if (SCM_BIGP (y))
6943 {
6944 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6945 scm_remember_upto_here_2 (x, y);
6946 return (cmp > 0) ? y : x;
6947 }
6948 else if (SCM_REALP (y))
6949 {
2a06f791
KR
6950 /* if y==NaN then xx<yy is false, so we return the NaN y */
6951 double xx, yy;
6952 big_real:
6953 xx = scm_i_big2dbl (x);
6954 yy = SCM_REAL_VALUE (y);
55f26379 6955 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 6956 }
f92e85f7
MV
6957 else if (SCM_FRACTIONP (y))
6958 {
e4bc5d6c 6959 goto use_less;
f92e85f7 6960 }
0aacf84e
MD
6961 else
6962 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 6963 }
0aacf84e
MD
6964 else if (SCM_REALP (x))
6965 {
e11e83f3 6966 if (SCM_I_INUMP (y))
0aacf84e 6967 {
e11e83f3 6968 double z = SCM_I_INUM (y);
0aacf84e 6969 /* if x==NaN then "<" is false and we return NaN */
55f26379 6970 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
6971 }
6972 else if (SCM_BIGP (y))
6973 {
b6f8f763 6974 SCM_SWAP (x, y);
2a06f791 6975 goto big_real;
0aacf84e
MD
6976 }
6977 else if (SCM_REALP (y))
6978 {
0aacf84e 6979 double xx = SCM_REAL_VALUE (x);
2e274311
MW
6980 double yy = SCM_REAL_VALUE (y);
6981
6982 /* For purposes of min: -inf.0 < nan < everything else, per R6RS */
6983 if (xx < yy)
6984 return x;
6985 else if (SCM_LIKELY (xx > yy))
6986 return y;
6987 /* If neither (xx < yy) nor (xx > yy), then
6988 either they're equal or one is a NaN */
6989 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 6990 return DOUBLE_IS_NEGATIVE_INFINITY (yy) ? y : x;
2e274311 6991 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 6992 return DOUBLE_IS_NEGATIVE_INFINITY (xx) ? x : y;
2e274311
MW
6993 /* xx == yy, but handle signed zeroes properly */
6994 else if (double_is_non_negative_zero (xx))
6995 return y;
6996 else
6997 return x;
0aacf84e 6998 }
f92e85f7
MV
6999 else if (SCM_FRACTIONP (y))
7000 {
7001 double yy = scm_i_fraction2double (y);
7002 double xx = SCM_REAL_VALUE (x);
55f26379 7003 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 7004 }
0aacf84e
MD
7005 else
7006 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 7007 }
f92e85f7
MV
7008 else if (SCM_FRACTIONP (x))
7009 {
e11e83f3 7010 if (SCM_I_INUMP (y))
f92e85f7 7011 {
e4bc5d6c 7012 goto use_less;
f92e85f7
MV
7013 }
7014 else if (SCM_BIGP (y))
7015 {
e4bc5d6c 7016 goto use_less;
f92e85f7
MV
7017 }
7018 else if (SCM_REALP (y))
7019 {
7020 double xx = scm_i_fraction2double (x);
2e274311
MW
7021 /* if y==NaN then "<" is false, so we return the NaN y */
7022 return (xx < SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
7023 }
7024 else if (SCM_FRACTIONP (y))
7025 {
e4bc5d6c 7026 goto use_less;
f92e85f7
MV
7027 }
7028 else
78d3deb1 7029 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f92e85f7 7030 }
0aacf84e 7031 else
f4c627b3 7032 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
7033}
7034
7035
8ccd24f7
AW
7036SCM_PRIMITIVE_GENERIC (scm_i_sum, "+", 0, 2, 1,
7037 (SCM x, SCM y, SCM rest),
7038 "Return the sum of all parameter values. Return 0 if called without\n"
7039 "any parameters." )
7040#define FUNC_NAME s_scm_i_sum
7041{
7042 while (!scm_is_null (rest))
7043 { x = scm_sum (x, y);
7044 y = scm_car (rest);
7045 rest = scm_cdr (rest);
7046 }
7047 return scm_sum (x, y);
7048}
7049#undef FUNC_NAME
7050
7051#define s_sum s_scm_i_sum
7052#define g_sum g_scm_i_sum
7053
0f2d19dd 7054SCM
6e8d25a6 7055scm_sum (SCM x, SCM y)
0f2d19dd 7056{
9cc37597 7057 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
7058 {
7059 if (SCM_NUMBERP (x)) return x;
7060 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 7061 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 7062 }
c209c88e 7063
9cc37597 7064 if (SCM_LIKELY (SCM_I_INUMP (x)))
ca46fb90 7065 {
9cc37597 7066 if (SCM_LIKELY (SCM_I_INUMP (y)))
ca46fb90 7067 {
e25f3727
AW
7068 scm_t_inum xx = SCM_I_INUM (x);
7069 scm_t_inum yy = SCM_I_INUM (y);
7070 scm_t_inum z = xx + yy;
7071 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_inum2big (z);
ca46fb90
RB
7072 }
7073 else if (SCM_BIGP (y))
7074 {
7075 SCM_SWAP (x, y);
7076 goto add_big_inum;
7077 }
7078 else if (SCM_REALP (y))
7079 {
e25f3727 7080 scm_t_inum xx = SCM_I_INUM (x);
55f26379 7081 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
7082 }
7083 else if (SCM_COMPLEXP (y))
7084 {
e25f3727 7085 scm_t_inum xx = SCM_I_INUM (x);
8507ec80 7086 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
7087 SCM_COMPLEX_IMAG (y));
7088 }
f92e85f7 7089 else if (SCM_FRACTIONP (y))
cba42c93 7090 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
7091 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
7092 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
7093 else
7094 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
7095 } else if (SCM_BIGP (x))
7096 {
e11e83f3 7097 if (SCM_I_INUMP (y))
0aacf84e 7098 {
e25f3727 7099 scm_t_inum inum;
0aacf84e
MD
7100 int bigsgn;
7101 add_big_inum:
e11e83f3 7102 inum = SCM_I_INUM (y);
0aacf84e
MD
7103 if (inum == 0)
7104 return x;
7105 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
7106 if (inum < 0)
7107 {
7108 SCM result = scm_i_mkbig ();
7109 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
7110 scm_remember_upto_here_1 (x);
7111 /* we know the result will have to be a bignum */
7112 if (bigsgn == -1)
7113 return result;
7114 return scm_i_normbig (result);
7115 }
7116 else
7117 {
7118 SCM result = scm_i_mkbig ();
7119 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
7120 scm_remember_upto_here_1 (x);
7121 /* we know the result will have to be a bignum */
7122 if (bigsgn == 1)
7123 return result;
7124 return scm_i_normbig (result);
7125 }
7126 }
7127 else if (SCM_BIGP (y))
7128 {
7129 SCM result = scm_i_mkbig ();
7130 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
7131 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7132 mpz_add (SCM_I_BIG_MPZ (result),
7133 SCM_I_BIG_MPZ (x),
7134 SCM_I_BIG_MPZ (y));
7135 scm_remember_upto_here_2 (x, y);
7136 /* we know the result will have to be a bignum */
7137 if (sgn_x == sgn_y)
7138 return result;
7139 return scm_i_normbig (result);
7140 }
7141 else if (SCM_REALP (y))
7142 {
7143 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
7144 scm_remember_upto_here_1 (x);
55f26379 7145 return scm_from_double (result);
0aacf84e
MD
7146 }
7147 else if (SCM_COMPLEXP (y))
7148 {
7149 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
7150 + SCM_COMPLEX_REAL (y));
7151 scm_remember_upto_here_1 (x);
8507ec80 7152 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 7153 }
f92e85f7 7154 else if (SCM_FRACTIONP (y))
cba42c93 7155 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
7156 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
7157 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7158 else
7159 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 7160 }
0aacf84e
MD
7161 else if (SCM_REALP (x))
7162 {
e11e83f3 7163 if (SCM_I_INUMP (y))
55f26379 7164 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
7165 else if (SCM_BIGP (y))
7166 {
7167 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
7168 scm_remember_upto_here_1 (y);
55f26379 7169 return scm_from_double (result);
0aacf84e
MD
7170 }
7171 else if (SCM_REALP (y))
55f26379 7172 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 7173 else if (SCM_COMPLEXP (y))
8507ec80 7174 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 7175 SCM_COMPLEX_IMAG (y));
f92e85f7 7176 else if (SCM_FRACTIONP (y))
55f26379 7177 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
7178 else
7179 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 7180 }
0aacf84e
MD
7181 else if (SCM_COMPLEXP (x))
7182 {
e11e83f3 7183 if (SCM_I_INUMP (y))
8507ec80 7184 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
7185 SCM_COMPLEX_IMAG (x));
7186 else if (SCM_BIGP (y))
7187 {
7188 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
7189 + SCM_COMPLEX_REAL (x));
7190 scm_remember_upto_here_1 (y);
8507ec80 7191 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
7192 }
7193 else if (SCM_REALP (y))
8507ec80 7194 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
7195 SCM_COMPLEX_IMAG (x));
7196 else if (SCM_COMPLEXP (y))
8507ec80 7197 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 7198 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 7199 else if (SCM_FRACTIONP (y))
8507ec80 7200 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
7201 SCM_COMPLEX_IMAG (x));
7202 else
7203 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
7204 }
7205 else if (SCM_FRACTIONP (x))
7206 {
e11e83f3 7207 if (SCM_I_INUMP (y))
cba42c93 7208 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7209 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
7210 SCM_FRACTION_DENOMINATOR (x));
7211 else if (SCM_BIGP (y))
cba42c93 7212 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7213 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
7214 SCM_FRACTION_DENOMINATOR (x));
7215 else if (SCM_REALP (y))
55f26379 7216 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 7217 else if (SCM_COMPLEXP (y))
8507ec80 7218 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
7219 SCM_COMPLEX_IMAG (y));
7220 else if (SCM_FRACTIONP (y))
7221 /* a/b + c/d = (ad + bc) / bd */
cba42c93 7222 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7223 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
7224 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
7225 else
7226 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 7227 }
0aacf84e 7228 else
98cb6e75 7229 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
7230}
7231
7232
40882e3d
KR
7233SCM_DEFINE (scm_oneplus, "1+", 1, 0, 0,
7234 (SCM x),
7235 "Return @math{@var{x}+1}.")
7236#define FUNC_NAME s_scm_oneplus
7237{
cff5fa33 7238 return scm_sum (x, SCM_INUM1);
40882e3d
KR
7239}
7240#undef FUNC_NAME
7241
7242
78d3deb1
AW
7243SCM_PRIMITIVE_GENERIC (scm_i_difference, "-", 0, 2, 1,
7244 (SCM x, SCM y, SCM rest),
7245 "If called with one argument @var{z1}, -@var{z1} returned. Otherwise\n"
7246 "the sum of all but the first argument are subtracted from the first\n"
7247 "argument.")
7248#define FUNC_NAME s_scm_i_difference
7249{
7250 while (!scm_is_null (rest))
7251 { x = scm_difference (x, y);
7252 y = scm_car (rest);
7253 rest = scm_cdr (rest);
7254 }
7255 return scm_difference (x, y);
7256}
7257#undef FUNC_NAME
7258
7259#define s_difference s_scm_i_difference
7260#define g_difference g_scm_i_difference
7261
0f2d19dd 7262SCM
6e8d25a6 7263scm_difference (SCM x, SCM y)
78d3deb1 7264#define FUNC_NAME s_difference
0f2d19dd 7265{
9cc37597 7266 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
7267 {
7268 if (SCM_UNBNDP (x))
7269 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
7270 else
e11e83f3 7271 if (SCM_I_INUMP (x))
ca46fb90 7272 {
e25f3727 7273 scm_t_inum xx = -SCM_I_INUM (x);
ca46fb90 7274 if (SCM_FIXABLE (xx))
d956fa6f 7275 return SCM_I_MAKINUM (xx);
ca46fb90 7276 else
e25f3727 7277 return scm_i_inum2big (xx);
ca46fb90
RB
7278 }
7279 else if (SCM_BIGP (x))
a9ad4847
KR
7280 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
7281 bignum, but negating that gives a fixnum. */
ca46fb90
RB
7282 return scm_i_normbig (scm_i_clonebig (x, 0));
7283 else if (SCM_REALP (x))
55f26379 7284 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 7285 else if (SCM_COMPLEXP (x))
8507ec80 7286 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 7287 -SCM_COMPLEX_IMAG (x));
f92e85f7 7288 else if (SCM_FRACTIONP (x))
cba42c93 7289 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 7290 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
7291 else
7292 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 7293 }
ca46fb90 7294
9cc37597 7295 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7296 {
9cc37597 7297 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7298 {
e25f3727
AW
7299 scm_t_inum xx = SCM_I_INUM (x);
7300 scm_t_inum yy = SCM_I_INUM (y);
7301 scm_t_inum z = xx - yy;
0aacf84e 7302 if (SCM_FIXABLE (z))
d956fa6f 7303 return SCM_I_MAKINUM (z);
0aacf84e 7304 else
e25f3727 7305 return scm_i_inum2big (z);
0aacf84e
MD
7306 }
7307 else if (SCM_BIGP (y))
7308 {
7309 /* inum-x - big-y */
e25f3727 7310 scm_t_inum xx = SCM_I_INUM (x);
ca46fb90 7311
0aacf84e 7312 if (xx == 0)
b5c40589
MW
7313 {
7314 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
7315 bignum, but negating that gives a fixnum. */
7316 return scm_i_normbig (scm_i_clonebig (y, 0));
7317 }
0aacf84e
MD
7318 else
7319 {
7320 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7321 SCM result = scm_i_mkbig ();
ca46fb90 7322
0aacf84e
MD
7323 if (xx >= 0)
7324 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
7325 else
7326 {
7327 /* x - y == -(y + -x) */
7328 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
7329 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
7330 }
7331 scm_remember_upto_here_1 (y);
ca46fb90 7332
0aacf84e
MD
7333 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
7334 /* we know the result will have to be a bignum */
7335 return result;
7336 else
7337 return scm_i_normbig (result);
7338 }
7339 }
7340 else if (SCM_REALP (y))
7341 {
e25f3727 7342 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
7343
7344 /*
7345 * We need to handle x == exact 0
7346 * specially because R6RS states that:
7347 * (- 0.0) ==> -0.0 and
7348 * (- 0.0 0.0) ==> 0.0
7349 * and the scheme compiler changes
7350 * (- 0.0) into (- 0 0.0)
7351 * So we need to treat (- 0 0.0) like (- 0.0).
7352 * At the C level, (-x) is different than (0.0 - x).
7353 * (0.0 - 0.0) ==> 0.0, but (- 0.0) ==> -0.0.
7354 */
7355 if (xx == 0)
7356 return scm_from_double (- SCM_REAL_VALUE (y));
7357 else
7358 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
7359 }
7360 else if (SCM_COMPLEXP (y))
7361 {
e25f3727 7362 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
7363
7364 /* We need to handle x == exact 0 specially.
7365 See the comment above (for SCM_REALP (y)) */
7366 if (xx == 0)
7367 return scm_c_make_rectangular (- SCM_COMPLEX_REAL (y),
7368 - SCM_COMPLEX_IMAG (y));
7369 else
7370 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
7371 - SCM_COMPLEX_IMAG (y));
0aacf84e 7372 }
f92e85f7
MV
7373 else if (SCM_FRACTIONP (y))
7374 /* a - b/c = (ac - b) / c */
cba42c93 7375 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7376 SCM_FRACTION_NUMERATOR (y)),
7377 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7378 else
7379 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 7380 }
0aacf84e
MD
7381 else if (SCM_BIGP (x))
7382 {
e11e83f3 7383 if (SCM_I_INUMP (y))
0aacf84e
MD
7384 {
7385 /* big-x - inum-y */
e25f3727 7386 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e 7387 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 7388
0aacf84e
MD
7389 scm_remember_upto_here_1 (x);
7390 if (sgn_x == 0)
c71b0706 7391 return (SCM_FIXABLE (-yy) ?
e25f3727 7392 SCM_I_MAKINUM (-yy) : scm_from_inum (-yy));
0aacf84e
MD
7393 else
7394 {
7395 SCM result = scm_i_mkbig ();
ca46fb90 7396
708f22c6
KR
7397 if (yy >= 0)
7398 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
7399 else
7400 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 7401 scm_remember_upto_here_1 (x);
ca46fb90 7402
0aacf84e
MD
7403 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
7404 /* we know the result will have to be a bignum */
7405 return result;
7406 else
7407 return scm_i_normbig (result);
7408 }
7409 }
7410 else if (SCM_BIGP (y))
7411 {
7412 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
7413 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7414 SCM result = scm_i_mkbig ();
7415 mpz_sub (SCM_I_BIG_MPZ (result),
7416 SCM_I_BIG_MPZ (x),
7417 SCM_I_BIG_MPZ (y));
7418 scm_remember_upto_here_2 (x, y);
7419 /* we know the result will have to be a bignum */
7420 if ((sgn_x == 1) && (sgn_y == -1))
7421 return result;
7422 if ((sgn_x == -1) && (sgn_y == 1))
7423 return result;
7424 return scm_i_normbig (result);
7425 }
7426 else if (SCM_REALP (y))
7427 {
7428 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
7429 scm_remember_upto_here_1 (x);
55f26379 7430 return scm_from_double (result);
0aacf84e
MD
7431 }
7432 else if (SCM_COMPLEXP (y))
7433 {
7434 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
7435 - SCM_COMPLEX_REAL (y));
7436 scm_remember_upto_here_1 (x);
8507ec80 7437 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 7438 }
f92e85f7 7439 else if (SCM_FRACTIONP (y))
cba42c93 7440 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7441 SCM_FRACTION_NUMERATOR (y)),
7442 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 7443 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 7444 }
0aacf84e
MD
7445 else if (SCM_REALP (x))
7446 {
e11e83f3 7447 if (SCM_I_INUMP (y))
55f26379 7448 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
7449 else if (SCM_BIGP (y))
7450 {
7451 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
7452 scm_remember_upto_here_1 (x);
55f26379 7453 return scm_from_double (result);
0aacf84e
MD
7454 }
7455 else if (SCM_REALP (y))
55f26379 7456 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 7457 else if (SCM_COMPLEXP (y))
8507ec80 7458 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 7459 -SCM_COMPLEX_IMAG (y));
f92e85f7 7460 else if (SCM_FRACTIONP (y))
55f26379 7461 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
7462 else
7463 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 7464 }
0aacf84e
MD
7465 else if (SCM_COMPLEXP (x))
7466 {
e11e83f3 7467 if (SCM_I_INUMP (y))
8507ec80 7468 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
7469 SCM_COMPLEX_IMAG (x));
7470 else if (SCM_BIGP (y))
7471 {
7472 double real_part = (SCM_COMPLEX_REAL (x)
7473 - mpz_get_d (SCM_I_BIG_MPZ (y)));
7474 scm_remember_upto_here_1 (x);
8507ec80 7475 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
7476 }
7477 else if (SCM_REALP (y))
8507ec80 7478 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
7479 SCM_COMPLEX_IMAG (x));
7480 else if (SCM_COMPLEXP (y))
8507ec80 7481 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 7482 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 7483 else if (SCM_FRACTIONP (y))
8507ec80 7484 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
7485 SCM_COMPLEX_IMAG (x));
7486 else
7487 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
7488 }
7489 else if (SCM_FRACTIONP (x))
7490 {
e11e83f3 7491 if (SCM_I_INUMP (y))
f92e85f7 7492 /* a/b - c = (a - cb) / b */
cba42c93 7493 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7494 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
7495 SCM_FRACTION_DENOMINATOR (x));
7496 else if (SCM_BIGP (y))
cba42c93 7497 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7498 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
7499 SCM_FRACTION_DENOMINATOR (x));
7500 else if (SCM_REALP (y))
55f26379 7501 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 7502 else if (SCM_COMPLEXP (y))
8507ec80 7503 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
7504 -SCM_COMPLEX_IMAG (y));
7505 else if (SCM_FRACTIONP (y))
7506 /* a/b - c/d = (ad - bc) / bd */
cba42c93 7507 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7508 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
7509 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
7510 else
7511 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 7512 }
0aacf84e 7513 else
98cb6e75 7514 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 7515}
c05e97b7 7516#undef FUNC_NAME
0f2d19dd 7517
ca46fb90 7518
40882e3d
KR
7519SCM_DEFINE (scm_oneminus, "1-", 1, 0, 0,
7520 (SCM x),
7521 "Return @math{@var{x}-1}.")
7522#define FUNC_NAME s_scm_oneminus
7523{
cff5fa33 7524 return scm_difference (x, SCM_INUM1);
40882e3d
KR
7525}
7526#undef FUNC_NAME
7527
7528
78d3deb1
AW
7529SCM_PRIMITIVE_GENERIC (scm_i_product, "*", 0, 2, 1,
7530 (SCM x, SCM y, SCM rest),
7531 "Return the product of all arguments. If called without arguments,\n"
7532 "1 is returned.")
7533#define FUNC_NAME s_scm_i_product
7534{
7535 while (!scm_is_null (rest))
7536 { x = scm_product (x, y);
7537 y = scm_car (rest);
7538 rest = scm_cdr (rest);
7539 }
7540 return scm_product (x, y);
7541}
7542#undef FUNC_NAME
7543
7544#define s_product s_scm_i_product
7545#define g_product g_scm_i_product
7546
0f2d19dd 7547SCM
6e8d25a6 7548scm_product (SCM x, SCM y)
0f2d19dd 7549{
9cc37597 7550 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
7551 {
7552 if (SCM_UNBNDP (x))
d956fa6f 7553 return SCM_I_MAKINUM (1L);
0aacf84e
MD
7554 else if (SCM_NUMBERP (x))
7555 return x;
7556 else
7557 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 7558 }
ca46fb90 7559
9cc37597 7560 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7561 {
e25f3727 7562 scm_t_inum xx;
f4c627b3 7563
5e791807 7564 xinum:
e11e83f3 7565 xx = SCM_I_INUM (x);
f4c627b3 7566
0aacf84e
MD
7567 switch (xx)
7568 {
5e791807
MW
7569 case 1:
7570 /* exact1 is the universal multiplicative identity */
7571 return y;
7572 break;
7573 case 0:
7574 /* exact0 times a fixnum is exact0: optimize this case */
7575 if (SCM_LIKELY (SCM_I_INUMP (y)))
7576 return SCM_INUM0;
7577 /* if the other argument is inexact, the result is inexact,
7578 and we must do the multiplication in order to handle
7579 infinities and NaNs properly. */
7580 else if (SCM_REALP (y))
7581 return scm_from_double (0.0 * SCM_REAL_VALUE (y));
7582 else if (SCM_COMPLEXP (y))
7583 return scm_c_make_rectangular (0.0 * SCM_COMPLEX_REAL (y),
7584 0.0 * SCM_COMPLEX_IMAG (y));
7585 /* we've already handled inexact numbers,
7586 so y must be exact, and we return exact0 */
7587 else if (SCM_NUMP (y))
7588 return SCM_INUM0;
7589 else
7590 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
7591 break;
7592 case -1:
b5c40589 7593 /*
5e791807
MW
7594 * This case is important for more than just optimization.
7595 * It handles the case of negating
b5c40589
MW
7596 * (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
7597 * which is a bignum that must be changed back into a fixnum.
7598 * Failure to do so will cause the following to return #f:
7599 * (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
7600 */
b5c40589
MW
7601 return scm_difference(y, SCM_UNDEFINED);
7602 break;
0aacf84e 7603 }
f4c627b3 7604
9cc37597 7605 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7606 {
e25f3727
AW
7607 scm_t_inum yy = SCM_I_INUM (y);
7608 scm_t_inum kk = xx * yy;
d956fa6f 7609 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 7610 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
7611 return k;
7612 else
7613 {
e25f3727 7614 SCM result = scm_i_inum2big (xx);
0aacf84e
MD
7615 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
7616 return scm_i_normbig (result);
7617 }
7618 }
7619 else if (SCM_BIGP (y))
7620 {
7621 SCM result = scm_i_mkbig ();
7622 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
7623 scm_remember_upto_here_1 (y);
7624 return result;
7625 }
7626 else if (SCM_REALP (y))
55f26379 7627 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 7628 else if (SCM_COMPLEXP (y))
8507ec80 7629 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 7630 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 7631 else if (SCM_FRACTIONP (y))
cba42c93 7632 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 7633 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7634 else
7635 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7636 }
0aacf84e
MD
7637 else if (SCM_BIGP (x))
7638 {
e11e83f3 7639 if (SCM_I_INUMP (y))
0aacf84e
MD
7640 {
7641 SCM_SWAP (x, y);
5e791807 7642 goto xinum;
0aacf84e
MD
7643 }
7644 else if (SCM_BIGP (y))
7645 {
7646 SCM result = scm_i_mkbig ();
7647 mpz_mul (SCM_I_BIG_MPZ (result),
7648 SCM_I_BIG_MPZ (x),
7649 SCM_I_BIG_MPZ (y));
7650 scm_remember_upto_here_2 (x, y);
7651 return result;
7652 }
7653 else if (SCM_REALP (y))
7654 {
7655 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
7656 scm_remember_upto_here_1 (x);
55f26379 7657 return scm_from_double (result);
0aacf84e
MD
7658 }
7659 else if (SCM_COMPLEXP (y))
7660 {
7661 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
7662 scm_remember_upto_here_1 (x);
8507ec80 7663 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
7664 z * SCM_COMPLEX_IMAG (y));
7665 }
f92e85f7 7666 else if (SCM_FRACTIONP (y))
cba42c93 7667 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 7668 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7669 else
7670 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7671 }
0aacf84e
MD
7672 else if (SCM_REALP (x))
7673 {
e11e83f3 7674 if (SCM_I_INUMP (y))
5e791807
MW
7675 {
7676 SCM_SWAP (x, y);
7677 goto xinum;
7678 }
0aacf84e
MD
7679 else if (SCM_BIGP (y))
7680 {
7681 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
7682 scm_remember_upto_here_1 (y);
55f26379 7683 return scm_from_double (result);
0aacf84e
MD
7684 }
7685 else if (SCM_REALP (y))
55f26379 7686 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 7687 else if (SCM_COMPLEXP (y))
8507ec80 7688 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 7689 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 7690 else if (SCM_FRACTIONP (y))
55f26379 7691 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
7692 else
7693 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7694 }
0aacf84e
MD
7695 else if (SCM_COMPLEXP (x))
7696 {
e11e83f3 7697 if (SCM_I_INUMP (y))
5e791807
MW
7698 {
7699 SCM_SWAP (x, y);
7700 goto xinum;
7701 }
0aacf84e
MD
7702 else if (SCM_BIGP (y))
7703 {
7704 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
7705 scm_remember_upto_here_1 (y);
8507ec80 7706 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 7707 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
7708 }
7709 else if (SCM_REALP (y))
8507ec80 7710 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
7711 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
7712 else if (SCM_COMPLEXP (y))
7713 {
8507ec80 7714 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
7715 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
7716 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
7717 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
7718 }
f92e85f7
MV
7719 else if (SCM_FRACTIONP (y))
7720 {
7721 double yy = scm_i_fraction2double (y);
8507ec80 7722 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
7723 yy * SCM_COMPLEX_IMAG (x));
7724 }
7725 else
7726 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
7727 }
7728 else if (SCM_FRACTIONP (x))
7729 {
e11e83f3 7730 if (SCM_I_INUMP (y))
cba42c93 7731 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
7732 SCM_FRACTION_DENOMINATOR (x));
7733 else if (SCM_BIGP (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_REALP (y))
55f26379 7737 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
7738 else if (SCM_COMPLEXP (y))
7739 {
7740 double xx = scm_i_fraction2double (x);
8507ec80 7741 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
7742 xx * SCM_COMPLEX_IMAG (y));
7743 }
7744 else if (SCM_FRACTIONP (y))
7745 /* a/b * c/d = ac / bd */
cba42c93 7746 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7747 SCM_FRACTION_NUMERATOR (y)),
7748 scm_product (SCM_FRACTION_DENOMINATOR (x),
7749 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
7750 else
7751 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7752 }
0aacf84e 7753 else
f4c627b3 7754 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
7755}
7756
7351e207
MV
7757#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
7758 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
7759#define ALLOW_DIVIDE_BY_ZERO
7760/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
7761#endif
0f2d19dd 7762
ba74ef4e
MV
7763/* The code below for complex division is adapted from the GNU
7764 libstdc++, which adapted it from f2c's libF77, and is subject to
7765 this copyright: */
7766
7767/****************************************************************
7768Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
7769
7770Permission to use, copy, modify, and distribute this software
7771and its documentation for any purpose and without fee is hereby
7772granted, provided that the above copyright notice appear in all
7773copies and that both that the copyright notice and this
7774permission notice and warranty disclaimer appear in supporting
7775documentation, and that the names of AT&T Bell Laboratories or
7776Bellcore or any of their entities not be used in advertising or
7777publicity pertaining to distribution of the software without
7778specific, written prior permission.
7779
7780AT&T and Bellcore disclaim all warranties with regard to this
7781software, including all implied warranties of merchantability
7782and fitness. In no event shall AT&T or Bellcore be liable for
7783any special, indirect or consequential damages or any damages
7784whatsoever resulting from loss of use, data or profits, whether
7785in an action of contract, negligence or other tortious action,
7786arising out of or in connection with the use or performance of
7787this software.
7788****************************************************************/
7789
78d3deb1
AW
7790SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
7791 (SCM x, SCM y, SCM rest),
7792 "Divide the first argument by the product of the remaining\n"
7793 "arguments. If called with one argument @var{z1}, 1/@var{z1} is\n"
7794 "returned.")
7795#define FUNC_NAME s_scm_i_divide
7796{
7797 while (!scm_is_null (rest))
7798 { x = scm_divide (x, y);
7799 y = scm_car (rest);
7800 rest = scm_cdr (rest);
7801 }
7802 return scm_divide (x, y);
7803}
7804#undef FUNC_NAME
7805
7806#define s_divide s_scm_i_divide
7807#define g_divide g_scm_i_divide
7808
f92e85f7 7809static SCM
78d3deb1
AW
7810do_divide (SCM x, SCM y, int inexact)
7811#define FUNC_NAME s_divide
0f2d19dd 7812{
f8de44c1
DH
7813 double a;
7814
9cc37597 7815 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
7816 {
7817 if (SCM_UNBNDP (x))
7818 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 7819 else if (SCM_I_INUMP (x))
0aacf84e 7820 {
e25f3727 7821 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
7822 if (xx == 1 || xx == -1)
7823 return x;
7351e207 7824#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
7825 else if (xx == 0)
7826 scm_num_overflow (s_divide);
7351e207 7827#endif
0aacf84e 7828 else
f92e85f7
MV
7829 {
7830 if (inexact)
55f26379 7831 return scm_from_double (1.0 / (double) xx);
cff5fa33 7832 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 7833 }
0aacf84e
MD
7834 }
7835 else if (SCM_BIGP (x))
f92e85f7
MV
7836 {
7837 if (inexact)
55f26379 7838 return scm_from_double (1.0 / scm_i_big2dbl (x));
cff5fa33 7839 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 7840 }
0aacf84e
MD
7841 else if (SCM_REALP (x))
7842 {
7843 double xx = SCM_REAL_VALUE (x);
7351e207 7844#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
7845 if (xx == 0.0)
7846 scm_num_overflow (s_divide);
7847 else
7351e207 7848#endif
55f26379 7849 return scm_from_double (1.0 / xx);
0aacf84e
MD
7850 }
7851 else if (SCM_COMPLEXP (x))
7852 {
7853 double r = SCM_COMPLEX_REAL (x);
7854 double i = SCM_COMPLEX_IMAG (x);
4c6e36a6 7855 if (fabs(r) <= fabs(i))
0aacf84e
MD
7856 {
7857 double t = r / i;
7858 double d = i * (1.0 + t * t);
8507ec80 7859 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
7860 }
7861 else
7862 {
7863 double t = i / r;
7864 double d = r * (1.0 + t * t);
8507ec80 7865 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
7866 }
7867 }
f92e85f7 7868 else if (SCM_FRACTIONP (x))
cba42c93 7869 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 7870 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
7871 else
7872 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 7873 }
f8de44c1 7874
9cc37597 7875 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7876 {
e25f3727 7877 scm_t_inum xx = SCM_I_INUM (x);
9cc37597 7878 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7879 {
e25f3727 7880 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
7881 if (yy == 0)
7882 {
7351e207 7883#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 7884 scm_num_overflow (s_divide);
7351e207 7885#else
55f26379 7886 return scm_from_double ((double) xx / (double) yy);
7351e207 7887#endif
0aacf84e
MD
7888 }
7889 else if (xx % yy != 0)
f92e85f7
MV
7890 {
7891 if (inexact)
55f26379 7892 return scm_from_double ((double) xx / (double) yy);
cba42c93 7893 else return scm_i_make_ratio (x, y);
f92e85f7 7894 }
0aacf84e
MD
7895 else
7896 {
e25f3727 7897 scm_t_inum z = xx / yy;
0aacf84e 7898 if (SCM_FIXABLE (z))
d956fa6f 7899 return SCM_I_MAKINUM (z);
0aacf84e 7900 else
e25f3727 7901 return scm_i_inum2big (z);
0aacf84e 7902 }
f872b822 7903 }
0aacf84e 7904 else if (SCM_BIGP (y))
f92e85f7
MV
7905 {
7906 if (inexact)
55f26379 7907 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 7908 else return scm_i_make_ratio (x, y);
f92e85f7 7909 }
0aacf84e
MD
7910 else if (SCM_REALP (y))
7911 {
7912 double yy = SCM_REAL_VALUE (y);
7351e207 7913#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
7914 if (yy == 0.0)
7915 scm_num_overflow (s_divide);
7916 else
7351e207 7917#endif
55f26379 7918 return scm_from_double ((double) xx / yy);
ba74ef4e 7919 }
0aacf84e
MD
7920 else if (SCM_COMPLEXP (y))
7921 {
7922 a = xx;
7923 complex_div: /* y _must_ be a complex number */
7924 {
7925 double r = SCM_COMPLEX_REAL (y);
7926 double i = SCM_COMPLEX_IMAG (y);
4c6e36a6 7927 if (fabs(r) <= fabs(i))
0aacf84e
MD
7928 {
7929 double t = r / i;
7930 double d = i * (1.0 + t * t);
8507ec80 7931 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
7932 }
7933 else
7934 {
7935 double t = i / r;
7936 double d = r * (1.0 + t * t);
8507ec80 7937 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
7938 }
7939 }
7940 }
f92e85f7
MV
7941 else if (SCM_FRACTIONP (y))
7942 /* a / b/c = ac / b */
cba42c93 7943 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 7944 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
7945 else
7946 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 7947 }
0aacf84e
MD
7948 else if (SCM_BIGP (x))
7949 {
e11e83f3 7950 if (SCM_I_INUMP (y))
0aacf84e 7951 {
e25f3727 7952 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
7953 if (yy == 0)
7954 {
7351e207 7955#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 7956 scm_num_overflow (s_divide);
7351e207 7957#else
0aacf84e
MD
7958 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
7959 scm_remember_upto_here_1 (x);
7960 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 7961#endif
0aacf84e
MD
7962 }
7963 else if (yy == 1)
7964 return x;
7965 else
7966 {
7967 /* FIXME: HMM, what are the relative performance issues here?
7968 We need to test. Is it faster on average to test
7969 divisible_p, then perform whichever operation, or is it
7970 faster to perform the integer div opportunistically and
7971 switch to real if there's a remainder? For now we take the
7972 middle ground: test, then if divisible, use the faster div
7973 func. */
7974
e25f3727 7975 scm_t_inum abs_yy = yy < 0 ? -yy : yy;
0aacf84e
MD
7976 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
7977
7978 if (divisible_p)
7979 {
7980 SCM result = scm_i_mkbig ();
7981 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
7982 scm_remember_upto_here_1 (x);
7983 if (yy < 0)
7984 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
7985 return scm_i_normbig (result);
7986 }
7987 else
f92e85f7
MV
7988 {
7989 if (inexact)
55f26379 7990 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 7991 else return scm_i_make_ratio (x, y);
f92e85f7 7992 }
0aacf84e
MD
7993 }
7994 }
7995 else if (SCM_BIGP (y))
7996 {
a4955a04
MW
7997 /* big_x / big_y */
7998 if (inexact)
0aacf84e 7999 {
a4955a04
MW
8000 /* It's easily possible for the ratio x/y to fit a double
8001 but one or both x and y be too big to fit a double,
8002 hence the use of mpq_get_d rather than converting and
8003 dividing. */
8004 mpq_t q;
8005 *mpq_numref(q) = *SCM_I_BIG_MPZ (x);
8006 *mpq_denref(q) = *SCM_I_BIG_MPZ (y);
8007 return scm_from_double (mpq_get_d (q));
0aacf84e
MD
8008 }
8009 else
8010 {
a4955a04
MW
8011 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
8012 SCM_I_BIG_MPZ (y));
8013 if (divisible_p)
8014 {
8015 SCM result = scm_i_mkbig ();
8016 mpz_divexact (SCM_I_BIG_MPZ (result),
8017 SCM_I_BIG_MPZ (x),
8018 SCM_I_BIG_MPZ (y));
8019 scm_remember_upto_here_2 (x, y);
8020 return scm_i_normbig (result);
8021 }
8022 else
8023 return scm_i_make_ratio (x, y);
0aacf84e
MD
8024 }
8025 }
8026 else if (SCM_REALP (y))
8027 {
8028 double yy = SCM_REAL_VALUE (y);
7351e207 8029#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8030 if (yy == 0.0)
8031 scm_num_overflow (s_divide);
8032 else
7351e207 8033#endif
55f26379 8034 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
8035 }
8036 else if (SCM_COMPLEXP (y))
8037 {
8038 a = scm_i_big2dbl (x);
8039 goto complex_div;
8040 }
f92e85f7 8041 else if (SCM_FRACTIONP (y))
cba42c93 8042 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 8043 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
8044 else
8045 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 8046 }
0aacf84e
MD
8047 else if (SCM_REALP (x))
8048 {
8049 double rx = SCM_REAL_VALUE (x);
e11e83f3 8050 if (SCM_I_INUMP (y))
0aacf84e 8051 {
e25f3727 8052 scm_t_inum yy = SCM_I_INUM (y);
7351e207 8053#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
8054 if (yy == 0)
8055 scm_num_overflow (s_divide);
8056 else
7351e207 8057#endif
55f26379 8058 return scm_from_double (rx / (double) yy);
0aacf84e
MD
8059 }
8060 else if (SCM_BIGP (y))
8061 {
8062 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
8063 scm_remember_upto_here_1 (y);
55f26379 8064 return scm_from_double (rx / dby);
0aacf84e
MD
8065 }
8066 else if (SCM_REALP (y))
8067 {
8068 double yy = SCM_REAL_VALUE (y);
7351e207 8069#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8070 if (yy == 0.0)
8071 scm_num_overflow (s_divide);
8072 else
7351e207 8073#endif
55f26379 8074 return scm_from_double (rx / yy);
0aacf84e
MD
8075 }
8076 else if (SCM_COMPLEXP (y))
8077 {
8078 a = rx;
8079 goto complex_div;
8080 }
f92e85f7 8081 else if (SCM_FRACTIONP (y))
55f26379 8082 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
8083 else
8084 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 8085 }
0aacf84e
MD
8086 else if (SCM_COMPLEXP (x))
8087 {
8088 double rx = SCM_COMPLEX_REAL (x);
8089 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 8090 if (SCM_I_INUMP (y))
0aacf84e 8091 {
e25f3727 8092 scm_t_inum yy = SCM_I_INUM (y);
7351e207 8093#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
8094 if (yy == 0)
8095 scm_num_overflow (s_divide);
8096 else
7351e207 8097#endif
0aacf84e
MD
8098 {
8099 double d = yy;
8507ec80 8100 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
8101 }
8102 }
8103 else if (SCM_BIGP (y))
8104 {
8105 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
8106 scm_remember_upto_here_1 (y);
8507ec80 8107 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
8108 }
8109 else if (SCM_REALP (y))
8110 {
8111 double yy = SCM_REAL_VALUE (y);
7351e207 8112#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8113 if (yy == 0.0)
8114 scm_num_overflow (s_divide);
8115 else
7351e207 8116#endif
8507ec80 8117 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
8118 }
8119 else if (SCM_COMPLEXP (y))
8120 {
8121 double ry = SCM_COMPLEX_REAL (y);
8122 double iy = SCM_COMPLEX_IMAG (y);
4c6e36a6 8123 if (fabs(ry) <= fabs(iy))
0aacf84e
MD
8124 {
8125 double t = ry / iy;
8126 double d = iy * (1.0 + t * t);
8507ec80 8127 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
8128 }
8129 else
8130 {
8131 double t = iy / ry;
8132 double d = ry * (1.0 + t * t);
8507ec80 8133 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
8134 }
8135 }
f92e85f7
MV
8136 else if (SCM_FRACTIONP (y))
8137 {
8138 double yy = scm_i_fraction2double (y);
8507ec80 8139 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 8140 }
0aacf84e
MD
8141 else
8142 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 8143 }
f92e85f7
MV
8144 else if (SCM_FRACTIONP (x))
8145 {
e11e83f3 8146 if (SCM_I_INUMP (y))
f92e85f7 8147 {
e25f3727 8148 scm_t_inum yy = SCM_I_INUM (y);
f92e85f7
MV
8149#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
8150 if (yy == 0)
8151 scm_num_overflow (s_divide);
8152 else
8153#endif
cba42c93 8154 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
8155 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
8156 }
8157 else if (SCM_BIGP (y))
8158 {
cba42c93 8159 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
8160 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
8161 }
8162 else if (SCM_REALP (y))
8163 {
8164 double yy = SCM_REAL_VALUE (y);
8165#ifndef ALLOW_DIVIDE_BY_ZERO
8166 if (yy == 0.0)
8167 scm_num_overflow (s_divide);
8168 else
8169#endif
55f26379 8170 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
8171 }
8172 else if (SCM_COMPLEXP (y))
8173 {
8174 a = scm_i_fraction2double (x);
8175 goto complex_div;
8176 }
8177 else if (SCM_FRACTIONP (y))
cba42c93 8178 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
8179 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
8180 else
8181 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
8182 }
0aacf84e 8183 else
f8de44c1 8184 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 8185}
f92e85f7
MV
8186
8187SCM
8188scm_divide (SCM x, SCM y)
8189{
78d3deb1 8190 return do_divide (x, y, 0);
f92e85f7
MV
8191}
8192
8193static SCM scm_divide2real (SCM x, SCM y)
8194{
78d3deb1 8195 return do_divide (x, y, 1);
f92e85f7 8196}
c05e97b7 8197#undef FUNC_NAME
0f2d19dd 8198
fa605590 8199
0f2d19dd 8200double
3101f40f 8201scm_c_truncate (double x)
0f2d19dd 8202{
fa605590 8203 return trunc (x);
0f2d19dd 8204}
0f2d19dd 8205
3101f40f
MV
8206/* scm_c_round is done using floor(x+0.5) to round to nearest and with
8207 half-way case (ie. when x is an integer plus 0.5) going upwards.
8208 Then half-way cases are identified and adjusted down if the
8209 round-upwards didn't give the desired even integer.
6187f48b
KR
8210
8211 "plus_half == result" identifies a half-way case. If plus_half, which is
8212 x + 0.5, is an integer then x must be an integer plus 0.5.
8213
8214 An odd "result" value is identified with result/2 != floor(result/2).
8215 This is done with plus_half, since that value is ready for use sooner in
8216 a pipelined cpu, and we're already requiring plus_half == result.
8217
8218 Note however that we need to be careful when x is big and already an
8219 integer. In that case "x+0.5" may round to an adjacent integer, causing
8220 us to return such a value, incorrectly. For instance if the hardware is
8221 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
8222 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
8223 returned. Or if the hardware is in round-upwards mode, then other bigger
8224 values like say x == 2^128 will see x+0.5 rounding up to the next higher
8225 representable value, 2^128+2^76 (or whatever), again incorrect.
8226
8227 These bad roundings of x+0.5 are avoided by testing at the start whether
8228 x is already an integer. If it is then clearly that's the desired result
8229 already. And if it's not then the exponent must be small enough to allow
8230 an 0.5 to be represented, and hence added without a bad rounding. */
8231
0f2d19dd 8232double
3101f40f 8233scm_c_round (double x)
0f2d19dd 8234{
6187f48b
KR
8235 double plus_half, result;
8236
8237 if (x == floor (x))
8238 return x;
8239
8240 plus_half = x + 0.5;
8241 result = floor (plus_half);
3101f40f 8242 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
8243 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
8244 ? result - 1
8245 : result);
0f2d19dd
JB
8246}
8247
8b56bcec
MW
8248SCM_PRIMITIVE_GENERIC (scm_truncate_number, "truncate", 1, 0, 0,
8249 (SCM x),
8250 "Round the number @var{x} towards zero.")
f92e85f7
MV
8251#define FUNC_NAME s_scm_truncate_number
8252{
8b56bcec
MW
8253 if (SCM_I_INUMP (x) || SCM_BIGP (x))
8254 return x;
8255 else if (SCM_REALP (x))
c251ab63 8256 return scm_from_double (trunc (SCM_REAL_VALUE (x)));
8b56bcec
MW
8257 else if (SCM_FRACTIONP (x))
8258 return scm_truncate_quotient (SCM_FRACTION_NUMERATOR (x),
8259 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8260 else
8b56bcec
MW
8261 SCM_WTA_DISPATCH_1 (g_scm_truncate_number, x, SCM_ARG1,
8262 s_scm_truncate_number);
f92e85f7
MV
8263}
8264#undef FUNC_NAME
8265
8b56bcec
MW
8266SCM_PRIMITIVE_GENERIC (scm_round_number, "round", 1, 0, 0,
8267 (SCM x),
8268 "Round the number @var{x} towards the nearest integer. "
8269 "When it is exactly halfway between two integers, "
8270 "round towards the even one.")
f92e85f7
MV
8271#define FUNC_NAME s_scm_round_number
8272{
e11e83f3 8273 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
8274 return x;
8275 else if (SCM_REALP (x))
3101f40f 8276 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
8b56bcec
MW
8277 else if (SCM_FRACTIONP (x))
8278 return scm_round_quotient (SCM_FRACTION_NUMERATOR (x),
8279 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8280 else
8b56bcec
MW
8281 SCM_WTA_DISPATCH_1 (g_scm_round_number, x, SCM_ARG1,
8282 s_scm_round_number);
f92e85f7
MV
8283}
8284#undef FUNC_NAME
8285
8286SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
8287 (SCM x),
8288 "Round the number @var{x} towards minus infinity.")
8289#define FUNC_NAME s_scm_floor
8290{
e11e83f3 8291 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
8292 return x;
8293 else if (SCM_REALP (x))
55f26379 8294 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7 8295 else if (SCM_FRACTIONP (x))
8b56bcec
MW
8296 return scm_floor_quotient (SCM_FRACTION_NUMERATOR (x),
8297 SCM_FRACTION_DENOMINATOR (x));
f92e85f7
MV
8298 else
8299 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
8300}
8301#undef FUNC_NAME
8302
8303SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
8304 (SCM x),
8305 "Round the number @var{x} towards infinity.")
8306#define FUNC_NAME s_scm_ceiling
8307{
e11e83f3 8308 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
8309 return x;
8310 else if (SCM_REALP (x))
55f26379 8311 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7 8312 else if (SCM_FRACTIONP (x))
8b56bcec
MW
8313 return scm_ceiling_quotient (SCM_FRACTION_NUMERATOR (x),
8314 SCM_FRACTION_DENOMINATOR (x));
f92e85f7
MV
8315 else
8316 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
8317}
8318#undef FUNC_NAME
0f2d19dd 8319
2519490c
MW
8320SCM_PRIMITIVE_GENERIC (scm_expt, "expt", 2, 0, 0,
8321 (SCM x, SCM y),
8322 "Return @var{x} raised to the power of @var{y}.")
6fc4d012 8323#define FUNC_NAME s_scm_expt
0f2d19dd 8324{
01c7284a
MW
8325 if (scm_is_integer (y))
8326 {
8327 if (scm_is_true (scm_exact_p (y)))
8328 return scm_integer_expt (x, y);
8329 else
8330 {
8331 /* Here we handle the case where the exponent is an inexact
8332 integer. We make the exponent exact in order to use
8333 scm_integer_expt, and thus avoid the spurious imaginary
8334 parts that may result from round-off errors in the general
8335 e^(y log x) method below (for example when squaring a large
8336 negative number). In this case, we must return an inexact
8337 result for correctness. We also make the base inexact so
8338 that scm_integer_expt will use fast inexact arithmetic
8339 internally. Note that making the base inexact is not
8340 sufficient to guarantee an inexact result, because
8341 scm_integer_expt will return an exact 1 when the exponent
8342 is 0, even if the base is inexact. */
8343 return scm_exact_to_inexact
8344 (scm_integer_expt (scm_exact_to_inexact (x),
8345 scm_inexact_to_exact (y)));
8346 }
8347 }
6fc4d012
AW
8348 else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
8349 {
8350 return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
8351 }
2519490c 8352 else if (scm_is_complex (x) && scm_is_complex (y))
6fc4d012 8353 return scm_exp (scm_product (scm_log (x), y));
2519490c
MW
8354 else if (scm_is_complex (x))
8355 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG2, s_scm_expt);
8356 else
8357 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG1, s_scm_expt);
0f2d19dd 8358}
1bbd0b84 8359#undef FUNC_NAME
0f2d19dd 8360
7f41099e
MW
8361/* sin/cos/tan/asin/acos/atan
8362 sinh/cosh/tanh/asinh/acosh/atanh
8363 Derived from "Transcen.scm", Complex trancendental functions for SCM.
8364 Written by Jerry D. Hedden, (C) FSF.
8365 See the file `COPYING' for terms applying to this program. */
8366
ad79736c
AW
8367SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
8368 (SCM z),
8369 "Compute the sine of @var{z}.")
8370#define FUNC_NAME s_scm_sin
8371{
8deddc94
MW
8372 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8373 return z; /* sin(exact0) = exact0 */
8374 else if (scm_is_real (z))
ad79736c
AW
8375 return scm_from_double (sin (scm_to_double (z)));
8376 else if (SCM_COMPLEXP (z))
8377 { double x, y;
8378 x = SCM_COMPLEX_REAL (z);
8379 y = SCM_COMPLEX_IMAG (z);
8380 return scm_c_make_rectangular (sin (x) * cosh (y),
8381 cos (x) * sinh (y));
8382 }
8383 else
8384 SCM_WTA_DISPATCH_1 (g_scm_sin, z, 1, s_scm_sin);
8385}
8386#undef FUNC_NAME
0f2d19dd 8387
ad79736c
AW
8388SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
8389 (SCM z),
8390 "Compute the cosine of @var{z}.")
8391#define FUNC_NAME s_scm_cos
8392{
8deddc94
MW
8393 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8394 return SCM_INUM1; /* cos(exact0) = exact1 */
8395 else if (scm_is_real (z))
ad79736c
AW
8396 return scm_from_double (cos (scm_to_double (z)));
8397 else if (SCM_COMPLEXP (z))
8398 { double x, y;
8399 x = SCM_COMPLEX_REAL (z);
8400 y = SCM_COMPLEX_IMAG (z);
8401 return scm_c_make_rectangular (cos (x) * cosh (y),
8402 -sin (x) * sinh (y));
8403 }
8404 else
8405 SCM_WTA_DISPATCH_1 (g_scm_cos, z, 1, s_scm_cos);
8406}
8407#undef FUNC_NAME
8408
8409SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
8410 (SCM z),
8411 "Compute the tangent of @var{z}.")
8412#define FUNC_NAME s_scm_tan
0f2d19dd 8413{
8deddc94
MW
8414 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8415 return z; /* tan(exact0) = exact0 */
8416 else if (scm_is_real (z))
ad79736c
AW
8417 return scm_from_double (tan (scm_to_double (z)));
8418 else if (SCM_COMPLEXP (z))
8419 { double x, y, w;
8420 x = 2.0 * SCM_COMPLEX_REAL (z);
8421 y = 2.0 * SCM_COMPLEX_IMAG (z);
8422 w = cos (x) + cosh (y);
8423#ifndef ALLOW_DIVIDE_BY_ZERO
8424 if (w == 0.0)
8425 scm_num_overflow (s_scm_tan);
8426#endif
8427 return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
8428 }
8429 else
8430 SCM_WTA_DISPATCH_1 (g_scm_tan, z, 1, s_scm_tan);
8431}
8432#undef FUNC_NAME
8433
8434SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
8435 (SCM z),
8436 "Compute the hyperbolic sine of @var{z}.")
8437#define FUNC_NAME s_scm_sinh
8438{
8deddc94
MW
8439 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8440 return z; /* sinh(exact0) = exact0 */
8441 else if (scm_is_real (z))
ad79736c
AW
8442 return scm_from_double (sinh (scm_to_double (z)));
8443 else if (SCM_COMPLEXP (z))
8444 { double x, y;
8445 x = SCM_COMPLEX_REAL (z);
8446 y = SCM_COMPLEX_IMAG (z);
8447 return scm_c_make_rectangular (sinh (x) * cos (y),
8448 cosh (x) * sin (y));
8449 }
8450 else
8451 SCM_WTA_DISPATCH_1 (g_scm_sinh, z, 1, s_scm_sinh);
8452}
8453#undef FUNC_NAME
8454
8455SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
8456 (SCM z),
8457 "Compute the hyperbolic cosine of @var{z}.")
8458#define FUNC_NAME s_scm_cosh
8459{
8deddc94
MW
8460 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8461 return SCM_INUM1; /* cosh(exact0) = exact1 */
8462 else if (scm_is_real (z))
ad79736c
AW
8463 return scm_from_double (cosh (scm_to_double (z)));
8464 else if (SCM_COMPLEXP (z))
8465 { double x, y;
8466 x = SCM_COMPLEX_REAL (z);
8467 y = SCM_COMPLEX_IMAG (z);
8468 return scm_c_make_rectangular (cosh (x) * cos (y),
8469 sinh (x) * sin (y));
8470 }
8471 else
8472 SCM_WTA_DISPATCH_1 (g_scm_cosh, z, 1, s_scm_cosh);
8473}
8474#undef FUNC_NAME
8475
8476SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
8477 (SCM z),
8478 "Compute the hyperbolic tangent of @var{z}.")
8479#define FUNC_NAME s_scm_tanh
8480{
8deddc94
MW
8481 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8482 return z; /* tanh(exact0) = exact0 */
8483 else if (scm_is_real (z))
ad79736c
AW
8484 return scm_from_double (tanh (scm_to_double (z)));
8485 else if (SCM_COMPLEXP (z))
8486 { double x, y, w;
8487 x = 2.0 * SCM_COMPLEX_REAL (z);
8488 y = 2.0 * SCM_COMPLEX_IMAG (z);
8489 w = cosh (x) + cos (y);
8490#ifndef ALLOW_DIVIDE_BY_ZERO
8491 if (w == 0.0)
8492 scm_num_overflow (s_scm_tanh);
8493#endif
8494 return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
8495 }
8496 else
8497 SCM_WTA_DISPATCH_1 (g_scm_tanh, z, 1, s_scm_tanh);
8498}
8499#undef FUNC_NAME
8500
8501SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
8502 (SCM z),
8503 "Compute the arc sine of @var{z}.")
8504#define FUNC_NAME s_scm_asin
8505{
8deddc94
MW
8506 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8507 return z; /* asin(exact0) = exact0 */
8508 else if (scm_is_real (z))
ad79736c
AW
8509 {
8510 double w = scm_to_double (z);
8511 if (w >= -1.0 && w <= 1.0)
8512 return scm_from_double (asin (w));
8513 else
8514 return scm_product (scm_c_make_rectangular (0, -1),
8515 scm_sys_asinh (scm_c_make_rectangular (0, w)));
8516 }
8517 else if (SCM_COMPLEXP (z))
8518 { double x, y;
8519 x = SCM_COMPLEX_REAL (z);
8520 y = SCM_COMPLEX_IMAG (z);
8521 return scm_product (scm_c_make_rectangular (0, -1),
8522 scm_sys_asinh (scm_c_make_rectangular (-y, x)));
8523 }
8524 else
8525 SCM_WTA_DISPATCH_1 (g_scm_asin, z, 1, s_scm_asin);
8526}
8527#undef FUNC_NAME
8528
8529SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
8530 (SCM z),
8531 "Compute the arc cosine of @var{z}.")
8532#define FUNC_NAME s_scm_acos
8533{
8deddc94
MW
8534 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
8535 return SCM_INUM0; /* acos(exact1) = exact0 */
8536 else if (scm_is_real (z))
ad79736c
AW
8537 {
8538 double w = scm_to_double (z);
8539 if (w >= -1.0 && w <= 1.0)
8540 return scm_from_double (acos (w));
8541 else
8542 return scm_sum (scm_from_double (acos (0.0)),
8543 scm_product (scm_c_make_rectangular (0, 1),
8544 scm_sys_asinh (scm_c_make_rectangular (0, w))));
8545 }
8546 else if (SCM_COMPLEXP (z))
8547 { double x, y;
8548 x = SCM_COMPLEX_REAL (z);
8549 y = SCM_COMPLEX_IMAG (z);
8550 return scm_sum (scm_from_double (acos (0.0)),
8551 scm_product (scm_c_make_rectangular (0, 1),
8552 scm_sys_asinh (scm_c_make_rectangular (-y, x))));
8553 }
8554 else
8555 SCM_WTA_DISPATCH_1 (g_scm_acos, z, 1, s_scm_acos);
8556}
8557#undef FUNC_NAME
8558
8559SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
8560 (SCM z, SCM y),
8561 "With one argument, compute the arc tangent of @var{z}.\n"
8562 "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
8563 "using the sign of @var{z} and @var{y} to determine the quadrant.")
8564#define FUNC_NAME s_scm_atan
8565{
8566 if (SCM_UNBNDP (y))
8567 {
8deddc94
MW
8568 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8569 return z; /* atan(exact0) = exact0 */
8570 else if (scm_is_real (z))
ad79736c
AW
8571 return scm_from_double (atan (scm_to_double (z)));
8572 else if (SCM_COMPLEXP (z))
8573 {
8574 double v, w;
8575 v = SCM_COMPLEX_REAL (z);
8576 w = SCM_COMPLEX_IMAG (z);
8577 return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
8578 scm_c_make_rectangular (v, w + 1.0))),
8579 scm_c_make_rectangular (0, 2));
8580 }
8581 else
18104cac 8582 SCM_WTA_DISPATCH_1 (g_scm_atan, z, SCM_ARG1, s_scm_atan);
ad79736c
AW
8583 }
8584 else if (scm_is_real (z))
8585 {
8586 if (scm_is_real (y))
8587 return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
8588 else
8589 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
8590 }
8591 else
8592 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
8593}
8594#undef FUNC_NAME
8595
8596SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
8597 (SCM z),
8598 "Compute the inverse hyperbolic sine of @var{z}.")
8599#define FUNC_NAME s_scm_sys_asinh
8600{
8deddc94
MW
8601 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8602 return z; /* asinh(exact0) = exact0 */
8603 else if (scm_is_real (z))
ad79736c
AW
8604 return scm_from_double (asinh (scm_to_double (z)));
8605 else if (scm_is_number (z))
8606 return scm_log (scm_sum (z,
8607 scm_sqrt (scm_sum (scm_product (z, z),
cff5fa33 8608 SCM_INUM1))));
ad79736c
AW
8609 else
8610 SCM_WTA_DISPATCH_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
8611}
8612#undef FUNC_NAME
8613
8614SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
8615 (SCM z),
8616 "Compute the inverse hyperbolic cosine of @var{z}.")
8617#define FUNC_NAME s_scm_sys_acosh
8618{
8deddc94
MW
8619 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
8620 return SCM_INUM0; /* acosh(exact1) = exact0 */
8621 else if (scm_is_real (z) && scm_to_double (z) >= 1.0)
ad79736c
AW
8622 return scm_from_double (acosh (scm_to_double (z)));
8623 else if (scm_is_number (z))
8624 return scm_log (scm_sum (z,
8625 scm_sqrt (scm_difference (scm_product (z, z),
cff5fa33 8626 SCM_INUM1))));
ad79736c
AW
8627 else
8628 SCM_WTA_DISPATCH_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
8629}
8630#undef FUNC_NAME
8631
8632SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
8633 (SCM z),
8634 "Compute the inverse hyperbolic tangent of @var{z}.")
8635#define FUNC_NAME s_scm_sys_atanh
8636{
8deddc94
MW
8637 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8638 return z; /* atanh(exact0) = exact0 */
8639 else if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
ad79736c
AW
8640 return scm_from_double (atanh (scm_to_double (z)));
8641 else if (scm_is_number (z))
cff5fa33
MW
8642 return scm_divide (scm_log (scm_divide (scm_sum (SCM_INUM1, z),
8643 scm_difference (SCM_INUM1, z))),
ad79736c
AW
8644 SCM_I_MAKINUM (2));
8645 else
8646 SCM_WTA_DISPATCH_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
0f2d19dd 8647}
1bbd0b84 8648#undef FUNC_NAME
0f2d19dd 8649
8507ec80
MV
8650SCM
8651scm_c_make_rectangular (double re, double im)
8652{
c7218482 8653 SCM z;
03604fcf 8654
c7218482
MW
8655 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
8656 "complex"));
8657 SCM_SET_CELL_TYPE (z, scm_tc16_complex);
8658 SCM_COMPLEX_REAL (z) = re;
8659 SCM_COMPLEX_IMAG (z) = im;
8660 return z;
8507ec80 8661}
0f2d19dd 8662
a1ec6916 8663SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
a2c25234
LC
8664 (SCM real_part, SCM imaginary_part),
8665 "Return a complex number constructed of the given @var{real-part} "
8666 "and @var{imaginary-part} parts.")
1bbd0b84 8667#define FUNC_NAME s_scm_make_rectangular
0f2d19dd 8668{
ad79736c
AW
8669 SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
8670 SCM_ARG1, FUNC_NAME, "real");
8671 SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
8672 SCM_ARG2, FUNC_NAME, "real");
c7218482
MW
8673
8674 /* Return a real if and only if the imaginary_part is an _exact_ 0 */
8675 if (scm_is_eq (imaginary_part, SCM_INUM0))
8676 return real_part;
8677 else
8678 return scm_c_make_rectangular (scm_to_double (real_part),
8679 scm_to_double (imaginary_part));
0f2d19dd 8680}
1bbd0b84 8681#undef FUNC_NAME
0f2d19dd 8682
8507ec80
MV
8683SCM
8684scm_c_make_polar (double mag, double ang)
8685{
8686 double s, c;
5e647d08
LC
8687
8688 /* The sincos(3) function is undocumented an broken on Tru64. Thus we only
8689 use it on Glibc-based systems that have it (it's a GNU extension). See
8690 http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
8691 details. */
8692#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
8507ec80
MV
8693 sincos (ang, &s, &c);
8694#else
8695 s = sin (ang);
8696 c = cos (ang);
8697#endif
9d427b2c
MW
8698
8699 /* If s and c are NaNs, this indicates that the angle is a NaN,
8700 infinite, or perhaps simply too large to determine its value
8701 mod 2*pi. However, we know something that the floating-point
8702 implementation doesn't know: We know that s and c are finite.
8703 Therefore, if the magnitude is zero, return a complex zero.
8704
8705 The reason we check for the NaNs instead of using this case
8706 whenever mag == 0.0 is because when the angle is known, we'd
8707 like to return the correct kind of non-real complex zero:
8708 +0.0+0.0i, -0.0+0.0i, -0.0-0.0i, or +0.0-0.0i, depending
8709 on which quadrant the angle is in.
8710 */
8711 if (SCM_UNLIKELY (isnan(s)) && isnan(c) && (mag == 0.0))
8712 return scm_c_make_rectangular (0.0, 0.0);
8713 else
8714 return scm_c_make_rectangular (mag * c, mag * s);
8507ec80 8715}
0f2d19dd 8716
a1ec6916 8717SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
c7218482
MW
8718 (SCM mag, SCM ang),
8719 "Return the complex number @var{mag} * e^(i * @var{ang}).")
1bbd0b84 8720#define FUNC_NAME s_scm_make_polar
0f2d19dd 8721{
c7218482
MW
8722 SCM_ASSERT_TYPE (scm_is_real (mag), mag, SCM_ARG1, FUNC_NAME, "real");
8723 SCM_ASSERT_TYPE (scm_is_real (ang), ang, SCM_ARG2, FUNC_NAME, "real");
8724
8725 /* If mag is exact0, return exact0 */
8726 if (scm_is_eq (mag, SCM_INUM0))
8727 return SCM_INUM0;
8728 /* Return a real if ang is exact0 */
8729 else if (scm_is_eq (ang, SCM_INUM0))
8730 return mag;
8731 else
8732 return scm_c_make_polar (scm_to_double (mag), scm_to_double (ang));
0f2d19dd 8733}
1bbd0b84 8734#undef FUNC_NAME
0f2d19dd
JB
8735
8736
2519490c
MW
8737SCM_PRIMITIVE_GENERIC (scm_real_part, "real-part", 1, 0, 0,
8738 (SCM z),
8739 "Return the real part of the number @var{z}.")
8740#define FUNC_NAME s_scm_real_part
0f2d19dd 8741{
2519490c 8742 if (SCM_COMPLEXP (z))
55f26379 8743 return scm_from_double (SCM_COMPLEX_REAL (z));
2519490c 8744 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_REALP (z) || SCM_FRACTIONP (z))
2fa2d879 8745 return z;
0aacf84e 8746 else
2519490c 8747 SCM_WTA_DISPATCH_1 (g_scm_real_part, z, SCM_ARG1, s_scm_real_part);
0f2d19dd 8748}
2519490c 8749#undef FUNC_NAME
0f2d19dd
JB
8750
8751
2519490c
MW
8752SCM_PRIMITIVE_GENERIC (scm_imag_part, "imag-part", 1, 0, 0,
8753 (SCM z),
8754 "Return the imaginary part of the number @var{z}.")
8755#define FUNC_NAME s_scm_imag_part
0f2d19dd 8756{
2519490c
MW
8757 if (SCM_COMPLEXP (z))
8758 return scm_from_double (SCM_COMPLEX_IMAG (z));
c7218482 8759 else if (SCM_I_INUMP (z) || SCM_REALP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f92e85f7 8760 return SCM_INUM0;
0aacf84e 8761 else
2519490c 8762 SCM_WTA_DISPATCH_1 (g_scm_imag_part, z, SCM_ARG1, s_scm_imag_part);
0f2d19dd 8763}
2519490c 8764#undef FUNC_NAME
0f2d19dd 8765
2519490c
MW
8766SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
8767 (SCM z),
8768 "Return the numerator of the number @var{z}.")
8769#define FUNC_NAME s_scm_numerator
f92e85f7 8770{
2519490c 8771 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f92e85f7
MV
8772 return z;
8773 else if (SCM_FRACTIONP (z))
e2bf3b19 8774 return SCM_FRACTION_NUMERATOR (z);
f92e85f7
MV
8775 else if (SCM_REALP (z))
8776 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
8777 else
2519490c 8778 SCM_WTA_DISPATCH_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
f92e85f7 8779}
2519490c 8780#undef FUNC_NAME
f92e85f7
MV
8781
8782
2519490c
MW
8783SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
8784 (SCM z),
8785 "Return the denominator of the number @var{z}.")
8786#define FUNC_NAME s_scm_denominator
f92e85f7 8787{
2519490c 8788 if (SCM_I_INUMP (z) || SCM_BIGP (z))
cff5fa33 8789 return SCM_INUM1;
f92e85f7 8790 else if (SCM_FRACTIONP (z))
e2bf3b19 8791 return SCM_FRACTION_DENOMINATOR (z);
f92e85f7
MV
8792 else if (SCM_REALP (z))
8793 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
8794 else
2519490c 8795 SCM_WTA_DISPATCH_1 (g_scm_denominator, z, SCM_ARG1, s_scm_denominator);
f92e85f7 8796}
2519490c 8797#undef FUNC_NAME
0f2d19dd 8798
2519490c
MW
8799
8800SCM_PRIMITIVE_GENERIC (scm_magnitude, "magnitude", 1, 0, 0,
8801 (SCM z),
8802 "Return the magnitude of the number @var{z}. This is the same as\n"
8803 "@code{abs} for real arguments, but also allows complex numbers.")
8804#define FUNC_NAME s_scm_magnitude
0f2d19dd 8805{
e11e83f3 8806 if (SCM_I_INUMP (z))
0aacf84e 8807 {
e25f3727 8808 scm_t_inum zz = SCM_I_INUM (z);
0aacf84e
MD
8809 if (zz >= 0)
8810 return z;
8811 else if (SCM_POSFIXABLE (-zz))
d956fa6f 8812 return SCM_I_MAKINUM (-zz);
0aacf84e 8813 else
e25f3727 8814 return scm_i_inum2big (-zz);
5986c47d 8815 }
0aacf84e
MD
8816 else if (SCM_BIGP (z))
8817 {
8818 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
8819 scm_remember_upto_here_1 (z);
8820 if (sgn < 0)
8821 return scm_i_clonebig (z, 0);
8822 else
8823 return z;
5986c47d 8824 }
0aacf84e 8825 else if (SCM_REALP (z))
55f26379 8826 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 8827 else if (SCM_COMPLEXP (z))
55f26379 8828 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
8829 else if (SCM_FRACTIONP (z))
8830 {
73e4de09 8831 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 8832 return z;
cba42c93 8833 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
8834 SCM_FRACTION_DENOMINATOR (z));
8835 }
0aacf84e 8836 else
2519490c 8837 SCM_WTA_DISPATCH_1 (g_scm_magnitude, z, SCM_ARG1, s_scm_magnitude);
0f2d19dd 8838}
2519490c 8839#undef FUNC_NAME
0f2d19dd
JB
8840
8841
2519490c
MW
8842SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
8843 (SCM z),
8844 "Return the angle of the complex number @var{z}.")
8845#define FUNC_NAME s_scm_angle
0f2d19dd 8846{
c8ae173e 8847 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
e7efe8e7 8848 flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
8849 But if atan2 follows the floating point rounding mode, then the value
8850 is not a constant. Maybe it'd be close enough though. */
e11e83f3 8851 if (SCM_I_INUMP (z))
0aacf84e 8852 {
e11e83f3 8853 if (SCM_I_INUM (z) >= 0)
e7efe8e7 8854 return flo0;
0aacf84e 8855 else
55f26379 8856 return scm_from_double (atan2 (0.0, -1.0));
f872b822 8857 }
0aacf84e
MD
8858 else if (SCM_BIGP (z))
8859 {
8860 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
8861 scm_remember_upto_here_1 (z);
8862 if (sgn < 0)
55f26379 8863 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 8864 else
e7efe8e7 8865 return flo0;
0f2d19dd 8866 }
0aacf84e 8867 else if (SCM_REALP (z))
c8ae173e
KR
8868 {
8869 if (SCM_REAL_VALUE (z) >= 0)
e7efe8e7 8870 return flo0;
c8ae173e 8871 else
55f26379 8872 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 8873 }
0aacf84e 8874 else if (SCM_COMPLEXP (z))
55f26379 8875 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
8876 else if (SCM_FRACTIONP (z))
8877 {
73e4de09 8878 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
e7efe8e7 8879 return flo0;
55f26379 8880 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 8881 }
0aacf84e 8882 else
2519490c 8883 SCM_WTA_DISPATCH_1 (g_scm_angle, z, SCM_ARG1, s_scm_angle);
0f2d19dd 8884}
2519490c 8885#undef FUNC_NAME
0f2d19dd
JB
8886
8887
2519490c
MW
8888SCM_PRIMITIVE_GENERIC (scm_exact_to_inexact, "exact->inexact", 1, 0, 0,
8889 (SCM z),
8890 "Convert the number @var{z} to its inexact representation.\n")
8891#define FUNC_NAME s_scm_exact_to_inexact
3c9a524f 8892{
e11e83f3 8893 if (SCM_I_INUMP (z))
55f26379 8894 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 8895 else if (SCM_BIGP (z))
55f26379 8896 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 8897 else if (SCM_FRACTIONP (z))
55f26379 8898 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
8899 else if (SCM_INEXACTP (z))
8900 return z;
8901 else
2519490c 8902 SCM_WTA_DISPATCH_1 (g_scm_exact_to_inexact, z, 1, s_scm_exact_to_inexact);
3c9a524f 8903}
2519490c 8904#undef FUNC_NAME
3c9a524f
DH
8905
8906
2519490c
MW
8907SCM_PRIMITIVE_GENERIC (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
8908 (SCM z),
8909 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 8910#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 8911{
c7218482 8912 if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f872b822 8913 return z;
c7218482 8914 else
0aacf84e 8915 {
c7218482
MW
8916 double val;
8917
8918 if (SCM_REALP (z))
8919 val = SCM_REAL_VALUE (z);
8920 else if (SCM_COMPLEXP (z) && SCM_COMPLEX_IMAG (z) == 0.0)
8921 val = SCM_COMPLEX_REAL (z);
8922 else
8923 SCM_WTA_DISPATCH_1 (g_scm_inexact_to_exact, z, 1, s_scm_inexact_to_exact);
8924
8925 if (!SCM_LIKELY (DOUBLE_IS_FINITE (val)))
f92e85f7 8926 SCM_OUT_OF_RANGE (1, z);
2be24db4 8927 else
f92e85f7
MV
8928 {
8929 mpq_t frac;
8930 SCM q;
8931
8932 mpq_init (frac);
c7218482 8933 mpq_set_d (frac, val);
cba42c93 8934 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
c7218482 8935 scm_i_mpz2num (mpq_denref (frac)));
f92e85f7 8936
cba42c93 8937 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
8938 for frac...
8939 */
8940 mpq_clear (frac);
8941 return q;
8942 }
c2ff8ab0 8943 }
0f2d19dd 8944}
1bbd0b84 8945#undef FUNC_NAME
0f2d19dd 8946
f92e85f7 8947SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
76dae881
NJ
8948 (SCM x, SCM eps),
8949 "Returns the @emph{simplest} rational number differing\n"
8950 "from @var{x} by no more than @var{eps}.\n"
8951 "\n"
8952 "As required by @acronym{R5RS}, @code{rationalize} only returns an\n"
8953 "exact result when both its arguments are exact. Thus, you might need\n"
8954 "to use @code{inexact->exact} on the arguments.\n"
8955 "\n"
8956 "@lisp\n"
8957 "(rationalize (inexact->exact 1.2) 1/100)\n"
8958 "@result{} 6/5\n"
8959 "@end lisp")
f92e85f7
MV
8960#define FUNC_NAME s_scm_rationalize
8961{
605f6980
MW
8962 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
8963 SCM_ASSERT_TYPE (scm_is_real (eps), eps, SCM_ARG2, FUNC_NAME, "real");
8964 eps = scm_abs (eps);
8965 if (scm_is_false (scm_positive_p (eps)))
8966 {
8967 /* eps is either zero or a NaN */
8968 if (scm_is_true (scm_nan_p (eps)))
8969 return scm_nan ();
8970 else if (SCM_INEXACTP (eps))
8971 return scm_exact_to_inexact (x);
8972 else
8973 return x;
8974 }
8975 else if (scm_is_false (scm_finite_p (eps)))
8976 {
8977 if (scm_is_true (scm_finite_p (x)))
8978 return flo0;
8979 else
8980 return scm_nan ();
8981 }
8982 else if (scm_is_false (scm_finite_p (x))) /* checks for both inf and nan */
f92e85f7 8983 return x;
605f6980
MW
8984 else if (scm_is_false (scm_less_p (scm_floor (scm_sum (x, eps)),
8985 scm_ceiling (scm_difference (x, eps)))))
8986 {
8987 /* There's an integer within range; we want the one closest to zero */
8988 if (scm_is_false (scm_less_p (eps, scm_abs (x))))
8989 {
8990 /* zero is within range */
8991 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
8992 return flo0;
8993 else
8994 return SCM_INUM0;
8995 }
8996 else if (scm_is_true (scm_positive_p (x)))
8997 return scm_ceiling (scm_difference (x, eps));
8998 else
8999 return scm_floor (scm_sum (x, eps));
9000 }
9001 else
f92e85f7
MV
9002 {
9003 /* Use continued fractions to find closest ratio. All
9004 arithmetic is done with exact numbers.
9005 */
9006
9007 SCM ex = scm_inexact_to_exact (x);
9008 SCM int_part = scm_floor (ex);
cff5fa33
MW
9009 SCM tt = SCM_INUM1;
9010 SCM a1 = SCM_INUM0, a2 = SCM_INUM1, a = SCM_INUM0;
9011 SCM b1 = SCM_INUM1, b2 = SCM_INUM0, b = SCM_INUM0;
f92e85f7
MV
9012 SCM rx;
9013 int i = 0;
9014
f92e85f7
MV
9015 ex = scm_difference (ex, int_part); /* x = x-int_part */
9016 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
9017
9018 /* We stop after a million iterations just to be absolutely sure
9019 that we don't go into an infinite loop. The process normally
9020 converges after less than a dozen iterations.
9021 */
9022
f92e85f7
MV
9023 while (++i < 1000000)
9024 {
9025 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
9026 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
9027 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
9028 scm_is_false
f92e85f7 9029 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
76dae881 9030 eps))) /* abs(x-a/b) <= eps */
02164269
MV
9031 {
9032 SCM res = scm_sum (int_part, scm_divide (a, b));
605f6980 9033 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
02164269
MV
9034 return scm_exact_to_inexact (res);
9035 else
9036 return res;
9037 }
f92e85f7
MV
9038 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
9039 SCM_UNDEFINED);
9040 tt = scm_floor (rx); /* tt = floor (rx) */
9041 a2 = a1;
9042 b2 = b1;
9043 a1 = a;
9044 b1 = b;
9045 }
9046 scm_num_overflow (s_scm_rationalize);
9047 }
f92e85f7
MV
9048}
9049#undef FUNC_NAME
9050
73e4de09
MV
9051/* conversion functions */
9052
9053int
9054scm_is_integer (SCM val)
9055{
9056 return scm_is_true (scm_integer_p (val));
9057}
9058
9059int
9060scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
9061{
e11e83f3 9062 if (SCM_I_INUMP (val))
73e4de09 9063 {
e11e83f3 9064 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
9065 return n >= min && n <= max;
9066 }
9067 else if (SCM_BIGP (val))
9068 {
9069 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
9070 return 0;
9071 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
9072 {
9073 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
9074 {
9075 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
9076 return n >= min && n <= max;
9077 }
9078 else
9079 return 0;
9080 }
73e4de09
MV
9081 else
9082 {
d956fa6f
MV
9083 scm_t_intmax n;
9084 size_t count;
73e4de09 9085
d956fa6f
MV
9086 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
9087 > CHAR_BIT*sizeof (scm_t_uintmax))
9088 return 0;
9089
9090 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
9091 SCM_I_BIG_MPZ (val));
73e4de09 9092
d956fa6f 9093 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 9094 {
d956fa6f
MV
9095 if (n < 0)
9096 return 0;
73e4de09 9097 }
73e4de09
MV
9098 else
9099 {
d956fa6f
MV
9100 n = -n;
9101 if (n >= 0)
9102 return 0;
73e4de09 9103 }
d956fa6f
MV
9104
9105 return n >= min && n <= max;
73e4de09
MV
9106 }
9107 }
73e4de09
MV
9108 else
9109 return 0;
9110}
9111
9112int
9113scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
9114{
e11e83f3 9115 if (SCM_I_INUMP (val))
73e4de09 9116 {
e11e83f3 9117 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
9118 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
9119 }
9120 else if (SCM_BIGP (val))
9121 {
9122 if (max <= SCM_MOST_POSITIVE_FIXNUM)
9123 return 0;
9124 else if (max <= ULONG_MAX)
d956fa6f
MV
9125 {
9126 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
9127 {
9128 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
9129 return n >= min && n <= max;
9130 }
9131 else
9132 return 0;
9133 }
73e4de09
MV
9134 else
9135 {
d956fa6f
MV
9136 scm_t_uintmax n;
9137 size_t count;
73e4de09 9138
d956fa6f
MV
9139 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
9140 return 0;
73e4de09 9141
d956fa6f
MV
9142 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
9143 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 9144 return 0;
d956fa6f
MV
9145
9146 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
9147 SCM_I_BIG_MPZ (val));
73e4de09 9148
d956fa6f 9149 return n >= min && n <= max;
73e4de09
MV
9150 }
9151 }
73e4de09
MV
9152 else
9153 return 0;
9154}
9155
1713d319
MV
9156static void
9157scm_i_range_error (SCM bad_val, SCM min, SCM max)
9158{
9159 scm_error (scm_out_of_range_key,
9160 NULL,
9161 "Value out of range ~S to ~S: ~S",
9162 scm_list_3 (min, max, bad_val),
9163 scm_list_1 (bad_val));
9164}
9165
bfd7932e
MV
9166#define TYPE scm_t_intmax
9167#define TYPE_MIN min
9168#define TYPE_MAX max
9169#define SIZEOF_TYPE 0
9170#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
9171#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
9172#include "libguile/conv-integer.i.c"
9173
9174#define TYPE scm_t_uintmax
9175#define TYPE_MIN min
9176#define TYPE_MAX max
9177#define SIZEOF_TYPE 0
9178#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
9179#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
9180#include "libguile/conv-uinteger.i.c"
9181
9182#define TYPE scm_t_int8
9183#define TYPE_MIN SCM_T_INT8_MIN
9184#define TYPE_MAX SCM_T_INT8_MAX
9185#define SIZEOF_TYPE 1
9186#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
9187#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
9188#include "libguile/conv-integer.i.c"
9189
9190#define TYPE scm_t_uint8
9191#define TYPE_MIN 0
9192#define TYPE_MAX SCM_T_UINT8_MAX
9193#define SIZEOF_TYPE 1
9194#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
9195#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
9196#include "libguile/conv-uinteger.i.c"
9197
9198#define TYPE scm_t_int16
9199#define TYPE_MIN SCM_T_INT16_MIN
9200#define TYPE_MAX SCM_T_INT16_MAX
9201#define SIZEOF_TYPE 2
9202#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
9203#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
9204#include "libguile/conv-integer.i.c"
9205
9206#define TYPE scm_t_uint16
9207#define TYPE_MIN 0
9208#define TYPE_MAX SCM_T_UINT16_MAX
9209#define SIZEOF_TYPE 2
9210#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
9211#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
9212#include "libguile/conv-uinteger.i.c"
9213
9214#define TYPE scm_t_int32
9215#define TYPE_MIN SCM_T_INT32_MIN
9216#define TYPE_MAX SCM_T_INT32_MAX
9217#define SIZEOF_TYPE 4
9218#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
9219#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
9220#include "libguile/conv-integer.i.c"
9221
9222#define TYPE scm_t_uint32
9223#define TYPE_MIN 0
9224#define TYPE_MAX SCM_T_UINT32_MAX
9225#define SIZEOF_TYPE 4
9226#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
9227#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
9228#include "libguile/conv-uinteger.i.c"
9229
904a78f1
MG
9230#define TYPE scm_t_wchar
9231#define TYPE_MIN (scm_t_int32)-1
9232#define TYPE_MAX (scm_t_int32)0x10ffff
9233#define SIZEOF_TYPE 4
9234#define SCM_TO_TYPE_PROTO(arg) scm_to_wchar (arg)
9235#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
9236#include "libguile/conv-integer.i.c"
9237
bfd7932e
MV
9238#define TYPE scm_t_int64
9239#define TYPE_MIN SCM_T_INT64_MIN
9240#define TYPE_MAX SCM_T_INT64_MAX
9241#define SIZEOF_TYPE 8
9242#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
9243#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
9244#include "libguile/conv-integer.i.c"
9245
9246#define TYPE scm_t_uint64
9247#define TYPE_MIN 0
9248#define TYPE_MAX SCM_T_UINT64_MAX
9249#define SIZEOF_TYPE 8
9250#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
9251#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
9252#include "libguile/conv-uinteger.i.c"
73e4de09 9253
cd036260
MV
9254void
9255scm_to_mpz (SCM val, mpz_t rop)
9256{
9257 if (SCM_I_INUMP (val))
9258 mpz_set_si (rop, SCM_I_INUM (val));
9259 else if (SCM_BIGP (val))
9260 mpz_set (rop, SCM_I_BIG_MPZ (val));
9261 else
9262 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
9263}
9264
9265SCM
9266scm_from_mpz (mpz_t val)
9267{
9268 return scm_i_mpz2num (val);
9269}
9270
73e4de09
MV
9271int
9272scm_is_real (SCM val)
9273{
9274 return scm_is_true (scm_real_p (val));
9275}
9276
55f26379
MV
9277int
9278scm_is_rational (SCM val)
9279{
9280 return scm_is_true (scm_rational_p (val));
9281}
9282
73e4de09
MV
9283double
9284scm_to_double (SCM val)
9285{
55f26379
MV
9286 if (SCM_I_INUMP (val))
9287 return SCM_I_INUM (val);
9288 else if (SCM_BIGP (val))
9289 return scm_i_big2dbl (val);
9290 else if (SCM_FRACTIONP (val))
9291 return scm_i_fraction2double (val);
9292 else if (SCM_REALP (val))
9293 return SCM_REAL_VALUE (val);
9294 else
7a1aba42 9295 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
9296}
9297
9298SCM
9299scm_from_double (double val)
9300{
978c52d1
LC
9301 SCM z;
9302
9303 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
9304
9305 SCM_SET_CELL_TYPE (z, scm_tc16_real);
55f26379 9306 SCM_REAL_VALUE (z) = val;
978c52d1 9307
55f26379 9308 return z;
73e4de09
MV
9309}
9310
220058a8 9311#if SCM_ENABLE_DEPRECATED == 1
55f26379
MV
9312
9313float
e25f3727 9314scm_num2float (SCM num, unsigned long pos, const char *s_caller)
55f26379 9315{
220058a8
AW
9316 scm_c_issue_deprecation_warning
9317 ("`scm_num2float' is deprecated. Use scm_to_double instead.");
9318
55f26379
MV
9319 if (SCM_BIGP (num))
9320 {
9321 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 9322 if (!isinf (res))
55f26379
MV
9323 return res;
9324 else
9325 scm_out_of_range (NULL, num);
9326 }
9327 else
9328 return scm_to_double (num);
9329}
9330
9331double
e25f3727 9332scm_num2double (SCM num, unsigned long pos, const char *s_caller)
55f26379 9333{
220058a8
AW
9334 scm_c_issue_deprecation_warning
9335 ("`scm_num2double' is deprecated. Use scm_to_double instead.");
9336
55f26379
MV
9337 if (SCM_BIGP (num))
9338 {
9339 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 9340 if (!isinf (res))
55f26379
MV
9341 return res;
9342 else
9343 scm_out_of_range (NULL, num);
9344 }
9345 else
9346 return scm_to_double (num);
9347}
9348
9349#endif
9350
8507ec80
MV
9351int
9352scm_is_complex (SCM val)
9353{
9354 return scm_is_true (scm_complex_p (val));
9355}
9356
9357double
9358scm_c_real_part (SCM z)
9359{
9360 if (SCM_COMPLEXP (z))
9361 return SCM_COMPLEX_REAL (z);
9362 else
9363 {
9364 /* Use the scm_real_part to get proper error checking and
9365 dispatching.
9366 */
9367 return scm_to_double (scm_real_part (z));
9368 }
9369}
9370
9371double
9372scm_c_imag_part (SCM z)
9373{
9374 if (SCM_COMPLEXP (z))
9375 return SCM_COMPLEX_IMAG (z);
9376 else
9377 {
9378 /* Use the scm_imag_part to get proper error checking and
9379 dispatching. The result will almost always be 0.0, but not
9380 always.
9381 */
9382 return scm_to_double (scm_imag_part (z));
9383 }
9384}
9385
9386double
9387scm_c_magnitude (SCM z)
9388{
9389 return scm_to_double (scm_magnitude (z));
9390}
9391
9392double
9393scm_c_angle (SCM z)
9394{
9395 return scm_to_double (scm_angle (z));
9396}
9397
9398int
9399scm_is_number (SCM z)
9400{
9401 return scm_is_true (scm_number_p (z));
9402}
9403
8ab3d8a0 9404
a5f6b751
MW
9405/* Returns log(x * 2^shift) */
9406static SCM
9407log_of_shifted_double (double x, long shift)
9408{
9409 double ans = log (fabs (x)) + shift * M_LN2;
9410
9411 if (x > 0.0 || double_is_non_negative_zero (x))
9412 return scm_from_double (ans);
9413 else
9414 return scm_c_make_rectangular (ans, M_PI);
9415}
9416
9417/* Returns log(n), for exact integer n of integer-length size */
9418static SCM
9419log_of_exact_integer_with_size (SCM n, long size)
9420{
9421 long shift = size - 2 * scm_dblprec[0];
9422
9423 if (shift > 0)
9424 return log_of_shifted_double
9425 (scm_to_double (scm_ash (n, scm_from_long(-shift))),
9426 shift);
9427 else
9428 return log_of_shifted_double (scm_to_double (n), 0);
9429}
9430
85bdb6ac 9431/* Returns log(n), for exact integer n */
a5f6b751
MW
9432static SCM
9433log_of_exact_integer (SCM n)
9434{
9435 return log_of_exact_integer_with_size
9436 (n, scm_to_long (scm_integer_length (n)));
9437}
9438
9439/* Returns log(n/d), for exact non-zero integers n and d */
9440static SCM
9441log_of_fraction (SCM n, SCM d)
9442{
9443 long n_size = scm_to_long (scm_integer_length (n));
9444 long d_size = scm_to_long (scm_integer_length (d));
9445
9446 if (abs (n_size - d_size) > 1)
9447 return (scm_difference (log_of_exact_integer_with_size (n, n_size),
9448 log_of_exact_integer_with_size (d, d_size)));
9449 else if (scm_is_false (scm_negative_p (n)))
9450 return scm_from_double
9451 (log1p (scm_to_double (scm_divide2real (scm_difference (n, d), d))));
9452 else
9453 return scm_c_make_rectangular
9454 (log1p (scm_to_double (scm_divide2real
9455 (scm_difference (scm_abs (n), d),
9456 d))),
9457 M_PI);
9458}
9459
9460
8ab3d8a0
KR
9461/* In the following functions we dispatch to the real-arg funcs like log()
9462 when we know the arg is real, instead of just handing everything to
9463 clog() for instance. This is in case clog() doesn't optimize for a
9464 real-only case, and because we have to test SCM_COMPLEXP anyway so may as
9465 well use it to go straight to the applicable C func. */
9466
2519490c
MW
9467SCM_PRIMITIVE_GENERIC (scm_log, "log", 1, 0, 0,
9468 (SCM z),
9469 "Return the natural logarithm of @var{z}.")
8ab3d8a0
KR
9470#define FUNC_NAME s_scm_log
9471{
9472 if (SCM_COMPLEXP (z))
9473 {
03976fee
AW
9474#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG \
9475 && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
9476 return scm_from_complex_double (clog (SCM_COMPLEX_VALUE (z)));
9477#else
9478 double re = SCM_COMPLEX_REAL (z);
9479 double im = SCM_COMPLEX_IMAG (z);
9480 return scm_c_make_rectangular (log (hypot (re, im)),
9481 atan2 (im, re));
9482#endif
9483 }
a5f6b751
MW
9484 else if (SCM_REALP (z))
9485 return log_of_shifted_double (SCM_REAL_VALUE (z), 0);
9486 else if (SCM_I_INUMP (z))
8ab3d8a0 9487 {
a5f6b751
MW
9488#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
9489 if (scm_is_eq (z, SCM_INUM0))
9490 scm_num_overflow (s_scm_log);
9491#endif
9492 return log_of_shifted_double (SCM_I_INUM (z), 0);
8ab3d8a0 9493 }
a5f6b751
MW
9494 else if (SCM_BIGP (z))
9495 return log_of_exact_integer (z);
9496 else if (SCM_FRACTIONP (z))
9497 return log_of_fraction (SCM_FRACTION_NUMERATOR (z),
9498 SCM_FRACTION_DENOMINATOR (z));
2519490c
MW
9499 else
9500 SCM_WTA_DISPATCH_1 (g_scm_log, z, 1, s_scm_log);
8ab3d8a0
KR
9501}
9502#undef FUNC_NAME
9503
9504
2519490c
MW
9505SCM_PRIMITIVE_GENERIC (scm_log10, "log10", 1, 0, 0,
9506 (SCM z),
9507 "Return the base 10 logarithm of @var{z}.")
8ab3d8a0
KR
9508#define FUNC_NAME s_scm_log10
9509{
9510 if (SCM_COMPLEXP (z))
9511 {
9512 /* Mingw has clog() but not clog10(). (Maybe it'd be worth using
9513 clog() and a multiply by M_LOG10E, rather than the fallback
9514 log10+hypot+atan2.) */
f328f862
LC
9515#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
9516 && defined SCM_COMPLEX_VALUE
8ab3d8a0
KR
9517 return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
9518#else
9519 double re = SCM_COMPLEX_REAL (z);
9520 double im = SCM_COMPLEX_IMAG (z);
9521 return scm_c_make_rectangular (log10 (hypot (re, im)),
9522 M_LOG10E * atan2 (im, re));
9523#endif
9524 }
a5f6b751 9525 else if (SCM_REALP (z) || SCM_I_INUMP (z))
8ab3d8a0 9526 {
a5f6b751
MW
9527#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
9528 if (scm_is_eq (z, SCM_INUM0))
9529 scm_num_overflow (s_scm_log10);
9530#endif
9531 {
9532 double re = scm_to_double (z);
9533 double l = log10 (fabs (re));
9534 if (re > 0.0 || double_is_non_negative_zero (re))
9535 return scm_from_double (l);
9536 else
9537 return scm_c_make_rectangular (l, M_LOG10E * M_PI);
9538 }
8ab3d8a0 9539 }
a5f6b751
MW
9540 else if (SCM_BIGP (z))
9541 return scm_product (flo_log10e, log_of_exact_integer (z));
9542 else if (SCM_FRACTIONP (z))
9543 return scm_product (flo_log10e,
9544 log_of_fraction (SCM_FRACTION_NUMERATOR (z),
9545 SCM_FRACTION_DENOMINATOR (z)));
2519490c
MW
9546 else
9547 SCM_WTA_DISPATCH_1 (g_scm_log10, z, 1, s_scm_log10);
8ab3d8a0
KR
9548}
9549#undef FUNC_NAME
9550
9551
2519490c
MW
9552SCM_PRIMITIVE_GENERIC (scm_exp, "exp", 1, 0, 0,
9553 (SCM z),
9554 "Return @math{e} to the power of @var{z}, where @math{e} is the\n"
9555 "base of natural logarithms (2.71828@dots{}).")
8ab3d8a0
KR
9556#define FUNC_NAME s_scm_exp
9557{
9558 if (SCM_COMPLEXP (z))
9559 {
03976fee
AW
9560#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CEXP \
9561 && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
9562 return scm_from_complex_double (cexp (SCM_COMPLEX_VALUE (z)));
9563#else
9564 return scm_c_make_polar (exp (SCM_COMPLEX_REAL (z)),
9565 SCM_COMPLEX_IMAG (z));
9566#endif
9567 }
2519490c 9568 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
9569 {
9570 /* When z is a negative bignum the conversion to double overflows,
9571 giving -infinity, but that's ok, the exp is still 0.0. */
9572 return scm_from_double (exp (scm_to_double (z)));
9573 }
2519490c
MW
9574 else
9575 SCM_WTA_DISPATCH_1 (g_scm_exp, z, 1, s_scm_exp);
8ab3d8a0
KR
9576}
9577#undef FUNC_NAME
9578
9579
882c8963
MW
9580SCM_DEFINE (scm_i_exact_integer_sqrt, "exact-integer-sqrt", 1, 0, 0,
9581 (SCM k),
9582 "Return two exact non-negative integers @var{s} and @var{r}\n"
9583 "such that @math{@var{k} = @var{s}^2 + @var{r}} and\n"
9584 "@math{@var{s}^2 <= @var{k} < (@var{s} + 1)^2}.\n"
9585 "An error is raised if @var{k} is not an exact non-negative integer.\n"
9586 "\n"
9587 "@lisp\n"
9588 "(exact-integer-sqrt 10) @result{} 3 and 1\n"
9589 "@end lisp")
9590#define FUNC_NAME s_scm_i_exact_integer_sqrt
9591{
9592 SCM s, r;
9593
9594 scm_exact_integer_sqrt (k, &s, &r);
9595 return scm_values (scm_list_2 (s, r));
9596}
9597#undef FUNC_NAME
9598
9599void
9600scm_exact_integer_sqrt (SCM k, SCM *sp, SCM *rp)
9601{
9602 if (SCM_LIKELY (SCM_I_INUMP (k)))
9603 {
9604 scm_t_inum kk = SCM_I_INUM (k);
9605 scm_t_inum uu = kk;
9606 scm_t_inum ss;
9607
9608 if (SCM_LIKELY (kk > 0))
9609 {
9610 do
9611 {
9612 ss = uu;
9613 uu = (ss + kk/ss) / 2;
9614 } while (uu < ss);
9615 *sp = SCM_I_MAKINUM (ss);
9616 *rp = SCM_I_MAKINUM (kk - ss*ss);
9617 }
9618 else if (SCM_LIKELY (kk == 0))
9619 *sp = *rp = SCM_INUM0;
9620 else
9621 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9622 "exact non-negative integer");
9623 }
9624 else if (SCM_LIKELY (SCM_BIGP (k)))
9625 {
9626 SCM s, r;
9627
9628 if (mpz_sgn (SCM_I_BIG_MPZ (k)) < 0)
9629 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9630 "exact non-negative integer");
9631 s = scm_i_mkbig ();
9632 r = scm_i_mkbig ();
9633 mpz_sqrtrem (SCM_I_BIG_MPZ (s), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (k));
9634 scm_remember_upto_here_1 (k);
9635 *sp = scm_i_normbig (s);
9636 *rp = scm_i_normbig (r);
9637 }
9638 else
9639 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9640 "exact non-negative integer");
9641}
9642
9643
2519490c
MW
9644SCM_PRIMITIVE_GENERIC (scm_sqrt, "sqrt", 1, 0, 0,
9645 (SCM z),
9646 "Return the square root of @var{z}. Of the two possible roots\n"
ffb62a43 9647 "(positive and negative), the one with positive real part\n"
2519490c
MW
9648 "is returned, or if that's zero then a positive imaginary part.\n"
9649 "Thus,\n"
9650 "\n"
9651 "@example\n"
9652 "(sqrt 9.0) @result{} 3.0\n"
9653 "(sqrt -9.0) @result{} 0.0+3.0i\n"
9654 "(sqrt 1.0+1.0i) @result{} 1.09868411346781+0.455089860562227i\n"
9655 "(sqrt -1.0-1.0i) @result{} 0.455089860562227-1.09868411346781i\n"
9656 "@end example")
8ab3d8a0
KR
9657#define FUNC_NAME s_scm_sqrt
9658{
2519490c 9659 if (SCM_COMPLEXP (z))
8ab3d8a0 9660 {
f328f862
LC
9661#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT \
9662 && defined SCM_COMPLEX_VALUE
2519490c 9663 return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (z)));
8ab3d8a0 9664#else
2519490c
MW
9665 double re = SCM_COMPLEX_REAL (z);
9666 double im = SCM_COMPLEX_IMAG (z);
8ab3d8a0
KR
9667 return scm_c_make_polar (sqrt (hypot (re, im)),
9668 0.5 * atan2 (im, re));
9669#endif
9670 }
2519490c 9671 else if (SCM_NUMBERP (z))
8ab3d8a0 9672 {
2519490c 9673 double xx = scm_to_double (z);
8ab3d8a0
KR
9674 if (xx < 0)
9675 return scm_c_make_rectangular (0.0, sqrt (-xx));
9676 else
9677 return scm_from_double (sqrt (xx));
9678 }
2519490c
MW
9679 else
9680 SCM_WTA_DISPATCH_1 (g_scm_sqrt, z, 1, s_scm_sqrt);
8ab3d8a0
KR
9681}
9682#undef FUNC_NAME
9683
9684
9685
0f2d19dd
JB
9686void
9687scm_init_numbers ()
0f2d19dd 9688{
0b799eea
MV
9689 int i;
9690
713a4259
KR
9691 mpz_init_set_si (z_negative_one, -1);
9692
a261c0e9
DH
9693 /* It may be possible to tune the performance of some algorithms by using
9694 * the following constants to avoid the creation of bignums. Please, before
9695 * using these values, remember the two rules of program optimization:
9696 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 9697 scm_c_define ("most-positive-fixnum",
d956fa6f 9698 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 9699 scm_c_define ("most-negative-fixnum",
d956fa6f 9700 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 9701
f3ae5d60
MD
9702 scm_add_feature ("complex");
9703 scm_add_feature ("inexact");
e7efe8e7 9704 flo0 = scm_from_double (0.0);
a5f6b751 9705 flo_log10e = scm_from_double (M_LOG10E);
0b799eea
MV
9706
9707 /* determine floating point precision */
55f26379 9708 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
9709 {
9710 init_dblprec(&scm_dblprec[i-2],i);
9711 init_fx_radix(fx_per_radix[i-2],i);
9712 }
f872b822 9713#ifdef DBL_DIG
0b799eea 9714 /* hard code precision for base 10 if the preprocessor tells us to... */
f39448c5 9715 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
0b799eea 9716#endif
1be6b49c 9717
cff5fa33 9718 exactly_one_half = scm_divide (SCM_INUM1, SCM_I_MAKINUM (2));
a0599745 9719#include "libguile/numbers.x"
0f2d19dd 9720}
89e00824
ML
9721
9722/*
9723 Local Variables:
9724 c-file-style: "gnu"
9725 End:
9726*/