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