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