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