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