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