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