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