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