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