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