Handle products with exact 0 differently
[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
5e791807 5903 xinum:
e11e83f3 5904 xx = SCM_I_INUM (x);
f4c627b3 5905
0aacf84e
MD
5906 switch (xx)
5907 {
5e791807
MW
5908 case 1:
5909 /* exact1 is the universal multiplicative identity */
5910 return y;
5911 break;
5912 case 0:
5913 /* exact0 times a fixnum is exact0: optimize this case */
5914 if (SCM_LIKELY (SCM_I_INUMP (y)))
5915 return SCM_INUM0;
5916 /* if the other argument is inexact, the result is inexact,
5917 and we must do the multiplication in order to handle
5918 infinities and NaNs properly. */
5919 else if (SCM_REALP (y))
5920 return scm_from_double (0.0 * SCM_REAL_VALUE (y));
5921 else if (SCM_COMPLEXP (y))
5922 return scm_c_make_rectangular (0.0 * SCM_COMPLEX_REAL (y),
5923 0.0 * SCM_COMPLEX_IMAG (y));
5924 /* we've already handled inexact numbers,
5925 so y must be exact, and we return exact0 */
5926 else if (SCM_NUMP (y))
5927 return SCM_INUM0;
5928 else
5929 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
5930 break;
5931 case -1:
b5c40589 5932 /*
5e791807
MW
5933 * This case is important for more than just optimization.
5934 * It handles the case of negating
b5c40589
MW
5935 * (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
5936 * which is a bignum that must be changed back into a fixnum.
5937 * Failure to do so will cause the following to return #f:
5938 * (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
5939 */
b5c40589
MW
5940 return scm_difference(y, SCM_UNDEFINED);
5941 break;
0aacf84e 5942 }
f4c627b3 5943
9cc37597 5944 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 5945 {
e25f3727
AW
5946 scm_t_inum yy = SCM_I_INUM (y);
5947 scm_t_inum kk = xx * yy;
d956fa6f 5948 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 5949 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
5950 return k;
5951 else
5952 {
e25f3727 5953 SCM result = scm_i_inum2big (xx);
0aacf84e
MD
5954 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
5955 return scm_i_normbig (result);
5956 }
5957 }
5958 else if (SCM_BIGP (y))
5959 {
5960 SCM result = scm_i_mkbig ();
5961 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
5962 scm_remember_upto_here_1 (y);
5963 return result;
5964 }
5965 else if (SCM_REALP (y))
55f26379 5966 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 5967 else if (SCM_COMPLEXP (y))
8507ec80 5968 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 5969 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 5970 else if (SCM_FRACTIONP (y))
cba42c93 5971 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 5972 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
5973 else
5974 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 5975 }
0aacf84e
MD
5976 else if (SCM_BIGP (x))
5977 {
e11e83f3 5978 if (SCM_I_INUMP (y))
0aacf84e
MD
5979 {
5980 SCM_SWAP (x, y);
5e791807 5981 goto xinum;
0aacf84e
MD
5982 }
5983 else if (SCM_BIGP (y))
5984 {
5985 SCM result = scm_i_mkbig ();
5986 mpz_mul (SCM_I_BIG_MPZ (result),
5987 SCM_I_BIG_MPZ (x),
5988 SCM_I_BIG_MPZ (y));
5989 scm_remember_upto_here_2 (x, y);
5990 return result;
5991 }
5992 else if (SCM_REALP (y))
5993 {
5994 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
5995 scm_remember_upto_here_1 (x);
55f26379 5996 return scm_from_double (result);
0aacf84e
MD
5997 }
5998 else if (SCM_COMPLEXP (y))
5999 {
6000 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
6001 scm_remember_upto_here_1 (x);
8507ec80 6002 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
6003 z * SCM_COMPLEX_IMAG (y));
6004 }
f92e85f7 6005 else if (SCM_FRACTIONP (y))
cba42c93 6006 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 6007 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
6008 else
6009 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6010 }
0aacf84e
MD
6011 else if (SCM_REALP (x))
6012 {
e11e83f3 6013 if (SCM_I_INUMP (y))
5e791807
MW
6014 {
6015 SCM_SWAP (x, y);
6016 goto xinum;
6017 }
0aacf84e
MD
6018 else if (SCM_BIGP (y))
6019 {
6020 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
6021 scm_remember_upto_here_1 (y);
55f26379 6022 return scm_from_double (result);
0aacf84e
MD
6023 }
6024 else if (SCM_REALP (y))
55f26379 6025 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 6026 else if (SCM_COMPLEXP (y))
8507ec80 6027 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 6028 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 6029 else if (SCM_FRACTIONP (y))
55f26379 6030 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
6031 else
6032 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6033 }
0aacf84e
MD
6034 else if (SCM_COMPLEXP (x))
6035 {
e11e83f3 6036 if (SCM_I_INUMP (y))
5e791807
MW
6037 {
6038 SCM_SWAP (x, y);
6039 goto xinum;
6040 }
0aacf84e
MD
6041 else if (SCM_BIGP (y))
6042 {
6043 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
6044 scm_remember_upto_here_1 (y);
8507ec80 6045 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 6046 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
6047 }
6048 else if (SCM_REALP (y))
8507ec80 6049 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
6050 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
6051 else if (SCM_COMPLEXP (y))
6052 {
8507ec80 6053 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
6054 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
6055 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
6056 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
6057 }
f92e85f7
MV
6058 else if (SCM_FRACTIONP (y))
6059 {
6060 double yy = scm_i_fraction2double (y);
8507ec80 6061 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
6062 yy * SCM_COMPLEX_IMAG (x));
6063 }
6064 else
6065 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
6066 }
6067 else if (SCM_FRACTIONP (x))
6068 {
e11e83f3 6069 if (SCM_I_INUMP (y))
cba42c93 6070 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
6071 SCM_FRACTION_DENOMINATOR (x));
6072 else if (SCM_BIGP (y))
cba42c93 6073 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
6074 SCM_FRACTION_DENOMINATOR (x));
6075 else if (SCM_REALP (y))
55f26379 6076 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
6077 else if (SCM_COMPLEXP (y))
6078 {
6079 double xx = scm_i_fraction2double (x);
8507ec80 6080 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
6081 xx * SCM_COMPLEX_IMAG (y));
6082 }
6083 else if (SCM_FRACTIONP (y))
6084 /* a/b * c/d = ac / bd */
cba42c93 6085 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6086 SCM_FRACTION_NUMERATOR (y)),
6087 scm_product (SCM_FRACTION_DENOMINATOR (x),
6088 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
6089 else
6090 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 6091 }
0aacf84e 6092 else
f4c627b3 6093 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
6094}
6095
7351e207
MV
6096#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
6097 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
6098#define ALLOW_DIVIDE_BY_ZERO
6099/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
6100#endif
0f2d19dd 6101
ba74ef4e
MV
6102/* The code below for complex division is adapted from the GNU
6103 libstdc++, which adapted it from f2c's libF77, and is subject to
6104 this copyright: */
6105
6106/****************************************************************
6107Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
6108
6109Permission to use, copy, modify, and distribute this software
6110and its documentation for any purpose and without fee is hereby
6111granted, provided that the above copyright notice appear in all
6112copies and that both that the copyright notice and this
6113permission notice and warranty disclaimer appear in supporting
6114documentation, and that the names of AT&T Bell Laboratories or
6115Bellcore or any of their entities not be used in advertising or
6116publicity pertaining to distribution of the software without
6117specific, written prior permission.
6118
6119AT&T and Bellcore disclaim all warranties with regard to this
6120software, including all implied warranties of merchantability
6121and fitness. In no event shall AT&T or Bellcore be liable for
6122any special, indirect or consequential damages or any damages
6123whatsoever resulting from loss of use, data or profits, whether
6124in an action of contract, negligence or other tortious action,
6125arising out of or in connection with the use or performance of
6126this software.
6127****************************************************************/
6128
78d3deb1
AW
6129SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
6130 (SCM x, SCM y, SCM rest),
6131 "Divide the first argument by the product of the remaining\n"
6132 "arguments. If called with one argument @var{z1}, 1/@var{z1} is\n"
6133 "returned.")
6134#define FUNC_NAME s_scm_i_divide
6135{
6136 while (!scm_is_null (rest))
6137 { x = scm_divide (x, y);
6138 y = scm_car (rest);
6139 rest = scm_cdr (rest);
6140 }
6141 return scm_divide (x, y);
6142}
6143#undef FUNC_NAME
6144
6145#define s_divide s_scm_i_divide
6146#define g_divide g_scm_i_divide
6147
f92e85f7 6148static SCM
78d3deb1
AW
6149do_divide (SCM x, SCM y, int inexact)
6150#define FUNC_NAME s_divide
0f2d19dd 6151{
f8de44c1
DH
6152 double a;
6153
9cc37597 6154 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
6155 {
6156 if (SCM_UNBNDP (x))
6157 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 6158 else if (SCM_I_INUMP (x))
0aacf84e 6159 {
e25f3727 6160 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
6161 if (xx == 1 || xx == -1)
6162 return x;
7351e207 6163#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6164 else if (xx == 0)
6165 scm_num_overflow (s_divide);
7351e207 6166#endif
0aacf84e 6167 else
f92e85f7
MV
6168 {
6169 if (inexact)
55f26379 6170 return scm_from_double (1.0 / (double) xx);
cff5fa33 6171 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 6172 }
0aacf84e
MD
6173 }
6174 else if (SCM_BIGP (x))
f92e85f7
MV
6175 {
6176 if (inexact)
55f26379 6177 return scm_from_double (1.0 / scm_i_big2dbl (x));
cff5fa33 6178 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 6179 }
0aacf84e
MD
6180 else if (SCM_REALP (x))
6181 {
6182 double xx = SCM_REAL_VALUE (x);
7351e207 6183#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6184 if (xx == 0.0)
6185 scm_num_overflow (s_divide);
6186 else
7351e207 6187#endif
55f26379 6188 return scm_from_double (1.0 / xx);
0aacf84e
MD
6189 }
6190 else if (SCM_COMPLEXP (x))
6191 {
6192 double r = SCM_COMPLEX_REAL (x);
6193 double i = SCM_COMPLEX_IMAG (x);
4c6e36a6 6194 if (fabs(r) <= fabs(i))
0aacf84e
MD
6195 {
6196 double t = r / i;
6197 double d = i * (1.0 + t * t);
8507ec80 6198 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
6199 }
6200 else
6201 {
6202 double t = i / r;
6203 double d = r * (1.0 + t * t);
8507ec80 6204 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
6205 }
6206 }
f92e85f7 6207 else if (SCM_FRACTIONP (x))
cba42c93 6208 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 6209 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
6210 else
6211 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 6212 }
f8de44c1 6213
9cc37597 6214 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 6215 {
e25f3727 6216 scm_t_inum xx = SCM_I_INUM (x);
9cc37597 6217 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 6218 {
e25f3727 6219 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6220 if (yy == 0)
6221 {
7351e207 6222#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 6223 scm_num_overflow (s_divide);
7351e207 6224#else
55f26379 6225 return scm_from_double ((double) xx / (double) yy);
7351e207 6226#endif
0aacf84e
MD
6227 }
6228 else if (xx % yy != 0)
f92e85f7
MV
6229 {
6230 if (inexact)
55f26379 6231 return scm_from_double ((double) xx / (double) yy);
cba42c93 6232 else return scm_i_make_ratio (x, y);
f92e85f7 6233 }
0aacf84e
MD
6234 else
6235 {
e25f3727 6236 scm_t_inum z = xx / yy;
0aacf84e 6237 if (SCM_FIXABLE (z))
d956fa6f 6238 return SCM_I_MAKINUM (z);
0aacf84e 6239 else
e25f3727 6240 return scm_i_inum2big (z);
0aacf84e 6241 }
f872b822 6242 }
0aacf84e 6243 else if (SCM_BIGP (y))
f92e85f7
MV
6244 {
6245 if (inexact)
55f26379 6246 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 6247 else return scm_i_make_ratio (x, y);
f92e85f7 6248 }
0aacf84e
MD
6249 else if (SCM_REALP (y))
6250 {
6251 double yy = SCM_REAL_VALUE (y);
7351e207 6252#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6253 if (yy == 0.0)
6254 scm_num_overflow (s_divide);
6255 else
7351e207 6256#endif
55f26379 6257 return scm_from_double ((double) xx / yy);
ba74ef4e 6258 }
0aacf84e
MD
6259 else if (SCM_COMPLEXP (y))
6260 {
6261 a = xx;
6262 complex_div: /* y _must_ be a complex number */
6263 {
6264 double r = SCM_COMPLEX_REAL (y);
6265 double i = SCM_COMPLEX_IMAG (y);
4c6e36a6 6266 if (fabs(r) <= fabs(i))
0aacf84e
MD
6267 {
6268 double t = r / i;
6269 double d = i * (1.0 + t * t);
8507ec80 6270 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
6271 }
6272 else
6273 {
6274 double t = i / r;
6275 double d = r * (1.0 + t * t);
8507ec80 6276 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
6277 }
6278 }
6279 }
f92e85f7
MV
6280 else if (SCM_FRACTIONP (y))
6281 /* a / b/c = ac / b */
cba42c93 6282 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 6283 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
6284 else
6285 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 6286 }
0aacf84e
MD
6287 else if (SCM_BIGP (x))
6288 {
e11e83f3 6289 if (SCM_I_INUMP (y))
0aacf84e 6290 {
e25f3727 6291 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6292 if (yy == 0)
6293 {
7351e207 6294#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 6295 scm_num_overflow (s_divide);
7351e207 6296#else
0aacf84e
MD
6297 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6298 scm_remember_upto_here_1 (x);
6299 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 6300#endif
0aacf84e
MD
6301 }
6302 else if (yy == 1)
6303 return x;
6304 else
6305 {
6306 /* FIXME: HMM, what are the relative performance issues here?
6307 We need to test. Is it faster on average to test
6308 divisible_p, then perform whichever operation, or is it
6309 faster to perform the integer div opportunistically and
6310 switch to real if there's a remainder? For now we take the
6311 middle ground: test, then if divisible, use the faster div
6312 func. */
6313
e25f3727 6314 scm_t_inum abs_yy = yy < 0 ? -yy : yy;
0aacf84e
MD
6315 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
6316
6317 if (divisible_p)
6318 {
6319 SCM result = scm_i_mkbig ();
6320 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
6321 scm_remember_upto_here_1 (x);
6322 if (yy < 0)
6323 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
6324 return scm_i_normbig (result);
6325 }
6326 else
f92e85f7
MV
6327 {
6328 if (inexact)
55f26379 6329 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 6330 else return scm_i_make_ratio (x, y);
f92e85f7 6331 }
0aacf84e
MD
6332 }
6333 }
6334 else if (SCM_BIGP (y))
6335 {
a4955a04
MW
6336 /* big_x / big_y */
6337 if (inexact)
0aacf84e 6338 {
a4955a04
MW
6339 /* It's easily possible for the ratio x/y to fit a double
6340 but one or both x and y be too big to fit a double,
6341 hence the use of mpq_get_d rather than converting and
6342 dividing. */
6343 mpq_t q;
6344 *mpq_numref(q) = *SCM_I_BIG_MPZ (x);
6345 *mpq_denref(q) = *SCM_I_BIG_MPZ (y);
6346 return scm_from_double (mpq_get_d (q));
0aacf84e
MD
6347 }
6348 else
6349 {
a4955a04
MW
6350 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
6351 SCM_I_BIG_MPZ (y));
6352 if (divisible_p)
6353 {
6354 SCM result = scm_i_mkbig ();
6355 mpz_divexact (SCM_I_BIG_MPZ (result),
6356 SCM_I_BIG_MPZ (x),
6357 SCM_I_BIG_MPZ (y));
6358 scm_remember_upto_here_2 (x, y);
6359 return scm_i_normbig (result);
6360 }
6361 else
6362 return scm_i_make_ratio (x, y);
0aacf84e
MD
6363 }
6364 }
6365 else if (SCM_REALP (y))
6366 {
6367 double yy = SCM_REAL_VALUE (y);
7351e207 6368#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6369 if (yy == 0.0)
6370 scm_num_overflow (s_divide);
6371 else
7351e207 6372#endif
55f26379 6373 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
6374 }
6375 else if (SCM_COMPLEXP (y))
6376 {
6377 a = scm_i_big2dbl (x);
6378 goto complex_div;
6379 }
f92e85f7 6380 else if (SCM_FRACTIONP (y))
cba42c93 6381 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 6382 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
6383 else
6384 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 6385 }
0aacf84e
MD
6386 else if (SCM_REALP (x))
6387 {
6388 double rx = SCM_REAL_VALUE (x);
e11e83f3 6389 if (SCM_I_INUMP (y))
0aacf84e 6390 {
e25f3727 6391 scm_t_inum yy = SCM_I_INUM (y);
7351e207 6392#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6393 if (yy == 0)
6394 scm_num_overflow (s_divide);
6395 else
7351e207 6396#endif
55f26379 6397 return scm_from_double (rx / (double) yy);
0aacf84e
MD
6398 }
6399 else if (SCM_BIGP (y))
6400 {
6401 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
6402 scm_remember_upto_here_1 (y);
55f26379 6403 return scm_from_double (rx / dby);
0aacf84e
MD
6404 }
6405 else if (SCM_REALP (y))
6406 {
6407 double yy = SCM_REAL_VALUE (y);
7351e207 6408#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6409 if (yy == 0.0)
6410 scm_num_overflow (s_divide);
6411 else
7351e207 6412#endif
55f26379 6413 return scm_from_double (rx / yy);
0aacf84e
MD
6414 }
6415 else if (SCM_COMPLEXP (y))
6416 {
6417 a = rx;
6418 goto complex_div;
6419 }
f92e85f7 6420 else if (SCM_FRACTIONP (y))
55f26379 6421 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
6422 else
6423 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 6424 }
0aacf84e
MD
6425 else if (SCM_COMPLEXP (x))
6426 {
6427 double rx = SCM_COMPLEX_REAL (x);
6428 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 6429 if (SCM_I_INUMP (y))
0aacf84e 6430 {
e25f3727 6431 scm_t_inum yy = SCM_I_INUM (y);
7351e207 6432#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
6433 if (yy == 0)
6434 scm_num_overflow (s_divide);
6435 else
7351e207 6436#endif
0aacf84e
MD
6437 {
6438 double d = yy;
8507ec80 6439 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
6440 }
6441 }
6442 else if (SCM_BIGP (y))
6443 {
6444 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
6445 scm_remember_upto_here_1 (y);
8507ec80 6446 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
6447 }
6448 else if (SCM_REALP (y))
6449 {
6450 double yy = SCM_REAL_VALUE (y);
7351e207 6451#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
6452 if (yy == 0.0)
6453 scm_num_overflow (s_divide);
6454 else
7351e207 6455#endif
8507ec80 6456 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
6457 }
6458 else if (SCM_COMPLEXP (y))
6459 {
6460 double ry = SCM_COMPLEX_REAL (y);
6461 double iy = SCM_COMPLEX_IMAG (y);
4c6e36a6 6462 if (fabs(ry) <= fabs(iy))
0aacf84e
MD
6463 {
6464 double t = ry / iy;
6465 double d = iy * (1.0 + t * t);
8507ec80 6466 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
6467 }
6468 else
6469 {
6470 double t = iy / ry;
6471 double d = ry * (1.0 + t * t);
8507ec80 6472 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
6473 }
6474 }
f92e85f7
MV
6475 else if (SCM_FRACTIONP (y))
6476 {
6477 double yy = scm_i_fraction2double (y);
8507ec80 6478 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 6479 }
0aacf84e
MD
6480 else
6481 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 6482 }
f92e85f7
MV
6483 else if (SCM_FRACTIONP (x))
6484 {
e11e83f3 6485 if (SCM_I_INUMP (y))
f92e85f7 6486 {
e25f3727 6487 scm_t_inum yy = SCM_I_INUM (y);
f92e85f7
MV
6488#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
6489 if (yy == 0)
6490 scm_num_overflow (s_divide);
6491 else
6492#endif
cba42c93 6493 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6494 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
6495 }
6496 else if (SCM_BIGP (y))
6497 {
cba42c93 6498 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
6499 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
6500 }
6501 else if (SCM_REALP (y))
6502 {
6503 double yy = SCM_REAL_VALUE (y);
6504#ifndef ALLOW_DIVIDE_BY_ZERO
6505 if (yy == 0.0)
6506 scm_num_overflow (s_divide);
6507 else
6508#endif
55f26379 6509 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
6510 }
6511 else if (SCM_COMPLEXP (y))
6512 {
6513 a = scm_i_fraction2double (x);
6514 goto complex_div;
6515 }
6516 else if (SCM_FRACTIONP (y))
cba42c93 6517 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
6518 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
6519 else
6520 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
6521 }
0aacf84e 6522 else
f8de44c1 6523 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 6524}
f92e85f7
MV
6525
6526SCM
6527scm_divide (SCM x, SCM y)
6528{
78d3deb1 6529 return do_divide (x, y, 0);
f92e85f7
MV
6530}
6531
6532static SCM scm_divide2real (SCM x, SCM y)
6533{
78d3deb1 6534 return do_divide (x, y, 1);
f92e85f7 6535}
c05e97b7 6536#undef FUNC_NAME
0f2d19dd 6537
fa605590 6538
0f2d19dd 6539double
3101f40f 6540scm_c_truncate (double x)
0f2d19dd 6541{
fa605590
KR
6542#if HAVE_TRUNC
6543 return trunc (x);
6544#else
f872b822
MD
6545 if (x < 0.0)
6546 return -floor (-x);
6547 return floor (x);
fa605590 6548#endif
0f2d19dd 6549}
0f2d19dd 6550
3101f40f
MV
6551/* scm_c_round is done using floor(x+0.5) to round to nearest and with
6552 half-way case (ie. when x is an integer plus 0.5) going upwards.
6553 Then half-way cases are identified and adjusted down if the
6554 round-upwards didn't give the desired even integer.
6187f48b
KR
6555
6556 "plus_half == result" identifies a half-way case. If plus_half, which is
6557 x + 0.5, is an integer then x must be an integer plus 0.5.
6558
6559 An odd "result" value is identified with result/2 != floor(result/2).
6560 This is done with plus_half, since that value is ready for use sooner in
6561 a pipelined cpu, and we're already requiring plus_half == result.
6562
6563 Note however that we need to be careful when x is big and already an
6564 integer. In that case "x+0.5" may round to an adjacent integer, causing
6565 us to return such a value, incorrectly. For instance if the hardware is
6566 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
6567 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
6568 returned. Or if the hardware is in round-upwards mode, then other bigger
6569 values like say x == 2^128 will see x+0.5 rounding up to the next higher
6570 representable value, 2^128+2^76 (or whatever), again incorrect.
6571
6572 These bad roundings of x+0.5 are avoided by testing at the start whether
6573 x is already an integer. If it is then clearly that's the desired result
6574 already. And if it's not then the exponent must be small enough to allow
6575 an 0.5 to be represented, and hence added without a bad rounding. */
6576
0f2d19dd 6577double
3101f40f 6578scm_c_round (double x)
0f2d19dd 6579{
6187f48b
KR
6580 double plus_half, result;
6581
6582 if (x == floor (x))
6583 return x;
6584
6585 plus_half = x + 0.5;
6586 result = floor (plus_half);
3101f40f 6587 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
6588 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
6589 ? result - 1
6590 : result);
0f2d19dd
JB
6591}
6592
f92e85f7
MV
6593SCM_DEFINE (scm_truncate_number, "truncate", 1, 0, 0,
6594 (SCM x),
6595 "Round the number @var{x} towards zero.")
6596#define FUNC_NAME s_scm_truncate_number
6597{
73e4de09 6598 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
6599 return scm_floor (x);
6600 else
6601 return scm_ceiling (x);
6602}
6603#undef FUNC_NAME
6604
f92e85f7
MV
6605SCM_DEFINE (scm_round_number, "round", 1, 0, 0,
6606 (SCM x),
6607 "Round the number @var{x} towards the nearest integer. "
6608 "When it is exactly halfway between two integers, "
6609 "round towards the even one.")
6610#define FUNC_NAME s_scm_round_number
6611{
e11e83f3 6612 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
6613 return x;
6614 else if (SCM_REALP (x))
3101f40f 6615 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
f92e85f7 6616 else
bae30667
KR
6617 {
6618 /* OPTIMIZE-ME: Fraction case could be done more efficiently by a
6619 single quotient+remainder division then examining to see which way
6620 the rounding should go. */
6621 SCM plus_half = scm_sum (x, exactly_one_half);
6622 SCM result = scm_floor (plus_half);
3101f40f 6623 /* Adjust so that the rounding is towards even. */
73e4de09
MV
6624 if (scm_is_true (scm_num_eq_p (plus_half, result))
6625 && scm_is_true (scm_odd_p (result)))
cff5fa33 6626 return scm_difference (result, SCM_INUM1);
bae30667
KR
6627 else
6628 return result;
6629 }
f92e85f7
MV
6630}
6631#undef FUNC_NAME
6632
6633SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
6634 (SCM x),
6635 "Round the number @var{x} towards minus infinity.")
6636#define FUNC_NAME s_scm_floor
6637{
e11e83f3 6638 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
6639 return x;
6640 else if (SCM_REALP (x))
55f26379 6641 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7
MV
6642 else if (SCM_FRACTIONP (x))
6643 {
6644 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
6645 SCM_FRACTION_DENOMINATOR (x));
73e4de09 6646 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
6647 {
6648 /* For positive x, rounding towards zero is correct. */
6649 return q;
6650 }
6651 else
6652 {
6653 /* For negative x, we need to return q-1 unless x is an
6654 integer. But fractions are never integer, per our
6655 assumptions. */
cff5fa33 6656 return scm_difference (q, SCM_INUM1);
f92e85f7
MV
6657 }
6658 }
6659 else
6660 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
6661}
6662#undef FUNC_NAME
6663
6664SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
6665 (SCM x),
6666 "Round the number @var{x} towards infinity.")
6667#define FUNC_NAME s_scm_ceiling
6668{
e11e83f3 6669 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
6670 return x;
6671 else if (SCM_REALP (x))
55f26379 6672 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7
MV
6673 else if (SCM_FRACTIONP (x))
6674 {
6675 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
6676 SCM_FRACTION_DENOMINATOR (x));
73e4de09 6677 if (scm_is_false (scm_positive_p (x)))
f92e85f7
MV
6678 {
6679 /* For negative x, rounding towards zero is correct. */
6680 return q;
6681 }
6682 else
6683 {
6684 /* For positive x, we need to return q+1 unless x is an
6685 integer. But fractions are never integer, per our
6686 assumptions. */
cff5fa33 6687 return scm_sum (q, SCM_INUM1);
f92e85f7
MV
6688 }
6689 }
6690 else
6691 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
6692}
6693#undef FUNC_NAME
0f2d19dd 6694
ad79736c
AW
6695/* sin/cos/tan/asin/acos/atan
6696 sinh/cosh/tanh/asinh/acosh/atanh
6697 Derived from "Transcen.scm", Complex trancendental functions for SCM.
6698 Written by Jerry D. Hedden, (C) FSF.
6699 See the file `COPYING' for terms applying to this program. */
0f2d19dd 6700
2519490c
MW
6701SCM_PRIMITIVE_GENERIC (scm_expt, "expt", 2, 0, 0,
6702 (SCM x, SCM y),
6703 "Return @var{x} raised to the power of @var{y}.")
6fc4d012 6704#define FUNC_NAME s_scm_expt
0f2d19dd 6705{
01c7284a
MW
6706 if (scm_is_integer (y))
6707 {
6708 if (scm_is_true (scm_exact_p (y)))
6709 return scm_integer_expt (x, y);
6710 else
6711 {
6712 /* Here we handle the case where the exponent is an inexact
6713 integer. We make the exponent exact in order to use
6714 scm_integer_expt, and thus avoid the spurious imaginary
6715 parts that may result from round-off errors in the general
6716 e^(y log x) method below (for example when squaring a large
6717 negative number). In this case, we must return an inexact
6718 result for correctness. We also make the base inexact so
6719 that scm_integer_expt will use fast inexact arithmetic
6720 internally. Note that making the base inexact is not
6721 sufficient to guarantee an inexact result, because
6722 scm_integer_expt will return an exact 1 when the exponent
6723 is 0, even if the base is inexact. */
6724 return scm_exact_to_inexact
6725 (scm_integer_expt (scm_exact_to_inexact (x),
6726 scm_inexact_to_exact (y)));
6727 }
6728 }
6fc4d012
AW
6729 else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
6730 {
6731 return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
6732 }
2519490c 6733 else if (scm_is_complex (x) && scm_is_complex (y))
6fc4d012 6734 return scm_exp (scm_product (scm_log (x), y));
2519490c
MW
6735 else if (scm_is_complex (x))
6736 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG2, s_scm_expt);
6737 else
6738 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG1, s_scm_expt);
0f2d19dd 6739}
1bbd0b84 6740#undef FUNC_NAME
0f2d19dd 6741
ad79736c
AW
6742SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
6743 (SCM z),
6744 "Compute the sine of @var{z}.")
6745#define FUNC_NAME s_scm_sin
6746{
6747 if (scm_is_real (z))
6748 return scm_from_double (sin (scm_to_double (z)));
6749 else if (SCM_COMPLEXP (z))
6750 { double x, y;
6751 x = SCM_COMPLEX_REAL (z);
6752 y = SCM_COMPLEX_IMAG (z);
6753 return scm_c_make_rectangular (sin (x) * cosh (y),
6754 cos (x) * sinh (y));
6755 }
6756 else
6757 SCM_WTA_DISPATCH_1 (g_scm_sin, z, 1, s_scm_sin);
6758}
6759#undef FUNC_NAME
0f2d19dd 6760
ad79736c
AW
6761SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
6762 (SCM z),
6763 "Compute the cosine of @var{z}.")
6764#define FUNC_NAME s_scm_cos
6765{
6766 if (scm_is_real (z))
6767 return scm_from_double (cos (scm_to_double (z)));
6768 else if (SCM_COMPLEXP (z))
6769 { double x, y;
6770 x = SCM_COMPLEX_REAL (z);
6771 y = SCM_COMPLEX_IMAG (z);
6772 return scm_c_make_rectangular (cos (x) * cosh (y),
6773 -sin (x) * sinh (y));
6774 }
6775 else
6776 SCM_WTA_DISPATCH_1 (g_scm_cos, z, 1, s_scm_cos);
6777}
6778#undef FUNC_NAME
6779
6780SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
6781 (SCM z),
6782 "Compute the tangent of @var{z}.")
6783#define FUNC_NAME s_scm_tan
0f2d19dd 6784{
ad79736c
AW
6785 if (scm_is_real (z))
6786 return scm_from_double (tan (scm_to_double (z)));
6787 else if (SCM_COMPLEXP (z))
6788 { double x, y, w;
6789 x = 2.0 * SCM_COMPLEX_REAL (z);
6790 y = 2.0 * SCM_COMPLEX_IMAG (z);
6791 w = cos (x) + cosh (y);
6792#ifndef ALLOW_DIVIDE_BY_ZERO
6793 if (w == 0.0)
6794 scm_num_overflow (s_scm_tan);
6795#endif
6796 return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
6797 }
6798 else
6799 SCM_WTA_DISPATCH_1 (g_scm_tan, z, 1, s_scm_tan);
6800}
6801#undef FUNC_NAME
6802
6803SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
6804 (SCM z),
6805 "Compute the hyperbolic sine of @var{z}.")
6806#define FUNC_NAME s_scm_sinh
6807{
6808 if (scm_is_real (z))
6809 return scm_from_double (sinh (scm_to_double (z)));
6810 else if (SCM_COMPLEXP (z))
6811 { double x, y;
6812 x = SCM_COMPLEX_REAL (z);
6813 y = SCM_COMPLEX_IMAG (z);
6814 return scm_c_make_rectangular (sinh (x) * cos (y),
6815 cosh (x) * sin (y));
6816 }
6817 else
6818 SCM_WTA_DISPATCH_1 (g_scm_sinh, z, 1, s_scm_sinh);
6819}
6820#undef FUNC_NAME
6821
6822SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
6823 (SCM z),
6824 "Compute the hyperbolic cosine of @var{z}.")
6825#define FUNC_NAME s_scm_cosh
6826{
6827 if (scm_is_real (z))
6828 return scm_from_double (cosh (scm_to_double (z)));
6829 else if (SCM_COMPLEXP (z))
6830 { double x, y;
6831 x = SCM_COMPLEX_REAL (z);
6832 y = SCM_COMPLEX_IMAG (z);
6833 return scm_c_make_rectangular (cosh (x) * cos (y),
6834 sinh (x) * sin (y));
6835 }
6836 else
6837 SCM_WTA_DISPATCH_1 (g_scm_cosh, z, 1, s_scm_cosh);
6838}
6839#undef FUNC_NAME
6840
6841SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
6842 (SCM z),
6843 "Compute the hyperbolic tangent of @var{z}.")
6844#define FUNC_NAME s_scm_tanh
6845{
6846 if (scm_is_real (z))
6847 return scm_from_double (tanh (scm_to_double (z)));
6848 else if (SCM_COMPLEXP (z))
6849 { double x, y, w;
6850 x = 2.0 * SCM_COMPLEX_REAL (z);
6851 y = 2.0 * SCM_COMPLEX_IMAG (z);
6852 w = cosh (x) + cos (y);
6853#ifndef ALLOW_DIVIDE_BY_ZERO
6854 if (w == 0.0)
6855 scm_num_overflow (s_scm_tanh);
6856#endif
6857 return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
6858 }
6859 else
6860 SCM_WTA_DISPATCH_1 (g_scm_tanh, z, 1, s_scm_tanh);
6861}
6862#undef FUNC_NAME
6863
6864SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
6865 (SCM z),
6866 "Compute the arc sine of @var{z}.")
6867#define FUNC_NAME s_scm_asin
6868{
6869 if (scm_is_real (z))
6870 {
6871 double w = scm_to_double (z);
6872 if (w >= -1.0 && w <= 1.0)
6873 return scm_from_double (asin (w));
6874 else
6875 return scm_product (scm_c_make_rectangular (0, -1),
6876 scm_sys_asinh (scm_c_make_rectangular (0, w)));
6877 }
6878 else if (SCM_COMPLEXP (z))
6879 { double x, y;
6880 x = SCM_COMPLEX_REAL (z);
6881 y = SCM_COMPLEX_IMAG (z);
6882 return scm_product (scm_c_make_rectangular (0, -1),
6883 scm_sys_asinh (scm_c_make_rectangular (-y, x)));
6884 }
6885 else
6886 SCM_WTA_DISPATCH_1 (g_scm_asin, z, 1, s_scm_asin);
6887}
6888#undef FUNC_NAME
6889
6890SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
6891 (SCM z),
6892 "Compute the arc cosine of @var{z}.")
6893#define FUNC_NAME s_scm_acos
6894{
6895 if (scm_is_real (z))
6896 {
6897 double w = scm_to_double (z);
6898 if (w >= -1.0 && w <= 1.0)
6899 return scm_from_double (acos (w));
6900 else
6901 return scm_sum (scm_from_double (acos (0.0)),
6902 scm_product (scm_c_make_rectangular (0, 1),
6903 scm_sys_asinh (scm_c_make_rectangular (0, w))));
6904 }
6905 else if (SCM_COMPLEXP (z))
6906 { double x, y;
6907 x = SCM_COMPLEX_REAL (z);
6908 y = SCM_COMPLEX_IMAG (z);
6909 return scm_sum (scm_from_double (acos (0.0)),
6910 scm_product (scm_c_make_rectangular (0, 1),
6911 scm_sys_asinh (scm_c_make_rectangular (-y, x))));
6912 }
6913 else
6914 SCM_WTA_DISPATCH_1 (g_scm_acos, z, 1, s_scm_acos);
6915}
6916#undef FUNC_NAME
6917
6918SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
6919 (SCM z, SCM y),
6920 "With one argument, compute the arc tangent of @var{z}.\n"
6921 "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
6922 "using the sign of @var{z} and @var{y} to determine the quadrant.")
6923#define FUNC_NAME s_scm_atan
6924{
6925 if (SCM_UNBNDP (y))
6926 {
6927 if (scm_is_real (z))
6928 return scm_from_double (atan (scm_to_double (z)));
6929 else if (SCM_COMPLEXP (z))
6930 {
6931 double v, w;
6932 v = SCM_COMPLEX_REAL (z);
6933 w = SCM_COMPLEX_IMAG (z);
6934 return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
6935 scm_c_make_rectangular (v, w + 1.0))),
6936 scm_c_make_rectangular (0, 2));
6937 }
6938 else
6939 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
6940 }
6941 else if (scm_is_real (z))
6942 {
6943 if (scm_is_real (y))
6944 return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
6945 else
6946 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
6947 }
6948 else
6949 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
6950}
6951#undef FUNC_NAME
6952
6953SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
6954 (SCM z),
6955 "Compute the inverse hyperbolic sine of @var{z}.")
6956#define FUNC_NAME s_scm_sys_asinh
6957{
6958 if (scm_is_real (z))
6959 return scm_from_double (asinh (scm_to_double (z)));
6960 else if (scm_is_number (z))
6961 return scm_log (scm_sum (z,
6962 scm_sqrt (scm_sum (scm_product (z, z),
cff5fa33 6963 SCM_INUM1))));
ad79736c
AW
6964 else
6965 SCM_WTA_DISPATCH_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
6966}
6967#undef FUNC_NAME
6968
6969SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
6970 (SCM z),
6971 "Compute the inverse hyperbolic cosine of @var{z}.")
6972#define FUNC_NAME s_scm_sys_acosh
6973{
6974 if (scm_is_real (z) && scm_to_double (z) >= 1.0)
6975 return scm_from_double (acosh (scm_to_double (z)));
6976 else if (scm_is_number (z))
6977 return scm_log (scm_sum (z,
6978 scm_sqrt (scm_difference (scm_product (z, z),
cff5fa33 6979 SCM_INUM1))));
ad79736c
AW
6980 else
6981 SCM_WTA_DISPATCH_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
6982}
6983#undef FUNC_NAME
6984
6985SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
6986 (SCM z),
6987 "Compute the inverse hyperbolic tangent of @var{z}.")
6988#define FUNC_NAME s_scm_sys_atanh
6989{
6990 if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
6991 return scm_from_double (atanh (scm_to_double (z)));
6992 else if (scm_is_number (z))
cff5fa33
MW
6993 return scm_divide (scm_log (scm_divide (scm_sum (SCM_INUM1, z),
6994 scm_difference (SCM_INUM1, z))),
ad79736c
AW
6995 SCM_I_MAKINUM (2));
6996 else
6997 SCM_WTA_DISPATCH_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
0f2d19dd 6998}
1bbd0b84 6999#undef FUNC_NAME
0f2d19dd 7000
8507ec80
MV
7001SCM
7002scm_c_make_rectangular (double re, double im)
7003{
7004 if (im == 0.0)
7005 return scm_from_double (re);
7006 else
7007 {
7008 SCM z;
03604fcf
LC
7009
7010 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
92d8fd32 7011 "complex"));
03604fcf 7012 SCM_SET_CELL_TYPE (z, scm_tc16_complex);
8507ec80
MV
7013 SCM_COMPLEX_REAL (z) = re;
7014 SCM_COMPLEX_IMAG (z) = im;
7015 return z;
7016 }
7017}
0f2d19dd 7018
a1ec6916 7019SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
a2c25234
LC
7020 (SCM real_part, SCM imaginary_part),
7021 "Return a complex number constructed of the given @var{real-part} "
7022 "and @var{imaginary-part} parts.")
1bbd0b84 7023#define FUNC_NAME s_scm_make_rectangular
0f2d19dd 7024{
ad79736c
AW
7025 SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
7026 SCM_ARG1, FUNC_NAME, "real");
7027 SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
7028 SCM_ARG2, FUNC_NAME, "real");
7029 return scm_c_make_rectangular (scm_to_double (real_part),
7030 scm_to_double (imaginary_part));
0f2d19dd 7031}
1bbd0b84 7032#undef FUNC_NAME
0f2d19dd 7033
8507ec80
MV
7034SCM
7035scm_c_make_polar (double mag, double ang)
7036{
7037 double s, c;
5e647d08
LC
7038
7039 /* The sincos(3) function is undocumented an broken on Tru64. Thus we only
7040 use it on Glibc-based systems that have it (it's a GNU extension). See
7041 http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
7042 details. */
7043#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
8507ec80
MV
7044 sincos (ang, &s, &c);
7045#else
7046 s = sin (ang);
7047 c = cos (ang);
7048#endif
7049 return scm_c_make_rectangular (mag * c, mag * s);
7050}
0f2d19dd 7051
a1ec6916 7052SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
27c37006 7053 (SCM x, SCM y),
942e5b91 7054 "Return the complex number @var{x} * e^(i * @var{y}).")
1bbd0b84 7055#define FUNC_NAME s_scm_make_polar
0f2d19dd 7056{
ad79736c
AW
7057 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
7058 SCM_ASSERT_TYPE (scm_is_real (y), y, SCM_ARG2, FUNC_NAME, "real");
7059 return scm_c_make_polar (scm_to_double (x), scm_to_double (y));
0f2d19dd 7060}
1bbd0b84 7061#undef FUNC_NAME
0f2d19dd
JB
7062
7063
2519490c
MW
7064SCM_PRIMITIVE_GENERIC (scm_real_part, "real-part", 1, 0, 0,
7065 (SCM z),
7066 "Return the real part of the number @var{z}.")
7067#define FUNC_NAME s_scm_real_part
0f2d19dd 7068{
2519490c 7069 if (SCM_COMPLEXP (z))
55f26379 7070 return scm_from_double (SCM_COMPLEX_REAL (z));
2519490c 7071 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_REALP (z) || SCM_FRACTIONP (z))
2fa2d879 7072 return z;
0aacf84e 7073 else
2519490c 7074 SCM_WTA_DISPATCH_1 (g_scm_real_part, z, SCM_ARG1, s_scm_real_part);
0f2d19dd 7075}
2519490c 7076#undef FUNC_NAME
0f2d19dd
JB
7077
7078
2519490c
MW
7079SCM_PRIMITIVE_GENERIC (scm_imag_part, "imag-part", 1, 0, 0,
7080 (SCM z),
7081 "Return the imaginary part of the number @var{z}.")
7082#define FUNC_NAME s_scm_imag_part
0f2d19dd 7083{
2519490c
MW
7084 if (SCM_COMPLEXP (z))
7085 return scm_from_double (SCM_COMPLEX_IMAG (z));
0aacf84e 7086 else if (SCM_REALP (z))
e7efe8e7 7087 return flo0;
2519490c 7088 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f92e85f7 7089 return SCM_INUM0;
0aacf84e 7090 else
2519490c 7091 SCM_WTA_DISPATCH_1 (g_scm_imag_part, z, SCM_ARG1, s_scm_imag_part);
0f2d19dd 7092}
2519490c 7093#undef FUNC_NAME
0f2d19dd 7094
2519490c
MW
7095SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
7096 (SCM z),
7097 "Return the numerator of the number @var{z}.")
7098#define FUNC_NAME s_scm_numerator
f92e85f7 7099{
2519490c 7100 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f92e85f7
MV
7101 return z;
7102 else if (SCM_FRACTIONP (z))
e2bf3b19 7103 return SCM_FRACTION_NUMERATOR (z);
f92e85f7
MV
7104 else if (SCM_REALP (z))
7105 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
7106 else
2519490c 7107 SCM_WTA_DISPATCH_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
f92e85f7 7108}
2519490c 7109#undef FUNC_NAME
f92e85f7
MV
7110
7111
2519490c
MW
7112SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
7113 (SCM z),
7114 "Return the denominator of the number @var{z}.")
7115#define FUNC_NAME s_scm_denominator
f92e85f7 7116{
2519490c 7117 if (SCM_I_INUMP (z) || SCM_BIGP (z))
cff5fa33 7118 return SCM_INUM1;
f92e85f7 7119 else if (SCM_FRACTIONP (z))
e2bf3b19 7120 return SCM_FRACTION_DENOMINATOR (z);
f92e85f7
MV
7121 else if (SCM_REALP (z))
7122 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
7123 else
2519490c 7124 SCM_WTA_DISPATCH_1 (g_scm_denominator, z, SCM_ARG1, s_scm_denominator);
f92e85f7 7125}
2519490c 7126#undef FUNC_NAME
0f2d19dd 7127
2519490c
MW
7128
7129SCM_PRIMITIVE_GENERIC (scm_magnitude, "magnitude", 1, 0, 0,
7130 (SCM z),
7131 "Return the magnitude of the number @var{z}. This is the same as\n"
7132 "@code{abs} for real arguments, but also allows complex numbers.")
7133#define FUNC_NAME s_scm_magnitude
0f2d19dd 7134{
e11e83f3 7135 if (SCM_I_INUMP (z))
0aacf84e 7136 {
e25f3727 7137 scm_t_inum zz = SCM_I_INUM (z);
0aacf84e
MD
7138 if (zz >= 0)
7139 return z;
7140 else if (SCM_POSFIXABLE (-zz))
d956fa6f 7141 return SCM_I_MAKINUM (-zz);
0aacf84e 7142 else
e25f3727 7143 return scm_i_inum2big (-zz);
5986c47d 7144 }
0aacf84e
MD
7145 else if (SCM_BIGP (z))
7146 {
7147 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
7148 scm_remember_upto_here_1 (z);
7149 if (sgn < 0)
7150 return scm_i_clonebig (z, 0);
7151 else
7152 return z;
5986c47d 7153 }
0aacf84e 7154 else if (SCM_REALP (z))
55f26379 7155 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 7156 else if (SCM_COMPLEXP (z))
55f26379 7157 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
7158 else if (SCM_FRACTIONP (z))
7159 {
73e4de09 7160 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 7161 return z;
cba42c93 7162 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
7163 SCM_FRACTION_DENOMINATOR (z));
7164 }
0aacf84e 7165 else
2519490c 7166 SCM_WTA_DISPATCH_1 (g_scm_magnitude, z, SCM_ARG1, s_scm_magnitude);
0f2d19dd 7167}
2519490c 7168#undef FUNC_NAME
0f2d19dd
JB
7169
7170
2519490c
MW
7171SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
7172 (SCM z),
7173 "Return the angle of the complex number @var{z}.")
7174#define FUNC_NAME s_scm_angle
0f2d19dd 7175{
c8ae173e 7176 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
e7efe8e7 7177 flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
7178 But if atan2 follows the floating point rounding mode, then the value
7179 is not a constant. Maybe it'd be close enough though. */
e11e83f3 7180 if (SCM_I_INUMP (z))
0aacf84e 7181 {
e11e83f3 7182 if (SCM_I_INUM (z) >= 0)
e7efe8e7 7183 return flo0;
0aacf84e 7184 else
55f26379 7185 return scm_from_double (atan2 (0.0, -1.0));
f872b822 7186 }
0aacf84e
MD
7187 else if (SCM_BIGP (z))
7188 {
7189 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
7190 scm_remember_upto_here_1 (z);
7191 if (sgn < 0)
55f26379 7192 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 7193 else
e7efe8e7 7194 return flo0;
0f2d19dd 7195 }
0aacf84e 7196 else if (SCM_REALP (z))
c8ae173e
KR
7197 {
7198 if (SCM_REAL_VALUE (z) >= 0)
e7efe8e7 7199 return flo0;
c8ae173e 7200 else
55f26379 7201 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 7202 }
0aacf84e 7203 else if (SCM_COMPLEXP (z))
55f26379 7204 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
7205 else if (SCM_FRACTIONP (z))
7206 {
73e4de09 7207 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
e7efe8e7 7208 return flo0;
55f26379 7209 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 7210 }
0aacf84e 7211 else
2519490c 7212 SCM_WTA_DISPATCH_1 (g_scm_angle, z, SCM_ARG1, s_scm_angle);
0f2d19dd 7213}
2519490c 7214#undef FUNC_NAME
0f2d19dd
JB
7215
7216
2519490c
MW
7217SCM_PRIMITIVE_GENERIC (scm_exact_to_inexact, "exact->inexact", 1, 0, 0,
7218 (SCM z),
7219 "Convert the number @var{z} to its inexact representation.\n")
7220#define FUNC_NAME s_scm_exact_to_inexact
3c9a524f 7221{
e11e83f3 7222 if (SCM_I_INUMP (z))
55f26379 7223 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 7224 else if (SCM_BIGP (z))
55f26379 7225 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 7226 else if (SCM_FRACTIONP (z))
55f26379 7227 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
7228 else if (SCM_INEXACTP (z))
7229 return z;
7230 else
2519490c 7231 SCM_WTA_DISPATCH_1 (g_scm_exact_to_inexact, z, 1, s_scm_exact_to_inexact);
3c9a524f 7232}
2519490c 7233#undef FUNC_NAME
3c9a524f
DH
7234
7235
2519490c
MW
7236SCM_PRIMITIVE_GENERIC (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
7237 (SCM z),
7238 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 7239#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 7240{
2519490c 7241 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f872b822 7242 return z;
0aacf84e
MD
7243 else if (SCM_REALP (z))
7244 {
2519490c 7245 if (!DOUBLE_IS_FINITE (SCM_REAL_VALUE (z)))
f92e85f7 7246 SCM_OUT_OF_RANGE (1, z);
2be24db4 7247 else
f92e85f7
MV
7248 {
7249 mpq_t frac;
7250 SCM q;
7251
7252 mpq_init (frac);
7253 mpq_set_d (frac, SCM_REAL_VALUE (z));
cba42c93 7254 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
f92e85f7
MV
7255 scm_i_mpz2num (mpq_denref (frac)));
7256
cba42c93 7257 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
7258 for frac...
7259 */
7260 mpq_clear (frac);
7261 return q;
7262 }
c2ff8ab0 7263 }
f92e85f7
MV
7264 else if (SCM_FRACTIONP (z))
7265 return z;
0aacf84e 7266 else
2519490c 7267 SCM_WTA_DISPATCH_1 (g_scm_inexact_to_exact, z, 1, s_scm_inexact_to_exact);
0f2d19dd 7268}
1bbd0b84 7269#undef FUNC_NAME
0f2d19dd 7270
f92e85f7 7271SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
76dae881
NJ
7272 (SCM x, SCM eps),
7273 "Returns the @emph{simplest} rational number differing\n"
7274 "from @var{x} by no more than @var{eps}.\n"
7275 "\n"
7276 "As required by @acronym{R5RS}, @code{rationalize} only returns an\n"
7277 "exact result when both its arguments are exact. Thus, you might need\n"
7278 "to use @code{inexact->exact} on the arguments.\n"
7279 "\n"
7280 "@lisp\n"
7281 "(rationalize (inexact->exact 1.2) 1/100)\n"
7282 "@result{} 6/5\n"
7283 "@end lisp")
f92e85f7
MV
7284#define FUNC_NAME s_scm_rationalize
7285{
605f6980
MW
7286 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
7287 SCM_ASSERT_TYPE (scm_is_real (eps), eps, SCM_ARG2, FUNC_NAME, "real");
7288 eps = scm_abs (eps);
7289 if (scm_is_false (scm_positive_p (eps)))
7290 {
7291 /* eps is either zero or a NaN */
7292 if (scm_is_true (scm_nan_p (eps)))
7293 return scm_nan ();
7294 else if (SCM_INEXACTP (eps))
7295 return scm_exact_to_inexact (x);
7296 else
7297 return x;
7298 }
7299 else if (scm_is_false (scm_finite_p (eps)))
7300 {
7301 if (scm_is_true (scm_finite_p (x)))
7302 return flo0;
7303 else
7304 return scm_nan ();
7305 }
7306 else if (scm_is_false (scm_finite_p (x))) /* checks for both inf and nan */
f92e85f7 7307 return x;
605f6980
MW
7308 else if (scm_is_false (scm_less_p (scm_floor (scm_sum (x, eps)),
7309 scm_ceiling (scm_difference (x, eps)))))
7310 {
7311 /* There's an integer within range; we want the one closest to zero */
7312 if (scm_is_false (scm_less_p (eps, scm_abs (x))))
7313 {
7314 /* zero is within range */
7315 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
7316 return flo0;
7317 else
7318 return SCM_INUM0;
7319 }
7320 else if (scm_is_true (scm_positive_p (x)))
7321 return scm_ceiling (scm_difference (x, eps));
7322 else
7323 return scm_floor (scm_sum (x, eps));
7324 }
7325 else
f92e85f7
MV
7326 {
7327 /* Use continued fractions to find closest ratio. All
7328 arithmetic is done with exact numbers.
7329 */
7330
7331 SCM ex = scm_inexact_to_exact (x);
7332 SCM int_part = scm_floor (ex);
cff5fa33
MW
7333 SCM tt = SCM_INUM1;
7334 SCM a1 = SCM_INUM0, a2 = SCM_INUM1, a = SCM_INUM0;
7335 SCM b1 = SCM_INUM1, b2 = SCM_INUM0, b = SCM_INUM0;
f92e85f7
MV
7336 SCM rx;
7337 int i = 0;
7338
f92e85f7
MV
7339 ex = scm_difference (ex, int_part); /* x = x-int_part */
7340 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
7341
7342 /* We stop after a million iterations just to be absolutely sure
7343 that we don't go into an infinite loop. The process normally
7344 converges after less than a dozen iterations.
7345 */
7346
f92e85f7
MV
7347 while (++i < 1000000)
7348 {
7349 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
7350 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
7351 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
7352 scm_is_false
f92e85f7 7353 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
76dae881 7354 eps))) /* abs(x-a/b) <= eps */
02164269
MV
7355 {
7356 SCM res = scm_sum (int_part, scm_divide (a, b));
605f6980 7357 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
02164269
MV
7358 return scm_exact_to_inexact (res);
7359 else
7360 return res;
7361 }
f92e85f7
MV
7362 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
7363 SCM_UNDEFINED);
7364 tt = scm_floor (rx); /* tt = floor (rx) */
7365 a2 = a1;
7366 b2 = b1;
7367 a1 = a;
7368 b1 = b;
7369 }
7370 scm_num_overflow (s_scm_rationalize);
7371 }
f92e85f7
MV
7372}
7373#undef FUNC_NAME
7374
73e4de09
MV
7375/* conversion functions */
7376
7377int
7378scm_is_integer (SCM val)
7379{
7380 return scm_is_true (scm_integer_p (val));
7381}
7382
7383int
7384scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
7385{
e11e83f3 7386 if (SCM_I_INUMP (val))
73e4de09 7387 {
e11e83f3 7388 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
7389 return n >= min && n <= max;
7390 }
7391 else if (SCM_BIGP (val))
7392 {
7393 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
7394 return 0;
7395 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
7396 {
7397 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
7398 {
7399 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
7400 return n >= min && n <= max;
7401 }
7402 else
7403 return 0;
7404 }
73e4de09
MV
7405 else
7406 {
d956fa6f
MV
7407 scm_t_intmax n;
7408 size_t count;
73e4de09 7409
d956fa6f
MV
7410 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
7411 > CHAR_BIT*sizeof (scm_t_uintmax))
7412 return 0;
7413
7414 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
7415 SCM_I_BIG_MPZ (val));
73e4de09 7416
d956fa6f 7417 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 7418 {
d956fa6f
MV
7419 if (n < 0)
7420 return 0;
73e4de09 7421 }
73e4de09
MV
7422 else
7423 {
d956fa6f
MV
7424 n = -n;
7425 if (n >= 0)
7426 return 0;
73e4de09 7427 }
d956fa6f
MV
7428
7429 return n >= min && n <= max;
73e4de09
MV
7430 }
7431 }
73e4de09
MV
7432 else
7433 return 0;
7434}
7435
7436int
7437scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
7438{
e11e83f3 7439 if (SCM_I_INUMP (val))
73e4de09 7440 {
e11e83f3 7441 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
7442 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
7443 }
7444 else if (SCM_BIGP (val))
7445 {
7446 if (max <= SCM_MOST_POSITIVE_FIXNUM)
7447 return 0;
7448 else if (max <= ULONG_MAX)
d956fa6f
MV
7449 {
7450 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
7451 {
7452 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
7453 return n >= min && n <= max;
7454 }
7455 else
7456 return 0;
7457 }
73e4de09
MV
7458 else
7459 {
d956fa6f
MV
7460 scm_t_uintmax n;
7461 size_t count;
73e4de09 7462
d956fa6f
MV
7463 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
7464 return 0;
73e4de09 7465
d956fa6f
MV
7466 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
7467 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 7468 return 0;
d956fa6f
MV
7469
7470 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
7471 SCM_I_BIG_MPZ (val));
73e4de09 7472
d956fa6f 7473 return n >= min && n <= max;
73e4de09
MV
7474 }
7475 }
73e4de09
MV
7476 else
7477 return 0;
7478}
7479
1713d319
MV
7480static void
7481scm_i_range_error (SCM bad_val, SCM min, SCM max)
7482{
7483 scm_error (scm_out_of_range_key,
7484 NULL,
7485 "Value out of range ~S to ~S: ~S",
7486 scm_list_3 (min, max, bad_val),
7487 scm_list_1 (bad_val));
7488}
7489
bfd7932e
MV
7490#define TYPE scm_t_intmax
7491#define TYPE_MIN min
7492#define TYPE_MAX max
7493#define SIZEOF_TYPE 0
7494#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
7495#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
7496#include "libguile/conv-integer.i.c"
7497
7498#define TYPE scm_t_uintmax
7499#define TYPE_MIN min
7500#define TYPE_MAX max
7501#define SIZEOF_TYPE 0
7502#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
7503#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
7504#include "libguile/conv-uinteger.i.c"
7505
7506#define TYPE scm_t_int8
7507#define TYPE_MIN SCM_T_INT8_MIN
7508#define TYPE_MAX SCM_T_INT8_MAX
7509#define SIZEOF_TYPE 1
7510#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
7511#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
7512#include "libguile/conv-integer.i.c"
7513
7514#define TYPE scm_t_uint8
7515#define TYPE_MIN 0
7516#define TYPE_MAX SCM_T_UINT8_MAX
7517#define SIZEOF_TYPE 1
7518#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
7519#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
7520#include "libguile/conv-uinteger.i.c"
7521
7522#define TYPE scm_t_int16
7523#define TYPE_MIN SCM_T_INT16_MIN
7524#define TYPE_MAX SCM_T_INT16_MAX
7525#define SIZEOF_TYPE 2
7526#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
7527#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
7528#include "libguile/conv-integer.i.c"
7529
7530#define TYPE scm_t_uint16
7531#define TYPE_MIN 0
7532#define TYPE_MAX SCM_T_UINT16_MAX
7533#define SIZEOF_TYPE 2
7534#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
7535#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
7536#include "libguile/conv-uinteger.i.c"
7537
7538#define TYPE scm_t_int32
7539#define TYPE_MIN SCM_T_INT32_MIN
7540#define TYPE_MAX SCM_T_INT32_MAX
7541#define SIZEOF_TYPE 4
7542#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
7543#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
7544#include "libguile/conv-integer.i.c"
7545
7546#define TYPE scm_t_uint32
7547#define TYPE_MIN 0
7548#define TYPE_MAX SCM_T_UINT32_MAX
7549#define SIZEOF_TYPE 4
7550#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
7551#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
7552#include "libguile/conv-uinteger.i.c"
7553
904a78f1
MG
7554#define TYPE scm_t_wchar
7555#define TYPE_MIN (scm_t_int32)-1
7556#define TYPE_MAX (scm_t_int32)0x10ffff
7557#define SIZEOF_TYPE 4
7558#define SCM_TO_TYPE_PROTO(arg) scm_to_wchar (arg)
7559#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
7560#include "libguile/conv-integer.i.c"
7561
bfd7932e
MV
7562#define TYPE scm_t_int64
7563#define TYPE_MIN SCM_T_INT64_MIN
7564#define TYPE_MAX SCM_T_INT64_MAX
7565#define SIZEOF_TYPE 8
7566#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
7567#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
7568#include "libguile/conv-integer.i.c"
7569
7570#define TYPE scm_t_uint64
7571#define TYPE_MIN 0
7572#define TYPE_MAX SCM_T_UINT64_MAX
7573#define SIZEOF_TYPE 8
7574#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
7575#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
7576#include "libguile/conv-uinteger.i.c"
73e4de09 7577
cd036260
MV
7578void
7579scm_to_mpz (SCM val, mpz_t rop)
7580{
7581 if (SCM_I_INUMP (val))
7582 mpz_set_si (rop, SCM_I_INUM (val));
7583 else if (SCM_BIGP (val))
7584 mpz_set (rop, SCM_I_BIG_MPZ (val));
7585 else
7586 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
7587}
7588
7589SCM
7590scm_from_mpz (mpz_t val)
7591{
7592 return scm_i_mpz2num (val);
7593}
7594
73e4de09
MV
7595int
7596scm_is_real (SCM val)
7597{
7598 return scm_is_true (scm_real_p (val));
7599}
7600
55f26379
MV
7601int
7602scm_is_rational (SCM val)
7603{
7604 return scm_is_true (scm_rational_p (val));
7605}
7606
73e4de09
MV
7607double
7608scm_to_double (SCM val)
7609{
55f26379
MV
7610 if (SCM_I_INUMP (val))
7611 return SCM_I_INUM (val);
7612 else if (SCM_BIGP (val))
7613 return scm_i_big2dbl (val);
7614 else if (SCM_FRACTIONP (val))
7615 return scm_i_fraction2double (val);
7616 else if (SCM_REALP (val))
7617 return SCM_REAL_VALUE (val);
7618 else
7a1aba42 7619 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
7620}
7621
7622SCM
7623scm_from_double (double val)
7624{
978c52d1
LC
7625 SCM z;
7626
7627 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
7628
7629 SCM_SET_CELL_TYPE (z, scm_tc16_real);
55f26379 7630 SCM_REAL_VALUE (z) = val;
978c52d1 7631
55f26379 7632 return z;
73e4de09
MV
7633}
7634
220058a8 7635#if SCM_ENABLE_DEPRECATED == 1
55f26379
MV
7636
7637float
e25f3727 7638scm_num2float (SCM num, unsigned long pos, const char *s_caller)
55f26379 7639{
220058a8
AW
7640 scm_c_issue_deprecation_warning
7641 ("`scm_num2float' is deprecated. Use scm_to_double instead.");
7642
55f26379
MV
7643 if (SCM_BIGP (num))
7644 {
7645 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 7646 if (!isinf (res))
55f26379
MV
7647 return res;
7648 else
7649 scm_out_of_range (NULL, num);
7650 }
7651 else
7652 return scm_to_double (num);
7653}
7654
7655double
e25f3727 7656scm_num2double (SCM num, unsigned long pos, const char *s_caller)
55f26379 7657{
220058a8
AW
7658 scm_c_issue_deprecation_warning
7659 ("`scm_num2double' is deprecated. Use scm_to_double instead.");
7660
55f26379
MV
7661 if (SCM_BIGP (num))
7662 {
7663 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 7664 if (!isinf (res))
55f26379
MV
7665 return res;
7666 else
7667 scm_out_of_range (NULL, num);
7668 }
7669 else
7670 return scm_to_double (num);
7671}
7672
7673#endif
7674
8507ec80
MV
7675int
7676scm_is_complex (SCM val)
7677{
7678 return scm_is_true (scm_complex_p (val));
7679}
7680
7681double
7682scm_c_real_part (SCM z)
7683{
7684 if (SCM_COMPLEXP (z))
7685 return SCM_COMPLEX_REAL (z);
7686 else
7687 {
7688 /* Use the scm_real_part to get proper error checking and
7689 dispatching.
7690 */
7691 return scm_to_double (scm_real_part (z));
7692 }
7693}
7694
7695double
7696scm_c_imag_part (SCM z)
7697{
7698 if (SCM_COMPLEXP (z))
7699 return SCM_COMPLEX_IMAG (z);
7700 else
7701 {
7702 /* Use the scm_imag_part to get proper error checking and
7703 dispatching. The result will almost always be 0.0, but not
7704 always.
7705 */
7706 return scm_to_double (scm_imag_part (z));
7707 }
7708}
7709
7710double
7711scm_c_magnitude (SCM z)
7712{
7713 return scm_to_double (scm_magnitude (z));
7714}
7715
7716double
7717scm_c_angle (SCM z)
7718{
7719 return scm_to_double (scm_angle (z));
7720}
7721
7722int
7723scm_is_number (SCM z)
7724{
7725 return scm_is_true (scm_number_p (z));
7726}
7727
8ab3d8a0
KR
7728
7729/* In the following functions we dispatch to the real-arg funcs like log()
7730 when we know the arg is real, instead of just handing everything to
7731 clog() for instance. This is in case clog() doesn't optimize for a
7732 real-only case, and because we have to test SCM_COMPLEXP anyway so may as
7733 well use it to go straight to the applicable C func. */
7734
2519490c
MW
7735SCM_PRIMITIVE_GENERIC (scm_log, "log", 1, 0, 0,
7736 (SCM z),
7737 "Return the natural logarithm of @var{z}.")
8ab3d8a0
KR
7738#define FUNC_NAME s_scm_log
7739{
7740 if (SCM_COMPLEXP (z))
7741 {
4b26c03e 7742#if HAVE_COMPLEX_DOUBLE && HAVE_CLOG && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
7743 return scm_from_complex_double (clog (SCM_COMPLEX_VALUE (z)));
7744#else
7745 double re = SCM_COMPLEX_REAL (z);
7746 double im = SCM_COMPLEX_IMAG (z);
7747 return scm_c_make_rectangular (log (hypot (re, im)),
7748 atan2 (im, re));
7749#endif
7750 }
2519490c 7751 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7752 {
7753 /* ENHANCE-ME: When z is a bignum the logarithm will fit a double
7754 although the value itself overflows. */
7755 double re = scm_to_double (z);
7756 double l = log (fabs (re));
7757 if (re >= 0.0)
7758 return scm_from_double (l);
7759 else
7760 return scm_c_make_rectangular (l, M_PI);
7761 }
2519490c
MW
7762 else
7763 SCM_WTA_DISPATCH_1 (g_scm_log, z, 1, s_scm_log);
8ab3d8a0
KR
7764}
7765#undef FUNC_NAME
7766
7767
2519490c
MW
7768SCM_PRIMITIVE_GENERIC (scm_log10, "log10", 1, 0, 0,
7769 (SCM z),
7770 "Return the base 10 logarithm of @var{z}.")
8ab3d8a0
KR
7771#define FUNC_NAME s_scm_log10
7772{
7773 if (SCM_COMPLEXP (z))
7774 {
7775 /* Mingw has clog() but not clog10(). (Maybe it'd be worth using
7776 clog() and a multiply by M_LOG10E, rather than the fallback
7777 log10+hypot+atan2.) */
f328f862
LC
7778#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
7779 && defined SCM_COMPLEX_VALUE
8ab3d8a0
KR
7780 return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
7781#else
7782 double re = SCM_COMPLEX_REAL (z);
7783 double im = SCM_COMPLEX_IMAG (z);
7784 return scm_c_make_rectangular (log10 (hypot (re, im)),
7785 M_LOG10E * atan2 (im, re));
7786#endif
7787 }
2519490c 7788 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7789 {
7790 /* ENHANCE-ME: When z is a bignum the logarithm will fit a double
7791 although the value itself overflows. */
7792 double re = scm_to_double (z);
7793 double l = log10 (fabs (re));
7794 if (re >= 0.0)
7795 return scm_from_double (l);
7796 else
7797 return scm_c_make_rectangular (l, M_LOG10E * M_PI);
7798 }
2519490c
MW
7799 else
7800 SCM_WTA_DISPATCH_1 (g_scm_log10, z, 1, s_scm_log10);
8ab3d8a0
KR
7801}
7802#undef FUNC_NAME
7803
7804
2519490c
MW
7805SCM_PRIMITIVE_GENERIC (scm_exp, "exp", 1, 0, 0,
7806 (SCM z),
7807 "Return @math{e} to the power of @var{z}, where @math{e} is the\n"
7808 "base of natural logarithms (2.71828@dots{}).")
8ab3d8a0
KR
7809#define FUNC_NAME s_scm_exp
7810{
7811 if (SCM_COMPLEXP (z))
7812 {
4b26c03e 7813#if HAVE_COMPLEX_DOUBLE && HAVE_CEXP && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
7814 return scm_from_complex_double (cexp (SCM_COMPLEX_VALUE (z)));
7815#else
7816 return scm_c_make_polar (exp (SCM_COMPLEX_REAL (z)),
7817 SCM_COMPLEX_IMAG (z));
7818#endif
7819 }
2519490c 7820 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
7821 {
7822 /* When z is a negative bignum the conversion to double overflows,
7823 giving -infinity, but that's ok, the exp is still 0.0. */
7824 return scm_from_double (exp (scm_to_double (z)));
7825 }
2519490c
MW
7826 else
7827 SCM_WTA_DISPATCH_1 (g_scm_exp, z, 1, s_scm_exp);
8ab3d8a0
KR
7828}
7829#undef FUNC_NAME
7830
7831
2519490c
MW
7832SCM_PRIMITIVE_GENERIC (scm_sqrt, "sqrt", 1, 0, 0,
7833 (SCM z),
7834 "Return the square root of @var{z}. Of the two possible roots\n"
7835 "(positive and negative), the one with the a positive real part\n"
7836 "is returned, or if that's zero then a positive imaginary part.\n"
7837 "Thus,\n"
7838 "\n"
7839 "@example\n"
7840 "(sqrt 9.0) @result{} 3.0\n"
7841 "(sqrt -9.0) @result{} 0.0+3.0i\n"
7842 "(sqrt 1.0+1.0i) @result{} 1.09868411346781+0.455089860562227i\n"
7843 "(sqrt -1.0-1.0i) @result{} 0.455089860562227-1.09868411346781i\n"
7844 "@end example")
8ab3d8a0
KR
7845#define FUNC_NAME s_scm_sqrt
7846{
2519490c 7847 if (SCM_COMPLEXP (z))
8ab3d8a0 7848 {
f328f862
LC
7849#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT \
7850 && defined SCM_COMPLEX_VALUE
2519490c 7851 return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (z)));
8ab3d8a0 7852#else
2519490c
MW
7853 double re = SCM_COMPLEX_REAL (z);
7854 double im = SCM_COMPLEX_IMAG (z);
8ab3d8a0
KR
7855 return scm_c_make_polar (sqrt (hypot (re, im)),
7856 0.5 * atan2 (im, re));
7857#endif
7858 }
2519490c 7859 else if (SCM_NUMBERP (z))
8ab3d8a0 7860 {
2519490c 7861 double xx = scm_to_double (z);
8ab3d8a0
KR
7862 if (xx < 0)
7863 return scm_c_make_rectangular (0.0, sqrt (-xx));
7864 else
7865 return scm_from_double (sqrt (xx));
7866 }
2519490c
MW
7867 else
7868 SCM_WTA_DISPATCH_1 (g_scm_sqrt, z, 1, s_scm_sqrt);
8ab3d8a0
KR
7869}
7870#undef FUNC_NAME
7871
7872
7873
0f2d19dd
JB
7874void
7875scm_init_numbers ()
0f2d19dd 7876{
0b799eea
MV
7877 int i;
7878
713a4259
KR
7879 mpz_init_set_si (z_negative_one, -1);
7880
a261c0e9
DH
7881 /* It may be possible to tune the performance of some algorithms by using
7882 * the following constants to avoid the creation of bignums. Please, before
7883 * using these values, remember the two rules of program optimization:
7884 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 7885 scm_c_define ("most-positive-fixnum",
d956fa6f 7886 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 7887 scm_c_define ("most-negative-fixnum",
d956fa6f 7888 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 7889
f3ae5d60
MD
7890 scm_add_feature ("complex");
7891 scm_add_feature ("inexact");
e7efe8e7 7892 flo0 = scm_from_double (0.0);
0b799eea
MV
7893
7894 /* determine floating point precision */
55f26379 7895 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
7896 {
7897 init_dblprec(&scm_dblprec[i-2],i);
7898 init_fx_radix(fx_per_radix[i-2],i);
7899 }
f872b822 7900#ifdef DBL_DIG
0b799eea 7901 /* hard code precision for base 10 if the preprocessor tells us to... */
f39448c5 7902 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
0b799eea 7903#endif
1be6b49c 7904
cff5fa33 7905 exactly_one_half = scm_divide (SCM_INUM1, SCM_I_MAKINUM (2));
a0599745 7906#include "libguile/numbers.x"
0f2d19dd 7907}
89e00824
ML
7908
7909/*
7910 Local Variables:
7911 c-file-style: "gnu"
7912 End:
7913*/