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