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