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