(scm_execl, scm_execlp, scm_execle): Avoid memory leak under error throw.
[bpt/guile.git] / libguile / numbers.c
CommitLineData
238ebcef 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004 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
MV
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 11 *
73be1d9e
MV
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
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
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
1bbd0b84 21
0f2d19dd 22\f
ca46fb90
RB
23/* General assumptions:
24 * All objects satisfying SCM_COMPLEXP() have a non-zero complex component.
25 * All objects satisfying SCM_BIGP() are too large to fit in a fixnum.
26 * If an object satisfies integer?, it's either an inum, a bignum, or a real.
27 * If floor (r) == r, r is an int, and mpz_set_d will DTRT.
f92e85f7 28 * All objects satisfying SCM_FRACTIONP are never an integer.
ca46fb90
RB
29 */
30
31/* TODO:
32
33 - see if special casing bignums and reals in integer-exponent when
34 possible (to use mpz_pow and mpf_pow_ui) is faster.
35
36 - look in to better short-circuiting of common cases in
37 integer-expt and elsewhere.
38
39 - see if direct mpz operations can help in ash and elsewhere.
40
41 */
0f2d19dd 42
fa605590
KR
43/* tell glibc (2.3) to give prototype for C99 trunc() */
44#define _GNU_SOURCE
45
ee33d62a
RB
46#if HAVE_CONFIG_H
47# include <config.h>
48#endif
49
0f2d19dd 50#include <math.h>
3c9a524f 51#include <ctype.h>
fc194577 52#include <string.h>
ca46fb90 53#include <gmp.h>
f92e85f7 54
a0599745 55#include "libguile/_scm.h"
a0599745
MD
56#include "libguile/feature.h"
57#include "libguile/ports.h"
58#include "libguile/root.h"
59#include "libguile/smob.h"
60#include "libguile/strings.h"
a0599745
MD
61
62#include "libguile/validate.h"
63#include "libguile/numbers.h"
1be6b49c 64#include "libguile/deprecation.h"
f4c627b3 65
f92e85f7
MV
66#include "libguile/eq.h"
67
0f2d19dd 68\f
f4c627b3 69
ca46fb90
RB
70/*
71 Wonder if this might be faster for some of our code? A switch on
72 the numtag would jump directly to the right case, and the
73 SCM_I_NUMTAG code might be faster than repeated SCM_FOOP tests...
74
75 #define SCM_I_NUMTAG_NOTNUM 0
76 #define SCM_I_NUMTAG_INUM 1
77 #define SCM_I_NUMTAG_BIG scm_tc16_big
78 #define SCM_I_NUMTAG_REAL scm_tc16_real
79 #define SCM_I_NUMTAG_COMPLEX scm_tc16_complex
80 #define SCM_I_NUMTAG(x) \
81 (SCM_INUMP(x) ? SCM_I_NUMTAG_INUM \
82 : (SCM_IMP(x) ? SCM_I_NUMTAG_NOTNUM \
534c55a9 83 : (((0xfcff & SCM_CELL_TYPE (x)) == scm_tc7_number) ? SCM_TYP16(x) \
ca46fb90
RB
84 : SCM_I_NUMTAG_NOTNUM)))
85*/
f92e85f7 86/* the macro above will not work as is with fractions */
f4c627b3
DH
87
88
34d19ef6 89#define SCM_SWAP(x, y) do { SCM __t = x; x = y; y = __t; } while (0)
09fb7599 90
56e55ac7 91/* FLOBUFLEN is the maximum number of characters neccessary for the
3a9809df
DH
92 * printed or scm_string representation of an inexact number.
93 */
56e55ac7 94#define FLOBUFLEN (10+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
3a9809df 95
7351e207
MV
96#if defined (SCO)
97#if ! defined (HAVE_ISNAN)
98#define HAVE_ISNAN
99static int
100isnan (double x)
101{
102 return (IsNANorINF (x) && NaN (x) && ! IsINF (x)) ? 1 : 0;
103}
0f2d19dd 104#endif
7351e207
MV
105#if ! defined (HAVE_ISINF)
106#define HAVE_ISINF
107static int
108isinf (double x)
109{
110 return (IsNANorINF (x) && IsINF (x)) ? 1 : 0;
111}
0f2d19dd 112
7351e207 113#endif
e6f3ef58
MD
114#endif
115
b127c712
KR
116
117/* mpz_cmp_d only recognises infinities in gmp 4.2 and up.
118 For prior versions use an explicit check here. */
119#if __GNU_MP_VERSION < 4 \
120 || (__GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR < 2)
121#define xmpz_cmp_d(z, d) \
122 (xisinf (d) ? (d < 0.0 ? 1 : -1) : mpz_cmp_d (z, d))
123#else
124#define xmpz_cmp_d(z, d) mpz_cmp_d (z, d)
125#endif
126
f92e85f7
MV
127static int
128xisinf (double x)
129{
130#if defined (HAVE_ISINF)
131 return isinf (x);
132#elif defined (HAVE_FINITE) && defined (HAVE_ISNAN)
133 return (! (finite (x) || isnan (x)));
134#else
135 return 0;
136#endif
137}
138
139static int
140xisnan (double x)
141{
142#if defined (HAVE_ISNAN)
143 return isnan (x);
144#else
145 return 0;
146#endif
147}
148
0f2d19dd
JB
149\f
150
ac0c002c 151static SCM abs_most_negative_fixnum;
713a4259 152static mpz_t z_negative_one;
ac0c002c
DH
153
154\f
155
570b6821 156SCM_C_INLINE_KEYWORD SCM
ca46fb90
RB
157scm_i_mkbig ()
158{
159 /* Return a newly created bignum. */
160 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
161 mpz_init (SCM_I_BIG_MPZ (z));
162 return z;
163}
164
570b6821 165SCM_C_INLINE_KEYWORD static SCM
ca46fb90
RB
166scm_i_clonebig (SCM src_big, int same_sign_p)
167{
168 /* Copy src_big's value, negate it if same_sign_p is false, and return. */
169 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
170 mpz_init_set (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (src_big));
0aacf84e
MD
171 if (!same_sign_p)
172 mpz_neg (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (z));
ca46fb90
RB
173 return z;
174}
175
570b6821 176SCM_C_INLINE_KEYWORD int
ca46fb90
RB
177scm_i_bigcmp (SCM x, SCM y)
178{
179 /* Return neg if x < y, pos if x > y, and 0 if x == y */
180 /* presume we already know x and y are bignums */
181 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
182 scm_remember_upto_here_2 (x, y);
183 return result;
184}
185
570b6821 186SCM_C_INLINE_KEYWORD SCM
ca46fb90
RB
187scm_i_dbl2big (double d)
188{
189 /* results are only defined if d is an integer */
190 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
191 mpz_init_set_d (SCM_I_BIG_MPZ (z), d);
192 return z;
193}
194
f92e85f7
MV
195/* Convert a integer in double representation to a SCM number. */
196
197SCM_C_INLINE_KEYWORD SCM
198scm_i_dbl2num (double u)
199{
200 /* SCM_MOST_POSITIVE_FIXNUM+1 and SCM_MOST_NEGATIVE_FIXNUM are both
201 powers of 2, so there's no rounding when making "double" values
202 from them. If plain SCM_MOST_POSITIVE_FIXNUM was used it could
203 get rounded on a 64-bit machine, hence the "+1".
204
205 The use of floor() to force to an integer value ensures we get a
206 "numerically closest" value without depending on how a
207 double->long cast or how mpz_set_d will round. For reference,
208 double->long probably follows the hardware rounding mode,
209 mpz_set_d truncates towards zero. */
210
211 /* XXX - what happens when SCM_MOST_POSITIVE_FIXNUM etc is not
212 representable as a double? */
213
214 if (u < (double) (SCM_MOST_POSITIVE_FIXNUM+1)
215 && u >= (double) SCM_MOST_NEGATIVE_FIXNUM)
216 return SCM_MAKINUM ((long) u);
217 else
218 return scm_i_dbl2big (u);
219}
220
089c9a59
KR
221/* scm_i_big2dbl() rounds to the closest representable double, in accordance
222 with R5RS exact->inexact.
223
224 The approach is to use mpz_get_d to pick out the high DBL_MANT_DIG bits
225 (ie. it truncates towards zero), then adjust to get the closest double by
226 examining the next lower bit and adding 1 if necessary.
227
228 Note that bignums exactly half way between representable doubles are
229 rounded to the next higher absolute value (ie. away from zero). This
230 seems like an adequate interpretation of R5RS "numerically closest", and
231 it's easier and faster than a full "nearest-even" style.
232
233 The bit test is done on the absolute value of the mpz_t, which means we
234 must use mpz_getlimbn. mpz_tstbit is not right, it treats negatives as
235 twos complement.
236
237 Prior to GMP 4.2, the rounding done by mpz_get_d was unspecified. It
238 happened to follow the hardware rounding mode, but on the absolute value
239 of its operand. This is not what we want, so we put the high
240 DBL_MANT_DIG bits into a temporary. This extra init/clear is a slowdown,
241 but doesn't matter too much since it's only for older GMP. */
242
243double
ca46fb90
RB
244scm_i_big2dbl (SCM b)
245{
089c9a59
KR
246 double result;
247 size_t bits;
248
249 bits = mpz_sizeinbase (SCM_I_BIG_MPZ (b), 2);
250
251#if __GNU_MP_VERSION < 4 \
252 || (__GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR < 2)
253 {
254 /* GMP prior to 4.2, force truncate towards zero */
255 mpz_t tmp;
256 if (bits > DBL_MANT_DIG)
257 {
258 size_t shift = bits - DBL_MANT_DIG;
259 mpz_init2 (tmp, DBL_MANT_DIG);
260 mpz_tdiv_q_2exp (tmp, SCM_I_BIG_MPZ (b), shift);
261 result = ldexp (mpz_get_d (tmp), shift);
262 mpz_clear (tmp);
263 }
264 else
265 {
266 result = mpz_get_d (SCM_I_BIG_MPZ (b));
267 }
268 }
269#else
270 /* GMP 4.2 and up */
271 result = mpz_get_d (SCM_I_BIG_MPZ (b));
272#endif
273
274 if (bits > DBL_MANT_DIG)
275 {
276 unsigned long pos = bits - DBL_MANT_DIG - 1;
277 /* test bit number "pos" in absolute value */
278 if (mpz_getlimbn (SCM_I_BIG_MPZ (b), pos / GMP_NUMB_BITS)
279 & ((mp_limb_t) 1 << (pos % GMP_NUMB_BITS)))
280 {
281 result += ldexp ((double) mpz_sgn (SCM_I_BIG_MPZ (b)), pos + 1);
282 }
283 }
284
ca46fb90
RB
285 scm_remember_upto_here_1 (b);
286 return result;
287}
288
570b6821 289SCM_C_INLINE_KEYWORD SCM
ca46fb90
RB
290scm_i_normbig (SCM b)
291{
292 /* convert a big back to a fixnum if it'll fit */
293 /* presume b is a bignum */
294 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (b)))
295 {
296 long val = mpz_get_si (SCM_I_BIG_MPZ (b));
297 if (SCM_FIXABLE (val))
298 b = SCM_MAKINUM (val);
299 }
300 return b;
301}
f872b822 302
f92e85f7
MV
303static SCM_C_INLINE_KEYWORD SCM
304scm_i_mpz2num (mpz_t b)
305{
306 /* convert a mpz number to a SCM number. */
307 if (mpz_fits_slong_p (b))
308 {
309 long val = mpz_get_si (b);
310 if (SCM_FIXABLE (val))
311 return SCM_MAKINUM (val);
312 }
313
314 {
315 SCM z = scm_double_cell (scm_tc16_big, 0, 0, 0);
316 mpz_init_set (SCM_I_BIG_MPZ (z), b);
317 return z;
318 }
319}
320
321/* this is needed when we want scm_divide to make a float, not a ratio, even if passed two ints */
322static SCM scm_divide2real (SCM x, SCM y);
323
324SCM
325scm_make_ratio (SCM numerator, SCM denominator)
c60e130c 326#define FUNC_NAME "make-ratio"
f92e85f7 327{
c60e130c
MV
328 /* First make sure the arguments are proper.
329 */
f92e85f7
MV
330 if (SCM_INUMP (denominator))
331 {
332 if (SCM_EQ_P (denominator, SCM_INUM0))
333 scm_num_overflow ("make-ratio");
334 if (SCM_EQ_P (denominator, SCM_MAKINUM(1)))
335 return numerator;
336 }
337 else
338 {
339 if (!(SCM_BIGP(denominator)))
340 SCM_WRONG_TYPE_ARG (2, denominator);
341 }
c60e130c
MV
342 if (!SCM_INUMP (numerator) && !SCM_BIGP (numerator))
343 SCM_WRONG_TYPE_ARG (1, numerator);
344
345 /* Then flip signs so that the denominator is positive.
346 */
347 if (SCM_NFALSEP (scm_negative_p (denominator)))
348 {
349 numerator = scm_difference (numerator, SCM_UNDEFINED);
350 denominator = scm_difference (denominator, SCM_UNDEFINED);
351 }
352
353 /* Now consider for each of the four fixnum/bignum combinations
354 whether the rational number is really an integer.
355 */
f92e85f7
MV
356 if (SCM_INUMP (numerator))
357 {
dd5130ca 358 long x = SCM_INUM (numerator);
f92e85f7
MV
359 if (SCM_EQ_P (numerator, SCM_INUM0))
360 return SCM_INUM0;
361 if (SCM_INUMP (denominator))
362 {
dd5130ca 363 long y;
f92e85f7
MV
364 y = SCM_INUM (denominator);
365 if (x == y)
366 return SCM_MAKINUM(1);
367 if ((x % y) == 0)
368 return SCM_MAKINUM (x / y);
f92e85f7 369 }
dd5130ca
KR
370 else
371 {
372 /* When x == SCM_MOST_NEGATIVE_FIXNUM we could have the negative
373 of that value for the denominator, as a bignum. */
374 long abs_x = (x >= 0 ? x : -x);
375 if (mpz_cmpabs_ui (SCM_I_BIG_MPZ (denominator), abs_x) == 0)
376 return SCM_MAKINUM(-1);
377 }
f92e85f7 378 }
c60e130c 379 else if (SCM_BIGP (numerator))
f92e85f7 380 {
c60e130c
MV
381 if (SCM_INUMP (denominator))
382 {
383 long yy = SCM_INUM (denominator);
384 if (mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), yy))
385 return scm_divide (numerator, denominator);
386 }
387 else
f92e85f7 388 {
c60e130c
MV
389 if (SCM_EQ_P (numerator, denominator))
390 return SCM_MAKINUM(1);
391 if (mpz_divisible_p (SCM_I_BIG_MPZ (numerator),
392 SCM_I_BIG_MPZ (denominator)))
393 return scm_divide(numerator, denominator);
f92e85f7 394 }
f92e85f7 395 }
c60e130c
MV
396
397 /* No, it's a proper fraction.
398 */
399 return scm_double_cell (scm_tc16_fraction,
400 SCM_UNPACK (numerator),
401 SCM_UNPACK (denominator), 0);
f92e85f7 402}
c60e130c 403#undef FUNC_NAME
f92e85f7
MV
404
405static void scm_i_fraction_reduce (SCM z)
406{
407 if (!(SCM_FRACTION_REDUCED (z)))
408 {
409 SCM divisor;
410 divisor = scm_gcd (SCM_FRACTION_NUMERATOR (z), SCM_FRACTION_DENOMINATOR (z));
411 if (!(SCM_EQ_P (divisor, SCM_MAKINUM(1))))
412 {
413 /* is this safe? */
414 SCM_FRACTION_SET_NUMERATOR (z, scm_divide (SCM_FRACTION_NUMERATOR (z), divisor));
415 SCM_FRACTION_SET_DENOMINATOR (z, scm_divide (SCM_FRACTION_DENOMINATOR (z), divisor));
416 }
417 SCM_FRACTION_REDUCED_SET (z);
418 }
419}
420
421double
422scm_i_fraction2double (SCM z)
423{
424 return scm_num2dbl (scm_divide2real (SCM_FRACTION_NUMERATOR (z),
425 SCM_FRACTION_DENOMINATOR (z)),
426 "fraction2real");
427}
428
a1ec6916 429SCM_DEFINE (scm_exact_p, "exact?", 1, 0, 0,
1bbd0b84 430 (SCM x),
942e5b91
MG
431 "Return @code{#t} if @var{x} is an exact number, @code{#f}\n"
432 "otherwise.")
1bbd0b84 433#define FUNC_NAME s_scm_exact_p
0f2d19dd 434{
0aacf84e
MD
435 if (SCM_INUMP (x))
436 return SCM_BOOL_T;
437 if (SCM_BIGP (x))
438 return SCM_BOOL_T;
f92e85f7
MV
439 if (SCM_FRACTIONP (x))
440 return SCM_BOOL_T;
eb927cb9
MV
441 if (SCM_NUMBERP (x))
442 return SCM_BOOL_F;
443 SCM_WRONG_TYPE_ARG (1, x);
0f2d19dd 444}
1bbd0b84 445#undef FUNC_NAME
0f2d19dd 446
4219f20d 447
a1ec6916 448SCM_DEFINE (scm_odd_p, "odd?", 1, 0, 0,
1bbd0b84 449 (SCM n),
942e5b91
MG
450 "Return @code{#t} if @var{n} is an odd number, @code{#f}\n"
451 "otherwise.")
1bbd0b84 452#define FUNC_NAME s_scm_odd_p
0f2d19dd 453{
0aacf84e
MD
454 if (SCM_INUMP (n))
455 {
456 long val = SCM_INUM (n);
457 return SCM_BOOL ((val & 1L) != 0);
458 }
459 else if (SCM_BIGP (n))
460 {
461 int odd_p = mpz_odd_p (SCM_I_BIG_MPZ (n));
462 scm_remember_upto_here_1 (n);
463 return SCM_BOOL (odd_p);
464 }
465 else if (!SCM_FALSEP (scm_inf_p (n)))
7351e207 466 return SCM_BOOL_T;
f92e85f7
MV
467 else if (SCM_REALP (n))
468 {
469 double rem = fabs (fmod (SCM_REAL_VALUE(n), 2.0));
470 if (rem == 1.0)
471 return SCM_BOOL_T;
472 else if (rem == 0.0)
473 return SCM_BOOL_F;
474 else
475 SCM_WRONG_TYPE_ARG (1, n);
476 }
0aacf84e 477 else
a1a33b0f 478 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 479}
1bbd0b84 480#undef FUNC_NAME
0f2d19dd 481
4219f20d 482
a1ec6916 483SCM_DEFINE (scm_even_p, "even?", 1, 0, 0,
1bbd0b84 484 (SCM n),
942e5b91
MG
485 "Return @code{#t} if @var{n} is an even number, @code{#f}\n"
486 "otherwise.")
1bbd0b84 487#define FUNC_NAME s_scm_even_p
0f2d19dd 488{
0aacf84e
MD
489 if (SCM_INUMP (n))
490 {
491 long val = SCM_INUM (n);
492 return SCM_BOOL ((val & 1L) == 0);
493 }
494 else if (SCM_BIGP (n))
495 {
496 int even_p = mpz_even_p (SCM_I_BIG_MPZ (n));
497 scm_remember_upto_here_1 (n);
498 return SCM_BOOL (even_p);
499 }
500 else if (!SCM_FALSEP (scm_inf_p (n)))
7351e207 501 return SCM_BOOL_T;
f92e85f7
MV
502 else if (SCM_REALP (n))
503 {
504 double rem = fabs (fmod (SCM_REAL_VALUE(n), 2.0));
505 if (rem == 1.0)
506 return SCM_BOOL_F;
507 else if (rem == 0.0)
508 return SCM_BOOL_T;
509 else
510 SCM_WRONG_TYPE_ARG (1, n);
511 }
0aacf84e 512 else
a1a33b0f 513 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 514}
1bbd0b84 515#undef FUNC_NAME
0f2d19dd 516
7351e207
MV
517SCM_DEFINE (scm_inf_p, "inf?", 1, 0, 0,
518 (SCM n),
519 "Return @code{#t} if @var{n} is infinite, @code{#f}\n"
520 "otherwise.")
521#define FUNC_NAME s_scm_inf_p
522{
0aacf84e 523 if (SCM_REALP (n))
7351e207 524 return SCM_BOOL (xisinf (SCM_REAL_VALUE (n)));
0aacf84e 525 else if (SCM_COMPLEXP (n))
7351e207
MV
526 return SCM_BOOL (xisinf (SCM_COMPLEX_REAL (n))
527 || xisinf (SCM_COMPLEX_IMAG (n)));
0aacf84e 528 else
7351e207 529 return SCM_BOOL_F;
7351e207
MV
530}
531#undef FUNC_NAME
532
533SCM_DEFINE (scm_nan_p, "nan?", 1, 0, 0,
534 (SCM n),
535 "Return @code{#t} if @var{n} is a NaN, @code{#f}\n"
536 "otherwise.")
537#define FUNC_NAME s_scm_nan_p
538{
0aacf84e 539 if (SCM_REALP (n))
7351e207 540 return SCM_BOOL (xisnan (SCM_REAL_VALUE (n)));
0aacf84e 541 else if (SCM_COMPLEXP (n))
7351e207
MV
542 return SCM_BOOL (xisnan (SCM_COMPLEX_REAL (n))
543 || xisnan (SCM_COMPLEX_IMAG (n)));
0aacf84e 544 else
7351e207 545 return SCM_BOOL_F;
7351e207
MV
546}
547#undef FUNC_NAME
548
549/* Guile's idea of infinity. */
550static double guile_Inf;
551
552/* Guile's idea of not a number. */
553static double guile_NaN;
554
555static void
556guile_ieee_init (void)
557{
558#if defined (HAVE_ISINF) || defined (HAVE_FINITE)
559
560/* Some version of gcc on some old version of Linux used to crash when
561 trying to make Inf and NaN. */
562
563#if defined (SCO)
564 double tmp = 1.0;
565 guile_Inf = 1.0 / (tmp - tmp);
566#elif defined (__alpha__) && ! defined (linux)
567 extern unsigned int DINFINITY[2];
568 guile_Inf = (*(X_CAST(double *, DINFINITY)));
569#else
570 double tmp = 1e+10;
571 guile_Inf = tmp;
572 for (;;)
573 {
574 guile_Inf *= 1e+10;
575 if (guile_Inf == tmp)
576 break;
577 tmp = guile_Inf;
578 }
579#endif
580
581#endif
582
583#if defined (HAVE_ISNAN)
584
585#if defined (__alpha__) && ! defined (linux)
586 extern unsigned int DQNAN[2];
587 guile_NaN = (*(X_CAST(double *, DQNAN)));
588#else
589 guile_NaN = guile_Inf / guile_Inf;
590#endif
591
592#endif
593}
594
595SCM_DEFINE (scm_inf, "inf", 0, 0, 0,
596 (void),
597 "Return Inf.")
598#define FUNC_NAME s_scm_inf
599{
600 static int initialized = 0;
601 if (! initialized)
602 {
603 guile_ieee_init ();
604 initialized = 1;
605 }
606 return scm_make_real (guile_Inf);
607}
608#undef FUNC_NAME
609
610SCM_DEFINE (scm_nan, "nan", 0, 0, 0,
611 (void),
612 "Return NaN.")
613#define FUNC_NAME s_scm_nan
614{
615 static int initialized = 0;
0aacf84e 616 if (!initialized)
7351e207
MV
617 {
618 guile_ieee_init ();
619 initialized = 1;
620 }
621 return scm_make_real (guile_NaN);
622}
623#undef FUNC_NAME
624
4219f20d 625
a48d60b1
MD
626SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
627 (SCM x),
628 "Return the absolute value of @var{x}.")
629#define FUNC_NAME
0f2d19dd 630{
0aacf84e
MD
631 if (SCM_INUMP (x))
632 {
633 long int xx = SCM_INUM (x);
634 if (xx >= 0)
635 return x;
636 else if (SCM_POSFIXABLE (-xx))
637 return SCM_MAKINUM (-xx);
638 else
639 return scm_i_long2big (-xx);
4219f20d 640 }
0aacf84e
MD
641 else if (SCM_BIGP (x))
642 {
643 const int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
644 if (sgn < 0)
645 return scm_i_clonebig (x, 0);
646 else
647 return x;
4219f20d 648 }
0aacf84e 649 else if (SCM_REALP (x))
ae38324d
KR
650 {
651 /* note that if x is a NaN then xx<0 is false so we return x unchanged */
652 double xx = SCM_REAL_VALUE (x);
653 if (xx < 0.0)
654 return scm_make_real (-xx);
655 else
656 return x;
657 }
f92e85f7
MV
658 else if (SCM_FRACTIONP (x))
659 {
660 if (SCM_FALSEP (scm_negative_p (SCM_FRACTION_NUMERATOR (x))))
661 return x;
662 return scm_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
663 SCM_FRACTION_DENOMINATOR (x));
664 }
0aacf84e 665 else
a48d60b1 666 SCM_WTA_DISPATCH_1 (g_scm_abs, x, 1, s_scm_abs);
0f2d19dd 667}
a48d60b1 668#undef FUNC_NAME
0f2d19dd 669
4219f20d 670
9de33deb 671SCM_GPROC (s_quotient, "quotient", 2, 0, 0, scm_quotient, g_quotient);
942e5b91
MG
672/* "Return the quotient of the numbers @var{x} and @var{y}."
673 */
0f2d19dd 674SCM
6e8d25a6 675scm_quotient (SCM x, SCM y)
0f2d19dd 676{
0aacf84e
MD
677 if (SCM_INUMP (x))
678 {
679 long xx = SCM_INUM (x);
680 if (SCM_INUMP (y))
681 {
682 long yy = SCM_INUM (y);
683 if (yy == 0)
684 scm_num_overflow (s_quotient);
685 else
686 {
687 long z = xx / yy;
688 if (SCM_FIXABLE (z))
689 return SCM_MAKINUM (z);
690 else
691 return scm_i_long2big (z);
692 }
828865c3 693 }
0aacf84e 694 else if (SCM_BIGP (y))
ac0c002c 695 {
0aacf84e
MD
696 if ((SCM_INUM (x) == SCM_MOST_NEGATIVE_FIXNUM)
697 && (scm_i_bigcmp (abs_most_negative_fixnum, y) == 0))
698 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
699 return SCM_MAKINUM (-1);
700 else
701 return SCM_MAKINUM (0);
ac0c002c
DH
702 }
703 else
0aacf84e 704 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
828865c3 705 }
0aacf84e
MD
706 else if (SCM_BIGP (x))
707 {
708 if (SCM_INUMP (y))
709 {
710 long yy = SCM_INUM (y);
711 if (yy == 0)
712 scm_num_overflow (s_quotient);
713 else if (yy == 1)
714 return x;
715 else
716 {
717 SCM result = scm_i_mkbig ();
718 if (yy < 0)
719 {
720 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (result),
721 SCM_I_BIG_MPZ (x),
722 - yy);
723 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
724 }
725 else
726 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
727 scm_remember_upto_here_1 (x);
728 return scm_i_normbig (result);
729 }
730 }
731 else if (SCM_BIGP (y))
732 {
733 SCM result = scm_i_mkbig ();
734 mpz_tdiv_q (SCM_I_BIG_MPZ (result),
735 SCM_I_BIG_MPZ (x),
736 SCM_I_BIG_MPZ (y));
737 scm_remember_upto_here_2 (x, y);
738 return scm_i_normbig (result);
739 }
740 else
741 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG2, s_quotient);
f872b822 742 }
0aacf84e 743 else
89a7e495 744 SCM_WTA_DISPATCH_2 (g_quotient, x, y, SCM_ARG1, s_quotient);
0f2d19dd
JB
745}
746
9de33deb 747SCM_GPROC (s_remainder, "remainder", 2, 0, 0, scm_remainder, g_remainder);
942e5b91
MG
748/* "Return the remainder of the numbers @var{x} and @var{y}.\n"
749 * "@lisp\n"
750 * "(remainder 13 4) @result{} 1\n"
751 * "(remainder -13 4) @result{} -1\n"
752 * "@end lisp"
753 */
0f2d19dd 754SCM
6e8d25a6 755scm_remainder (SCM x, SCM y)
0f2d19dd 756{
0aacf84e
MD
757 if (SCM_INUMP (x))
758 {
759 if (SCM_INUMP (y))
760 {
761 long yy = SCM_INUM (y);
762 if (yy == 0)
763 scm_num_overflow (s_remainder);
764 else
765 {
766 long z = SCM_INUM (x) % yy;
767 return SCM_MAKINUM (z);
768 }
769 }
770 else if (SCM_BIGP (y))
ac0c002c 771 {
0aacf84e
MD
772 if ((SCM_INUM (x) == SCM_MOST_NEGATIVE_FIXNUM)
773 && (scm_i_bigcmp (abs_most_negative_fixnum, y) == 0))
774 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
775 return SCM_MAKINUM (0);
776 else
777 return x;
ac0c002c
DH
778 }
779 else
0aacf84e 780 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
89a7e495 781 }
0aacf84e
MD
782 else if (SCM_BIGP (x))
783 {
784 if (SCM_INUMP (y))
785 {
786 long yy = SCM_INUM (y);
787 if (yy == 0)
788 scm_num_overflow (s_remainder);
789 else
790 {
791 SCM result = scm_i_mkbig ();
792 if (yy < 0)
793 yy = - yy;
794 mpz_tdiv_r_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ(x), yy);
795 scm_remember_upto_here_1 (x);
796 return scm_i_normbig (result);
797 }
798 }
799 else if (SCM_BIGP (y))
800 {
801 SCM result = scm_i_mkbig ();
802 mpz_tdiv_r (SCM_I_BIG_MPZ (result),
803 SCM_I_BIG_MPZ (x),
804 SCM_I_BIG_MPZ (y));
805 scm_remember_upto_here_2 (x, y);
806 return scm_i_normbig (result);
807 }
808 else
809 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG2, s_remainder);
f872b822 810 }
0aacf84e 811 else
89a7e495 812 SCM_WTA_DISPATCH_2 (g_remainder, x, y, SCM_ARG1, s_remainder);
0f2d19dd
JB
813}
814
89a7e495 815
9de33deb 816SCM_GPROC (s_modulo, "modulo", 2, 0, 0, scm_modulo, g_modulo);
942e5b91
MG
817/* "Return the modulo of the numbers @var{x} and @var{y}.\n"
818 * "@lisp\n"
819 * "(modulo 13 4) @result{} 1\n"
820 * "(modulo -13 4) @result{} 3\n"
821 * "@end lisp"
822 */
0f2d19dd 823SCM
6e8d25a6 824scm_modulo (SCM x, SCM y)
0f2d19dd 825{
0aacf84e
MD
826 if (SCM_INUMP (x))
827 {
828 long xx = SCM_INUM (x);
829 if (SCM_INUMP (y))
830 {
831 long yy = SCM_INUM (y);
832 if (yy == 0)
833 scm_num_overflow (s_modulo);
834 else
835 {
836 /* FIXME: I think this may be a bug on some arches -- results
837 of % with negative second arg are undefined... */
838 long z = xx % yy;
839 long result;
840
841 if (yy < 0)
842 {
843 if (z > 0)
844 result = z + yy;
845 else
846 result = z;
847 }
848 else
849 {
850 if (z < 0)
851 result = z + yy;
852 else
853 result = z;
854 }
855 return SCM_MAKINUM (result);
856 }
857 }
858 else if (SCM_BIGP (y))
859 {
860 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
861
862 if (sgn_y == 0)
863 scm_num_overflow (s_modulo);
864 else
865 {
866 mpz_t z_x;
867 SCM result;
868
869 if (sgn_y < 0)
870 {
871 SCM pos_y = scm_i_clonebig (y, 0);
872 /* do this after the last scm_op */
873 mpz_init_set_si (z_x, xx);
874 result = pos_y; /* re-use this bignum */
875 mpz_mod (SCM_I_BIG_MPZ (result),
876 z_x,
877 SCM_I_BIG_MPZ (pos_y));
878 scm_remember_upto_here_1 (pos_y);
879 }
880 else
881 {
882 result = scm_i_mkbig ();
883 /* do this after the last scm_op */
884 mpz_init_set_si (z_x, xx);
885 mpz_mod (SCM_I_BIG_MPZ (result),
886 z_x,
887 SCM_I_BIG_MPZ (y));
888 scm_remember_upto_here_1 (y);
889 }
ca46fb90 890
0aacf84e
MD
891 if ((sgn_y < 0) && mpz_sgn (SCM_I_BIG_MPZ (result)) != 0)
892 mpz_add (SCM_I_BIG_MPZ (result),
893 SCM_I_BIG_MPZ (y),
894 SCM_I_BIG_MPZ (result));
895 scm_remember_upto_here_1 (y);
896 /* and do this before the next one */
897 mpz_clear (z_x);
898 return scm_i_normbig (result);
899 }
900 }
901 else
902 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
f872b822 903 }
0aacf84e
MD
904 else if (SCM_BIGP (x))
905 {
906 if (SCM_INUMP (y))
907 {
908 long yy = SCM_INUM (y);
909 if (yy == 0)
910 scm_num_overflow (s_modulo);
911 else
912 {
913 SCM result = scm_i_mkbig ();
914 mpz_mod_ui (SCM_I_BIG_MPZ (result),
915 SCM_I_BIG_MPZ (x),
916 (yy < 0) ? - yy : yy);
917 scm_remember_upto_here_1 (x);
918 if ((yy < 0) && (mpz_sgn (SCM_I_BIG_MPZ (result)) != 0))
919 mpz_sub_ui (SCM_I_BIG_MPZ (result),
920 SCM_I_BIG_MPZ (result),
921 - yy);
922 return scm_i_normbig (result);
923 }
924 }
925 else if (SCM_BIGP (y))
926 {
927 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
928 if (sgn_y == 0)
929 scm_num_overflow (s_modulo);
930 else
931 {
932 SCM result = scm_i_mkbig ();
933 int y_sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
934 SCM pos_y = scm_i_clonebig (y, y_sgn >= 0);
935 mpz_mod (SCM_I_BIG_MPZ (result),
936 SCM_I_BIG_MPZ (x),
937 SCM_I_BIG_MPZ (pos_y));
ca46fb90 938
0aacf84e
MD
939 scm_remember_upto_here_1 (x);
940 if ((y_sgn < 0) && (mpz_sgn (SCM_I_BIG_MPZ (result)) != 0))
941 mpz_add (SCM_I_BIG_MPZ (result),
942 SCM_I_BIG_MPZ (y),
943 SCM_I_BIG_MPZ (result));
944 scm_remember_upto_here_2 (y, pos_y);
945 return scm_i_normbig (result);
946 }
947 }
948 else
949 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG2, s_modulo);
828865c3 950 }
0aacf84e 951 else
09fb7599 952 SCM_WTA_DISPATCH_2 (g_modulo, x, y, SCM_ARG1, s_modulo);
0f2d19dd
JB
953}
954
9de33deb 955SCM_GPROC1 (s_gcd, "gcd", scm_tc7_asubr, scm_gcd, g_gcd);
942e5b91
MG
956/* "Return the greatest common divisor of all arguments.\n"
957 * "If called without arguments, 0 is returned."
958 */
0f2d19dd 959SCM
6e8d25a6 960scm_gcd (SCM x, SCM y)
0f2d19dd 961{
ca46fb90 962 if (SCM_UNBNDP (y))
0aacf84e 963 return SCM_UNBNDP (x) ? SCM_INUM0 : x;
ca46fb90
RB
964
965 if (SCM_INUMP (x))
966 {
967 if (SCM_INUMP (y))
968 {
969 long xx = SCM_INUM (x);
970 long yy = SCM_INUM (y);
971 long u = xx < 0 ? -xx : xx;
972 long v = yy < 0 ? -yy : yy;
973 long result;
0aacf84e
MD
974 if (xx == 0)
975 result = v;
976 else if (yy == 0)
977 result = u;
978 else
979 {
980 long k = 1;
981 long t;
982 /* Determine a common factor 2^k */
983 while (!(1 & (u | v)))
984 {
985 k <<= 1;
986 u >>= 1;
987 v >>= 1;
988 }
989 /* Now, any factor 2^n can be eliminated */
990 if (u & 1)
991 t = -v;
992 else
993 {
994 t = u;
995 b3:
996 t = SCM_SRS (t, 1);
997 }
998 if (!(1 & t))
999 goto b3;
1000 if (t > 0)
1001 u = t;
1002 else
1003 v = -t;
1004 t = u - v;
1005 if (t != 0)
1006 goto b3;
1007 result = u * k;
1008 }
1009 return (SCM_POSFIXABLE (result)
1010 ? SCM_MAKINUM (result)
1011 : scm_i_long2big (result));
ca46fb90
RB
1012 }
1013 else if (SCM_BIGP (y))
1014 {
1015 SCM result = scm_i_mkbig ();
1016 SCM mx = scm_i_mkbig ();
0aacf84e 1017 mpz_set_si (SCM_I_BIG_MPZ (mx), SCM_INUM (x));
ca46fb90 1018 scm_remember_upto_here_1 (x);
0aacf84e
MD
1019 mpz_gcd (SCM_I_BIG_MPZ (result),
1020 SCM_I_BIG_MPZ (mx),
1021 SCM_I_BIG_MPZ (y));
1022 scm_remember_upto_here_2 (mx, y);
ca46fb90
RB
1023 return scm_i_normbig (result);
1024 }
1025 else
1026 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 1027 }
ca46fb90
RB
1028 else if (SCM_BIGP (x))
1029 {
1030 if (SCM_INUMP (y))
1031 {
1032 unsigned long result;
1033 long yy = SCM_INUM (y);
8c5b0afc
KR
1034 if (yy == 0)
1035 return scm_abs (x);
0aacf84e
MD
1036 if (yy < 0)
1037 yy = -yy;
ca46fb90
RB
1038 result = mpz_gcd_ui (NULL, SCM_I_BIG_MPZ (x), yy);
1039 scm_remember_upto_here_1 (x);
0aacf84e
MD
1040 return (SCM_POSFIXABLE (result)
1041 ? SCM_MAKINUM (result)
1042 : scm_ulong2num (result));
ca46fb90
RB
1043 }
1044 else if (SCM_BIGP (y))
1045 {
1046 SCM result = scm_i_mkbig ();
0aacf84e
MD
1047 mpz_gcd (SCM_I_BIG_MPZ (result),
1048 SCM_I_BIG_MPZ (x),
1049 SCM_I_BIG_MPZ (y));
1050 scm_remember_upto_here_2 (x, y);
ca46fb90
RB
1051 return scm_i_normbig (result);
1052 }
1053 else
1054 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
09fb7599 1055 }
ca46fb90 1056 else
09fb7599 1057 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
0f2d19dd
JB
1058}
1059
9de33deb 1060SCM_GPROC1 (s_lcm, "lcm", scm_tc7_asubr, scm_lcm, g_lcm);
942e5b91
MG
1061/* "Return the least common multiple of the arguments.\n"
1062 * "If called without arguments, 1 is returned."
1063 */
0f2d19dd 1064SCM
6e8d25a6 1065scm_lcm (SCM n1, SCM n2)
0f2d19dd 1066{
ca46fb90
RB
1067 if (SCM_UNBNDP (n2))
1068 {
1069 if (SCM_UNBNDP (n1))
1070 return SCM_MAKINUM (1L);
09fb7599
DH
1071 n2 = SCM_MAKINUM (1L);
1072 }
09fb7599 1073
09fb7599 1074 SCM_GASSERT2 (SCM_INUMP (n1) || SCM_BIGP (n1),
ca46fb90 1075 g_lcm, n1, n2, SCM_ARG1, s_lcm);
09fb7599 1076 SCM_GASSERT2 (SCM_INUMP (n2) || SCM_BIGP (n2),
ca46fb90 1077 g_lcm, n1, n2, SCM_ARGn, s_lcm);
09fb7599 1078
ca46fb90
RB
1079 if (SCM_INUMP (n1))
1080 {
1081 if (SCM_INUMP (n2))
1082 {
1083 SCM d = scm_gcd (n1, n2);
1084 if (SCM_EQ_P (d, SCM_INUM0))
1085 return d;
1086 else
1087 return scm_abs (scm_product (n1, scm_quotient (n2, d)));
1088 }
1089 else
1090 {
1091 /* inum n1, big n2 */
1092 inumbig:
1093 {
1094 SCM result = scm_i_mkbig ();
1095 long nn1 = SCM_INUM (n1);
1096 if (nn1 == 0) return SCM_INUM0;
1097 if (nn1 < 0) nn1 = - nn1;
1098 mpz_lcm_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n2), nn1);
1099 scm_remember_upto_here_1 (n2);
1100 return result;
1101 }
1102 }
1103 }
1104 else
1105 {
1106 /* big n1 */
1107 if (SCM_INUMP (n2))
1108 {
1109 SCM_SWAP (n1, n2);
1110 goto inumbig;
1111 }
1112 else
1113 {
1114 SCM result = scm_i_mkbig ();
1115 mpz_lcm(SCM_I_BIG_MPZ (result),
1116 SCM_I_BIG_MPZ (n1),
1117 SCM_I_BIG_MPZ (n2));
1118 scm_remember_upto_here_2(n1, n2);
1119 /* shouldn't need to normalize b/c lcm of 2 bigs should be big */
1120 return result;
1121 }
f872b822 1122 }
0f2d19dd
JB
1123}
1124
0f2d19dd 1125#ifndef scm_long2num
c1bfcf60
GB
1126#define SCM_LOGOP_RETURN(x) scm_ulong2num(x)
1127#else
1128#define SCM_LOGOP_RETURN(x) SCM_MAKINUM(x)
1129#endif
1130
8a525303
GB
1131/* Emulating 2's complement bignums with sign magnitude arithmetic:
1132
1133 Logand:
1134 X Y Result Method:
1135 (len)
1136 + + + x (map digit:logand X Y)
1137 + - + x (map digit:logand X (lognot (+ -1 Y)))
1138 - + + y (map digit:logand (lognot (+ -1 X)) Y)
1139 - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y)))
1140
1141 Logior:
1142 X Y Result Method:
1143
1144 + + + (map digit:logior X Y)
1145 + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y)))
1146 - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y)))
1147 - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y)))
1148
1149 Logxor:
1150 X Y Result Method:
1151
1152 + + + (map digit:logxor X Y)
1153 + - - (+ 1 (map digit:logxor X (+ -1 Y)))
1154 - + - (+ 1 (map digit:logxor (+ -1 X) Y))
1155 - - + (map digit:logxor (+ -1 X) (+ -1 Y))
1156
1157 Logtest:
1158 X Y Result
1159
1160 + + (any digit:logand X Y)
1161 + - (any digit:logand X (lognot (+ -1 Y)))
1162 - + (any digit:logand (lognot (+ -1 X)) Y)
1163 - - #t
1164
1165*/
1166
c3ee7520 1167SCM_DEFINE1 (scm_logand, "logand", scm_tc7_asubr,
1bbd0b84 1168 (SCM n1, SCM n2),
3c3db128
GH
1169 "Return the bitwise AND of the integer arguments.\n\n"
1170 "@lisp\n"
1171 "(logand) @result{} -1\n"
1172 "(logand 7) @result{} 7\n"
535f2a51 1173 "(logand #b111 #b011 #b001) @result{} 1\n"
3c3db128 1174 "@end lisp")
1bbd0b84 1175#define FUNC_NAME s_scm_logand
0f2d19dd 1176{
9a00c9fc
DH
1177 long int nn1;
1178
0aacf84e
MD
1179 if (SCM_UNBNDP (n2))
1180 {
1181 if (SCM_UNBNDP (n1))
1182 return SCM_MAKINUM (-1);
1183 else if (!SCM_NUMBERP (n1))
1184 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
1185 else if (SCM_NUMBERP (n1))
1186 return n1;
1187 else
1188 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 1189 }
09fb7599 1190
0aacf84e
MD
1191 if (SCM_INUMP (n1))
1192 {
9a00c9fc 1193 nn1 = SCM_INUM (n1);
0aacf84e
MD
1194 if (SCM_INUMP (n2))
1195 {
1196 long nn2 = SCM_INUM (n2);
1197 return SCM_MAKINUM (nn1 & nn2);
1198 }
1199 else if SCM_BIGP (n2)
1200 {
1201 intbig:
1202 if (n1 == 0)
1203 return SCM_INUM0;
1204 {
1205 SCM result_z = scm_i_mkbig ();
1206 mpz_t nn1_z;
1207 mpz_init_set_si (nn1_z, nn1);
1208 mpz_and (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
1209 scm_remember_upto_here_1 (n2);
1210 mpz_clear (nn1_z);
1211 return scm_i_normbig (result_z);
1212 }
1213 }
1214 else
1215 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1216 }
1217 else if (SCM_BIGP (n1))
1218 {
1219 if (SCM_INUMP (n2))
1220 {
1221 SCM_SWAP (n1, n2);
1222 nn1 = SCM_INUM (n1);
1223 goto intbig;
1224 }
1225 else if (SCM_BIGP (n2))
1226 {
1227 SCM result_z = scm_i_mkbig ();
1228 mpz_and (SCM_I_BIG_MPZ (result_z),
1229 SCM_I_BIG_MPZ (n1),
1230 SCM_I_BIG_MPZ (n2));
1231 scm_remember_upto_here_2 (n1, n2);
1232 return scm_i_normbig (result_z);
1233 }
1234 else
1235 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 1236 }
0aacf84e 1237 else
09fb7599 1238 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 1239}
1bbd0b84 1240#undef FUNC_NAME
0f2d19dd 1241
09fb7599 1242
c3ee7520 1243SCM_DEFINE1 (scm_logior, "logior", scm_tc7_asubr,
1bbd0b84 1244 (SCM n1, SCM n2),
3c3db128
GH
1245 "Return the bitwise OR of the integer arguments.\n\n"
1246 "@lisp\n"
1247 "(logior) @result{} 0\n"
1248 "(logior 7) @result{} 7\n"
1249 "(logior #b000 #b001 #b011) @result{} 3\n"
1e6808ea 1250 "@end lisp")
1bbd0b84 1251#define FUNC_NAME s_scm_logior
0f2d19dd 1252{
9a00c9fc
DH
1253 long int nn1;
1254
0aacf84e
MD
1255 if (SCM_UNBNDP (n2))
1256 {
1257 if (SCM_UNBNDP (n1))
1258 return SCM_INUM0;
1259 else if (SCM_NUMBERP (n1))
1260 return n1;
1261 else
1262 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 1263 }
09fb7599 1264
0aacf84e
MD
1265 if (SCM_INUMP (n1))
1266 {
9a00c9fc 1267 nn1 = SCM_INUM (n1);
0aacf84e
MD
1268 if (SCM_INUMP (n2))
1269 {
1270 long nn2 = SCM_INUM (n2);
1271 return SCM_MAKINUM (nn1 | nn2);
1272 }
1273 else if (SCM_BIGP (n2))
1274 {
1275 intbig:
1276 if (nn1 == 0)
1277 return n2;
1278 {
1279 SCM result_z = scm_i_mkbig ();
1280 mpz_t nn1_z;
1281 mpz_init_set_si (nn1_z, nn1);
1282 mpz_ior (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
1283 scm_remember_upto_here_1 (n2);
1284 mpz_clear (nn1_z);
1285 return result_z;
1286 }
1287 }
1288 else
1289 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1290 }
1291 else if (SCM_BIGP (n1))
1292 {
1293 if (SCM_INUMP (n2))
1294 {
1295 SCM_SWAP (n1, n2);
1296 nn1 = SCM_INUM (n1);
1297 goto intbig;
1298 }
1299 else if (SCM_BIGP (n2))
1300 {
1301 SCM result_z = scm_i_mkbig ();
1302 mpz_ior (SCM_I_BIG_MPZ (result_z),
1303 SCM_I_BIG_MPZ (n1),
1304 SCM_I_BIG_MPZ (n2));
1305 scm_remember_upto_here_2 (n1, n2);
1306 return result_z;
1307 }
1308 else
1309 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 1310 }
0aacf84e 1311 else
09fb7599 1312 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 1313}
1bbd0b84 1314#undef FUNC_NAME
0f2d19dd 1315
09fb7599 1316
c3ee7520 1317SCM_DEFINE1 (scm_logxor, "logxor", scm_tc7_asubr,
1bbd0b84 1318 (SCM n1, SCM n2),
3c3db128
GH
1319 "Return the bitwise XOR of the integer arguments. A bit is\n"
1320 "set in the result if it is set in an odd number of arguments.\n"
1321 "@lisp\n"
1322 "(logxor) @result{} 0\n"
1323 "(logxor 7) @result{} 7\n"
1324 "(logxor #b000 #b001 #b011) @result{} 2\n"
1325 "(logxor #b000 #b001 #b011 #b011) @result{} 1\n"
1e6808ea 1326 "@end lisp")
1bbd0b84 1327#define FUNC_NAME s_scm_logxor
0f2d19dd 1328{
9a00c9fc
DH
1329 long int nn1;
1330
0aacf84e
MD
1331 if (SCM_UNBNDP (n2))
1332 {
1333 if (SCM_UNBNDP (n1))
1334 return SCM_INUM0;
1335 else if (SCM_NUMBERP (n1))
1336 return n1;
1337 else
1338 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 1339 }
09fb7599 1340
0aacf84e
MD
1341 if (SCM_INUMP (n1))
1342 {
9a00c9fc 1343 nn1 = SCM_INUM (n1);
0aacf84e
MD
1344 if (SCM_INUMP (n2))
1345 {
1346 long nn2 = SCM_INUM (n2);
1347 return SCM_MAKINUM (nn1 ^ nn2);
1348 }
1349 else if (SCM_BIGP (n2))
1350 {
1351 intbig:
1352 {
1353 SCM result_z = scm_i_mkbig ();
1354 mpz_t nn1_z;
1355 mpz_init_set_si (nn1_z, nn1);
1356 mpz_xor (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
1357 scm_remember_upto_here_1 (n2);
1358 mpz_clear (nn1_z);
1359 return scm_i_normbig (result_z);
1360 }
1361 }
1362 else
1363 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
1364 }
1365 else if (SCM_BIGP (n1))
1366 {
1367 if (SCM_INUMP (n2))
1368 {
1369 SCM_SWAP (n1, n2);
1370 nn1 = SCM_INUM (n1);
1371 goto intbig;
1372 }
1373 else if (SCM_BIGP (n2))
1374 {
1375 SCM result_z = scm_i_mkbig ();
1376 mpz_xor (SCM_I_BIG_MPZ (result_z),
1377 SCM_I_BIG_MPZ (n1),
1378 SCM_I_BIG_MPZ (n2));
1379 scm_remember_upto_here_2 (n1, n2);
1380 return scm_i_normbig (result_z);
1381 }
1382 else
1383 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 1384 }
0aacf84e 1385 else
09fb7599 1386 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 1387}
1bbd0b84 1388#undef FUNC_NAME
0f2d19dd 1389
09fb7599 1390
a1ec6916 1391SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1e6808ea
MG
1392 (SCM j, SCM k),
1393 "@lisp\n"
b380b885
MD
1394 "(logtest j k) @equiv{} (not (zero? (logand j k)))\n\n"
1395 "(logtest #b0100 #b1011) @result{} #f\n"
1396 "(logtest #b0100 #b0111) @result{} #t\n"
1e6808ea 1397 "@end lisp")
1bbd0b84 1398#define FUNC_NAME s_scm_logtest
0f2d19dd 1399{
1e6808ea 1400 long int nj;
9a00c9fc 1401
0aacf84e
MD
1402 if (SCM_INUMP (j))
1403 {
1e6808ea 1404 nj = SCM_INUM (j);
0aacf84e
MD
1405 if (SCM_INUMP (k))
1406 {
1407 long nk = SCM_INUM (k);
1408 return SCM_BOOL (nj & nk);
1409 }
1410 else if (SCM_BIGP (k))
1411 {
1412 intbig:
1413 if (nj == 0)
1414 return SCM_BOOL_F;
1415 {
1416 SCM result;
1417 mpz_t nj_z;
1418 mpz_init_set_si (nj_z, nj);
1419 mpz_and (nj_z, nj_z, SCM_I_BIG_MPZ (k));
1420 scm_remember_upto_here_1 (k);
1421 result = SCM_BOOL (mpz_sgn (nj_z) != 0);
1422 mpz_clear (nj_z);
1423 return result;
1424 }
1425 }
1426 else
1427 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
1428 }
1429 else if (SCM_BIGP (j))
1430 {
1431 if (SCM_INUMP (k))
1432 {
1433 SCM_SWAP (j, k);
1434 nj = SCM_INUM (j);
1435 goto intbig;
1436 }
1437 else if (SCM_BIGP (k))
1438 {
1439 SCM result;
1440 mpz_t result_z;
1441 mpz_init (result_z);
1442 mpz_and (result_z,
1443 SCM_I_BIG_MPZ (j),
1444 SCM_I_BIG_MPZ (k));
1445 scm_remember_upto_here_2 (j, k);
1446 result = SCM_BOOL (mpz_sgn (result_z) != 0);
1447 mpz_clear (result_z);
1448 return result;
1449 }
1450 else
1451 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
1452 }
1453 else
1454 SCM_WRONG_TYPE_ARG (SCM_ARG1, j);
0f2d19dd 1455}
1bbd0b84 1456#undef FUNC_NAME
0f2d19dd 1457
c1bfcf60 1458
a1ec6916 1459SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 1460 (SCM index, SCM j),
1e6808ea 1461 "@lisp\n"
b380b885
MD
1462 "(logbit? index j) @equiv{} (logtest (integer-expt 2 index) j)\n\n"
1463 "(logbit? 0 #b1101) @result{} #t\n"
1464 "(logbit? 1 #b1101) @result{} #f\n"
1465 "(logbit? 2 #b1101) @result{} #t\n"
1466 "(logbit? 3 #b1101) @result{} #t\n"
1467 "(logbit? 4 #b1101) @result{} #f\n"
1e6808ea 1468 "@end lisp")
1bbd0b84 1469#define FUNC_NAME s_scm_logbit_p
0f2d19dd 1470{
78166ad5
DH
1471 unsigned long int iindex;
1472
1473 SCM_VALIDATE_INUM_MIN (SCM_ARG1, index, 0);
1474 iindex = (unsigned long int) SCM_INUM (index);
1475
0aacf84e 1476 if (SCM_INUMP (j))
78166ad5 1477 return SCM_BOOL ((1L << iindex) & SCM_INUM (j));
0aacf84e
MD
1478 else if (SCM_BIGP (j))
1479 {
1480 int val = mpz_tstbit (SCM_I_BIG_MPZ (j), iindex);
1481 scm_remember_upto_here_1 (j);
1482 return SCM_BOOL (val);
1483 }
1484 else
78166ad5 1485 SCM_WRONG_TYPE_ARG (SCM_ARG2, j);
0f2d19dd 1486}
1bbd0b84 1487#undef FUNC_NAME
0f2d19dd 1488
78166ad5 1489
a1ec6916 1490SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 1491 (SCM n),
4d814788 1492 "Return the integer which is the ones-complement of the integer\n"
1e6808ea
MG
1493 "argument.\n"
1494 "\n"
b380b885
MD
1495 "@lisp\n"
1496 "(number->string (lognot #b10000000) 2)\n"
1497 " @result{} \"-10000001\"\n"
1498 "(number->string (lognot #b0) 2)\n"
1499 " @result{} \"-1\"\n"
1e6808ea 1500 "@end lisp")
1bbd0b84 1501#define FUNC_NAME s_scm_lognot
0f2d19dd 1502{
f9811f9f
KR
1503 if (SCM_INUMP (n)) {
1504 /* No overflow here, just need to toggle all the bits making up the inum.
1505 Enhancement: No need to strip the tag and add it back, could just xor
1506 a block of 1 bits, if that worked with the various debug versions of
1507 the SCM typedef. */
1508 return SCM_MAKINUM (~ SCM_INUM (n));
1509
1510 } else if (SCM_BIGP (n)) {
1511 SCM result = scm_i_mkbig ();
1512 mpz_com (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n));
1513 scm_remember_upto_here_1 (n);
1514 return result;
1515
1516 } else {
1517 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
1518 }
0f2d19dd 1519}
1bbd0b84 1520#undef FUNC_NAME
0f2d19dd 1521
a1ec6916 1522SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 1523 (SCM n, SCM k),
1e6808ea
MG
1524 "Return @var{n} raised to the non-negative integer exponent\n"
1525 "@var{k}.\n"
1526 "\n"
b380b885
MD
1527 "@lisp\n"
1528 "(integer-expt 2 5)\n"
1529 " @result{} 32\n"
1530 "(integer-expt -3 3)\n"
1531 " @result{} -27\n"
1532 "@end lisp")
1bbd0b84 1533#define FUNC_NAME s_scm_integer_expt
0f2d19dd 1534{
1c35cb19
RB
1535 long i2 = 0;
1536 SCM z_i2 = SCM_BOOL_F;
1537 int i2_is_big = 0;
f872b822 1538 SCM acc = SCM_MAKINUM (1L);
ca46fb90 1539
d57ed702 1540 /* 0^0 == 1 according to R5RS */
4260a7fc 1541 if (SCM_EQ_P (n, SCM_INUM0) || SCM_EQ_P (n, acc))
7b3381f4 1542 return SCM_FALSEP (scm_zero_p(k)) ? n : acc;
4260a7fc
DH
1543 else if (SCM_EQ_P (n, SCM_MAKINUM (-1L)))
1544 return SCM_FALSEP (scm_even_p (k)) ? n : acc;
ca46fb90 1545
ca46fb90
RB
1546 if (SCM_INUMP (k))
1547 i2 = SCM_INUM (k);
1548 else if (SCM_BIGP (k))
1549 {
1550 z_i2 = scm_i_clonebig (k, 1);
ca46fb90
RB
1551 scm_remember_upto_here_1 (k);
1552 i2_is_big = 1;
1553 }
1554 else if (SCM_REALP (k))
2830fd91
MD
1555 {
1556 double r = SCM_REAL_VALUE (k);
ca46fb90
RB
1557 if (floor (r) != r)
1558 SCM_WRONG_TYPE_ARG (2, k);
1559 if ((r > SCM_MOST_POSITIVE_FIXNUM) || (r < SCM_MOST_NEGATIVE_FIXNUM))
1560 {
1561 z_i2 = scm_i_mkbig ();
753ac1e7 1562 mpz_set_d (SCM_I_BIG_MPZ (z_i2), r);
ca46fb90
RB
1563 i2_is_big = 1;
1564 }
1565 else
1566 {
1567 i2 = r;
1568 }
2830fd91
MD
1569 }
1570 else
ca46fb90
RB
1571 SCM_WRONG_TYPE_ARG (2, k);
1572
1573 if (i2_is_big)
f872b822 1574 {
ca46fb90
RB
1575 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == -1)
1576 {
1577 mpz_neg (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2));
1578 n = scm_divide (n, SCM_UNDEFINED);
1579 }
1580 while (1)
1581 {
1582 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == 0)
1583 {
ca46fb90
RB
1584 return acc;
1585 }
1586 if (mpz_cmp_ui(SCM_I_BIG_MPZ (z_i2), 1) == 0)
1587 {
ca46fb90
RB
1588 return scm_product (acc, n);
1589 }
1590 if (mpz_tstbit(SCM_I_BIG_MPZ (z_i2), 0))
1591 acc = scm_product (acc, n);
1592 n = scm_product (n, n);
1593 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2), 1);
1594 }
f872b822 1595 }
ca46fb90 1596 else
f872b822 1597 {
ca46fb90
RB
1598 if (i2 < 0)
1599 {
1600 i2 = -i2;
1601 n = scm_divide (n, SCM_UNDEFINED);
1602 }
1603 while (1)
1604 {
1605 if (0 == i2)
1606 return acc;
1607 if (1 == i2)
1608 return scm_product (acc, n);
1609 if (i2 & 1)
1610 acc = scm_product (acc, n);
1611 n = scm_product (n, n);
1612 i2 >>= 1;
1613 }
f872b822 1614 }
0f2d19dd 1615}
1bbd0b84 1616#undef FUNC_NAME
0f2d19dd 1617
a1ec6916 1618SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 1619 (SCM n, SCM cnt),
32f19569
KR
1620 "Return @var{n} shifted left by @var{cnt} bits, or shifted right\n"
1621 "if @var{cnt} is negative. This is an ``arithmetic'' shift.\n"
1e6808ea 1622 "\n"
32f19569
KR
1623 "This is effectively a multiplication by 2^@var{cnt}}, and when\n"
1624 "@var{cnt} is negative it's a division, rounded towards negative\n"
1625 "infinity. (Note that this is not the same rounding as\n"
1626 "@code{quotient} does.)\n"
1627 "\n"
1628 "With @var{n} viewed as an infinite precision twos complement,\n"
1629 "@code{ash} means a left shift introducing zero bits, or a right\n"
1630 "shift dropping bits.\n"
1e6808ea 1631 "\n"
b380b885 1632 "@lisp\n"
1e6808ea
MG
1633 "(number->string (ash #b1 3) 2) @result{} \"1000\"\n"
1634 "(number->string (ash #b1010 -1) 2) @result{} \"101\"\n"
32f19569
KR
1635 "\n"
1636 ";; -23 is bits ...11101001, -6 is bits ...111010\n"
1637 "(ash -23 -2) @result{} -6\n"
a3c8b9fc 1638 "@end lisp")
1bbd0b84 1639#define FUNC_NAME s_scm_ash
0f2d19dd 1640{
3ab9f56e
DH
1641 long bits_to_shift;
1642
3ab9f56e
DH
1643 SCM_VALIDATE_INUM (2, cnt);
1644
1645 bits_to_shift = SCM_INUM (cnt);
ca46fb90
RB
1646
1647 if (bits_to_shift < 0)
1648 {
1649 /* Shift right by abs(cnt) bits. This is realized as a division
1650 by div:=2^abs(cnt). However, to guarantee the floor
1651 rounding, negative values require some special treatment.
1652 */
1653 SCM div = scm_integer_expt (SCM_MAKINUM (2),
1654 SCM_MAKINUM (-bits_to_shift));
f92e85f7
MV
1655
1656 /* scm_quotient assumes its arguments are integers, but it's legal to (ash 1/2 -1) */
ca46fb90
RB
1657 if (SCM_FALSEP (scm_negative_p (n)))
1658 return scm_quotient (n, div);
1659 else
1660 return scm_sum (SCM_MAKINUM (-1L),
1661 scm_quotient (scm_sum (SCM_MAKINUM (1L), n), div));
1662 }
1663 else
3ab9f56e 1664 /* Shift left is done by multiplication with 2^CNT */
f872b822 1665 return scm_product (n, scm_integer_expt (SCM_MAKINUM (2), cnt));
0f2d19dd 1666}
1bbd0b84 1667#undef FUNC_NAME
0f2d19dd 1668
3c9f20f8 1669
7f848242
KR
1670#define MIN(x,y) ((x) < (y) ? (x) : (y))
1671
a1ec6916 1672SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 1673 (SCM n, SCM start, SCM end),
1e6808ea
MG
1674 "Return the integer composed of the @var{start} (inclusive)\n"
1675 "through @var{end} (exclusive) bits of @var{n}. The\n"
1676 "@var{start}th bit becomes the 0-th bit in the result.\n"
1677 "\n"
b380b885
MD
1678 "@lisp\n"
1679 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
1680 " @result{} \"1010\"\n"
1681 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
1682 " @result{} \"10110\"\n"
1683 "@end lisp")
1bbd0b84 1684#define FUNC_NAME s_scm_bit_extract
0f2d19dd 1685{
7f848242 1686 unsigned long int istart, iend, bits;
34d19ef6 1687 SCM_VALIDATE_INUM_MIN_COPY (2, start,0, istart);
c1bfcf60
GB
1688 SCM_VALIDATE_INUM_MIN_COPY (3, end, 0, iend);
1689 SCM_ASSERT_RANGE (3, end, (iend >= istart));
78166ad5 1690
7f848242
KR
1691 /* how many bits to keep */
1692 bits = iend - istart;
1693
0aacf84e
MD
1694 if (SCM_INUMP (n))
1695 {
1696 long int in = SCM_INUM (n);
7f848242
KR
1697
1698 /* When istart>=SCM_I_FIXNUM_BIT we can just limit the shift to
1699 SCM_I_FIXNUM_BIT-1 to get either 0 or -1 per the sign of "in".
1700 FIXME: This shift relies on signed right shifts being arithmetic,
1701 which is not guaranteed by C99. */
1702 in >>= MIN (istart, SCM_I_FIXNUM_BIT-1);
ac0c002c 1703
0aacf84e
MD
1704 if (in < 0 && bits >= SCM_I_FIXNUM_BIT)
1705 {
1706 /* Since we emulate two's complement encoded numbers, this
1707 * special case requires us to produce a result that has
7f848242 1708 * more bits than can be stored in a fixnum.
0aacf84e 1709 */
7f848242
KR
1710 SCM result = scm_i_long2big (in);
1711 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
1712 bits);
1713 return result;
0aacf84e 1714 }
ac0c002c 1715
7f848242
KR
1716 /* mask down to requisite bits */
1717 bits = MIN (bits, SCM_I_FIXNUM_BIT);
1718 return SCM_MAKINUM (in & ((1L << bits) - 1));
0aacf84e
MD
1719 }
1720 else if (SCM_BIGP (n))
ac0c002c 1721 {
7f848242
KR
1722 SCM result;
1723 if (bits == 1)
1724 {
1725 result = SCM_MAKINUM (mpz_tstbit (SCM_I_BIG_MPZ (n), istart));
1726 }
1727 else
1728 {
1729 /* ENHANCE-ME: It'd be nice not to allocate a new bignum when
1730 bits<SCM_I_FIXNUM_BIT. Would want some help from GMP to get
1731 such bits into a ulong. */
1732 result = scm_i_mkbig ();
1733 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(n), istart);
1734 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(result), bits);
1735 result = scm_i_normbig (result);
1736 }
1737 scm_remember_upto_here_1 (n);
1738 return result;
ac0c002c 1739 }
0aacf84e 1740 else
78166ad5 1741 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 1742}
1bbd0b84 1743#undef FUNC_NAME
0f2d19dd 1744
7f848242 1745
e4755e5c
JB
1746static const char scm_logtab[] = {
1747 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
1748};
1cc91f1b 1749
a1ec6916 1750SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 1751 (SCM n),
1e6808ea
MG
1752 "Return the number of bits in integer @var{n}. If integer is\n"
1753 "positive, the 1-bits in its binary representation are counted.\n"
1754 "If negative, the 0-bits in its two's-complement binary\n"
1755 "representation are counted. If 0, 0 is returned.\n"
1756 "\n"
b380b885
MD
1757 "@lisp\n"
1758 "(logcount #b10101010)\n"
ca46fb90
RB
1759 " @result{} 4\n"
1760 "(logcount 0)\n"
1761 " @result{} 0\n"
1762 "(logcount -2)\n"
1763 " @result{} 1\n"
1764 "@end lisp")
1765#define FUNC_NAME s_scm_logcount
1766{
1767 if (SCM_INUMP (n))
f872b822 1768 {
ca46fb90
RB
1769 unsigned long int c = 0;
1770 long int nn = SCM_INUM (n);
1771 if (nn < 0)
1772 nn = -1 - nn;
1773 while (nn)
1774 {
1775 c += scm_logtab[15 & nn];
1776 nn >>= 4;
1777 }
1778 return SCM_MAKINUM (c);
f872b822 1779 }
ca46fb90 1780 else if (SCM_BIGP (n))
f872b822 1781 {
ca46fb90 1782 unsigned long count;
713a4259
KR
1783 if (mpz_sgn (SCM_I_BIG_MPZ (n)) >= 0)
1784 count = mpz_popcount (SCM_I_BIG_MPZ (n));
ca46fb90 1785 else
713a4259
KR
1786 count = mpz_hamdist (SCM_I_BIG_MPZ (n), z_negative_one);
1787 scm_remember_upto_here_1 (n);
ca46fb90 1788 return SCM_MAKINUM (count);
f872b822 1789 }
ca46fb90
RB
1790 else
1791 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 1792}
ca46fb90 1793#undef FUNC_NAME
0f2d19dd
JB
1794
1795
ca46fb90
RB
1796static const char scm_ilentab[] = {
1797 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
1798};
1799
0f2d19dd 1800
ca46fb90
RB
1801SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
1802 (SCM n),
1803 "Return the number of bits necessary to represent @var{n}.\n"
1804 "\n"
1805 "@lisp\n"
1806 "(integer-length #b10101010)\n"
1807 " @result{} 8\n"
1808 "(integer-length 0)\n"
1809 " @result{} 0\n"
1810 "(integer-length #b1111)\n"
1811 " @result{} 4\n"
1812 "@end lisp")
1813#define FUNC_NAME s_scm_integer_length
1814{
0aacf84e
MD
1815 if (SCM_INUMP (n))
1816 {
1817 unsigned long int c = 0;
1818 unsigned int l = 4;
1819 long int nn = SCM_INUM (n);
1820 if (nn < 0)
1821 nn = -1 - nn;
1822 while (nn)
1823 {
1824 c += 4;
1825 l = scm_ilentab [15 & nn];
1826 nn >>= 4;
1827 }
1828 return SCM_MAKINUM (c - 4 + l);
1829 }
1830 else if (SCM_BIGP (n))
1831 {
1832 /* mpz_sizeinbase looks at the absolute value of negatives, whereas we
1833 want a ones-complement. If n is ...111100..00 then mpz_sizeinbase is
1834 1 too big, so check for that and adjust. */
1835 size_t size = mpz_sizeinbase (SCM_I_BIG_MPZ (n), 2);
1836 if (mpz_sgn (SCM_I_BIG_MPZ (n)) < 0
1837 && mpz_scan0 (SCM_I_BIG_MPZ (n), /* no 0 bits above the lowest 1 */
1838 mpz_scan1 (SCM_I_BIG_MPZ (n), 0)) == ULONG_MAX)
1839 size--;
1840 scm_remember_upto_here_1 (n);
1841 return SCM_MAKINUM (size);
1842 }
1843 else
ca46fb90 1844 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
ca46fb90
RB
1845}
1846#undef FUNC_NAME
0f2d19dd
JB
1847
1848/*** NUMBERS -> STRINGS ***/
0f2d19dd 1849int scm_dblprec;
e4755e5c 1850static const double fx[] =
f872b822
MD
1851{ 0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5,
1852 5e-6, 5e-7, 5e-8, 5e-9, 5e-10,
1853 5e-11, 5e-12, 5e-13, 5e-14, 5e-15,
1854 5e-16, 5e-17, 5e-18, 5e-19, 5e-20};
0f2d19dd 1855
1be6b49c 1856static size_t
1bbd0b84 1857idbl2str (double f, char *a)
0f2d19dd
JB
1858{
1859 int efmt, dpt, d, i, wp = scm_dblprec;
1be6b49c 1860 size_t ch = 0;
0f2d19dd
JB
1861 int exp = 0;
1862
f872b822 1863 if (f == 0.0)
abb7e44d
MV
1864 {
1865#ifdef HAVE_COPYSIGN
1866 double sgn = copysign (1.0, f);
1867
1868 if (sgn < 0.0)
1869 a[ch++] = '-';
1870#endif
1871
1872 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
1873 }
7351e207
MV
1874
1875 if (xisinf (f))
1876 {
1877 if (f < 0)
1878 strcpy (a, "-inf.0");
1879 else
1880 strcpy (a, "+inf.0");
1881 return ch+6;
1882 }
1883 else if (xisnan (f))
1884 {
1885 strcpy (a, "+nan.0");
1886 return ch+6;
1887 }
1888
f872b822
MD
1889 if (f < 0.0)
1890 {
1891 f = -f;
1892 a[ch++] = '-';
1893 }
7351e207 1894
f872b822
MD
1895#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
1896 make-uniform-vector, from causing infinite loops. */
1897 while (f < 1.0)
1898 {
1899 f *= 10.0;
1900 if (exp-- < DBL_MIN_10_EXP)
7351e207
MV
1901 {
1902 a[ch++] = '#';
1903 a[ch++] = '.';
1904 a[ch++] = '#';
1905 return ch;
1906 }
f872b822
MD
1907 }
1908 while (f > 10.0)
1909 {
1910 f *= 0.10;
1911 if (exp++ > DBL_MAX_10_EXP)
7351e207
MV
1912 {
1913 a[ch++] = '#';
1914 a[ch++] = '.';
1915 a[ch++] = '#';
1916 return ch;
1917 }
f872b822
MD
1918 }
1919#else
1920 while (f < 1.0)
1921 {
1922 f *= 10.0;
1923 exp--;
1924 }
1925 while (f > 10.0)
1926 {
1927 f /= 10.0;
1928 exp++;
1929 }
1930#endif
1931 if (f + fx[wp] >= 10.0)
1932 {
1933 f = 1.0;
1934 exp++;
1935 }
0f2d19dd 1936 zero:
f872b822
MD
1937#ifdef ENGNOT
1938 dpt = (exp + 9999) % 3;
0f2d19dd
JB
1939 exp -= dpt++;
1940 efmt = 1;
f872b822
MD
1941#else
1942 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 1943 if (!efmt)
cda139a7
MD
1944 {
1945 if (exp < 0)
1946 {
1947 a[ch++] = '0';
1948 a[ch++] = '.';
1949 dpt = exp;
f872b822
MD
1950 while (++dpt)
1951 a[ch++] = '0';
cda139a7
MD
1952 }
1953 else
f872b822 1954 dpt = exp + 1;
cda139a7 1955 }
0f2d19dd
JB
1956 else
1957 dpt = 1;
f872b822
MD
1958#endif
1959
1960 do
1961 {
1962 d = f;
1963 f -= d;
1964 a[ch++] = d + '0';
1965 if (f < fx[wp])
1966 break;
1967 if (f + fx[wp] >= 1.0)
1968 {
1969 a[ch - 1]++;
1970 break;
1971 }
1972 f *= 10.0;
1973 if (!(--dpt))
1974 a[ch++] = '.';
0f2d19dd 1975 }
f872b822 1976 while (wp--);
0f2d19dd
JB
1977
1978 if (dpt > 0)
cda139a7 1979 {
f872b822 1980#ifndef ENGNOT
cda139a7
MD
1981 if ((dpt > 4) && (exp > 6))
1982 {
f872b822 1983 d = (a[0] == '-' ? 2 : 1);
cda139a7 1984 for (i = ch++; i > d; i--)
f872b822 1985 a[i] = a[i - 1];
cda139a7
MD
1986 a[d] = '.';
1987 efmt = 1;
1988 }
1989 else
f872b822 1990#endif
cda139a7 1991 {
f872b822
MD
1992 while (--dpt)
1993 a[ch++] = '0';
cda139a7
MD
1994 a[ch++] = '.';
1995 }
1996 }
f872b822
MD
1997 if (a[ch - 1] == '.')
1998 a[ch++] = '0'; /* trailing zero */
1999 if (efmt && exp)
2000 {
2001 a[ch++] = 'e';
2002 if (exp < 0)
2003 {
2004 exp = -exp;
2005 a[ch++] = '-';
2006 }
2007 for (i = 10; i <= exp; i *= 10);
2008 for (i /= 10; i; i /= 10)
2009 {
2010 a[ch++] = exp / i + '0';
2011 exp %= i;
2012 }
0f2d19dd 2013 }
0f2d19dd
JB
2014 return ch;
2015}
2016
1cc91f1b 2017
1be6b49c 2018static size_t
1bbd0b84 2019iflo2str (SCM flt, char *str)
0f2d19dd 2020{
1be6b49c 2021 size_t i;
3c9a524f 2022 if (SCM_REALP (flt))
f3ae5d60 2023 i = idbl2str (SCM_REAL_VALUE (flt), str);
0f2d19dd 2024 else
f872b822 2025 {
f3ae5d60
MD
2026 i = idbl2str (SCM_COMPLEX_REAL (flt), str);
2027 if (SCM_COMPLEX_IMAG (flt) != 0.0)
2028 {
7351e207
MV
2029 double imag = SCM_COMPLEX_IMAG (flt);
2030 /* Don't output a '+' for negative numbers or for Inf and
2031 NaN. They will provide their own sign. */
2032 if (0 <= imag && !xisinf (imag) && !xisnan (imag))
f3ae5d60 2033 str[i++] = '+';
7351e207 2034 i += idbl2str (imag, &str[i]);
f3ae5d60
MD
2035 str[i++] = 'i';
2036 }
f872b822 2037 }
0f2d19dd
JB
2038 return i;
2039}
0f2d19dd 2040
5c11cc9d 2041/* convert a long to a string (unterminated). returns the number of
1bbd0b84
GB
2042 characters in the result.
2043 rad is output base
2044 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 2045size_t
1bbd0b84 2046scm_iint2str (long num, int rad, char *p)
0f2d19dd 2047{
1be6b49c
ML
2048 size_t j = 1;
2049 size_t i;
5c11cc9d
GH
2050 unsigned long n = (num < 0) ? -num : num;
2051
f872b822 2052 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2053 j++;
2054
2055 i = j;
2056 if (num < 0)
f872b822 2057 {
f872b822 2058 *p++ = '-';
5c11cc9d
GH
2059 j++;
2060 n = -num;
f872b822 2061 }
5c11cc9d
GH
2062 else
2063 n = num;
f872b822
MD
2064 while (i--)
2065 {
5c11cc9d
GH
2066 int d = n % rad;
2067
f872b822
MD
2068 n /= rad;
2069 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2070 }
0f2d19dd
JB
2071 return j;
2072}
2073
a1ec6916 2074SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
2075 (SCM n, SCM radix),
2076 "Return a string holding the external representation of the\n"
942e5b91
MG
2077 "number @var{n} in the given @var{radix}. If @var{n} is\n"
2078 "inexact, a radix of 10 will be used.")
1bbd0b84 2079#define FUNC_NAME s_scm_number_to_string
0f2d19dd 2080{
1bbd0b84 2081 int base;
98cb6e75 2082
0aacf84e 2083 if (SCM_UNBNDP (radix))
98cb6e75 2084 base = 10;
0aacf84e
MD
2085 else
2086 {
2087 SCM_VALIDATE_INUM (2, radix);
2088 base = SCM_INUM (radix);
2089 /* FIXME: ask if range limit was OK, and if so, document */
2090 SCM_ASSERT_RANGE (2, radix, (base >= 2) && (base <= 36));
2091 }
98cb6e75 2092
0aacf84e
MD
2093 if (SCM_INUMP (n))
2094 {
2095 char num_buf [SCM_INTBUFLEN];
2096 size_t length = scm_iint2str (SCM_INUM (n), base, num_buf);
2097 return scm_mem2string (num_buf, length);
2098 }
2099 else if (SCM_BIGP (n))
2100 {
2101 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
2102 scm_remember_upto_here_1 (n);
2103 return scm_take0str (str);
2104 }
f92e85f7
MV
2105 else if (SCM_FRACTIONP (n))
2106 {
2107 scm_i_fraction_reduce (n);
2108 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
2109 scm_mem2string ("/", 1),
2110 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
2111 }
0aacf84e
MD
2112 else if (SCM_INEXACTP (n))
2113 {
2114 char num_buf [FLOBUFLEN];
2115 return scm_mem2string (num_buf, iflo2str (n, num_buf));
2116 }
2117 else
bb628794 2118 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 2119}
1bbd0b84 2120#undef FUNC_NAME
0f2d19dd
JB
2121
2122
ca46fb90
RB
2123/* These print routines used to be stubbed here so that scm_repl.c
2124 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 2125
0f2d19dd 2126int
e81d98ec 2127scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2128{
56e55ac7 2129 char num_buf[FLOBUFLEN];
f872b822 2130 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
0f2d19dd
JB
2131 return !0;
2132}
2133
f3ae5d60 2134int
e81d98ec 2135scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 2136
f3ae5d60 2137{
56e55ac7 2138 char num_buf[FLOBUFLEN];
f3ae5d60
MD
2139 scm_lfwrite (num_buf, iflo2str (sexp, num_buf), port);
2140 return !0;
2141}
1cc91f1b 2142
f92e85f7
MV
2143int
2144scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
2145{
2146 SCM str;
2147 scm_i_fraction_reduce (sexp);
2148 str = scm_number_to_string (sexp, SCM_UNDEFINED);
2149 scm_lfwrite (SCM_STRING_CHARS (str), SCM_STRING_LENGTH (str), port);
2150 scm_remember_upto_here_1 (str);
2151 return !0;
2152}
2153
0f2d19dd 2154int
e81d98ec 2155scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2156{
ca46fb90
RB
2157 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
2158 scm_remember_upto_here_1 (exp);
2159 scm_lfwrite (str, (size_t) strlen (str), port);
2160 free (str);
0f2d19dd
JB
2161 return !0;
2162}
2163/*** END nums->strs ***/
2164
3c9a524f 2165
0f2d19dd 2166/*** STRINGS -> NUMBERS ***/
2a8fecee 2167
3c9a524f
DH
2168/* The following functions implement the conversion from strings to numbers.
2169 * The implementation somehow follows the grammar for numbers as it is given
2170 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
2171 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
2172 * points should be noted about the implementation:
2173 * * Each function keeps a local index variable 'idx' that points at the
2174 * current position within the parsed string. The global index is only
2175 * updated if the function could parse the corresponding syntactic unit
2176 * successfully.
2177 * * Similarly, the functions keep track of indicators of inexactness ('#',
2178 * '.' or exponents) using local variables ('hash_seen', 'x'). Again, the
2179 * global exactness information is only updated after each part has been
2180 * successfully parsed.
2181 * * Sequences of digits are parsed into temporary variables holding fixnums.
2182 * Only if these fixnums would overflow, the result variables are updated
2183 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
2184 * the temporary variables holding the fixnums are cleared, and the process
2185 * starts over again. If for example fixnums were able to store five decimal
2186 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
2187 * and the result was computed as 12345 * 100000 + 67890. In other words,
2188 * only every five digits two bignum operations were performed.
2189 */
2190
2191enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
2192
2193/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
2194
2195/* In non ASCII-style encodings the following macro might not work. */
2196#define XDIGIT2UINT(d) (isdigit (d) ? (d) - '0' : tolower (d) - 'a' + 10)
2197
2a8fecee 2198static SCM
3c9a524f
DH
2199mem2uinteger (const char* mem, size_t len, unsigned int *p_idx,
2200 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 2201{
3c9a524f
DH
2202 unsigned int idx = *p_idx;
2203 unsigned int hash_seen = 0;
2204 scm_t_bits shift = 1;
2205 scm_t_bits add = 0;
2206 unsigned int digit_value;
2207 SCM result;
2208 char c;
2209
2210 if (idx == len)
2211 return SCM_BOOL_F;
2a8fecee 2212
3c9a524f
DH
2213 c = mem[idx];
2214 if (!isxdigit (c))
2215 return SCM_BOOL_F;
2216 digit_value = XDIGIT2UINT (c);
2217 if (digit_value >= radix)
2218 return SCM_BOOL_F;
2219
2220 idx++;
2221 result = SCM_MAKINUM (digit_value);
2222 while (idx != len)
f872b822 2223 {
3c9a524f
DH
2224 char c = mem[idx];
2225 if (isxdigit (c))
f872b822 2226 {
3c9a524f 2227 if (hash_seen)
1fe5e088 2228 break;
3c9a524f
DH
2229 digit_value = XDIGIT2UINT (c);
2230 if (digit_value >= radix)
1fe5e088 2231 break;
f872b822 2232 }
3c9a524f
DH
2233 else if (c == '#')
2234 {
2235 hash_seen = 1;
2236 digit_value = 0;
2237 }
2238 else
2239 break;
2240
2241 idx++;
2242 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
2243 {
2244 result = scm_product (result, SCM_MAKINUM (shift));
2245 if (add > 0)
2246 result = scm_sum (result, SCM_MAKINUM (add));
2247
2248 shift = radix;
2249 add = digit_value;
2250 }
2251 else
2252 {
2253 shift = shift * radix;
2254 add = add * radix + digit_value;
2255 }
2256 };
2257
2258 if (shift > 1)
2259 result = scm_product (result, SCM_MAKINUM (shift));
2260 if (add > 0)
2261 result = scm_sum (result, SCM_MAKINUM (add));
2262
2263 *p_idx = idx;
2264 if (hash_seen)
2265 *p_exactness = INEXACT;
2266
2267 return result;
2a8fecee
JB
2268}
2269
2270
3c9a524f
DH
2271/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
2272 * covers the parts of the rules that start at a potential point. The value
2273 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
2274 * in variable result. The content of *p_exactness indicates, whether a hash
2275 * has already been seen in the digits before the point.
3c9a524f 2276 */
1cc91f1b 2277
3c9a524f
DH
2278/* In non ASCII-style encodings the following macro might not work. */
2279#define DIGIT2UINT(d) ((d) - '0')
2280
2281static SCM
79d34f68 2282mem2decimal_from_point (SCM result, const char* mem, size_t len,
3c9a524f 2283 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 2284{
3c9a524f
DH
2285 unsigned int idx = *p_idx;
2286 enum t_exactness x = *p_exactness;
3c9a524f
DH
2287
2288 if (idx == len)
79d34f68 2289 return result;
3c9a524f
DH
2290
2291 if (mem[idx] == '.')
2292 {
2293 scm_t_bits shift = 1;
2294 scm_t_bits add = 0;
2295 unsigned int digit_value;
79d34f68 2296 SCM big_shift = SCM_MAKINUM (1);
3c9a524f
DH
2297
2298 idx++;
2299 while (idx != len)
2300 {
2301 char c = mem[idx];
2302 if (isdigit (c))
2303 {
2304 if (x == INEXACT)
2305 return SCM_BOOL_F;
2306 else
2307 digit_value = DIGIT2UINT (c);
2308 }
2309 else if (c == '#')
2310 {
2311 x = INEXACT;
2312 digit_value = 0;
2313 }
2314 else
2315 break;
2316
2317 idx++;
2318 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
2319 {
2320 big_shift = scm_product (big_shift, SCM_MAKINUM (shift));
79d34f68 2321 result = scm_product (result, SCM_MAKINUM (shift));
3c9a524f 2322 if (add > 0)
79d34f68 2323 result = scm_sum (result, SCM_MAKINUM (add));
3c9a524f
DH
2324
2325 shift = 10;
2326 add = digit_value;
2327 }
2328 else
2329 {
2330 shift = shift * 10;
2331 add = add * 10 + digit_value;
2332 }
2333 };
2334
2335 if (add > 0)
2336 {
2337 big_shift = scm_product (big_shift, SCM_MAKINUM (shift));
79d34f68
DH
2338 result = scm_product (result, SCM_MAKINUM (shift));
2339 result = scm_sum (result, SCM_MAKINUM (add));
3c9a524f
DH
2340 }
2341
d8592269 2342 result = scm_divide (result, big_shift);
79d34f68 2343
3c9a524f
DH
2344 /* We've seen a decimal point, thus the value is implicitly inexact. */
2345 x = INEXACT;
f872b822 2346 }
3c9a524f 2347
3c9a524f 2348 if (idx != len)
f872b822 2349 {
3c9a524f
DH
2350 int sign = 1;
2351 unsigned int start;
2352 char c;
2353 int exponent;
2354 SCM e;
2355
2356 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
2357
2358 switch (mem[idx])
f872b822 2359 {
3c9a524f
DH
2360 case 'd': case 'D':
2361 case 'e': case 'E':
2362 case 'f': case 'F':
2363 case 'l': case 'L':
2364 case 's': case 'S':
2365 idx++;
2366 start = idx;
2367 c = mem[idx];
2368 if (c == '-')
2369 {
2370 idx++;
2371 sign = -1;
2372 c = mem[idx];
2373 }
2374 else if (c == '+')
2375 {
2376 idx++;
2377 sign = 1;
2378 c = mem[idx];
2379 }
2380 else
2381 sign = 1;
2382
2383 if (!isdigit (c))
2384 return SCM_BOOL_F;
2385
2386 idx++;
2387 exponent = DIGIT2UINT (c);
2388 while (idx != len)
f872b822 2389 {
3c9a524f
DH
2390 char c = mem[idx];
2391 if (isdigit (c))
2392 {
2393 idx++;
2394 if (exponent <= SCM_MAXEXP)
2395 exponent = exponent * 10 + DIGIT2UINT (c);
2396 }
2397 else
2398 break;
f872b822 2399 }
3c9a524f
DH
2400
2401 if (exponent > SCM_MAXEXP)
f872b822 2402 {
3c9a524f
DH
2403 size_t exp_len = idx - start;
2404 SCM exp_string = scm_mem2string (&mem[start], exp_len);
2405 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
2406 scm_out_of_range ("string->number", exp_num);
f872b822 2407 }
3c9a524f
DH
2408
2409 e = scm_integer_expt (SCM_MAKINUM (10), SCM_MAKINUM (exponent));
2410 if (sign == 1)
2411 result = scm_product (result, e);
2412 else
f92e85f7 2413 result = scm_divide2real (result, e);
3c9a524f
DH
2414
2415 /* We've seen an exponent, thus the value is implicitly inexact. */
2416 x = INEXACT;
2417
f872b822 2418 break;
3c9a524f 2419
f872b822 2420 default:
3c9a524f 2421 break;
f872b822 2422 }
0f2d19dd 2423 }
3c9a524f
DH
2424
2425 *p_idx = idx;
2426 if (x == INEXACT)
2427 *p_exactness = x;
2428
2429 return result;
0f2d19dd 2430}
0f2d19dd 2431
3c9a524f
DH
2432
2433/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
2434
2435static SCM
2436mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
2437 unsigned int radix, enum t_exactness *p_exactness)
0f2d19dd 2438{
3c9a524f 2439 unsigned int idx = *p_idx;
164d2481 2440 SCM result;
3c9a524f
DH
2441
2442 if (idx == len)
2443 return SCM_BOOL_F;
2444
7351e207
MV
2445 if (idx+5 <= len && !strncmp (mem+idx, "inf.0", 5))
2446 {
2447 *p_idx = idx+5;
2448 return scm_inf ();
2449 }
2450
2451 if (idx+4 < len && !strncmp (mem+idx, "nan.", 4))
2452 {
2453 enum t_exactness x = EXACT;
2454
d8592269
MV
2455 /* Cobble up the fractional part. We might want to set the
2456 NaN's mantissa from it. */
7351e207
MV
2457 idx += 4;
2458 mem2uinteger (mem, len, &idx, 10, &x);
2459 *p_idx = idx;
2460 return scm_nan ();
2461 }
2462
3c9a524f
DH
2463 if (mem[idx] == '.')
2464 {
2465 if (radix != 10)
2466 return SCM_BOOL_F;
2467 else if (idx + 1 == len)
2468 return SCM_BOOL_F;
2469 else if (!isdigit (mem[idx + 1]))
2470 return SCM_BOOL_F;
2471 else
164d2481
MV
2472 result = mem2decimal_from_point (SCM_MAKINUM (0), mem, len,
2473 p_idx, p_exactness);
f872b822 2474 }
3c9a524f
DH
2475 else
2476 {
2477 enum t_exactness x = EXACT;
2478 SCM uinteger;
3c9a524f
DH
2479
2480 uinteger = mem2uinteger (mem, len, &idx, radix, &x);
2481 if (SCM_FALSEP (uinteger))
2482 return SCM_BOOL_F;
2483
2484 if (idx == len)
2485 result = uinteger;
2486 else if (mem[idx] == '/')
f872b822 2487 {
3c9a524f
DH
2488 SCM divisor;
2489
2490 idx++;
2491
2492 divisor = mem2uinteger (mem, len, &idx, radix, &x);
2493 if (SCM_FALSEP (divisor))
2494 return SCM_BOOL_F;
2495
f92e85f7
MV
2496 /* both are int/big here, I assume */
2497 result = scm_make_ratio (uinteger, divisor);
f872b822 2498 }
3c9a524f
DH
2499 else if (radix == 10)
2500 {
2501 result = mem2decimal_from_point (uinteger, mem, len, &idx, &x);
2502 if (SCM_FALSEP (result))
2503 return SCM_BOOL_F;
2504 }
2505 else
2506 result = uinteger;
2507
2508 *p_idx = idx;
2509 if (x == INEXACT)
2510 *p_exactness = x;
f872b822 2511 }
164d2481
MV
2512
2513 /* When returning an inexact zero, make sure it is represented as a
2514 floating point value so that we can change its sign.
2515 */
2516 if (SCM_EQ_P (result, SCM_MAKINUM(0)) && *p_exactness == INEXACT)
2517 result = scm_make_real (0.0);
2518
2519 return result;
3c9a524f 2520}
0f2d19dd 2521
0f2d19dd 2522
3c9a524f 2523/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 2524
3c9a524f
DH
2525static SCM
2526mem2complex (const char* mem, size_t len, unsigned int idx,
2527 unsigned int radix, enum t_exactness *p_exactness)
2528{
2529 char c;
2530 int sign = 0;
2531 SCM ureal;
2532
2533 if (idx == len)
2534 return SCM_BOOL_F;
2535
2536 c = mem[idx];
2537 if (c == '+')
2538 {
2539 idx++;
2540 sign = 1;
2541 }
2542 else if (c == '-')
2543 {
2544 idx++;
2545 sign = -1;
0f2d19dd 2546 }
0f2d19dd 2547
3c9a524f
DH
2548 if (idx == len)
2549 return SCM_BOOL_F;
2550
2551 ureal = mem2ureal (mem, len, &idx, radix, p_exactness);
2552 if (SCM_FALSEP (ureal))
f872b822 2553 {
3c9a524f
DH
2554 /* input must be either +i or -i */
2555
2556 if (sign == 0)
2557 return SCM_BOOL_F;
2558
2559 if (mem[idx] == 'i' || mem[idx] == 'I')
f872b822 2560 {
3c9a524f
DH
2561 idx++;
2562 if (idx != len)
2563 return SCM_BOOL_F;
2564
2565 return scm_make_rectangular (SCM_MAKINUM (0), SCM_MAKINUM (sign));
f872b822 2566 }
3c9a524f
DH
2567 else
2568 return SCM_BOOL_F;
0f2d19dd 2569 }
3c9a524f
DH
2570 else
2571 {
fc194577 2572 if (sign == -1 && SCM_FALSEP (scm_nan_p (ureal)))
3c9a524f 2573 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 2574
3c9a524f
DH
2575 if (idx == len)
2576 return ureal;
2577
2578 c = mem[idx];
2579 switch (c)
f872b822 2580 {
3c9a524f
DH
2581 case 'i': case 'I':
2582 /* either +<ureal>i or -<ureal>i */
2583
2584 idx++;
2585 if (sign == 0)
2586 return SCM_BOOL_F;
2587 if (idx != len)
2588 return SCM_BOOL_F;
2589 return scm_make_rectangular (SCM_MAKINUM (0), ureal);
2590
2591 case '@':
2592 /* polar input: <real>@<real>. */
2593
2594 idx++;
2595 if (idx == len)
2596 return SCM_BOOL_F;
2597 else
f872b822 2598 {
3c9a524f
DH
2599 int sign;
2600 SCM angle;
2601 SCM result;
2602
2603 c = mem[idx];
2604 if (c == '+')
2605 {
2606 idx++;
2607 sign = 1;
2608 }
2609 else if (c == '-')
2610 {
2611 idx++;
2612 sign = -1;
2613 }
2614 else
2615 sign = 1;
2616
2617 angle = mem2ureal (mem, len, &idx, radix, p_exactness);
2618 if (SCM_FALSEP (angle))
2619 return SCM_BOOL_F;
2620 if (idx != len)
2621 return SCM_BOOL_F;
2622
fc194577 2623 if (sign == -1 && SCM_FALSEP (scm_nan_p (ureal)))
3c9a524f
DH
2624 angle = scm_difference (angle, SCM_UNDEFINED);
2625
2626 result = scm_make_polar (ureal, angle);
2627 return result;
f872b822 2628 }
3c9a524f
DH
2629 case '+':
2630 case '-':
2631 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 2632
3c9a524f
DH
2633 idx++;
2634 if (idx == len)
2635 return SCM_BOOL_F;
2636 else
2637 {
2638 int sign = (c == '+') ? 1 : -1;
2639 SCM imag = mem2ureal (mem, len, &idx, radix, p_exactness);
0f2d19dd 2640
3c9a524f
DH
2641 if (SCM_FALSEP (imag))
2642 imag = SCM_MAKINUM (sign);
fc194577 2643 else if (sign == -1 && SCM_FALSEP (scm_nan_p (ureal)))
1fe5e088 2644 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 2645
3c9a524f
DH
2646 if (idx == len)
2647 return SCM_BOOL_F;
2648 if (mem[idx] != 'i' && mem[idx] != 'I')
2649 return SCM_BOOL_F;
0f2d19dd 2650
3c9a524f
DH
2651 idx++;
2652 if (idx != len)
2653 return SCM_BOOL_F;
0f2d19dd 2654
1fe5e088 2655 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
2656 }
2657 default:
2658 return SCM_BOOL_F;
2659 }
2660 }
0f2d19dd 2661}
0f2d19dd
JB
2662
2663
3c9a524f
DH
2664/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
2665
2666enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 2667
0f2d19dd 2668SCM
3c9a524f 2669scm_i_mem2number (const char* mem, size_t len, unsigned int default_radix)
0f2d19dd 2670{
3c9a524f
DH
2671 unsigned int idx = 0;
2672 unsigned int radix = NO_RADIX;
2673 enum t_exactness forced_x = NO_EXACTNESS;
2674 enum t_exactness implicit_x = EXACT;
2675 SCM result;
2676
2677 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
2678 while (idx + 2 < len && mem[idx] == '#')
2679 {
2680 switch (mem[idx + 1])
2681 {
2682 case 'b': case 'B':
2683 if (radix != NO_RADIX)
2684 return SCM_BOOL_F;
2685 radix = DUAL;
2686 break;
2687 case 'd': case 'D':
2688 if (radix != NO_RADIX)
2689 return SCM_BOOL_F;
2690 radix = DEC;
2691 break;
2692 case 'i': case 'I':
2693 if (forced_x != NO_EXACTNESS)
2694 return SCM_BOOL_F;
2695 forced_x = INEXACT;
2696 break;
2697 case 'e': case 'E':
2698 if (forced_x != NO_EXACTNESS)
2699 return SCM_BOOL_F;
2700 forced_x = EXACT;
2701 break;
2702 case 'o': case 'O':
2703 if (radix != NO_RADIX)
2704 return SCM_BOOL_F;
2705 radix = OCT;
2706 break;
2707 case 'x': case 'X':
2708 if (radix != NO_RADIX)
2709 return SCM_BOOL_F;
2710 radix = HEX;
2711 break;
2712 default:
f872b822 2713 return SCM_BOOL_F;
3c9a524f
DH
2714 }
2715 idx += 2;
2716 }
2717
2718 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
2719 if (radix == NO_RADIX)
2720 result = mem2complex (mem, len, idx, default_radix, &implicit_x);
2721 else
2722 result = mem2complex (mem, len, idx, (unsigned int) radix, &implicit_x);
2723
2724 if (SCM_FALSEP (result))
2725 return SCM_BOOL_F;
f872b822 2726
3c9a524f 2727 switch (forced_x)
f872b822 2728 {
3c9a524f
DH
2729 case EXACT:
2730 if (SCM_INEXACTP (result))
3c9a524f
DH
2731 return scm_inexact_to_exact (result);
2732 else
2733 return result;
2734 case INEXACT:
2735 if (SCM_INEXACTP (result))
2736 return result;
2737 else
2738 return scm_exact_to_inexact (result);
2739 case NO_EXACTNESS:
2740 default:
2741 if (implicit_x == INEXACT)
2742 {
2743 if (SCM_INEXACTP (result))
2744 return result;
2745 else
2746 return scm_exact_to_inexact (result);
2747 }
2748 else
2749 return result;
f872b822 2750 }
0f2d19dd
JB
2751}
2752
2753
a1ec6916 2754SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 2755 (SCM string, SCM radix),
1e6808ea 2756 "Return a number of the maximally precise representation\n"
942e5b91 2757 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
2758 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
2759 "is a default radix that may be overridden by an explicit radix\n"
2760 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
2761 "supplied, then the default radix is 10. If string is not a\n"
2762 "syntactically valid notation for a number, then\n"
2763 "@code{string->number} returns @code{#f}.")
1bbd0b84 2764#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2765{
2766 SCM answer;
1bbd0b84 2767 int base;
a6d9e5ab 2768 SCM_VALIDATE_STRING (1, string);
34d19ef6 2769 SCM_VALIDATE_INUM_MIN_DEF_COPY (2, radix,2,10, base);
3c9a524f 2770 answer = scm_i_mem2number (SCM_STRING_CHARS (string),
d8592269
MV
2771 SCM_STRING_LENGTH (string),
2772 base);
bb628794 2773 return scm_return_first (answer, string);
0f2d19dd 2774}
1bbd0b84 2775#undef FUNC_NAME
3c9a524f
DH
2776
2777
0f2d19dd
JB
2778/*** END strs->nums ***/
2779
5986c47d 2780
0f2d19dd 2781SCM
f3ae5d60 2782scm_make_real (double x)
0f2d19dd 2783{
3553e1d1
GH
2784 SCM z = scm_double_cell (scm_tc16_real, 0, 0, 0);
2785
3a9809df 2786 SCM_REAL_VALUE (z) = x;
0f2d19dd
JB
2787 return z;
2788}
0f2d19dd 2789
5986c47d 2790
f3ae5d60
MD
2791SCM
2792scm_make_complex (double x, double y)
2793{
0aacf84e 2794 if (y == 0.0)
3a9809df 2795 return scm_make_real (x);
0aacf84e
MD
2796 else
2797 {
2798 SCM z;
29c4382a 2799 SCM_NEWSMOB (z, scm_tc16_complex, scm_gc_malloc (sizeof (scm_t_complex),
0aacf84e
MD
2800 "complex"));
2801 SCM_COMPLEX_REAL (z) = x;
2802 SCM_COMPLEX_IMAG (z) = y;
2803 return z;
2804 }
f3ae5d60 2805}
1cc91f1b 2806
5986c47d 2807
0f2d19dd 2808SCM
1bbd0b84 2809scm_bigequal (SCM x, SCM y)
0f2d19dd 2810{
47ae1f0e 2811 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
ca46fb90
RB
2812 scm_remember_upto_here_2 (x, y);
2813 return SCM_BOOL (0 == result);
0f2d19dd
JB
2814}
2815
0f2d19dd 2816SCM
f3ae5d60 2817scm_real_equalp (SCM x, SCM y)
0f2d19dd 2818{
f3ae5d60 2819 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
2820}
2821
f3ae5d60
MD
2822SCM
2823scm_complex_equalp (SCM x, SCM y)
2824{
2825 return SCM_BOOL (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
2826 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
2827}
0f2d19dd 2828
f92e85f7
MV
2829SCM
2830scm_i_fraction_equalp (SCM x, SCM y)
2831{
2832 scm_i_fraction_reduce (x);
2833 scm_i_fraction_reduce (y);
02164269
MV
2834 if (SCM_FALSEP (scm_equal_p (SCM_FRACTION_NUMERATOR (x),
2835 SCM_FRACTION_NUMERATOR (y)))
2836 || SCM_FALSEP (scm_equal_p (SCM_FRACTION_DENOMINATOR (x),
2837 SCM_FRACTION_DENOMINATOR (y))))
2838 return SCM_BOOL_F;
2839 else
2840 return SCM_BOOL_T;
f92e85f7 2841}
0f2d19dd
JB
2842
2843
1bbd0b84 2844SCM_REGISTER_PROC (s_number_p, "number?", 1, 0, 0, scm_number_p);
942e5b91
MG
2845/* "Return @code{#t} if @var{x} is a number, @code{#f}\n"
2846 * "else. Note that the sets of complex, real, rational and\n"
2847 * "integer values form subsets of the set of numbers, i. e. the\n"
2848 * "predicate will be fulfilled for any number."
2849 */
a1ec6916 2850SCM_DEFINE (scm_number_p, "complex?", 1, 0, 0,
1bbd0b84 2851 (SCM x),
942e5b91 2852 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 2853 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
2854 "values form subsets of the set of complex numbers, i. e. the\n"
2855 "predicate will also be fulfilled if @var{x} is a real,\n"
2856 "rational or integer number.")
1bbd0b84 2857#define FUNC_NAME s_scm_number_p
0f2d19dd 2858{
bb628794 2859 return SCM_BOOL (SCM_NUMBERP (x));
0f2d19dd 2860}
1bbd0b84 2861#undef FUNC_NAME
0f2d19dd
JB
2862
2863
f92e85f7
MV
2864SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
2865 (SCM x),
2866 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
2867 "otherwise. Note that the set of integer values forms a subset of\n"
2868 "the set of real numbers, i. e. the predicate will also be\n"
2869 "fulfilled if @var{x} is an integer number.")
2870#define FUNC_NAME s_scm_real_p
2871{
2872 /* we can't represent irrational numbers. */
2873 return scm_rational_p (x);
2874}
2875#undef FUNC_NAME
2876
2877SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 2878 (SCM x),
942e5b91 2879 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 2880 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 2881 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
2882 "fulfilled if @var{x} is an integer number.")
2883#define FUNC_NAME s_scm_rational_p
0f2d19dd 2884{
0aacf84e 2885 if (SCM_INUMP (x))
0f2d19dd 2886 return SCM_BOOL_T;
0aacf84e 2887 else if (SCM_IMP (x))
0f2d19dd 2888 return SCM_BOOL_F;
0aacf84e 2889 else if (SCM_BIGP (x))
0f2d19dd 2890 return SCM_BOOL_T;
f92e85f7
MV
2891 else if (SCM_FRACTIONP (x))
2892 return SCM_BOOL_T;
2893 else if (SCM_REALP (x))
2894 /* due to their limited precision, all floating point numbers are
2895 rational as well. */
2896 return SCM_BOOL_T;
0aacf84e 2897 else
bb628794 2898 return SCM_BOOL_F;
0f2d19dd 2899}
1bbd0b84 2900#undef FUNC_NAME
0f2d19dd
JB
2901
2902
a1ec6916 2903SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 2904 (SCM x),
942e5b91
MG
2905 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
2906 "else.")
1bbd0b84 2907#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
2908{
2909 double r;
f872b822
MD
2910 if (SCM_INUMP (x))
2911 return SCM_BOOL_T;
2912 if (SCM_IMP (x))
2913 return SCM_BOOL_F;
f872b822
MD
2914 if (SCM_BIGP (x))
2915 return SCM_BOOL_T;
3c9a524f 2916 if (!SCM_INEXACTP (x))
f872b822 2917 return SCM_BOOL_F;
3c9a524f 2918 if (SCM_COMPLEXP (x))
f872b822 2919 return SCM_BOOL_F;
5986c47d 2920 r = SCM_REAL_VALUE (x);
f872b822
MD
2921 if (r == floor (r))
2922 return SCM_BOOL_T;
0f2d19dd
JB
2923 return SCM_BOOL_F;
2924}
1bbd0b84 2925#undef FUNC_NAME
0f2d19dd
JB
2926
2927
a1ec6916 2928SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 2929 (SCM x),
942e5b91
MG
2930 "Return @code{#t} if @var{x} is an inexact number, @code{#f}\n"
2931 "else.")
1bbd0b84 2932#define FUNC_NAME s_scm_inexact_p
0f2d19dd 2933{
eb927cb9
MV
2934 if (SCM_INEXACTP (x))
2935 return SCM_BOOL_T;
2936 if (SCM_NUMBERP (x))
2937 return SCM_BOOL_F;
2938 SCM_WRONG_TYPE_ARG (1, x);
0f2d19dd 2939}
1bbd0b84 2940#undef FUNC_NAME
0f2d19dd
JB
2941
2942
152f82bf 2943SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
942e5b91 2944/* "Return @code{#t} if all parameters are numerically equal." */
0f2d19dd 2945SCM
6e8d25a6 2946scm_num_eq_p (SCM x, SCM y)
0f2d19dd 2947{
d8b95e27 2948 again:
0aacf84e
MD
2949 if (SCM_INUMP (x))
2950 {
2951 long xx = SCM_INUM (x);
2952 if (SCM_INUMP (y))
2953 {
2954 long yy = SCM_INUM (y);
2955 return SCM_BOOL (xx == yy);
2956 }
2957 else if (SCM_BIGP (y))
2958 return SCM_BOOL_F;
2959 else if (SCM_REALP (y))
2960 return SCM_BOOL ((double) xx == SCM_REAL_VALUE (y));
2961 else if (SCM_COMPLEXP (y))
2962 return SCM_BOOL (((double) xx == SCM_COMPLEX_REAL (y))
2963 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
2964 else if (SCM_FRACTIONP (y))
2965 return SCM_BOOL_F;
0aacf84e
MD
2966 else
2967 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 2968 }
0aacf84e
MD
2969 else if (SCM_BIGP (x))
2970 {
2971 if (SCM_INUMP (y))
2972 return SCM_BOOL_F;
2973 else if (SCM_BIGP (y))
2974 {
2975 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2976 scm_remember_upto_here_2 (x, y);
2977 return SCM_BOOL (0 == cmp);
2978 }
2979 else if (SCM_REALP (y))
2980 {
2981 int cmp;
2982 if (xisnan (SCM_REAL_VALUE (y)))
2983 return SCM_BOOL_F;
2984 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
2985 scm_remember_upto_here_1 (x);
2986 return SCM_BOOL (0 == cmp);
2987 }
2988 else if (SCM_COMPLEXP (y))
2989 {
2990 int cmp;
2991 if (0.0 != SCM_COMPLEX_IMAG (y))
2992 return SCM_BOOL_F;
2993 if (xisnan (SCM_COMPLEX_REAL (y)))
2994 return SCM_BOOL_F;
2995 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
2996 scm_remember_upto_here_1 (x);
2997 return SCM_BOOL (0 == cmp);
2998 }
f92e85f7
MV
2999 else if (SCM_FRACTIONP (y))
3000 return SCM_BOOL_F;
0aacf84e
MD
3001 else
3002 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f4c627b3 3003 }
0aacf84e
MD
3004 else if (SCM_REALP (x))
3005 {
3006 if (SCM_INUMP (y))
3007 return SCM_BOOL (SCM_REAL_VALUE (x) == (double) SCM_INUM (y));
3008 else if (SCM_BIGP (y))
3009 {
3010 int cmp;
3011 if (xisnan (SCM_REAL_VALUE (x)))
3012 return SCM_BOOL_F;
3013 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
3014 scm_remember_upto_here_1 (y);
3015 return SCM_BOOL (0 == cmp);
3016 }
3017 else if (SCM_REALP (y))
3018 return SCM_BOOL (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
3019 else if (SCM_COMPLEXP (y))
3020 return SCM_BOOL ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
3021 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 3022 else if (SCM_FRACTIONP (y))
d8b95e27
KR
3023 {
3024 double xx = SCM_REAL_VALUE (x);
3025 if (xisnan (xx))
3026 return SCM_BOOL_F;
3027 if (xisinf (xx))
3028 return SCM_BOOL (xx < 0.0);
3029 x = scm_inexact_to_exact (x); /* with x as frac or int */
3030 goto again;
3031 }
0aacf84e
MD
3032 else
3033 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3034 }
0aacf84e
MD
3035 else if (SCM_COMPLEXP (x))
3036 {
3037 if (SCM_INUMP (y))
3038 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == (double) SCM_INUM (y))
3039 && (SCM_COMPLEX_IMAG (x) == 0.0));
3040 else if (SCM_BIGP (y))
3041 {
3042 int cmp;
3043 if (0.0 != SCM_COMPLEX_IMAG (x))
3044 return SCM_BOOL_F;
3045 if (xisnan (SCM_COMPLEX_REAL (x)))
3046 return SCM_BOOL_F;
3047 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
3048 scm_remember_upto_here_1 (y);
3049 return SCM_BOOL (0 == cmp);
3050 }
3051 else if (SCM_REALP (y))
3052 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
3053 && (SCM_COMPLEX_IMAG (x) == 0.0));
3054 else if (SCM_COMPLEXP (y))
3055 return SCM_BOOL ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
3056 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 3057 else if (SCM_FRACTIONP (y))
d8b95e27
KR
3058 {
3059 double xx;
3060 if (SCM_COMPLEX_IMAG (x) != 0.0)
3061 return SCM_BOOL_F;
3062 xx = SCM_COMPLEX_REAL (x);
3063 if (xisnan (xx))
3064 return SCM_BOOL_F;
3065 if (xisinf (xx))
3066 return SCM_BOOL (xx < 0.0);
3067 x = scm_inexact_to_exact (x); /* with x as frac or int */
3068 goto again;
3069 }
f92e85f7
MV
3070 else
3071 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3072 }
3073 else if (SCM_FRACTIONP (x))
3074 {
3075 if (SCM_INUMP (y))
3076 return SCM_BOOL_F;
3077 else if (SCM_BIGP (y))
3078 return SCM_BOOL_F;
3079 else if (SCM_REALP (y))
d8b95e27
KR
3080 {
3081 double yy = SCM_REAL_VALUE (y);
3082 if (xisnan (yy))
3083 return SCM_BOOL_F;
3084 if (xisinf (yy))
3085 return SCM_BOOL (0.0 < yy);
3086 y = scm_inexact_to_exact (y); /* with y as frac or int */
3087 goto again;
3088 }
f92e85f7 3089 else if (SCM_COMPLEXP (y))
d8b95e27
KR
3090 {
3091 double yy;
3092 if (SCM_COMPLEX_IMAG (y) != 0.0)
3093 return SCM_BOOL_F;
3094 yy = SCM_COMPLEX_REAL (y);
3095 if (xisnan (yy))
3096 return SCM_BOOL_F;
3097 if (xisinf (yy))
3098 return SCM_BOOL (0.0 < yy);
3099 y = scm_inexact_to_exact (y); /* with y as frac or int */
3100 goto again;
3101 }
f92e85f7
MV
3102 else if (SCM_FRACTIONP (y))
3103 return scm_i_fraction_equalp (x, y);
0aacf84e
MD
3104 else
3105 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f4c627b3 3106 }
0aacf84e 3107 else
f4c627b3 3108 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
0f2d19dd
JB
3109}
3110
3111
a5f0b599
KR
3112/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
3113 done are good for inums, but for bignums an answer can almost always be
3114 had by just examining a few high bits of the operands, as done by GMP in
3115 mpq_cmp. flonum/frac compares likewise, but with the slight complication
3116 of the float exponent to take into account. */
3117
152f82bf 3118SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
942e5b91
MG
3119/* "Return @code{#t} if the list of parameters is monotonically\n"
3120 * "increasing."
3121 */
0f2d19dd 3122SCM
6e8d25a6 3123scm_less_p (SCM x, SCM y)
0f2d19dd 3124{
a5f0b599 3125 again:
0aacf84e
MD
3126 if (SCM_INUMP (x))
3127 {
3128 long xx = SCM_INUM (x);
3129 if (SCM_INUMP (y))
3130 {
3131 long yy = SCM_INUM (y);
3132 return SCM_BOOL (xx < yy);
3133 }
3134 else if (SCM_BIGP (y))
3135 {
3136 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3137 scm_remember_upto_here_1 (y);
3138 return SCM_BOOL (sgn > 0);
3139 }
3140 else if (SCM_REALP (y))
3141 return SCM_BOOL ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 3142 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3143 {
3144 /* "x < a/b" becomes "x*b < a" */
3145 int_frac:
3146 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
3147 y = SCM_FRACTION_NUMERATOR (y);
3148 goto again;
3149 }
0aacf84e
MD
3150 else
3151 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3152 }
0aacf84e
MD
3153 else if (SCM_BIGP (x))
3154 {
3155 if (SCM_INUMP (y))
3156 {
3157 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3158 scm_remember_upto_here_1 (x);
3159 return SCM_BOOL (sgn < 0);
3160 }
3161 else if (SCM_BIGP (y))
3162 {
3163 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3164 scm_remember_upto_here_2 (x, y);
3165 return SCM_BOOL (cmp < 0);
3166 }
3167 else if (SCM_REALP (y))
3168 {
3169 int cmp;
3170 if (xisnan (SCM_REAL_VALUE (y)))
3171 return SCM_BOOL_F;
3172 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
3173 scm_remember_upto_here_1 (x);
3174 return SCM_BOOL (cmp < 0);
3175 }
f92e85f7 3176 else if (SCM_FRACTIONP (y))
a5f0b599 3177 goto int_frac;
0aacf84e
MD
3178 else
3179 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f4c627b3 3180 }
0aacf84e
MD
3181 else if (SCM_REALP (x))
3182 {
3183 if (SCM_INUMP (y))
3184 return SCM_BOOL (SCM_REAL_VALUE (x) < (double) SCM_INUM (y));
3185 else if (SCM_BIGP (y))
3186 {
3187 int cmp;
3188 if (xisnan (SCM_REAL_VALUE (x)))
3189 return SCM_BOOL_F;
3190 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
3191 scm_remember_upto_here_1 (y);
3192 return SCM_BOOL (cmp > 0);
3193 }
3194 else if (SCM_REALP (y))
3195 return SCM_BOOL (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 3196 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3197 {
3198 double xx = SCM_REAL_VALUE (x);
3199 if (xisnan (xx))
3200 return SCM_BOOL_F;
3201 if (xisinf (xx))
3202 return SCM_BOOL (xx < 0.0);
3203 x = scm_inexact_to_exact (x); /* with x as frac or int */
3204 goto again;
3205 }
f92e85f7
MV
3206 else
3207 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3208 }
3209 else if (SCM_FRACTIONP (x))
3210 {
a5f0b599
KR
3211 if (SCM_INUMP (y) || SCM_BIGP (y))
3212 {
3213 /* "a/b < y" becomes "a < y*b" */
3214 y = scm_product (y, SCM_FRACTION_DENOMINATOR (x));
3215 x = SCM_FRACTION_NUMERATOR (x);
3216 goto again;
3217 }
f92e85f7 3218 else if (SCM_REALP (y))
a5f0b599
KR
3219 {
3220 double yy = SCM_REAL_VALUE (y);
3221 if (xisnan (yy))
3222 return SCM_BOOL_F;
3223 if (xisinf (yy))
3224 return SCM_BOOL (0.0 < yy);
3225 y = scm_inexact_to_exact (y); /* with y as frac or int */
3226 goto again;
3227 }
f92e85f7 3228 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3229 {
3230 /* "a/b < c/d" becomes "a*d < c*b" */
3231 SCM new_x = scm_product (SCM_FRACTION_NUMERATOR (x),
3232 SCM_FRACTION_DENOMINATOR (y));
3233 SCM new_y = scm_product (SCM_FRACTION_NUMERATOR (y),
3234 SCM_FRACTION_DENOMINATOR (x));
3235 x = new_x;
3236 y = new_y;
3237 goto again;
3238 }
0aacf84e
MD
3239 else
3240 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3241 }
0aacf84e 3242 else
f4c627b3 3243 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
0f2d19dd
JB
3244}
3245
3246
c76b1eaf 3247SCM_GPROC1 (s_scm_gr_p, ">", scm_tc7_rpsubr, scm_gr_p, g_gr_p);
942e5b91
MG
3248/* "Return @code{#t} if the list of parameters is monotonically\n"
3249 * "decreasing."
c76b1eaf 3250 */
1bbd0b84 3251#define FUNC_NAME s_scm_gr_p
c76b1eaf
MD
3252SCM
3253scm_gr_p (SCM x, SCM y)
0f2d19dd 3254{
c76b1eaf
MD
3255 if (!SCM_NUMBERP (x))
3256 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG1, FUNC_NAME);
3257 else if (!SCM_NUMBERP (y))
3258 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG2, FUNC_NAME);
3259 else
3260 return scm_less_p (y, x);
0f2d19dd 3261}
1bbd0b84 3262#undef FUNC_NAME
0f2d19dd
JB
3263
3264
c76b1eaf 3265SCM_GPROC1 (s_scm_leq_p, "<=", scm_tc7_rpsubr, scm_leq_p, g_leq_p);
942e5b91 3266/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3267 * "non-decreasing."
3268 */
1bbd0b84 3269#define FUNC_NAME s_scm_leq_p
c76b1eaf
MD
3270SCM
3271scm_leq_p (SCM x, SCM y)
0f2d19dd 3272{
c76b1eaf
MD
3273 if (!SCM_NUMBERP (x))
3274 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG1, FUNC_NAME);
3275 else if (!SCM_NUMBERP (y))
3276 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG2, FUNC_NAME);
fc194577
MV
3277 else if (SCM_NFALSEP (scm_nan_p (x)) || SCM_NFALSEP (scm_nan_p (y)))
3278 return SCM_BOOL_F;
c76b1eaf
MD
3279 else
3280 return SCM_BOOL_NOT (scm_less_p (y, x));
0f2d19dd 3281}
1bbd0b84 3282#undef FUNC_NAME
0f2d19dd
JB
3283
3284
c76b1eaf 3285SCM_GPROC1 (s_scm_geq_p, ">=", scm_tc7_rpsubr, scm_geq_p, g_geq_p);
942e5b91 3286/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3287 * "non-increasing."
3288 */
1bbd0b84 3289#define FUNC_NAME s_scm_geq_p
c76b1eaf
MD
3290SCM
3291scm_geq_p (SCM x, SCM y)
0f2d19dd 3292{
c76b1eaf
MD
3293 if (!SCM_NUMBERP (x))
3294 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG1, FUNC_NAME);
3295 else if (!SCM_NUMBERP (y))
3296 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG2, FUNC_NAME);
fc194577
MV
3297 else if (SCM_NFALSEP (scm_nan_p (x)) || SCM_NFALSEP (scm_nan_p (y)))
3298 return SCM_BOOL_F;
c76b1eaf 3299 else
fc194577 3300 return SCM_BOOL_NOT (scm_less_p (x, y));
0f2d19dd 3301}
1bbd0b84 3302#undef FUNC_NAME
0f2d19dd
JB
3303
3304
152f82bf 3305SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
942e5b91
MG
3306/* "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
3307 * "zero."
3308 */
0f2d19dd 3309SCM
6e8d25a6 3310scm_zero_p (SCM z)
0f2d19dd 3311{
0aacf84e 3312 if (SCM_INUMP (z))
c2ff8ab0 3313 return SCM_BOOL (SCM_EQ_P (z, SCM_INUM0));
0aacf84e 3314 else if (SCM_BIGP (z))
c2ff8ab0 3315 return SCM_BOOL_F;
0aacf84e 3316 else if (SCM_REALP (z))
c2ff8ab0 3317 return SCM_BOOL (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 3318 else if (SCM_COMPLEXP (z))
c2ff8ab0
DH
3319 return SCM_BOOL (SCM_COMPLEX_REAL (z) == 0.0
3320 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
3321 else if (SCM_FRACTIONP (z))
3322 return SCM_BOOL_F;
0aacf84e 3323 else
c2ff8ab0 3324 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
0f2d19dd
JB
3325}
3326
3327
152f82bf 3328SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
942e5b91
MG
3329/* "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
3330 * "zero."
3331 */
0f2d19dd 3332SCM
6e8d25a6 3333scm_positive_p (SCM x)
0f2d19dd 3334{
0aacf84e 3335 if (SCM_INUMP (x))
c2ff8ab0 3336 return SCM_BOOL (SCM_INUM (x) > 0);
0aacf84e
MD
3337 else if (SCM_BIGP (x))
3338 {
3339 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3340 scm_remember_upto_here_1 (x);
3341 return SCM_BOOL (sgn > 0);
3342 }
3343 else if (SCM_REALP (x))
c2ff8ab0 3344 return SCM_BOOL(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
3345 else if (SCM_FRACTIONP (x))
3346 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 3347 else
c2ff8ab0 3348 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
0f2d19dd
JB
3349}
3350
3351
152f82bf 3352SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
942e5b91
MG
3353/* "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
3354 * "zero."
3355 */
0f2d19dd 3356SCM
6e8d25a6 3357scm_negative_p (SCM x)
0f2d19dd 3358{
0aacf84e 3359 if (SCM_INUMP (x))
c2ff8ab0 3360 return SCM_BOOL (SCM_INUM (x) < 0);
0aacf84e
MD
3361 else if (SCM_BIGP (x))
3362 {
3363 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3364 scm_remember_upto_here_1 (x);
3365 return SCM_BOOL (sgn < 0);
3366 }
3367 else if (SCM_REALP (x))
c2ff8ab0 3368 return SCM_BOOL(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
3369 else if (SCM_FRACTIONP (x))
3370 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 3371 else
c2ff8ab0 3372 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
0f2d19dd
JB
3373}
3374
3375
9de33deb 3376SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
942e5b91
MG
3377/* "Return the maximum of all parameter values."
3378 */
0f2d19dd 3379SCM
6e8d25a6 3380scm_max (SCM x, SCM y)
0f2d19dd 3381{
0aacf84e
MD
3382 if (SCM_UNBNDP (y))
3383 {
3384 if (SCM_UNBNDP (x))
3385 SCM_WTA_DISPATCH_0 (g_max, s_max);
dab4e67a 3386 else if (SCM_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
3387 return x;
3388 else
3389 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3390 }
f4c627b3 3391
0aacf84e
MD
3392 if (SCM_INUMP (x))
3393 {
3394 long xx = SCM_INUM (x);
3395 if (SCM_INUMP (y))
3396 {
3397 long yy = SCM_INUM (y);
3398 return (xx < yy) ? y : x;
3399 }
3400 else if (SCM_BIGP (y))
3401 {
3402 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3403 scm_remember_upto_here_1 (y);
3404 return (sgn < 0) ? x : y;
3405 }
3406 else if (SCM_REALP (y))
3407 {
3408 double z = xx;
3409 /* if y==NaN then ">" is false and we return NaN */
3410 return (z > SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3411 }
f92e85f7
MV
3412 else if (SCM_FRACTIONP (y))
3413 {
3414 double z = xx;
3415 return (z > scm_i_fraction2double (y)) ? x : y;
3416 }
0aacf84e
MD
3417 else
3418 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3419 }
0aacf84e
MD
3420 else if (SCM_BIGP (x))
3421 {
3422 if (SCM_INUMP (y))
3423 {
3424 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3425 scm_remember_upto_here_1 (x);
3426 return (sgn < 0) ? y : x;
3427 }
3428 else if (SCM_BIGP (y))
3429 {
3430 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3431 scm_remember_upto_here_2 (x, y);
3432 return (cmp > 0) ? x : y;
3433 }
3434 else if (SCM_REALP (y))
3435 {
3436 double yy = SCM_REAL_VALUE (y);
3437 int cmp;
3438 if (xisnan (yy))
3439 return y;
3440 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), yy);
3441 scm_remember_upto_here_1 (x);
3442 return (cmp > 0) ? x : y;
3443 }
f92e85f7
MV
3444 else if (SCM_FRACTIONP (y))
3445 {
3446 double yy = scm_i_fraction2double (y);
3447 int cmp;
3448 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), yy);
3449 scm_remember_upto_here_1 (x);
3450 return (cmp > 0) ? x : y;
3451 }
0aacf84e
MD
3452 else
3453 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 3454 }
0aacf84e
MD
3455 else if (SCM_REALP (x))
3456 {
3457 if (SCM_INUMP (y))
3458 {
3459 double z = SCM_INUM (y);
3460 /* if x==NaN then "<" is false and we return NaN */
3461 return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
3462 }
3463 else if (SCM_BIGP (y))
3464 {
3465 double xx = SCM_REAL_VALUE (x);
3466 int cmp;
3467 if (xisnan (xx))
3468 return x;
3469 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), xx);
3470 scm_remember_upto_here_1 (y);
3471 return (cmp < 0) ? x : y;
3472 }
3473 else if (SCM_REALP (y))
3474 {
3475 /* if x==NaN then our explicit check means we return NaN
3476 if y==NaN then ">" is false and we return NaN
3477 calling isnan is unavoidable, since it's the only way to know
3478 which of x or y causes any compares to be false */
3479 double xx = SCM_REAL_VALUE (x);
3480 return (xisnan (xx) || xx > SCM_REAL_VALUE (y)) ? x : y;
3481 }
f92e85f7
MV
3482 else if (SCM_FRACTIONP (y))
3483 {
3484 double yy = scm_i_fraction2double (y);
3485 double xx = SCM_REAL_VALUE (x);
3486 return (xx < yy) ? scm_make_real (yy) : x;
3487 }
3488 else
3489 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3490 }
3491 else if (SCM_FRACTIONP (x))
3492 {
3493 if (SCM_INUMP (y))
3494 {
3495 double z = SCM_INUM (y);
3496 return (scm_i_fraction2double (x) < z) ? y : x;
3497 }
3498 else if (SCM_BIGP (y))
3499 {
3500 double xx = scm_i_fraction2double (x);
3501 int cmp;
3502 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), xx);
3503 scm_remember_upto_here_1 (y);
3504 return (cmp < 0) ? x : y;
3505 }
3506 else if (SCM_REALP (y))
3507 {
3508 double xx = scm_i_fraction2double (x);
3509 return (xx < SCM_REAL_VALUE (y)) ? y : scm_make_real (xx);
3510 }
3511 else if (SCM_FRACTIONP (y))
3512 {
3513 double yy = scm_i_fraction2double (y);
3514 double xx = scm_i_fraction2double (x);
3515 return (xx < yy) ? y : x;
3516 }
0aacf84e
MD
3517 else
3518 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3519 }
0aacf84e 3520 else
f4c627b3 3521 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
3522}
3523
3524
9de33deb 3525SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
942e5b91
MG
3526/* "Return the minium of all parameter values."
3527 */
0f2d19dd 3528SCM
6e8d25a6 3529scm_min (SCM x, SCM y)
0f2d19dd 3530{
0aacf84e
MD
3531 if (SCM_UNBNDP (y))
3532 {
3533 if (SCM_UNBNDP (x))
3534 SCM_WTA_DISPATCH_0 (g_min, s_min);
dab4e67a 3535 else if (SCM_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
3536 return x;
3537 else
3538 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3539 }
f4c627b3 3540
0aacf84e
MD
3541 if (SCM_INUMP (x))
3542 {
3543 long xx = SCM_INUM (x);
3544 if (SCM_INUMP (y))
3545 {
3546 long yy = SCM_INUM (y);
3547 return (xx < yy) ? x : y;
3548 }
3549 else if (SCM_BIGP (y))
3550 {
3551 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3552 scm_remember_upto_here_1 (y);
3553 return (sgn < 0) ? y : x;
3554 }
3555 else if (SCM_REALP (y))
3556 {
3557 double z = xx;
3558 /* if y==NaN then "<" is false and we return NaN */
3559 return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
3560 }
f92e85f7
MV
3561 else if (SCM_FRACTIONP (y))
3562 {
3563 double z = xx;
3564 return (z < scm_i_fraction2double (y)) ? x : y;
3565 }
0aacf84e
MD
3566 else
3567 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3568 }
0aacf84e
MD
3569 else if (SCM_BIGP (x))
3570 {
3571 if (SCM_INUMP (y))
3572 {
3573 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3574 scm_remember_upto_here_1 (x);
3575 return (sgn < 0) ? x : y;
3576 }
3577 else if (SCM_BIGP (y))
3578 {
3579 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3580 scm_remember_upto_here_2 (x, y);
3581 return (cmp > 0) ? y : x;
3582 }
3583 else if (SCM_REALP (y))
3584 {
3585 double yy = SCM_REAL_VALUE (y);
3586 int cmp;
3587 if (xisnan (yy))
3588 return y;
3589 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), yy);
3590 scm_remember_upto_here_1 (x);
3591 return (cmp > 0) ? y : x;
3592 }
f92e85f7
MV
3593 else if (SCM_FRACTIONP (y))
3594 {
3595 double yy = scm_i_fraction2double (y);
3596 int cmp;
3597 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), yy);
3598 scm_remember_upto_here_1 (x);
3599 return (cmp > 0) ? y : x;
3600 }
0aacf84e
MD
3601 else
3602 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 3603 }
0aacf84e
MD
3604 else if (SCM_REALP (x))
3605 {
3606 if (SCM_INUMP (y))
3607 {
3608 double z = SCM_INUM (y);
3609 /* if x==NaN then "<" is false and we return NaN */
3610 return (z < SCM_REAL_VALUE (x)) ? scm_make_real (z) : x;
3611 }
3612 else if (SCM_BIGP (y))
3613 {
3614 double xx = SCM_REAL_VALUE (x);
3615 int cmp;
3616 if (xisnan (xx))
3617 return x;
3618 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), xx);
3619 scm_remember_upto_here_1 (y);
3620 return (cmp < 0) ? y : x;
3621 }
3622 else if (SCM_REALP (y))
3623 {
3624 /* if x==NaN then our explicit check means we return NaN
3625 if y==NaN then "<" is false and we return NaN
3626 calling isnan is unavoidable, since it's the only way to know
3627 which of x or y causes any compares to be false */
3628 double xx = SCM_REAL_VALUE (x);
3629 return (xisnan (xx) || xx < SCM_REAL_VALUE (y)) ? x : y;
3630 }
f92e85f7
MV
3631 else if (SCM_FRACTIONP (y))
3632 {
3633 double yy = scm_i_fraction2double (y);
3634 double xx = SCM_REAL_VALUE (x);
3635 return (yy < xx) ? scm_make_real (yy) : x;
3636 }
0aacf84e
MD
3637 else
3638 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3639 }
f92e85f7
MV
3640 else if (SCM_FRACTIONP (x))
3641 {
3642 if (SCM_INUMP (y))
3643 {
3644 double z = SCM_INUM (y);
3645 return (scm_i_fraction2double (x) < z) ? x : y;
3646 }
3647 else if (SCM_BIGP (y))
3648 {
3649 double xx = scm_i_fraction2double (x);
3650 int cmp;
3651 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), xx);
3652 scm_remember_upto_here_1 (y);
3653 return (cmp < 0) ? y : x;
3654 }
3655 else if (SCM_REALP (y))
3656 {
3657 double xx = scm_i_fraction2double (x);
3658 return (SCM_REAL_VALUE (y) < xx) ? y : scm_make_real (xx);
3659 }
3660 else if (SCM_FRACTIONP (y))
3661 {
3662 double yy = scm_i_fraction2double (y);
3663 double xx = scm_i_fraction2double (x);
3664 return (xx < yy) ? x : y;
3665 }
3666 else
3667 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3668 }
0aacf84e 3669 else
f4c627b3 3670 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
3671}
3672
3673
9de33deb 3674SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
942e5b91
MG
3675/* "Return the sum of all parameter values. Return 0 if called without\n"
3676 * "any parameters."
3677 */
0f2d19dd 3678SCM
6e8d25a6 3679scm_sum (SCM x, SCM y)
0f2d19dd 3680{
ca46fb90
RB
3681 if (SCM_UNBNDP (y))
3682 {
3683 if (SCM_NUMBERP (x)) return x;
3684 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 3685 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3686 }
c209c88e 3687
ca46fb90
RB
3688 if (SCM_INUMP (x))
3689 {
3690 if (SCM_INUMP (y))
3691 {
3692 long xx = SCM_INUM (x);
3693 long yy = SCM_INUM (y);
3694 long int z = xx + yy;
3695 return SCM_FIXABLE (z) ? SCM_MAKINUM (z) : scm_i_long2big (z);
3696 }
3697 else if (SCM_BIGP (y))
3698 {
3699 SCM_SWAP (x, y);
3700 goto add_big_inum;
3701 }
3702 else if (SCM_REALP (y))
3703 {
3704 long int xx = SCM_INUM (x);
3705 return scm_make_real (xx + SCM_REAL_VALUE (y));
3706 }
3707 else if (SCM_COMPLEXP (y))
3708 {
3709 long int xx = SCM_INUM (x);
3710 return scm_make_complex (xx + SCM_COMPLEX_REAL (y),
3711 SCM_COMPLEX_IMAG (y));
3712 }
f92e85f7
MV
3713 else if (SCM_FRACTIONP (y))
3714 return scm_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
3715 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
3716 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
3717 else
3718 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
3719 } else if (SCM_BIGP (x))
3720 {
3721 if (SCM_INUMP (y))
3722 {
3723 long int inum;
3724 int bigsgn;
3725 add_big_inum:
3726 inum = SCM_INUM (y);
3727 if (inum == 0)
3728 return x;
3729 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3730 if (inum < 0)
3731 {
3732 SCM result = scm_i_mkbig ();
3733 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
3734 scm_remember_upto_here_1 (x);
3735 /* we know the result will have to be a bignum */
3736 if (bigsgn == -1)
3737 return result;
3738 return scm_i_normbig (result);
3739 }
3740 else
3741 {
3742 SCM result = scm_i_mkbig ();
3743 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
3744 scm_remember_upto_here_1 (x);
3745 /* we know the result will have to be a bignum */
3746 if (bigsgn == 1)
3747 return result;
3748 return scm_i_normbig (result);
3749 }
3750 }
3751 else if (SCM_BIGP (y))
3752 {
3753 SCM result = scm_i_mkbig ();
3754 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
3755 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
3756 mpz_add (SCM_I_BIG_MPZ (result),
3757 SCM_I_BIG_MPZ (x),
3758 SCM_I_BIG_MPZ (y));
3759 scm_remember_upto_here_2 (x, y);
3760 /* we know the result will have to be a bignum */
3761 if (sgn_x == sgn_y)
3762 return result;
3763 return scm_i_normbig (result);
3764 }
3765 else if (SCM_REALP (y))
3766 {
3767 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
3768 scm_remember_upto_here_1 (x);
3769 return scm_make_real (result);
3770 }
3771 else if (SCM_COMPLEXP (y))
3772 {
3773 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
3774 + SCM_COMPLEX_REAL (y));
3775 scm_remember_upto_here_1 (x);
3776 return scm_make_complex (real_part, SCM_COMPLEX_IMAG (y));
3777 }
f92e85f7
MV
3778 else if (SCM_FRACTIONP (y))
3779 return scm_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
3780 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
3781 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
3782 else
3783 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 3784 }
0aacf84e
MD
3785 else if (SCM_REALP (x))
3786 {
3787 if (SCM_INUMP (y))
3788 return scm_make_real (SCM_REAL_VALUE (x) + SCM_INUM (y));
3789 else if (SCM_BIGP (y))
3790 {
3791 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
3792 scm_remember_upto_here_1 (y);
3793 return scm_make_real (result);
3794 }
3795 else if (SCM_REALP (y))
3796 return scm_make_real (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
3797 else if (SCM_COMPLEXP (y))
3798 return scm_make_complex (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
3799 SCM_COMPLEX_IMAG (y));
f92e85f7
MV
3800 else if (SCM_FRACTIONP (y))
3801 return scm_make_real (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
3802 else
3803 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3804 }
0aacf84e
MD
3805 else if (SCM_COMPLEXP (x))
3806 {
3807 if (SCM_INUMP (y))
3808 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_INUM (y),
3809 SCM_COMPLEX_IMAG (x));
3810 else if (SCM_BIGP (y))
3811 {
3812 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
3813 + SCM_COMPLEX_REAL (x));
3814 scm_remember_upto_here_1 (y);
3815 return scm_make_complex (real_part, SCM_COMPLEX_IMAG (x));
3816 }
3817 else if (SCM_REALP (y))
3818 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
3819 SCM_COMPLEX_IMAG (x));
3820 else if (SCM_COMPLEXP (y))
3821 return scm_make_complex (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
3822 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7
MV
3823 else if (SCM_FRACTIONP (y))
3824 return scm_make_complex (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
3825 SCM_COMPLEX_IMAG (x));
3826 else
3827 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3828 }
3829 else if (SCM_FRACTIONP (x))
3830 {
3831 if (SCM_INUMP (y))
3832 return scm_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
3833 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
3834 SCM_FRACTION_DENOMINATOR (x));
3835 else if (SCM_BIGP (y))
3836 return scm_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
3837 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
3838 SCM_FRACTION_DENOMINATOR (x));
3839 else if (SCM_REALP (y))
3840 return scm_make_real (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
3841 else if (SCM_COMPLEXP (y))
3842 return scm_make_complex (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
3843 SCM_COMPLEX_IMAG (y));
3844 else if (SCM_FRACTIONP (y))
3845 /* a/b + c/d = (ad + bc) / bd */
3846 return scm_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
3847 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
3848 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
3849 else
3850 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 3851 }
0aacf84e 3852 else
98cb6e75 3853 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
3854}
3855
3856
9de33deb 3857SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
609c3d30
MG
3858/* If called with one argument @var{z1}, -@var{z1} returned. Otherwise
3859 * the sum of all but the first argument are subtracted from the first
3860 * argument. */
c05e97b7 3861#define FUNC_NAME s_difference
0f2d19dd 3862SCM
6e8d25a6 3863scm_difference (SCM x, SCM y)
0f2d19dd 3864{
ca46fb90
RB
3865 if (SCM_UNBNDP (y))
3866 {
3867 if (SCM_UNBNDP (x))
3868 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
3869 else
3870 if (SCM_INUMP (x))
3871 {
3872 long xx = -SCM_INUM (x);
3873 if (SCM_FIXABLE (xx))
3874 return SCM_MAKINUM (xx);
3875 else
3876 return scm_i_long2big (xx);
3877 }
3878 else if (SCM_BIGP (x))
3879 /* FIXME: do we really need to normalize here? */
3880 return scm_i_normbig (scm_i_clonebig (x, 0));
3881 else if (SCM_REALP (x))
3882 return scm_make_real (-SCM_REAL_VALUE (x));
3883 else if (SCM_COMPLEXP (x))
3884 return scm_make_complex (-SCM_COMPLEX_REAL (x),
3885 -SCM_COMPLEX_IMAG (x));
f92e85f7
MV
3886 else if (SCM_FRACTIONP (x))
3887 return scm_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
3888 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
3889 else
3890 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 3891 }
ca46fb90 3892
0aacf84e
MD
3893 if (SCM_INUMP (x))
3894 {
3895 if (SCM_INUMP (y))
3896 {
3897 long int xx = SCM_INUM (x);
3898 long int yy = SCM_INUM (y);
3899 long int z = xx - yy;
3900 if (SCM_FIXABLE (z))
3901 return SCM_MAKINUM (z);
3902 else
3903 return scm_i_long2big (z);
3904 }
3905 else if (SCM_BIGP (y))
3906 {
3907 /* inum-x - big-y */
3908 long xx = SCM_INUM (x);
ca46fb90 3909
0aacf84e
MD
3910 if (xx == 0)
3911 return scm_i_clonebig (y, 0);
3912 else
3913 {
3914 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
3915 SCM result = scm_i_mkbig ();
ca46fb90 3916
0aacf84e
MD
3917 if (xx >= 0)
3918 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
3919 else
3920 {
3921 /* x - y == -(y + -x) */
3922 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
3923 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
3924 }
3925 scm_remember_upto_here_1 (y);
ca46fb90 3926
0aacf84e
MD
3927 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
3928 /* we know the result will have to be a bignum */
3929 return result;
3930 else
3931 return scm_i_normbig (result);
3932 }
3933 }
3934 else if (SCM_REALP (y))
3935 {
3936 long int xx = SCM_INUM (x);
3937 return scm_make_real (xx - SCM_REAL_VALUE (y));
3938 }
3939 else if (SCM_COMPLEXP (y))
3940 {
3941 long int xx = SCM_INUM (x);
3942 return scm_make_complex (xx - SCM_COMPLEX_REAL (y),
3943 - SCM_COMPLEX_IMAG (y));
3944 }
f92e85f7
MV
3945 else if (SCM_FRACTIONP (y))
3946 /* a - b/c = (ac - b) / c */
3947 return scm_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
3948 SCM_FRACTION_NUMERATOR (y)),
3949 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
3950 else
3951 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 3952 }
0aacf84e
MD
3953 else if (SCM_BIGP (x))
3954 {
3955 if (SCM_INUMP (y))
3956 {
3957 /* big-x - inum-y */
3958 long yy = SCM_INUM (y);
3959 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 3960
0aacf84e
MD
3961 scm_remember_upto_here_1 (x);
3962 if (sgn_x == 0)
3963 return SCM_FIXABLE (-yy) ? SCM_MAKINUM (-yy) : scm_long2num (-yy);
3964 else
3965 {
3966 SCM result = scm_i_mkbig ();
ca46fb90 3967
708f22c6
KR
3968 if (yy >= 0)
3969 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
3970 else
3971 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 3972 scm_remember_upto_here_1 (x);
ca46fb90 3973
0aacf84e
MD
3974 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
3975 /* we know the result will have to be a bignum */
3976 return result;
3977 else
3978 return scm_i_normbig (result);
3979 }
3980 }
3981 else if (SCM_BIGP (y))
3982 {
3983 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
3984 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
3985 SCM result = scm_i_mkbig ();
3986 mpz_sub (SCM_I_BIG_MPZ (result),
3987 SCM_I_BIG_MPZ (x),
3988 SCM_I_BIG_MPZ (y));
3989 scm_remember_upto_here_2 (x, y);
3990 /* we know the result will have to be a bignum */
3991 if ((sgn_x == 1) && (sgn_y == -1))
3992 return result;
3993 if ((sgn_x == -1) && (sgn_y == 1))
3994 return result;
3995 return scm_i_normbig (result);
3996 }
3997 else if (SCM_REALP (y))
3998 {
3999 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
4000 scm_remember_upto_here_1 (x);
4001 return scm_make_real (result);
4002 }
4003 else if (SCM_COMPLEXP (y))
4004 {
4005 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
4006 - SCM_COMPLEX_REAL (y));
4007 scm_remember_upto_here_1 (x);
4008 return scm_make_complex (real_part, - SCM_COMPLEX_IMAG (y));
4009 }
f92e85f7
MV
4010 else if (SCM_FRACTIONP (y))
4011 return scm_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
4012 SCM_FRACTION_NUMERATOR (y)),
4013 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 4014 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 4015 }
0aacf84e
MD
4016 else if (SCM_REALP (x))
4017 {
4018 if (SCM_INUMP (y))
4019 return scm_make_real (SCM_REAL_VALUE (x) - SCM_INUM (y));
4020 else if (SCM_BIGP (y))
4021 {
4022 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
4023 scm_remember_upto_here_1 (x);
4024 return scm_make_real (result);
4025 }
4026 else if (SCM_REALP (y))
4027 return scm_make_real (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
4028 else if (SCM_COMPLEXP (y))
4029 return scm_make_complex (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
4030 -SCM_COMPLEX_IMAG (y));
f92e85f7
MV
4031 else if (SCM_FRACTIONP (y))
4032 return scm_make_real (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
4033 else
4034 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 4035 }
0aacf84e
MD
4036 else if (SCM_COMPLEXP (x))
4037 {
4038 if (SCM_INUMP (y))
4039 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_INUM (y),
4040 SCM_COMPLEX_IMAG (x));
4041 else if (SCM_BIGP (y))
4042 {
4043 double real_part = (SCM_COMPLEX_REAL (x)
4044 - mpz_get_d (SCM_I_BIG_MPZ (y)));
4045 scm_remember_upto_here_1 (x);
4046 return scm_make_complex (real_part, SCM_COMPLEX_IMAG (y));
4047 }
4048 else if (SCM_REALP (y))
4049 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
4050 SCM_COMPLEX_IMAG (x));
4051 else if (SCM_COMPLEXP (y))
4052 return scm_make_complex (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
4053 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7
MV
4054 else if (SCM_FRACTIONP (y))
4055 return scm_make_complex (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
4056 SCM_COMPLEX_IMAG (x));
4057 else
4058 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
4059 }
4060 else if (SCM_FRACTIONP (x))
4061 {
4062 if (SCM_INUMP (y))
4063 /* a/b - c = (a - cb) / b */
4064 return scm_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
4065 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
4066 SCM_FRACTION_DENOMINATOR (x));
4067 else if (SCM_BIGP (y))
4068 return scm_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
4069 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
4070 SCM_FRACTION_DENOMINATOR (x));
4071 else if (SCM_REALP (y))
4072 return scm_make_real (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
4073 else if (SCM_COMPLEXP (y))
4074 return scm_make_complex (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
4075 -SCM_COMPLEX_IMAG (y));
4076 else if (SCM_FRACTIONP (y))
4077 /* a/b - c/d = (ad - bc) / bd */
4078 return scm_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
4079 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
4080 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4081 else
4082 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 4083 }
0aacf84e 4084 else
98cb6e75 4085 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 4086}
c05e97b7 4087#undef FUNC_NAME
0f2d19dd 4088
ca46fb90 4089
9de33deb 4090SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
942e5b91
MG
4091/* "Return the product of all arguments. If called without arguments,\n"
4092 * "1 is returned."
4093 */
0f2d19dd 4094SCM
6e8d25a6 4095scm_product (SCM x, SCM y)
0f2d19dd 4096{
0aacf84e
MD
4097 if (SCM_UNBNDP (y))
4098 {
4099 if (SCM_UNBNDP (x))
4100 return SCM_MAKINUM (1L);
4101 else if (SCM_NUMBERP (x))
4102 return x;
4103 else
4104 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 4105 }
ca46fb90 4106
0aacf84e
MD
4107 if (SCM_INUMP (x))
4108 {
4109 long xx;
f4c627b3 4110
0aacf84e
MD
4111 intbig:
4112 xx = SCM_INUM (x);
f4c627b3 4113
0aacf84e
MD
4114 switch (xx)
4115 {
ca46fb90
RB
4116 case 0: return x; break;
4117 case 1: return y; break;
0aacf84e 4118 }
f4c627b3 4119
0aacf84e
MD
4120 if (SCM_INUMP (y))
4121 {
4122 long yy = SCM_INUM (y);
4123 long kk = xx * yy;
4124 SCM k = SCM_MAKINUM (kk);
4125 if ((kk == SCM_INUM (k)) && (kk / xx == yy))
4126 return k;
4127 else
4128 {
4129 SCM result = scm_i_long2big (xx);
4130 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
4131 return scm_i_normbig (result);
4132 }
4133 }
4134 else if (SCM_BIGP (y))
4135 {
4136 SCM result = scm_i_mkbig ();
4137 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
4138 scm_remember_upto_here_1 (y);
4139 return result;
4140 }
4141 else if (SCM_REALP (y))
4142 return scm_make_real (xx * SCM_REAL_VALUE (y));
4143 else if (SCM_COMPLEXP (y))
4144 return scm_make_complex (xx * SCM_COMPLEX_REAL (y),
4145 xx * SCM_COMPLEX_IMAG (y));
f92e85f7
MV
4146 else if (SCM_FRACTIONP (y))
4147 return scm_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
4148 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4149 else
4150 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4151 }
0aacf84e
MD
4152 else if (SCM_BIGP (x))
4153 {
4154 if (SCM_INUMP (y))
4155 {
4156 SCM_SWAP (x, y);
4157 goto intbig;
4158 }
4159 else if (SCM_BIGP (y))
4160 {
4161 SCM result = scm_i_mkbig ();
4162 mpz_mul (SCM_I_BIG_MPZ (result),
4163 SCM_I_BIG_MPZ (x),
4164 SCM_I_BIG_MPZ (y));
4165 scm_remember_upto_here_2 (x, y);
4166 return result;
4167 }
4168 else if (SCM_REALP (y))
4169 {
4170 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
4171 scm_remember_upto_here_1 (x);
4172 return scm_make_real (result);
4173 }
4174 else if (SCM_COMPLEXP (y))
4175 {
4176 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
4177 scm_remember_upto_here_1 (x);
4178 return scm_make_complex (z * SCM_COMPLEX_REAL (y),
4179 z * SCM_COMPLEX_IMAG (y));
4180 }
f92e85f7
MV
4181 else if (SCM_FRACTIONP (y))
4182 return scm_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
4183 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4184 else
4185 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4186 }
0aacf84e
MD
4187 else if (SCM_REALP (x))
4188 {
4189 if (SCM_INUMP (y))
4190 return scm_make_real (SCM_INUM (y) * SCM_REAL_VALUE (x));
4191 else if (SCM_BIGP (y))
4192 {
4193 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
4194 scm_remember_upto_here_1 (y);
4195 return scm_make_real (result);
4196 }
4197 else if (SCM_REALP (y))
4198 return scm_make_real (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
4199 else if (SCM_COMPLEXP (y))
4200 return scm_make_complex (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
4201 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7
MV
4202 else if (SCM_FRACTIONP (y))
4203 return scm_make_real (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
4204 else
4205 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4206 }
0aacf84e
MD
4207 else if (SCM_COMPLEXP (x))
4208 {
4209 if (SCM_INUMP (y))
4210 return scm_make_complex (SCM_INUM (y) * SCM_COMPLEX_REAL (x),
4211 SCM_INUM (y) * SCM_COMPLEX_IMAG (x));
4212 else if (SCM_BIGP (y))
4213 {
4214 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
4215 scm_remember_upto_here_1 (y);
76506335
KR
4216 return scm_make_complex (z * SCM_COMPLEX_REAL (x),
4217 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
4218 }
4219 else if (SCM_REALP (y))
4220 return scm_make_complex (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
4221 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
4222 else if (SCM_COMPLEXP (y))
4223 {
4224 return scm_make_complex (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
4225 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
4226 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
4227 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
4228 }
f92e85f7
MV
4229 else if (SCM_FRACTIONP (y))
4230 {
4231 double yy = scm_i_fraction2double (y);
4232 return scm_make_complex (yy * SCM_COMPLEX_REAL (x),
4233 yy * SCM_COMPLEX_IMAG (x));
4234 }
4235 else
4236 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
4237 }
4238 else if (SCM_FRACTIONP (x))
4239 {
4240 if (SCM_INUMP (y))
4241 return scm_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
4242 SCM_FRACTION_DENOMINATOR (x));
4243 else if (SCM_BIGP (y))
4244 return scm_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
4245 SCM_FRACTION_DENOMINATOR (x));
4246 else if (SCM_REALP (y))
4247 return scm_make_real (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
4248 else if (SCM_COMPLEXP (y))
4249 {
4250 double xx = scm_i_fraction2double (x);
4251 return scm_make_complex (xx * SCM_COMPLEX_REAL (y),
4252 xx * SCM_COMPLEX_IMAG (y));
4253 }
4254 else if (SCM_FRACTIONP (y))
4255 /* a/b * c/d = ac / bd */
4256 return scm_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
4257 SCM_FRACTION_NUMERATOR (y)),
4258 scm_product (SCM_FRACTION_DENOMINATOR (x),
4259 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4260 else
4261 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4262 }
0aacf84e 4263 else
f4c627b3 4264 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
4265}
4266
0f2d19dd 4267double
6e8d25a6 4268scm_num2dbl (SCM a, const char *why)
f4c627b3 4269#define FUNC_NAME why
0f2d19dd 4270{
0aacf84e 4271 if (SCM_INUMP (a))
0f2d19dd 4272 return (double) SCM_INUM (a);
0aacf84e
MD
4273 else if (SCM_BIGP (a))
4274 {
4275 double result = mpz_get_d (SCM_I_BIG_MPZ (a));
4276 scm_remember_upto_here_1 (a);
4277 return result;
4278 }
4279 else if (SCM_REALP (a))
f4c627b3 4280 return (SCM_REAL_VALUE (a));
f92e85f7
MV
4281 else if (SCM_FRACTIONP (a))
4282 return scm_i_fraction2double (a);
0aacf84e 4283 else
f4c627b3 4284 SCM_WRONG_TYPE_ARG (SCM_ARGn, a);
0f2d19dd 4285}
f4c627b3 4286#undef FUNC_NAME
0f2d19dd 4287
7351e207
MV
4288#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
4289 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
4290#define ALLOW_DIVIDE_BY_ZERO
4291/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
4292#endif
0f2d19dd 4293
ba74ef4e
MV
4294/* The code below for complex division is adapted from the GNU
4295 libstdc++, which adapted it from f2c's libF77, and is subject to
4296 this copyright: */
4297
4298/****************************************************************
4299Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
4300
4301Permission to use, copy, modify, and distribute this software
4302and its documentation for any purpose and without fee is hereby
4303granted, provided that the above copyright notice appear in all
4304copies and that both that the copyright notice and this
4305permission notice and warranty disclaimer appear in supporting
4306documentation, and that the names of AT&T Bell Laboratories or
4307Bellcore or any of their entities not be used in advertising or
4308publicity pertaining to distribution of the software without
4309specific, written prior permission.
4310
4311AT&T and Bellcore disclaim all warranties with regard to this
4312software, including all implied warranties of merchantability
4313and fitness. In no event shall AT&T or Bellcore be liable for
4314any special, indirect or consequential damages or any damages
4315whatsoever resulting from loss of use, data or profits, whether
4316in an action of contract, negligence or other tortious action,
4317arising out of or in connection with the use or performance of
4318this software.
4319****************************************************************/
4320
9de33deb 4321SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
609c3d30
MG
4322/* Divide the first argument by the product of the remaining
4323 arguments. If called with one argument @var{z1}, 1/@var{z1} is
4324 returned. */
c05e97b7 4325#define FUNC_NAME s_divide
f92e85f7
MV
4326static SCM
4327scm_i_divide (SCM x, SCM y, int inexact)
0f2d19dd 4328{
f8de44c1
DH
4329 double a;
4330
0aacf84e
MD
4331 if (SCM_UNBNDP (y))
4332 {
4333 if (SCM_UNBNDP (x))
4334 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
4335 else if (SCM_INUMP (x))
4336 {
4337 long xx = SCM_INUM (x);
4338 if (xx == 1 || xx == -1)
4339 return x;
7351e207 4340#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4341 else if (xx == 0)
4342 scm_num_overflow (s_divide);
7351e207 4343#endif
0aacf84e 4344 else
f92e85f7
MV
4345 {
4346 if (inexact)
4347 return scm_make_real (1.0 / (double) xx);
4348 else return scm_make_ratio (SCM_MAKINUM(1), x);
4349 }
0aacf84e
MD
4350 }
4351 else if (SCM_BIGP (x))
f92e85f7
MV
4352 {
4353 if (inexact)
4354 return scm_make_real (1.0 / scm_i_big2dbl (x));
4355 else return scm_make_ratio (SCM_MAKINUM(1), x);
4356 }
0aacf84e
MD
4357 else if (SCM_REALP (x))
4358 {
4359 double xx = SCM_REAL_VALUE (x);
7351e207 4360#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4361 if (xx == 0.0)
4362 scm_num_overflow (s_divide);
4363 else
7351e207 4364#endif
0aacf84e
MD
4365 return scm_make_real (1.0 / xx);
4366 }
4367 else if (SCM_COMPLEXP (x))
4368 {
4369 double r = SCM_COMPLEX_REAL (x);
4370 double i = SCM_COMPLEX_IMAG (x);
4371 if (r <= i)
4372 {
4373 double t = r / i;
4374 double d = i * (1.0 + t * t);
4375 return scm_make_complex (t / d, -1.0 / d);
4376 }
4377 else
4378 {
4379 double t = i / r;
4380 double d = r * (1.0 + t * t);
4381 return scm_make_complex (1.0 / d, -t / d);
4382 }
4383 }
f92e85f7
MV
4384 else if (SCM_FRACTIONP (x))
4385 return scm_make_ratio (SCM_FRACTION_DENOMINATOR (x),
4386 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
4387 else
4388 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 4389 }
f8de44c1 4390
0aacf84e
MD
4391 if (SCM_INUMP (x))
4392 {
4393 long xx = SCM_INUM (x);
4394 if (SCM_INUMP (y))
4395 {
4396 long yy = SCM_INUM (y);
4397 if (yy == 0)
4398 {
7351e207 4399#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4400 scm_num_overflow (s_divide);
7351e207 4401#else
0aacf84e 4402 return scm_make_real ((double) xx / (double) yy);
7351e207 4403#endif
0aacf84e
MD
4404 }
4405 else if (xx % yy != 0)
f92e85f7
MV
4406 {
4407 if (inexact)
4408 return scm_make_real ((double) xx / (double) yy);
4409 else return scm_make_ratio (x, y);
4410 }
0aacf84e
MD
4411 else
4412 {
4413 long z = xx / yy;
4414 if (SCM_FIXABLE (z))
4415 return SCM_MAKINUM (z);
4416 else
4417 return scm_i_long2big (z);
4418 }
f872b822 4419 }
0aacf84e 4420 else if (SCM_BIGP (y))
f92e85f7
MV
4421 {
4422 if (inexact)
4423 return scm_make_real ((double) xx / scm_i_big2dbl (y));
4424 else return scm_make_ratio (x, y);
4425 }
0aacf84e
MD
4426 else if (SCM_REALP (y))
4427 {
4428 double yy = SCM_REAL_VALUE (y);
7351e207 4429#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4430 if (yy == 0.0)
4431 scm_num_overflow (s_divide);
4432 else
7351e207 4433#endif
0aacf84e 4434 return scm_make_real ((double) xx / yy);
ba74ef4e 4435 }
0aacf84e
MD
4436 else if (SCM_COMPLEXP (y))
4437 {
4438 a = xx;
4439 complex_div: /* y _must_ be a complex number */
4440 {
4441 double r = SCM_COMPLEX_REAL (y);
4442 double i = SCM_COMPLEX_IMAG (y);
4443 if (r <= i)
4444 {
4445 double t = r / i;
4446 double d = i * (1.0 + t * t);
4447 return scm_make_complex ((a * t) / d, -a / d);
4448 }
4449 else
4450 {
4451 double t = i / r;
4452 double d = r * (1.0 + t * t);
4453 return scm_make_complex (a / d, -(a * t) / d);
4454 }
4455 }
4456 }
f92e85f7
MV
4457 else if (SCM_FRACTIONP (y))
4458 /* a / b/c = ac / b */
4459 return scm_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
4460 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
4461 else
4462 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 4463 }
0aacf84e
MD
4464 else if (SCM_BIGP (x))
4465 {
4466 if (SCM_INUMP (y))
4467 {
4468 long int yy = SCM_INUM (y);
4469 if (yy == 0)
4470 {
7351e207 4471#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4472 scm_num_overflow (s_divide);
7351e207 4473#else
0aacf84e
MD
4474 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4475 scm_remember_upto_here_1 (x);
4476 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 4477#endif
0aacf84e
MD
4478 }
4479 else if (yy == 1)
4480 return x;
4481 else
4482 {
4483 /* FIXME: HMM, what are the relative performance issues here?
4484 We need to test. Is it faster on average to test
4485 divisible_p, then perform whichever operation, or is it
4486 faster to perform the integer div opportunistically and
4487 switch to real if there's a remainder? For now we take the
4488 middle ground: test, then if divisible, use the faster div
4489 func. */
4490
4491 long abs_yy = yy < 0 ? -yy : yy;
4492 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
4493
4494 if (divisible_p)
4495 {
4496 SCM result = scm_i_mkbig ();
4497 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
4498 scm_remember_upto_here_1 (x);
4499 if (yy < 0)
4500 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
4501 return scm_i_normbig (result);
4502 }
4503 else
f92e85f7
MV
4504 {
4505 if (inexact)
4506 return scm_make_real (scm_i_big2dbl (x) / (double) yy);
4507 else return scm_make_ratio (x, y);
4508 }
0aacf84e
MD
4509 }
4510 }
4511 else if (SCM_BIGP (y))
4512 {
4513 int y_is_zero = (mpz_sgn (SCM_I_BIG_MPZ (y)) == 0);
4514 if (y_is_zero)
4515 {
ca46fb90 4516#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4517 scm_num_overflow (s_divide);
f872b822 4518#else
0aacf84e
MD
4519 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4520 scm_remember_upto_here_1 (x);
4521 return (sgn == 0) ? scm_nan () : scm_inf ();
f872b822 4522#endif
0aacf84e
MD
4523 }
4524 else
4525 {
4526 /* big_x / big_y */
4527 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
4528 SCM_I_BIG_MPZ (y));
4529 if (divisible_p)
4530 {
4531 SCM result = scm_i_mkbig ();
4532 mpz_divexact (SCM_I_BIG_MPZ (result),
4533 SCM_I_BIG_MPZ (x),
4534 SCM_I_BIG_MPZ (y));
4535 scm_remember_upto_here_2 (x, y);
4536 return scm_i_normbig (result);
4537 }
4538 else
4539 {
f92e85f7
MV
4540 if (inexact)
4541 {
4542 double dbx = mpz_get_d (SCM_I_BIG_MPZ (x));
4543 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4544 scm_remember_upto_here_2 (x, y);
4545 return scm_make_real (dbx / dby);
4546 }
4547 else return scm_make_ratio (x, y);
0aacf84e
MD
4548 }
4549 }
4550 }
4551 else if (SCM_REALP (y))
4552 {
4553 double yy = SCM_REAL_VALUE (y);
7351e207 4554#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4555 if (yy == 0.0)
4556 scm_num_overflow (s_divide);
4557 else
7351e207 4558#endif
0aacf84e
MD
4559 return scm_make_real (scm_i_big2dbl (x) / yy);
4560 }
4561 else if (SCM_COMPLEXP (y))
4562 {
4563 a = scm_i_big2dbl (x);
4564 goto complex_div;
4565 }
f92e85f7
MV
4566 else if (SCM_FRACTIONP (y))
4567 return scm_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
4568 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
4569 else
4570 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4571 }
0aacf84e
MD
4572 else if (SCM_REALP (x))
4573 {
4574 double rx = SCM_REAL_VALUE (x);
4575 if (SCM_INUMP (y))
4576 {
4577 long int yy = SCM_INUM (y);
7351e207 4578#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4579 if (yy == 0)
4580 scm_num_overflow (s_divide);
4581 else
7351e207 4582#endif
0aacf84e
MD
4583 return scm_make_real (rx / (double) yy);
4584 }
4585 else if (SCM_BIGP (y))
4586 {
4587 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4588 scm_remember_upto_here_1 (y);
4589 return scm_make_real (rx / dby);
4590 }
4591 else if (SCM_REALP (y))
4592 {
4593 double yy = SCM_REAL_VALUE (y);
7351e207 4594#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4595 if (yy == 0.0)
4596 scm_num_overflow (s_divide);
4597 else
7351e207 4598#endif
0aacf84e
MD
4599 return scm_make_real (rx / yy);
4600 }
4601 else if (SCM_COMPLEXP (y))
4602 {
4603 a = rx;
4604 goto complex_div;
4605 }
f92e85f7
MV
4606 else if (SCM_FRACTIONP (y))
4607 return scm_make_real (rx / scm_i_fraction2double (y));
0aacf84e
MD
4608 else
4609 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4610 }
0aacf84e
MD
4611 else if (SCM_COMPLEXP (x))
4612 {
4613 double rx = SCM_COMPLEX_REAL (x);
4614 double ix = SCM_COMPLEX_IMAG (x);
4615 if (SCM_INUMP (y))
4616 {
4617 long int yy = SCM_INUM (y);
7351e207 4618#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4619 if (yy == 0)
4620 scm_num_overflow (s_divide);
4621 else
7351e207 4622#endif
0aacf84e
MD
4623 {
4624 double d = yy;
4625 return scm_make_complex (rx / d, ix / d);
4626 }
4627 }
4628 else if (SCM_BIGP (y))
4629 {
4630 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4631 scm_remember_upto_here_1 (y);
4632 return scm_make_complex (rx / dby, ix / dby);
4633 }
4634 else if (SCM_REALP (y))
4635 {
4636 double yy = SCM_REAL_VALUE (y);
7351e207 4637#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4638 if (yy == 0.0)
4639 scm_num_overflow (s_divide);
4640 else
7351e207 4641#endif
0aacf84e
MD
4642 return scm_make_complex (rx / yy, ix / yy);
4643 }
4644 else if (SCM_COMPLEXP (y))
4645 {
4646 double ry = SCM_COMPLEX_REAL (y);
4647 double iy = SCM_COMPLEX_IMAG (y);
4648 if (ry <= iy)
4649 {
4650 double t = ry / iy;
4651 double d = iy * (1.0 + t * t);
4652 return scm_make_complex ((rx * t + ix) / d, (ix * t - rx) / d);
4653 }
4654 else
4655 {
4656 double t = iy / ry;
4657 double d = ry * (1.0 + t * t);
4658 return scm_make_complex ((rx + ix * t) / d, (ix - rx * t) / d);
4659 }
4660 }
f92e85f7
MV
4661 else if (SCM_FRACTIONP (y))
4662 {
4663 double yy = scm_i_fraction2double (y);
4664 return scm_make_complex (rx / yy, ix / yy);
4665 }
0aacf84e
MD
4666 else
4667 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 4668 }
f92e85f7
MV
4669 else if (SCM_FRACTIONP (x))
4670 {
4671 if (SCM_INUMP (y))
4672 {
4673 long int yy = SCM_INUM (y);
4674#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
4675 if (yy == 0)
4676 scm_num_overflow (s_divide);
4677 else
4678#endif
4679 return scm_make_ratio (SCM_FRACTION_NUMERATOR (x),
4680 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
4681 }
4682 else if (SCM_BIGP (y))
4683 {
4684 return scm_make_ratio (SCM_FRACTION_NUMERATOR (x),
4685 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
4686 }
4687 else if (SCM_REALP (y))
4688 {
4689 double yy = SCM_REAL_VALUE (y);
4690#ifndef ALLOW_DIVIDE_BY_ZERO
4691 if (yy == 0.0)
4692 scm_num_overflow (s_divide);
4693 else
4694#endif
4695 return scm_make_real (scm_i_fraction2double (x) / yy);
4696 }
4697 else if (SCM_COMPLEXP (y))
4698 {
4699 a = scm_i_fraction2double (x);
4700 goto complex_div;
4701 }
4702 else if (SCM_FRACTIONP (y))
4703 return scm_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
4704 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
4705 else
4706 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
4707 }
0aacf84e 4708 else
f8de44c1 4709 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 4710}
f92e85f7
MV
4711
4712SCM
4713scm_divide (SCM x, SCM y)
4714{
4715 return scm_i_divide (x, y, 0);
4716}
4717
4718static SCM scm_divide2real (SCM x, SCM y)
4719{
4720 return scm_i_divide (x, y, 1);
4721}
c05e97b7 4722#undef FUNC_NAME
0f2d19dd 4723
fa605590 4724
0f2d19dd 4725double
6e8d25a6 4726scm_asinh (double x)
0f2d19dd 4727{
fa605590
KR
4728#if HAVE_ASINH
4729 return asinh (x);
4730#else
4731#define asinh scm_asinh
f872b822 4732 return log (x + sqrt (x * x + 1));
fa605590 4733#endif
0f2d19dd 4734}
fa605590
KR
4735SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_dsubr, (SCM (*)()) asinh, g_asinh);
4736/* "Return the inverse hyperbolic sine of @var{x}."
4737 */
0f2d19dd
JB
4738
4739
0f2d19dd 4740double
6e8d25a6 4741scm_acosh (double x)
0f2d19dd 4742{
fa605590
KR
4743#if HAVE_ACOSH
4744 return acosh (x);
4745#else
4746#define acosh scm_acosh
f872b822 4747 return log (x + sqrt (x * x - 1));
fa605590 4748#endif
0f2d19dd 4749}
fa605590
KR
4750SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_dsubr, (SCM (*)()) acosh, g_acosh);
4751/* "Return the inverse hyperbolic cosine of @var{x}."
4752 */
0f2d19dd
JB
4753
4754
0f2d19dd 4755double
6e8d25a6 4756scm_atanh (double x)
0f2d19dd 4757{
fa605590
KR
4758#if HAVE_ATANH
4759 return atanh (x);
4760#else
4761#define atanh scm_atanh
f872b822 4762 return 0.5 * log ((1 + x) / (1 - x));
fa605590 4763#endif
0f2d19dd 4764}
fa605590
KR
4765SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_dsubr, (SCM (*)()) atanh, g_atanh);
4766/* "Return the inverse hyperbolic tangent of @var{x}."
4767 */
0f2d19dd
JB
4768
4769
f92e85f7
MV
4770/* XXX - eventually, we should remove this definition of scm_round and
4771 rename scm_round_number to scm_round. Likewise for scm_truncate
4772 and scm_truncate_number.
4773 */
4774
0f2d19dd 4775double
6e8d25a6 4776scm_truncate (double x)
0f2d19dd 4777{
fa605590
KR
4778#if HAVE_TRUNC
4779 return trunc (x);
4780#else
4781#define trunc scm_truncate
f872b822
MD
4782 if (x < 0.0)
4783 return -floor (-x);
4784 return floor (x);
fa605590 4785#endif
0f2d19dd 4786}
0f2d19dd 4787
0f2d19dd 4788double
6e8d25a6 4789scm_round (double x)
0f2d19dd
JB
4790{
4791 double plus_half = x + 0.5;
f872b822 4792 double result = floor (plus_half);
0f2d19dd 4793 /* Adjust so that the scm_round is towards even. */
0aacf84e
MD
4794 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
4795 ? result - 1
4796 : result);
0f2d19dd
JB
4797}
4798
f92e85f7
MV
4799SCM_DEFINE (scm_truncate_number, "truncate", 1, 0, 0,
4800 (SCM x),
4801 "Round the number @var{x} towards zero.")
4802#define FUNC_NAME s_scm_truncate_number
4803{
4804 if (SCM_FALSEP (scm_negative_p (x)))
4805 return scm_floor (x);
4806 else
4807 return scm_ceiling (x);
4808}
4809#undef FUNC_NAME
4810
4811static SCM exactly_one_half;
4812
4813SCM_DEFINE (scm_round_number, "round", 1, 0, 0,
4814 (SCM x),
4815 "Round the number @var{x} towards the nearest integer. "
4816 "When it is exactly halfway between two integers, "
4817 "round towards the even one.")
4818#define FUNC_NAME s_scm_round_number
4819{
4820 SCM plus_half = scm_sum (x, exactly_one_half);
4821 SCM result = scm_floor (plus_half);
4822 /* Adjust so that the scm_round is towards even. */
4823 if (!SCM_FALSEP (scm_num_eq_p (plus_half, result))
4824 && !SCM_FALSEP (scm_odd_p (result)))
4825 return scm_difference (result, SCM_MAKINUM (1));
4826 else
4827 return result;
4828}
4829#undef FUNC_NAME
4830
4831SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
4832 (SCM x),
4833 "Round the number @var{x} towards minus infinity.")
4834#define FUNC_NAME s_scm_floor
4835{
4836 if (SCM_INUMP (x) || SCM_BIGP (x))
4837 return x;
4838 else if (SCM_REALP (x))
4839 return scm_make_real (floor (SCM_REAL_VALUE (x)));
4840 else if (SCM_FRACTIONP (x))
4841 {
4842 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
4843 SCM_FRACTION_DENOMINATOR (x));
4844 if (SCM_FALSEP (scm_negative_p (x)))
4845 {
4846 /* For positive x, rounding towards zero is correct. */
4847 return q;
4848 }
4849 else
4850 {
4851 /* For negative x, we need to return q-1 unless x is an
4852 integer. But fractions are never integer, per our
4853 assumptions. */
4854 return scm_difference (q, SCM_MAKINUM (1));
4855 }
4856 }
4857 else
4858 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
4859}
4860#undef FUNC_NAME
4861
4862SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
4863 (SCM x),
4864 "Round the number @var{x} towards infinity.")
4865#define FUNC_NAME s_scm_ceiling
4866{
4867 if (SCM_INUMP (x) || SCM_BIGP (x))
4868 return x;
4869 else if (SCM_REALP (x))
4870 return scm_make_real (ceil (SCM_REAL_VALUE (x)));
4871 else if (SCM_FRACTIONP (x))
4872 {
4873 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
4874 SCM_FRACTION_DENOMINATOR (x));
4875 if (SCM_FALSEP (scm_positive_p (x)))
4876 {
4877 /* For negative x, rounding towards zero is correct. */
4878 return q;
4879 }
4880 else
4881 {
4882 /* For positive x, we need to return q+1 unless x is an
4883 integer. But fractions are never integer, per our
4884 assumptions. */
4885 return scm_sum (q, SCM_MAKINUM (1));
4886 }
4887 }
4888 else
4889 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
4890}
4891#undef FUNC_NAME
0f2d19dd 4892
14b18ed6 4893SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_dsubr, (SCM (*)()) sqrt, g_i_sqrt);
942e5b91
MG
4894/* "Return the square root of the real number @var{x}."
4895 */
14b18ed6 4896SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_dsubr, (SCM (*)()) fabs, g_i_abs);
942e5b91
MG
4897/* "Return the absolute value of the real number @var{x}."
4898 */
14b18ed6 4899SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_dsubr, (SCM (*)()) exp, g_i_exp);
942e5b91
MG
4900/* "Return the @var{x}th power of e."
4901 */
14b18ed6 4902SCM_GPROC1 (s_i_log, "$log", scm_tc7_dsubr, (SCM (*)()) log, g_i_log);
b3fcac34 4903/* "Return the natural logarithm of the real number @var{x}."
942e5b91 4904 */
14b18ed6 4905SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_dsubr, (SCM (*)()) sin, g_i_sin);
942e5b91
MG
4906/* "Return the sine of the real number @var{x}."
4907 */
14b18ed6 4908SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_dsubr, (SCM (*)()) cos, g_i_cos);
942e5b91
MG
4909/* "Return the cosine of the real number @var{x}."
4910 */
14b18ed6 4911SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_dsubr, (SCM (*)()) tan, g_i_tan);
942e5b91
MG
4912/* "Return the tangent of the real number @var{x}."
4913 */
14b18ed6 4914SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_dsubr, (SCM (*)()) asin, g_i_asin);
942e5b91
MG
4915/* "Return the arc sine of the real number @var{x}."
4916 */
14b18ed6 4917SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_dsubr, (SCM (*)()) acos, g_i_acos);
942e5b91
MG
4918/* "Return the arc cosine of the real number @var{x}."
4919 */
14b18ed6 4920SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_dsubr, (SCM (*)()) atan, g_i_atan);
942e5b91
MG
4921/* "Return the arc tangent of the real number @var{x}."
4922 */
14b18ed6 4923SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_dsubr, (SCM (*)()) sinh, g_i_sinh);
942e5b91
MG
4924/* "Return the hyperbolic sine of the real number @var{x}."
4925 */
14b18ed6 4926SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_dsubr, (SCM (*)()) cosh, g_i_cosh);
942e5b91
MG
4927/* "Return the hyperbolic cosine of the real number @var{x}."
4928 */
14b18ed6 4929SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_dsubr, (SCM (*)()) tanh, g_i_tanh);
942e5b91
MG
4930/* "Return the hyperbolic tangent of the real number @var{x}."
4931 */
f872b822
MD
4932
4933struct dpair
4934{
4935 double x, y;
4936};
4937
27c37006
NJ
4938static void scm_two_doubles (SCM x,
4939 SCM y,
3eeba8d4
JB
4940 const char *sstring,
4941 struct dpair * xy);
f872b822
MD
4942
4943static void
27c37006
NJ
4944scm_two_doubles (SCM x, SCM y, const char *sstring, struct dpair *xy)
4945{
0aacf84e 4946 if (SCM_INUMP (x))
27c37006 4947 xy->x = SCM_INUM (x);
0aacf84e 4948 else if (SCM_BIGP (x))
1be6b49c 4949 xy->x = scm_i_big2dbl (x);
0aacf84e 4950 else if (SCM_REALP (x))
27c37006 4951 xy->x = SCM_REAL_VALUE (x);
f92e85f7
MV
4952 else if (SCM_FRACTIONP (x))
4953 xy->x = scm_i_fraction2double (x);
0aacf84e 4954 else
27c37006 4955 scm_wrong_type_arg (sstring, SCM_ARG1, x);
98cb6e75 4956
0aacf84e 4957 if (SCM_INUMP (y))
27c37006 4958 xy->y = SCM_INUM (y);
0aacf84e 4959 else if (SCM_BIGP (y))
1be6b49c 4960 xy->y = scm_i_big2dbl (y);
0aacf84e 4961 else if (SCM_REALP (y))
27c37006 4962 xy->y = SCM_REAL_VALUE (y);
f92e85f7
MV
4963 else if (SCM_FRACTIONP (y))
4964 xy->y = scm_i_fraction2double (y);
0aacf84e 4965 else
27c37006 4966 scm_wrong_type_arg (sstring, SCM_ARG2, y);
0f2d19dd
JB
4967}
4968
4969
a1ec6916 4970SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
27c37006
NJ
4971 (SCM x, SCM y),
4972 "Return @var{x} raised to the power of @var{y}. This\n"
0137a31b 4973 "procedure does not accept complex arguments.")
1bbd0b84 4974#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
4975{
4976 struct dpair xy;
27c37006 4977 scm_two_doubles (x, y, FUNC_NAME, &xy);
f8de44c1 4978 return scm_make_real (pow (xy.x, xy.y));
0f2d19dd 4979}
1bbd0b84 4980#undef FUNC_NAME
0f2d19dd
JB
4981
4982
a1ec6916 4983SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
27c37006
NJ
4984 (SCM x, SCM y),
4985 "Return the arc tangent of the two arguments @var{x} and\n"
4986 "@var{y}. This is similar to calculating the arc tangent of\n"
4987 "@var{x} / @var{y}, except that the signs of both arguments\n"
0137a31b
MG
4988 "are used to determine the quadrant of the result. This\n"
4989 "procedure does not accept complex arguments.")
1bbd0b84 4990#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
4991{
4992 struct dpair xy;
27c37006 4993 scm_two_doubles (x, y, FUNC_NAME, &xy);
f8de44c1 4994 return scm_make_real (atan2 (xy.x, xy.y));
0f2d19dd 4995}
1bbd0b84 4996#undef FUNC_NAME
0f2d19dd
JB
4997
4998
a1ec6916 4999SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794 5000 (SCM real, SCM imaginary),
942e5b91
MG
5001 "Return a complex number constructed of the given @var{real} and\n"
5002 "@var{imaginary} parts.")
1bbd0b84 5003#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
5004{
5005 struct dpair xy;
bb628794 5006 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
f8de44c1 5007 return scm_make_complex (xy.x, xy.y);
0f2d19dd 5008}
1bbd0b84 5009#undef FUNC_NAME
0f2d19dd
JB
5010
5011
5012
a1ec6916 5013SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
27c37006 5014 (SCM x, SCM y),
942e5b91 5015 "Return the complex number @var{x} * e^(i * @var{y}).")
1bbd0b84 5016#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
5017{
5018 struct dpair xy;
6efadd7c 5019 double s, c;
27c37006 5020 scm_two_doubles (x, y, FUNC_NAME, &xy);
6efadd7c
KR
5021#if HAVE_SINCOS
5022 sincos (xy.y, &s, &c);
5023#else
5024 s = sin (xy.y);
5025 c = cos (xy.y);
5026#endif
5027 return scm_make_complex (xy.x * c, xy.x * s);
0f2d19dd 5028}
1bbd0b84 5029#undef FUNC_NAME
0f2d19dd
JB
5030
5031
152f82bf 5032SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
942e5b91
MG
5033/* "Return the real part of the number @var{z}."
5034 */
0f2d19dd 5035SCM
6e8d25a6 5036scm_real_part (SCM z)
0f2d19dd 5037{
0aacf84e 5038 if (SCM_INUMP (z))
c2ff8ab0 5039 return z;
0aacf84e 5040 else if (SCM_BIGP (z))
c2ff8ab0 5041 return z;
0aacf84e 5042 else if (SCM_REALP (z))
c2ff8ab0 5043 return z;
0aacf84e 5044 else if (SCM_COMPLEXP (z))
c2ff8ab0 5045 return scm_make_real (SCM_COMPLEX_REAL (z));
f92e85f7 5046 else if (SCM_FRACTIONP (z))
2fa2d879 5047 return z;
0aacf84e 5048 else
c2ff8ab0 5049 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
0f2d19dd
JB
5050}
5051
5052
152f82bf 5053SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
942e5b91
MG
5054/* "Return the imaginary part of the number @var{z}."
5055 */
0f2d19dd 5056SCM
6e8d25a6 5057scm_imag_part (SCM z)
0f2d19dd 5058{
0aacf84e 5059 if (SCM_INUMP (z))
f872b822 5060 return SCM_INUM0;
0aacf84e 5061 else if (SCM_BIGP (z))
f872b822 5062 return SCM_INUM0;
0aacf84e 5063 else if (SCM_REALP (z))
c2ff8ab0 5064 return scm_flo0;
0aacf84e 5065 else if (SCM_COMPLEXP (z))
c2ff8ab0 5066 return scm_make_real (SCM_COMPLEX_IMAG (z));
f92e85f7
MV
5067 else if (SCM_FRACTIONP (z))
5068 return SCM_INUM0;
0aacf84e 5069 else
c2ff8ab0 5070 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
0f2d19dd
JB
5071}
5072
f92e85f7
MV
5073SCM_GPROC (s_numerator, "numerator", 1, 0, 0, scm_numerator, g_numerator);
5074/* "Return the numerator of the number @var{z}."
5075 */
5076SCM
5077scm_numerator (SCM z)
5078{
5079 if (SCM_INUMP (z))
5080 return z;
5081 else if (SCM_BIGP (z))
5082 return z;
5083 else if (SCM_FRACTIONP (z))
5084 {
5085 scm_i_fraction_reduce (z);
5086 return SCM_FRACTION_NUMERATOR (z);
5087 }
5088 else if (SCM_REALP (z))
5089 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
5090 else
5091 SCM_WTA_DISPATCH_1 (g_numerator, z, SCM_ARG1, s_numerator);
5092}
5093
5094
5095SCM_GPROC (s_denominator, "denominator", 1, 0, 0, scm_denominator, g_denominator);
5096/* "Return the denominator of the number @var{z}."
5097 */
5098SCM
5099scm_denominator (SCM z)
5100{
5101 if (SCM_INUMP (z))
5102 return SCM_MAKINUM (1);
5103 else if (SCM_BIGP (z))
5104 return SCM_MAKINUM (1);
5105 else if (SCM_FRACTIONP (z))
5106 {
5107 scm_i_fraction_reduce (z);
5108 return SCM_FRACTION_DENOMINATOR (z);
5109 }
5110 else if (SCM_REALP (z))
5111 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
5112 else
5113 SCM_WTA_DISPATCH_1 (g_denominator, z, SCM_ARG1, s_denominator);
5114}
0f2d19dd 5115
9de33deb 5116SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
942e5b91
MG
5117/* "Return the magnitude of the number @var{z}. This is the same as\n"
5118 * "@code{abs} for real arguments, but also allows complex numbers."
5119 */
0f2d19dd 5120SCM
6e8d25a6 5121scm_magnitude (SCM z)
0f2d19dd 5122{
0aacf84e
MD
5123 if (SCM_INUMP (z))
5124 {
5125 long int zz = SCM_INUM (z);
5126 if (zz >= 0)
5127 return z;
5128 else if (SCM_POSFIXABLE (-zz))
5129 return SCM_MAKINUM (-zz);
5130 else
5131 return scm_i_long2big (-zz);
5986c47d 5132 }
0aacf84e
MD
5133 else if (SCM_BIGP (z))
5134 {
5135 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
5136 scm_remember_upto_here_1 (z);
5137 if (sgn < 0)
5138 return scm_i_clonebig (z, 0);
5139 else
5140 return z;
5986c47d 5141 }
0aacf84e 5142 else if (SCM_REALP (z))
c2ff8ab0 5143 return scm_make_real (fabs (SCM_REAL_VALUE (z)));
0aacf84e 5144 else if (SCM_COMPLEXP (z))
6efadd7c 5145 return scm_make_real (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
5146 else if (SCM_FRACTIONP (z))
5147 {
5148 if (SCM_FALSEP (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
5149 return z;
5150 return scm_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
5151 SCM_FRACTION_DENOMINATOR (z));
5152 }
0aacf84e 5153 else
c2ff8ab0 5154 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
0f2d19dd
JB
5155}
5156
5157
9de33deb 5158SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
942e5b91
MG
5159/* "Return the angle of the complex number @var{z}."
5160 */
0f2d19dd 5161SCM
6e8d25a6 5162scm_angle (SCM z)
0f2d19dd 5163{
c8ae173e
KR
5164 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
5165 scm_flo0 to save allocating a new flonum with scm_make_real each time.
5166 But if atan2 follows the floating point rounding mode, then the value
5167 is not a constant. Maybe it'd be close enough though. */
0aacf84e
MD
5168 if (SCM_INUMP (z))
5169 {
5170 if (SCM_INUM (z) >= 0)
c8ae173e 5171 return scm_flo0;
0aacf84e
MD
5172 else
5173 return scm_make_real (atan2 (0.0, -1.0));
f872b822 5174 }
0aacf84e
MD
5175 else if (SCM_BIGP (z))
5176 {
5177 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
5178 scm_remember_upto_here_1 (z);
5179 if (sgn < 0)
5180 return scm_make_real (atan2 (0.0, -1.0));
5181 else
c8ae173e 5182 return scm_flo0;
0f2d19dd 5183 }
0aacf84e 5184 else if (SCM_REALP (z))
c8ae173e
KR
5185 {
5186 if (SCM_REAL_VALUE (z) >= 0)
5187 return scm_flo0;
5188 else
5189 return scm_make_real (atan2 (0.0, -1.0));
5190 }
0aacf84e 5191 else if (SCM_COMPLEXP (z))
f4c627b3 5192 return scm_make_real (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
5193 else if (SCM_FRACTIONP (z))
5194 {
5195 if (SCM_FALSEP (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
5196 return scm_flo0;
5197 else return scm_make_real (atan2 (0.0, -1.0));
5198 }
0aacf84e 5199 else
f4c627b3 5200 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
0f2d19dd
JB
5201}
5202
5203
3c9a524f
DH
5204SCM_GPROC (s_exact_to_inexact, "exact->inexact", 1, 0, 0, scm_exact_to_inexact, g_exact_to_inexact);
5205/* Convert the number @var{x} to its inexact representation.\n"
5206 */
5207SCM
5208scm_exact_to_inexact (SCM z)
5209{
5210 if (SCM_INUMP (z))
5211 return scm_make_real ((double) SCM_INUM (z));
5212 else if (SCM_BIGP (z))
5213 return scm_make_real (scm_i_big2dbl (z));
f92e85f7
MV
5214 else if (SCM_FRACTIONP (z))
5215 return scm_make_real (scm_i_fraction2double (z));
3c9a524f
DH
5216 else if (SCM_INEXACTP (z))
5217 return z;
5218 else
5219 SCM_WTA_DISPATCH_1 (g_exact_to_inexact, z, 1, s_exact_to_inexact);
5220}
5221
5222
a1ec6916 5223SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 5224 (SCM z),
1e6808ea 5225 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 5226#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 5227{
0aacf84e 5228 if (SCM_INUMP (z))
f872b822 5229 return z;
0aacf84e 5230 else if (SCM_BIGP (z))
f872b822 5231 return z;
0aacf84e
MD
5232 else if (SCM_REALP (z))
5233 {
f92e85f7
MV
5234 if (xisinf (SCM_REAL_VALUE (z)) || xisnan (SCM_REAL_VALUE (z)))
5235 SCM_OUT_OF_RANGE (1, z);
2be24db4 5236 else
f92e85f7
MV
5237 {
5238 mpq_t frac;
5239 SCM q;
5240
5241 mpq_init (frac);
5242 mpq_set_d (frac, SCM_REAL_VALUE (z));
5243 q = scm_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
5244 scm_i_mpz2num (mpq_denref (frac)));
5245
5246 /* When scm_make_ratio throws, we leak the memory allocated
5247 for frac...
5248 */
5249 mpq_clear (frac);
5250 return q;
5251 }
c2ff8ab0 5252 }
f92e85f7
MV
5253 else if (SCM_FRACTIONP (z))
5254 return z;
0aacf84e 5255 else
c2ff8ab0 5256 SCM_WRONG_TYPE_ARG (1, z);
0f2d19dd 5257}
1bbd0b84 5258#undef FUNC_NAME
0f2d19dd 5259
f92e85f7
MV
5260SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
5261 (SCM x, SCM err),
5262 "Return an exact number that is within @var{err} of @var{x}.")
5263#define FUNC_NAME s_scm_rationalize
5264{
5265 if (SCM_INUMP (x))
5266 return x;
5267 else if (SCM_BIGP (x))
5268 return x;
5269 else if ((SCM_REALP (x)) || SCM_FRACTIONP (x))
5270 {
5271 /* Use continued fractions to find closest ratio. All
5272 arithmetic is done with exact numbers.
5273 */
5274
5275 SCM ex = scm_inexact_to_exact (x);
5276 SCM int_part = scm_floor (ex);
5277 SCM tt = SCM_MAKINUM (1);
5278 SCM a1 = SCM_MAKINUM (0), a2 = SCM_MAKINUM (1), a = SCM_MAKINUM (0);
5279 SCM b1 = SCM_MAKINUM (1), b2 = SCM_MAKINUM (0), b = SCM_MAKINUM (0);
5280 SCM rx;
5281 int i = 0;
5282
5283 if (!SCM_FALSEP (scm_num_eq_p (ex, int_part)))
5284 return ex;
5285
5286 ex = scm_difference (ex, int_part); /* x = x-int_part */
5287 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
5288
5289 /* We stop after a million iterations just to be absolutely sure
5290 that we don't go into an infinite loop. The process normally
5291 converges after less than a dozen iterations.
5292 */
5293
5294 err = scm_abs (err);
5295 while (++i < 1000000)
5296 {
5297 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
5298 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
5299 if (SCM_FALSEP (scm_zero_p (b)) && /* b != 0 */
5300 SCM_FALSEP
5301 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
5302 err))) /* abs(x-a/b) <= err */
02164269
MV
5303 {
5304 SCM res = scm_sum (int_part, scm_divide (a, b));
5305 if (SCM_FALSEP (scm_exact_p (x))
5306 || SCM_FALSEP (scm_exact_p (err)))
5307 return scm_exact_to_inexact (res);
5308 else
5309 return res;
5310 }
f92e85f7
MV
5311 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
5312 SCM_UNDEFINED);
5313 tt = scm_floor (rx); /* tt = floor (rx) */
5314 a2 = a1;
5315 b2 = b1;
5316 a1 = a;
5317 b1 = b;
5318 }
5319 scm_num_overflow (s_scm_rationalize);
5320 }
5321 else
5322 SCM_WRONG_TYPE_ARG (1, x);
5323}
5324#undef FUNC_NAME
5325
87617347 5326/* if you need to change this, change test-num2integral.c as well */
ee33d62a 5327#if SCM_SIZEOF_LONG_LONG != 0
1be6b49c
ML
5328# ifndef LLONG_MAX
5329# define ULLONG_MAX ((unsigned long long) (-1))
5330# define LLONG_MAX ((long long) (ULLONG_MAX >> 1))
5331# define LLONG_MIN (~LLONG_MAX)
5332# endif
f872b822 5333#endif
0f2d19dd 5334
3d2e8ceb
MV
5335/* Parameters for creating integer conversion routines.
5336
5337 Define the following preprocessor macros before including
5338 "libguile/num2integral.i.c":
5339
5340 NUM2INTEGRAL - the name of the function for converting from a
ca46fb90
RB
5341 Scheme object to the integral type. This function will be
5342 defined when including "num2integral.i.c".
3d2e8ceb
MV
5343
5344 INTEGRAL2NUM - the name of the function for converting from the
ca46fb90 5345 integral type to a Scheme object. This function will be defined.
3d2e8ceb
MV
5346
5347 INTEGRAL2BIG - the name of an internal function that createas a
ca46fb90
RB
5348 bignum from the integral type. This function will be defined.
5349 The name should start with "scm_i_".
5350
5351 ITYPE - the name of the integral type.
5352
9dd023e1
MV
5353 UNSIGNED - Define this to 1 when ITYPE is an unsigned type. Define
5354 it to 0 otherwise.
ca46fb90
RB
5355
5356 UNSIGNED_ITYPE - the name of the the unsigned variant of the
5357 integral type. If you don't define this, it defaults to
5358 "unsigned ITYPE" for signed types and simply "ITYPE" for unsigned
5359 ones.
5360
5361 SIZEOF_ITYPE - an expression giving the size of the integral type
5362 in bytes. This expression must be computable by the
5363 preprocessor. (SIZEOF_FOO values are calculated by configure.in
5364 for common types).
5365
3d2e8ceb
MV
5366*/
5367
1be6b49c
ML
5368#define NUM2INTEGRAL scm_num2short
5369#define INTEGRAL2NUM scm_short2num
5370#define INTEGRAL2BIG scm_i_short2big
ca46fb90 5371#define UNSIGNED 0
1be6b49c 5372#define ITYPE short
3d2e8ceb 5373#define SIZEOF_ITYPE SIZEOF_SHORT
1be6b49c
ML
5374#include "libguile/num2integral.i.c"
5375
5376#define NUM2INTEGRAL scm_num2ushort
5377#define INTEGRAL2NUM scm_ushort2num
5378#define INTEGRAL2BIG scm_i_ushort2big
ca46fb90 5379#define UNSIGNED 1
1be6b49c 5380#define ITYPE unsigned short
ca46fb90 5381#define SIZEOF_ITYPE SIZEOF_UNSIGNED_SHORT
1be6b49c
ML
5382#include "libguile/num2integral.i.c"
5383
5384#define NUM2INTEGRAL scm_num2int
5385#define INTEGRAL2NUM scm_int2num
5386#define INTEGRAL2BIG scm_i_int2big
ca46fb90 5387#define UNSIGNED 0
1be6b49c 5388#define ITYPE int
3d2e8ceb 5389#define SIZEOF_ITYPE SIZEOF_INT
1be6b49c
ML
5390#include "libguile/num2integral.i.c"
5391
5392#define NUM2INTEGRAL scm_num2uint
5393#define INTEGRAL2NUM scm_uint2num
5394#define INTEGRAL2BIG scm_i_uint2big
ca46fb90 5395#define UNSIGNED 1
1be6b49c 5396#define ITYPE unsigned int
ca46fb90 5397#define SIZEOF_ITYPE SIZEOF_UNSIGNED_INT
1be6b49c
ML
5398#include "libguile/num2integral.i.c"
5399
5400#define NUM2INTEGRAL scm_num2long
5401#define INTEGRAL2NUM scm_long2num
5402#define INTEGRAL2BIG scm_i_long2big
ca46fb90 5403#define UNSIGNED 0
1be6b49c 5404#define ITYPE long
3d2e8ceb 5405#define SIZEOF_ITYPE SIZEOF_LONG
1be6b49c
ML
5406#include "libguile/num2integral.i.c"
5407
5408#define NUM2INTEGRAL scm_num2ulong
5409#define INTEGRAL2NUM scm_ulong2num
5410#define INTEGRAL2BIG scm_i_ulong2big
ca46fb90 5411#define UNSIGNED 1
1be6b49c 5412#define ITYPE unsigned long
ca46fb90 5413#define SIZEOF_ITYPE SIZEOF_UNSIGNED_LONG
1be6b49c
ML
5414#include "libguile/num2integral.i.c"
5415
1be6b49c
ML
5416#define NUM2INTEGRAL scm_num2ptrdiff
5417#define INTEGRAL2NUM scm_ptrdiff2num
5418#define INTEGRAL2BIG scm_i_ptrdiff2big
ca46fb90 5419#define UNSIGNED 0
ee33d62a 5420#define ITYPE scm_t_ptrdiff
3d2e8ceb 5421#define UNSIGNED_ITYPE size_t
ee33d62a 5422#define SIZEOF_ITYPE SCM_SIZEOF_SCM_T_PTRDIFF
1be6b49c
ML
5423#include "libguile/num2integral.i.c"
5424
5425#define NUM2INTEGRAL scm_num2size
5426#define INTEGRAL2NUM scm_size2num
5427#define INTEGRAL2BIG scm_i_size2big
ca46fb90 5428#define UNSIGNED 1
1be6b49c 5429#define ITYPE size_t
3d2e8ceb 5430#define SIZEOF_ITYPE SIZEOF_SIZE_T
1be6b49c 5431#include "libguile/num2integral.i.c"
0f2d19dd 5432
ee33d62a 5433#if SCM_SIZEOF_LONG_LONG != 0
1cc91f1b 5434
caf08e65
MV
5435#ifndef ULONG_LONG_MAX
5436#define ULONG_LONG_MAX (~0ULL)
5437#endif
5438
1be6b49c
ML
5439#define NUM2INTEGRAL scm_num2long_long
5440#define INTEGRAL2NUM scm_long_long2num
5441#define INTEGRAL2BIG scm_i_long_long2big
ca46fb90 5442#define UNSIGNED 0
1be6b49c 5443#define ITYPE long long
3d2e8ceb 5444#define SIZEOF_ITYPE SIZEOF_LONG_LONG
1be6b49c
ML
5445#include "libguile/num2integral.i.c"
5446
5447#define NUM2INTEGRAL scm_num2ulong_long
5448#define INTEGRAL2NUM scm_ulong_long2num
5449#define INTEGRAL2BIG scm_i_ulong_long2big
ca46fb90 5450#define UNSIGNED 1
1be6b49c 5451#define ITYPE unsigned long long
ca46fb90 5452#define SIZEOF_ITYPE SIZEOF_UNSIGNED_LONG_LONG
1be6b49c 5453#include "libguile/num2integral.i.c"
0f2d19dd 5454
ee33d62a 5455#endif /* SCM_SIZEOF_LONG_LONG != 0 */
caf08e65 5456
5437598b
MD
5457#define NUM2FLOAT scm_num2float
5458#define FLOAT2NUM scm_float2num
5459#define FTYPE float
5460#include "libguile/num2float.i.c"
5461
5462#define NUM2FLOAT scm_num2double
5463#define FLOAT2NUM scm_double2num
5464#define FTYPE double
5465#include "libguile/num2float.i.c"
5466
1be6b49c 5467#ifdef GUILE_DEBUG
caf08e65 5468
6063dc1d
SJ
5469#ifndef SIZE_MAX
5470#define SIZE_MAX ((size_t) (-1))
5471#endif
5472#ifndef PTRDIFF_MIN
5473#define PTRDIFF_MIN \
b4fb7de8
RB
5474 ((scm_t_ptrdiff) ((scm_t_ptrdiff) 1 \
5475 << ((sizeof (scm_t_ptrdiff) * SCM_CHAR_BIT) - 1)))
6063dc1d
SJ
5476#endif
5477#ifndef PTRDIFF_MAX
5478#define PTRDIFF_MAX (~ PTRDIFF_MIN)
5479#endif
5480
0aacf84e
MD
5481#define CHECK(type, v) \
5482 do \
5483 { \
5484 if ((v) != scm_num2##type (scm_##type##2num (v), 1, "check_sanity")) \
5485 abort (); \
5486 } \
5487 while (0)
caf08e65 5488
1be6b49c
ML
5489static void
5490check_sanity ()
5491{
5492 CHECK (short, 0);
5493 CHECK (ushort, 0U);
5494 CHECK (int, 0);
5495 CHECK (uint, 0U);
5496 CHECK (long, 0L);
5497 CHECK (ulong, 0UL);
5498 CHECK (size, 0);
5499 CHECK (ptrdiff, 0);
5500
5501 CHECK (short, -1);
5502 CHECK (int, -1);
5503 CHECK (long, -1L);
5504 CHECK (ptrdiff, -1);
5505
5506 CHECK (short, SHRT_MAX);
5507 CHECK (short, SHRT_MIN);
5508 CHECK (ushort, USHRT_MAX);
5509 CHECK (int, INT_MAX);
5510 CHECK (int, INT_MIN);
5511 CHECK (uint, UINT_MAX);
5512 CHECK (long, LONG_MAX);
5513 CHECK (long, LONG_MIN);
5514 CHECK (ulong, ULONG_MAX);
5515 CHECK (size, SIZE_MAX);
5516 CHECK (ptrdiff, PTRDIFF_MAX);
5517 CHECK (ptrdiff, PTRDIFF_MIN);
0f2d19dd 5518
ee33d62a 5519#if SCM_SIZEOF_LONG_LONG != 0
1be6b49c
ML
5520 CHECK (long_long, 0LL);
5521 CHECK (ulong_long, 0ULL);
1be6b49c 5522 CHECK (long_long, -1LL);
1be6b49c
ML
5523 CHECK (long_long, LLONG_MAX);
5524 CHECK (long_long, LLONG_MIN);
5525 CHECK (ulong_long, ULLONG_MAX);
5526#endif
0f2d19dd
JB
5527}
5528
b10586f0
ML
5529#undef CHECK
5530
5531#define CHECK \
5532 scm_internal_catch (SCM_BOOL_T, check_body, &data, check_handler, &data); \
5533 if (!SCM_FALSEP (data)) abort();
5534
5535static SCM
5536check_body (void *data)
5537{
5538 SCM num = *(SCM *) data;
5539 scm_num2ulong (num, 1, NULL);
5540
5541 return SCM_UNSPECIFIED;
5542}
5543
5544static SCM
5545check_handler (void *data, SCM tag, SCM throw_args)
5546{
5547 SCM *num = (SCM *) data;
5548 *num = SCM_BOOL_F;
5549
5550 return SCM_UNSPECIFIED;
5551}
5552
5553SCM_DEFINE (scm_sys_check_number_conversions, "%check-number-conversions", 0, 0, 0,
b4e15479 5554 (void),
b10586f0
ML
5555 "Number conversion sanity checking.")
5556#define FUNC_NAME s_scm_sys_check_number_conversions
5557{
5558 SCM data = SCM_MAKINUM (-1);
5559 CHECK;
5560 data = scm_int2num (INT_MIN);
5561 CHECK;
5562 data = scm_ulong2num (ULONG_MAX);
5563 data = scm_difference (SCM_INUM0, data);
5564 CHECK;
5565 data = scm_ulong2num (ULONG_MAX);
5566 data = scm_sum (SCM_MAKINUM (1), data); data = scm_difference (SCM_INUM0, data);
5567 CHECK;
5568 data = scm_int2num (-10000); data = scm_product (data, data); data = scm_product (data, data);
5569 CHECK;
5570
5571 return SCM_UNSPECIFIED;
5572}
5573#undef FUNC_NAME
5574
1be6b49c 5575#endif
0f2d19dd 5576
0f2d19dd
JB
5577void
5578scm_init_numbers ()
0f2d19dd 5579{
1be6b49c 5580 abs_most_negative_fixnum = scm_i_long2big (- SCM_MOST_NEGATIVE_FIXNUM);
ac0c002c
DH
5581 scm_permanent_object (abs_most_negative_fixnum);
5582
713a4259
KR
5583 mpz_init_set_si (z_negative_one, -1);
5584
a261c0e9
DH
5585 /* It may be possible to tune the performance of some algorithms by using
5586 * the following constants to avoid the creation of bignums. Please, before
5587 * using these values, remember the two rules of program optimization:
5588 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe
MV
5589 scm_c_define ("most-positive-fixnum",
5590 SCM_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
5591 scm_c_define ("most-negative-fixnum",
5592 SCM_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 5593
f3ae5d60
MD
5594 scm_add_feature ("complex");
5595 scm_add_feature ("inexact");
5986c47d 5596 scm_flo0 = scm_make_real (0.0);
f872b822 5597#ifdef DBL_DIG
0f2d19dd 5598 scm_dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG;
f872b822 5599#else
0f2d19dd
JB
5600 { /* determine floating point precision */
5601 double f = 0.1;
f872b822 5602 double fsum = 1.0 + f;
0aacf84e
MD
5603 while (fsum != 1.0)
5604 {
5605 if (++scm_dblprec > 20)
5606 fsum = 1.0;
5607 else
5608 {
5609 f /= 10.0;
5610 fsum = f + 1.0;
5611 }
f872b822
MD
5612 }
5613 scm_dblprec = scm_dblprec - 1;
0f2d19dd 5614 }
f872b822 5615#endif /* DBL_DIG */
1be6b49c
ML
5616
5617#ifdef GUILE_DEBUG
5618 check_sanity ();
5619#endif
f92e85f7
MV
5620
5621 exactly_one_half = scm_permanent_object (scm_divide (SCM_MAKINUM (1),
5622 SCM_MAKINUM (2)));
a0599745 5623#include "libguile/numbers.x"
0f2d19dd 5624}
89e00824
ML
5625
5626/*
5627 Local Variables:
5628 c-file-style: "gnu"
5629 End:
5630*/