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