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