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