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