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