(scm_restricted_vector_sort_x): Validate startpos <= endpos. State
[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
5c11cc9d 2221/* convert a long 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
1bbd0b84 2226scm_iint2str (long num, int rad, char *p)
0f2d19dd 2227{
1be6b49c
ML
2228 size_t j = 1;
2229 size_t i;
5c11cc9d
GH
2230 unsigned long n = (num < 0) ? -num : num;
2231
f872b822 2232 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
2233 j++;
2234
2235 i = j;
2236 if (num < 0)
f872b822 2237 {
f872b822 2238 *p++ = '-';
5c11cc9d
GH
2239 j++;
2240 n = -num;
f872b822 2241 }
5c11cc9d
GH
2242 else
2243 n = num;
f872b822
MD
2244 while (i--)
2245 {
5c11cc9d
GH
2246 int d = n % rad;
2247
f872b822
MD
2248 n /= rad;
2249 p[i] = d + ((d < 10) ? '0' : 'a' - 10);
2250 }
0f2d19dd
JB
2251 return j;
2252}
2253
a1ec6916 2254SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
2255 (SCM n, SCM radix),
2256 "Return a string holding the external representation of the\n"
942e5b91
MG
2257 "number @var{n} in the given @var{radix}. If @var{n} is\n"
2258 "inexact, a radix of 10 will be used.")
1bbd0b84 2259#define FUNC_NAME s_scm_number_to_string
0f2d19dd 2260{
1bbd0b84 2261 int base;
98cb6e75 2262
0aacf84e 2263 if (SCM_UNBNDP (radix))
98cb6e75 2264 base = 10;
0aacf84e 2265 else
5efd3c7d 2266 base = scm_to_signed_integer (radix, 2, 36);
98cb6e75 2267
e11e83f3 2268 if (SCM_I_INUMP (n))
0aacf84e
MD
2269 {
2270 char num_buf [SCM_INTBUFLEN];
e11e83f3 2271 size_t length = scm_iint2str (SCM_I_INUM (n), base, num_buf);
cc95e00a 2272 return scm_from_locale_stringn (num_buf, length);
0aacf84e
MD
2273 }
2274 else if (SCM_BIGP (n))
2275 {
2276 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
2277 scm_remember_upto_here_1 (n);
cc95e00a 2278 return scm_take_locale_string (str);
0aacf84e 2279 }
f92e85f7
MV
2280 else if (SCM_FRACTIONP (n))
2281 {
2282 scm_i_fraction_reduce (n);
2283 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
cc95e00a 2284 scm_from_locale_string ("/"),
f92e85f7
MV
2285 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
2286 }
0aacf84e
MD
2287 else if (SCM_INEXACTP (n))
2288 {
2289 char num_buf [FLOBUFLEN];
cc95e00a 2290 return scm_from_locale_stringn (num_buf, iflo2str (n, num_buf, base));
0aacf84e
MD
2291 }
2292 else
bb628794 2293 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 2294}
1bbd0b84 2295#undef FUNC_NAME
0f2d19dd
JB
2296
2297
ca46fb90
RB
2298/* These print routines used to be stubbed here so that scm_repl.c
2299 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 2300
0f2d19dd 2301int
e81d98ec 2302scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2303{
56e55ac7 2304 char num_buf[FLOBUFLEN];
0b799eea 2305 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
0f2d19dd
JB
2306 return !0;
2307}
2308
f3ae5d60 2309int
e81d98ec 2310scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 2311
f3ae5d60 2312{
56e55ac7 2313 char num_buf[FLOBUFLEN];
0b799eea 2314 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
f3ae5d60
MD
2315 return !0;
2316}
1cc91f1b 2317
f92e85f7
MV
2318int
2319scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
2320{
2321 SCM str;
2322 scm_i_fraction_reduce (sexp);
2323 str = scm_number_to_string (sexp, SCM_UNDEFINED);
cc95e00a 2324 scm_lfwrite (scm_i_string_chars (str), scm_i_string_length (str), port);
f92e85f7
MV
2325 scm_remember_upto_here_1 (str);
2326 return !0;
2327}
2328
0f2d19dd 2329int
e81d98ec 2330scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 2331{
ca46fb90
RB
2332 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
2333 scm_remember_upto_here_1 (exp);
2334 scm_lfwrite (str, (size_t) strlen (str), port);
2335 free (str);
0f2d19dd
JB
2336 return !0;
2337}
2338/*** END nums->strs ***/
2339
3c9a524f 2340
0f2d19dd 2341/*** STRINGS -> NUMBERS ***/
2a8fecee 2342
3c9a524f
DH
2343/* The following functions implement the conversion from strings to numbers.
2344 * The implementation somehow follows the grammar for numbers as it is given
2345 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
2346 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
2347 * points should be noted about the implementation:
2348 * * Each function keeps a local index variable 'idx' that points at the
2349 * current position within the parsed string. The global index is only
2350 * updated if the function could parse the corresponding syntactic unit
2351 * successfully.
2352 * * Similarly, the functions keep track of indicators of inexactness ('#',
2353 * '.' or exponents) using local variables ('hash_seen', 'x'). Again, the
2354 * global exactness information is only updated after each part has been
2355 * successfully parsed.
2356 * * Sequences of digits are parsed into temporary variables holding fixnums.
2357 * Only if these fixnums would overflow, the result variables are updated
2358 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
2359 * the temporary variables holding the fixnums are cleared, and the process
2360 * starts over again. If for example fixnums were able to store five decimal
2361 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
2362 * and the result was computed as 12345 * 100000 + 67890. In other words,
2363 * only every five digits two bignum operations were performed.
2364 */
2365
2366enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
2367
2368/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
2369
2370/* In non ASCII-style encodings the following macro might not work. */
71df73ac
KR
2371#define XDIGIT2UINT(d) \
2372 (isdigit ((int) (unsigned char) d) \
2373 ? (d) - '0' \
2374 : tolower ((int) (unsigned char) d) - 'a' + 10)
3c9a524f 2375
2a8fecee 2376static SCM
3c9a524f
DH
2377mem2uinteger (const char* mem, size_t len, unsigned int *p_idx,
2378 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 2379{
3c9a524f
DH
2380 unsigned int idx = *p_idx;
2381 unsigned int hash_seen = 0;
2382 scm_t_bits shift = 1;
2383 scm_t_bits add = 0;
2384 unsigned int digit_value;
2385 SCM result;
2386 char c;
2387
2388 if (idx == len)
2389 return SCM_BOOL_F;
2a8fecee 2390
3c9a524f 2391 c = mem[idx];
71df73ac 2392 if (!isxdigit ((int) (unsigned char) c))
3c9a524f
DH
2393 return SCM_BOOL_F;
2394 digit_value = XDIGIT2UINT (c);
2395 if (digit_value >= radix)
2396 return SCM_BOOL_F;
2397
2398 idx++;
d956fa6f 2399 result = SCM_I_MAKINUM (digit_value);
3c9a524f 2400 while (idx != len)
f872b822 2401 {
3c9a524f 2402 char c = mem[idx];
71df73ac 2403 if (isxdigit ((int) (unsigned char) c))
f872b822 2404 {
3c9a524f 2405 if (hash_seen)
1fe5e088 2406 break;
3c9a524f
DH
2407 digit_value = XDIGIT2UINT (c);
2408 if (digit_value >= radix)
1fe5e088 2409 break;
f872b822 2410 }
3c9a524f
DH
2411 else if (c == '#')
2412 {
2413 hash_seen = 1;
2414 digit_value = 0;
2415 }
2416 else
2417 break;
2418
2419 idx++;
2420 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
2421 {
d956fa6f 2422 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 2423 if (add > 0)
d956fa6f 2424 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2425
2426 shift = radix;
2427 add = digit_value;
2428 }
2429 else
2430 {
2431 shift = shift * radix;
2432 add = add * radix + digit_value;
2433 }
2434 };
2435
2436 if (shift > 1)
d956fa6f 2437 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 2438 if (add > 0)
d956fa6f 2439 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2440
2441 *p_idx = idx;
2442 if (hash_seen)
2443 *p_exactness = INEXACT;
2444
2445 return result;
2a8fecee
JB
2446}
2447
2448
3c9a524f
DH
2449/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
2450 * covers the parts of the rules that start at a potential point. The value
2451 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
2452 * in variable result. The content of *p_exactness indicates, whether a hash
2453 * has already been seen in the digits before the point.
3c9a524f 2454 */
1cc91f1b 2455
3c9a524f
DH
2456/* In non ASCII-style encodings the following macro might not work. */
2457#define DIGIT2UINT(d) ((d) - '0')
2458
2459static SCM
79d34f68 2460mem2decimal_from_point (SCM result, const char* mem, size_t len,
3c9a524f 2461 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 2462{
3c9a524f
DH
2463 unsigned int idx = *p_idx;
2464 enum t_exactness x = *p_exactness;
3c9a524f
DH
2465
2466 if (idx == len)
79d34f68 2467 return result;
3c9a524f
DH
2468
2469 if (mem[idx] == '.')
2470 {
2471 scm_t_bits shift = 1;
2472 scm_t_bits add = 0;
2473 unsigned int digit_value;
d956fa6f 2474 SCM big_shift = SCM_I_MAKINUM (1);
3c9a524f
DH
2475
2476 idx++;
2477 while (idx != len)
2478 {
2479 char c = mem[idx];
71df73ac 2480 if (isdigit ((int) (unsigned char) c))
3c9a524f
DH
2481 {
2482 if (x == INEXACT)
2483 return SCM_BOOL_F;
2484 else
2485 digit_value = DIGIT2UINT (c);
2486 }
2487 else if (c == '#')
2488 {
2489 x = INEXACT;
2490 digit_value = 0;
2491 }
2492 else
2493 break;
2494
2495 idx++;
2496 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
2497 {
d956fa6f
MV
2498 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
2499 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 2500 if (add > 0)
d956fa6f 2501 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2502
2503 shift = 10;
2504 add = digit_value;
2505 }
2506 else
2507 {
2508 shift = shift * 10;
2509 add = add * 10 + digit_value;
2510 }
2511 };
2512
2513 if (add > 0)
2514 {
d956fa6f
MV
2515 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
2516 result = scm_product (result, SCM_I_MAKINUM (shift));
2517 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
2518 }
2519
d8592269 2520 result = scm_divide (result, big_shift);
79d34f68 2521
3c9a524f
DH
2522 /* We've seen a decimal point, thus the value is implicitly inexact. */
2523 x = INEXACT;
f872b822 2524 }
3c9a524f 2525
3c9a524f 2526 if (idx != len)
f872b822 2527 {
3c9a524f
DH
2528 int sign = 1;
2529 unsigned int start;
2530 char c;
2531 int exponent;
2532 SCM e;
2533
2534 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
2535
2536 switch (mem[idx])
f872b822 2537 {
3c9a524f
DH
2538 case 'd': case 'D':
2539 case 'e': case 'E':
2540 case 'f': case 'F':
2541 case 'l': case 'L':
2542 case 's': case 'S':
2543 idx++;
2544 start = idx;
2545 c = mem[idx];
2546 if (c == '-')
2547 {
2548 idx++;
2549 sign = -1;
2550 c = mem[idx];
2551 }
2552 else if (c == '+')
2553 {
2554 idx++;
2555 sign = 1;
2556 c = mem[idx];
2557 }
2558 else
2559 sign = 1;
2560
71df73ac 2561 if (!isdigit ((int) (unsigned char) c))
3c9a524f
DH
2562 return SCM_BOOL_F;
2563
2564 idx++;
2565 exponent = DIGIT2UINT (c);
2566 while (idx != len)
f872b822 2567 {
3c9a524f 2568 char c = mem[idx];
71df73ac 2569 if (isdigit ((int) (unsigned char) c))
3c9a524f
DH
2570 {
2571 idx++;
2572 if (exponent <= SCM_MAXEXP)
2573 exponent = exponent * 10 + DIGIT2UINT (c);
2574 }
2575 else
2576 break;
f872b822 2577 }
3c9a524f
DH
2578
2579 if (exponent > SCM_MAXEXP)
f872b822 2580 {
3c9a524f 2581 size_t exp_len = idx - start;
cc95e00a 2582 SCM exp_string = scm_from_locale_stringn (&mem[start], exp_len);
3c9a524f
DH
2583 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
2584 scm_out_of_range ("string->number", exp_num);
f872b822 2585 }
3c9a524f 2586
d956fa6f 2587 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
2588 if (sign == 1)
2589 result = scm_product (result, e);
2590 else
f92e85f7 2591 result = scm_divide2real (result, e);
3c9a524f
DH
2592
2593 /* We've seen an exponent, thus the value is implicitly inexact. */
2594 x = INEXACT;
2595
f872b822 2596 break;
3c9a524f 2597
f872b822 2598 default:
3c9a524f 2599 break;
f872b822 2600 }
0f2d19dd 2601 }
3c9a524f
DH
2602
2603 *p_idx = idx;
2604 if (x == INEXACT)
2605 *p_exactness = x;
2606
2607 return result;
0f2d19dd 2608}
0f2d19dd 2609
3c9a524f
DH
2610
2611/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
2612
2613static SCM
2614mem2ureal (const char* mem, size_t len, unsigned int *p_idx,
2615 unsigned int radix, enum t_exactness *p_exactness)
0f2d19dd 2616{
3c9a524f 2617 unsigned int idx = *p_idx;
164d2481 2618 SCM result;
3c9a524f
DH
2619
2620 if (idx == len)
2621 return SCM_BOOL_F;
2622
7351e207
MV
2623 if (idx+5 <= len && !strncmp (mem+idx, "inf.0", 5))
2624 {
2625 *p_idx = idx+5;
2626 return scm_inf ();
2627 }
2628
2629 if (idx+4 < len && !strncmp (mem+idx, "nan.", 4))
2630 {
2631 enum t_exactness x = EXACT;
2632
d8592269
MV
2633 /* Cobble up the fractional part. We might want to set the
2634 NaN's mantissa from it. */
7351e207
MV
2635 idx += 4;
2636 mem2uinteger (mem, len, &idx, 10, &x);
2637 *p_idx = idx;
2638 return scm_nan ();
2639 }
2640
3c9a524f
DH
2641 if (mem[idx] == '.')
2642 {
2643 if (radix != 10)
2644 return SCM_BOOL_F;
2645 else if (idx + 1 == len)
2646 return SCM_BOOL_F;
71df73ac 2647 else if (!isdigit ((int) (unsigned char) mem[idx + 1]))
3c9a524f
DH
2648 return SCM_BOOL_F;
2649 else
d956fa6f 2650 result = mem2decimal_from_point (SCM_I_MAKINUM (0), mem, len,
164d2481 2651 p_idx, p_exactness);
f872b822 2652 }
3c9a524f
DH
2653 else
2654 {
2655 enum t_exactness x = EXACT;
2656 SCM uinteger;
3c9a524f
DH
2657
2658 uinteger = mem2uinteger (mem, len, &idx, radix, &x);
73e4de09 2659 if (scm_is_false (uinteger))
3c9a524f
DH
2660 return SCM_BOOL_F;
2661
2662 if (idx == len)
2663 result = uinteger;
2664 else if (mem[idx] == '/')
f872b822 2665 {
3c9a524f
DH
2666 SCM divisor;
2667
2668 idx++;
2669
2670 divisor = mem2uinteger (mem, len, &idx, radix, &x);
73e4de09 2671 if (scm_is_false (divisor))
3c9a524f
DH
2672 return SCM_BOOL_F;
2673
f92e85f7 2674 /* both are int/big here, I assume */
cba42c93 2675 result = scm_i_make_ratio (uinteger, divisor);
f872b822 2676 }
3c9a524f
DH
2677 else if (radix == 10)
2678 {
2679 result = mem2decimal_from_point (uinteger, mem, len, &idx, &x);
73e4de09 2680 if (scm_is_false (result))
3c9a524f
DH
2681 return SCM_BOOL_F;
2682 }
2683 else
2684 result = uinteger;
2685
2686 *p_idx = idx;
2687 if (x == INEXACT)
2688 *p_exactness = x;
f872b822 2689 }
164d2481
MV
2690
2691 /* When returning an inexact zero, make sure it is represented as a
2692 floating point value so that we can change its sign.
2693 */
bc36d050 2694 if (scm_is_eq (result, SCM_I_MAKINUM(0)) && *p_exactness == INEXACT)
55f26379 2695 result = scm_from_double (0.0);
164d2481
MV
2696
2697 return result;
3c9a524f 2698}
0f2d19dd 2699
0f2d19dd 2700
3c9a524f 2701/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 2702
3c9a524f
DH
2703static SCM
2704mem2complex (const char* mem, size_t len, unsigned int idx,
2705 unsigned int radix, enum t_exactness *p_exactness)
2706{
2707 char c;
2708 int sign = 0;
2709 SCM ureal;
2710
2711 if (idx == len)
2712 return SCM_BOOL_F;
2713
2714 c = mem[idx];
2715 if (c == '+')
2716 {
2717 idx++;
2718 sign = 1;
2719 }
2720 else if (c == '-')
2721 {
2722 idx++;
2723 sign = -1;
0f2d19dd 2724 }
0f2d19dd 2725
3c9a524f
DH
2726 if (idx == len)
2727 return SCM_BOOL_F;
2728
2729 ureal = mem2ureal (mem, len, &idx, radix, p_exactness);
73e4de09 2730 if (scm_is_false (ureal))
f872b822 2731 {
3c9a524f
DH
2732 /* input must be either +i or -i */
2733
2734 if (sign == 0)
2735 return SCM_BOOL_F;
2736
2737 if (mem[idx] == 'i' || mem[idx] == 'I')
f872b822 2738 {
3c9a524f
DH
2739 idx++;
2740 if (idx != len)
2741 return SCM_BOOL_F;
2742
d956fa6f 2743 return scm_make_rectangular (SCM_I_MAKINUM (0), SCM_I_MAKINUM (sign));
f872b822 2744 }
3c9a524f
DH
2745 else
2746 return SCM_BOOL_F;
0f2d19dd 2747 }
3c9a524f
DH
2748 else
2749 {
73e4de09 2750 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 2751 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 2752
3c9a524f
DH
2753 if (idx == len)
2754 return ureal;
2755
2756 c = mem[idx];
2757 switch (c)
f872b822 2758 {
3c9a524f
DH
2759 case 'i': case 'I':
2760 /* either +<ureal>i or -<ureal>i */
2761
2762 idx++;
2763 if (sign == 0)
2764 return SCM_BOOL_F;
2765 if (idx != len)
2766 return SCM_BOOL_F;
d956fa6f 2767 return scm_make_rectangular (SCM_I_MAKINUM (0), ureal);
3c9a524f
DH
2768
2769 case '@':
2770 /* polar input: <real>@<real>. */
2771
2772 idx++;
2773 if (idx == len)
2774 return SCM_BOOL_F;
2775 else
f872b822 2776 {
3c9a524f
DH
2777 int sign;
2778 SCM angle;
2779 SCM result;
2780
2781 c = mem[idx];
2782 if (c == '+')
2783 {
2784 idx++;
2785 sign = 1;
2786 }
2787 else if (c == '-')
2788 {
2789 idx++;
2790 sign = -1;
2791 }
2792 else
2793 sign = 1;
2794
2795 angle = mem2ureal (mem, len, &idx, radix, p_exactness);
73e4de09 2796 if (scm_is_false (angle))
3c9a524f
DH
2797 return SCM_BOOL_F;
2798 if (idx != len)
2799 return SCM_BOOL_F;
2800
73e4de09 2801 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
2802 angle = scm_difference (angle, SCM_UNDEFINED);
2803
2804 result = scm_make_polar (ureal, angle);
2805 return result;
f872b822 2806 }
3c9a524f
DH
2807 case '+':
2808 case '-':
2809 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 2810
3c9a524f
DH
2811 idx++;
2812 if (idx == len)
2813 return SCM_BOOL_F;
2814 else
2815 {
2816 int sign = (c == '+') ? 1 : -1;
2817 SCM imag = mem2ureal (mem, len, &idx, radix, p_exactness);
0f2d19dd 2818
73e4de09 2819 if (scm_is_false (imag))
d956fa6f 2820 imag = SCM_I_MAKINUM (sign);
73e4de09 2821 else if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
1fe5e088 2822 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 2823
3c9a524f
DH
2824 if (idx == len)
2825 return SCM_BOOL_F;
2826 if (mem[idx] != 'i' && mem[idx] != 'I')
2827 return SCM_BOOL_F;
0f2d19dd 2828
3c9a524f
DH
2829 idx++;
2830 if (idx != len)
2831 return SCM_BOOL_F;
0f2d19dd 2832
1fe5e088 2833 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
2834 }
2835 default:
2836 return SCM_BOOL_F;
2837 }
2838 }
0f2d19dd 2839}
0f2d19dd
JB
2840
2841
3c9a524f
DH
2842/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
2843
2844enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 2845
0f2d19dd 2846SCM
3c9a524f 2847scm_i_mem2number (const char* mem, size_t len, unsigned int default_radix)
0f2d19dd 2848{
3c9a524f
DH
2849 unsigned int idx = 0;
2850 unsigned int radix = NO_RADIX;
2851 enum t_exactness forced_x = NO_EXACTNESS;
2852 enum t_exactness implicit_x = EXACT;
2853 SCM result;
2854
2855 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
2856 while (idx + 2 < len && mem[idx] == '#')
2857 {
2858 switch (mem[idx + 1])
2859 {
2860 case 'b': case 'B':
2861 if (radix != NO_RADIX)
2862 return SCM_BOOL_F;
2863 radix = DUAL;
2864 break;
2865 case 'd': case 'D':
2866 if (radix != NO_RADIX)
2867 return SCM_BOOL_F;
2868 radix = DEC;
2869 break;
2870 case 'i': case 'I':
2871 if (forced_x != NO_EXACTNESS)
2872 return SCM_BOOL_F;
2873 forced_x = INEXACT;
2874 break;
2875 case 'e': case 'E':
2876 if (forced_x != NO_EXACTNESS)
2877 return SCM_BOOL_F;
2878 forced_x = EXACT;
2879 break;
2880 case 'o': case 'O':
2881 if (radix != NO_RADIX)
2882 return SCM_BOOL_F;
2883 radix = OCT;
2884 break;
2885 case 'x': case 'X':
2886 if (radix != NO_RADIX)
2887 return SCM_BOOL_F;
2888 radix = HEX;
2889 break;
2890 default:
f872b822 2891 return SCM_BOOL_F;
3c9a524f
DH
2892 }
2893 idx += 2;
2894 }
2895
2896 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
2897 if (radix == NO_RADIX)
2898 result = mem2complex (mem, len, idx, default_radix, &implicit_x);
2899 else
2900 result = mem2complex (mem, len, idx, (unsigned int) radix, &implicit_x);
2901
73e4de09 2902 if (scm_is_false (result))
3c9a524f 2903 return SCM_BOOL_F;
f872b822 2904
3c9a524f 2905 switch (forced_x)
f872b822 2906 {
3c9a524f
DH
2907 case EXACT:
2908 if (SCM_INEXACTP (result))
3c9a524f
DH
2909 return scm_inexact_to_exact (result);
2910 else
2911 return result;
2912 case INEXACT:
2913 if (SCM_INEXACTP (result))
2914 return result;
2915 else
2916 return scm_exact_to_inexact (result);
2917 case NO_EXACTNESS:
2918 default:
2919 if (implicit_x == INEXACT)
2920 {
2921 if (SCM_INEXACTP (result))
2922 return result;
2923 else
2924 return scm_exact_to_inexact (result);
2925 }
2926 else
2927 return result;
f872b822 2928 }
0f2d19dd
JB
2929}
2930
2931
a1ec6916 2932SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 2933 (SCM string, SCM radix),
1e6808ea 2934 "Return a number of the maximally precise representation\n"
942e5b91 2935 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
2936 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
2937 "is a default radix that may be overridden by an explicit radix\n"
2938 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
2939 "supplied, then the default radix is 10. If string is not a\n"
2940 "syntactically valid notation for a number, then\n"
2941 "@code{string->number} returns @code{#f}.")
1bbd0b84 2942#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
2943{
2944 SCM answer;
5efd3c7d 2945 unsigned int base;
a6d9e5ab 2946 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
2947
2948 if (SCM_UNBNDP (radix))
2949 base = 10;
2950 else
2951 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
2952
cc95e00a
MV
2953 answer = scm_i_mem2number (scm_i_string_chars (string),
2954 scm_i_string_length (string),
d8592269 2955 base);
8824ac88
MV
2956 scm_remember_upto_here_1 (string);
2957 return answer;
0f2d19dd 2958}
1bbd0b84 2959#undef FUNC_NAME
3c9a524f
DH
2960
2961
0f2d19dd
JB
2962/*** END strs->nums ***/
2963
5986c47d 2964
0f2d19dd 2965SCM
1bbd0b84 2966scm_bigequal (SCM x, SCM y)
0f2d19dd 2967{
47ae1f0e 2968 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
ca46fb90 2969 scm_remember_upto_here_2 (x, y);
73e4de09 2970 return scm_from_bool (0 == result);
0f2d19dd
JB
2971}
2972
0f2d19dd 2973SCM
f3ae5d60 2974scm_real_equalp (SCM x, SCM y)
0f2d19dd 2975{
73e4de09 2976 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0f2d19dd
JB
2977}
2978
f3ae5d60
MD
2979SCM
2980scm_complex_equalp (SCM x, SCM y)
2981{
73e4de09 2982 return scm_from_bool (SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y)
f3ae5d60
MD
2983 && SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y));
2984}
0f2d19dd 2985
f92e85f7
MV
2986SCM
2987scm_i_fraction_equalp (SCM x, SCM y)
2988{
2989 scm_i_fraction_reduce (x);
2990 scm_i_fraction_reduce (y);
73e4de09 2991 if (scm_is_false (scm_equal_p (SCM_FRACTION_NUMERATOR (x),
02164269 2992 SCM_FRACTION_NUMERATOR (y)))
73e4de09 2993 || scm_is_false (scm_equal_p (SCM_FRACTION_DENOMINATOR (x),
02164269
MV
2994 SCM_FRACTION_DENOMINATOR (y))))
2995 return SCM_BOOL_F;
2996 else
2997 return SCM_BOOL_T;
f92e85f7 2998}
0f2d19dd
JB
2999
3000
8507ec80
MV
3001SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
3002 (SCM x),
3003 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
3004 "otherwise.")
3005#define FUNC_NAME s_scm_number_p
3006{
3007 return scm_from_bool (SCM_NUMBERP (x));
3008}
3009#undef FUNC_NAME
3010
3011SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 3012 (SCM x),
942e5b91 3013 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 3014 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
3015 "values form subsets of the set of complex numbers, i. e. the\n"
3016 "predicate will also be fulfilled if @var{x} is a real,\n"
3017 "rational or integer number.")
8507ec80 3018#define FUNC_NAME s_scm_complex_p
0f2d19dd 3019{
8507ec80
MV
3020 /* all numbers are complex. */
3021 return scm_number_p (x);
0f2d19dd 3022}
1bbd0b84 3023#undef FUNC_NAME
0f2d19dd 3024
f92e85f7
MV
3025SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
3026 (SCM x),
3027 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
3028 "otherwise. Note that the set of integer values forms a subset of\n"
3029 "the set of real numbers, i. e. the predicate will also be\n"
3030 "fulfilled if @var{x} is an integer number.")
3031#define FUNC_NAME s_scm_real_p
3032{
3033 /* we can't represent irrational numbers. */
3034 return scm_rational_p (x);
3035}
3036#undef FUNC_NAME
3037
3038SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 3039 (SCM x),
942e5b91 3040 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 3041 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 3042 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
3043 "fulfilled if @var{x} is an integer number.")
3044#define FUNC_NAME s_scm_rational_p
0f2d19dd 3045{
e11e83f3 3046 if (SCM_I_INUMP (x))
0f2d19dd 3047 return SCM_BOOL_T;
0aacf84e 3048 else if (SCM_IMP (x))
0f2d19dd 3049 return SCM_BOOL_F;
0aacf84e 3050 else if (SCM_BIGP (x))
0f2d19dd 3051 return SCM_BOOL_T;
f92e85f7
MV
3052 else if (SCM_FRACTIONP (x))
3053 return SCM_BOOL_T;
3054 else if (SCM_REALP (x))
3055 /* due to their limited precision, all floating point numbers are
3056 rational as well. */
3057 return SCM_BOOL_T;
0aacf84e 3058 else
bb628794 3059 return SCM_BOOL_F;
0f2d19dd 3060}
1bbd0b84 3061#undef FUNC_NAME
0f2d19dd 3062
a1ec6916 3063SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 3064 (SCM x),
942e5b91
MG
3065 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
3066 "else.")
1bbd0b84 3067#define FUNC_NAME s_scm_integer_p
0f2d19dd
JB
3068{
3069 double r;
e11e83f3 3070 if (SCM_I_INUMP (x))
f872b822
MD
3071 return SCM_BOOL_T;
3072 if (SCM_IMP (x))
3073 return SCM_BOOL_F;
f872b822
MD
3074 if (SCM_BIGP (x))
3075 return SCM_BOOL_T;
3c9a524f 3076 if (!SCM_INEXACTP (x))
f872b822 3077 return SCM_BOOL_F;
3c9a524f 3078 if (SCM_COMPLEXP (x))
f872b822 3079 return SCM_BOOL_F;
5986c47d 3080 r = SCM_REAL_VALUE (x);
1e35a229 3081 /* +/-inf passes r==floor(r), making those #t */
f872b822
MD
3082 if (r == floor (r))
3083 return SCM_BOOL_T;
0f2d19dd
JB
3084 return SCM_BOOL_F;
3085}
1bbd0b84 3086#undef FUNC_NAME
0f2d19dd
JB
3087
3088
a1ec6916 3089SCM_DEFINE (scm_inexact_p, "inexact?", 1, 0, 0,
1bbd0b84 3090 (SCM x),
942e5b91
MG
3091 "Return @code{#t} if @var{x} is an inexact number, @code{#f}\n"
3092 "else.")
1bbd0b84 3093#define FUNC_NAME s_scm_inexact_p
0f2d19dd 3094{
eb927cb9
MV
3095 if (SCM_INEXACTP (x))
3096 return SCM_BOOL_T;
3097 if (SCM_NUMBERP (x))
3098 return SCM_BOOL_F;
3099 SCM_WRONG_TYPE_ARG (1, x);
0f2d19dd 3100}
1bbd0b84 3101#undef FUNC_NAME
0f2d19dd
JB
3102
3103
152f82bf 3104SCM_GPROC1 (s_eq_p, "=", scm_tc7_rpsubr, scm_num_eq_p, g_eq_p);
942e5b91 3105/* "Return @code{#t} if all parameters are numerically equal." */
0f2d19dd 3106SCM
6e8d25a6 3107scm_num_eq_p (SCM x, SCM y)
0f2d19dd 3108{
d8b95e27 3109 again:
e11e83f3 3110 if (SCM_I_INUMP (x))
0aacf84e 3111 {
e11e83f3
MV
3112 long xx = SCM_I_INUM (x);
3113 if (SCM_I_INUMP (y))
0aacf84e 3114 {
e11e83f3 3115 long yy = SCM_I_INUM (y);
73e4de09 3116 return scm_from_bool (xx == yy);
0aacf84e
MD
3117 }
3118 else if (SCM_BIGP (y))
3119 return SCM_BOOL_F;
3120 else if (SCM_REALP (y))
73e4de09 3121 return scm_from_bool ((double) xx == SCM_REAL_VALUE (y));
0aacf84e 3122 else if (SCM_COMPLEXP (y))
73e4de09 3123 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 3124 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
3125 else if (SCM_FRACTIONP (y))
3126 return SCM_BOOL_F;
0aacf84e
MD
3127 else
3128 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3129 }
0aacf84e
MD
3130 else if (SCM_BIGP (x))
3131 {
e11e83f3 3132 if (SCM_I_INUMP (y))
0aacf84e
MD
3133 return SCM_BOOL_F;
3134 else if (SCM_BIGP (y))
3135 {
3136 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3137 scm_remember_upto_here_2 (x, y);
73e4de09 3138 return scm_from_bool (0 == cmp);
0aacf84e
MD
3139 }
3140 else if (SCM_REALP (y))
3141 {
3142 int cmp;
3143 if (xisnan (SCM_REAL_VALUE (y)))
3144 return SCM_BOOL_F;
3145 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
3146 scm_remember_upto_here_1 (x);
73e4de09 3147 return scm_from_bool (0 == cmp);
0aacf84e
MD
3148 }
3149 else if (SCM_COMPLEXP (y))
3150 {
3151 int cmp;
3152 if (0.0 != SCM_COMPLEX_IMAG (y))
3153 return SCM_BOOL_F;
3154 if (xisnan (SCM_COMPLEX_REAL (y)))
3155 return SCM_BOOL_F;
3156 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
3157 scm_remember_upto_here_1 (x);
73e4de09 3158 return scm_from_bool (0 == cmp);
0aacf84e 3159 }
f92e85f7
MV
3160 else if (SCM_FRACTIONP (y))
3161 return SCM_BOOL_F;
0aacf84e
MD
3162 else
3163 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f4c627b3 3164 }
0aacf84e
MD
3165 else if (SCM_REALP (x))
3166 {
e11e83f3
MV
3167 if (SCM_I_INUMP (y))
3168 return scm_from_bool (SCM_REAL_VALUE (x) == (double) SCM_I_INUM (y));
0aacf84e
MD
3169 else if (SCM_BIGP (y))
3170 {
3171 int cmp;
3172 if (xisnan (SCM_REAL_VALUE (x)))
3173 return SCM_BOOL_F;
3174 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
3175 scm_remember_upto_here_1 (y);
73e4de09 3176 return scm_from_bool (0 == cmp);
0aacf84e
MD
3177 }
3178 else if (SCM_REALP (y))
73e4de09 3179 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 3180 else if (SCM_COMPLEXP (y))
73e4de09 3181 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 3182 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 3183 else if (SCM_FRACTIONP (y))
d8b95e27
KR
3184 {
3185 double xx = SCM_REAL_VALUE (x);
3186 if (xisnan (xx))
3187 return SCM_BOOL_F;
3188 if (xisinf (xx))
73e4de09 3189 return scm_from_bool (xx < 0.0);
d8b95e27
KR
3190 x = scm_inexact_to_exact (x); /* with x as frac or int */
3191 goto again;
3192 }
0aacf84e
MD
3193 else
3194 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f872b822 3195 }
0aacf84e
MD
3196 else if (SCM_COMPLEXP (x))
3197 {
e11e83f3
MV
3198 if (SCM_I_INUMP (y))
3199 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
3200 && (SCM_COMPLEX_IMAG (x) == 0.0));
3201 else if (SCM_BIGP (y))
3202 {
3203 int cmp;
3204 if (0.0 != SCM_COMPLEX_IMAG (x))
3205 return SCM_BOOL_F;
3206 if (xisnan (SCM_COMPLEX_REAL (x)))
3207 return SCM_BOOL_F;
3208 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
3209 scm_remember_upto_here_1 (y);
73e4de09 3210 return scm_from_bool (0 == cmp);
0aacf84e
MD
3211 }
3212 else if (SCM_REALP (y))
73e4de09 3213 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
3214 && (SCM_COMPLEX_IMAG (x) == 0.0));
3215 else if (SCM_COMPLEXP (y))
73e4de09 3216 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 3217 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 3218 else if (SCM_FRACTIONP (y))
d8b95e27
KR
3219 {
3220 double xx;
3221 if (SCM_COMPLEX_IMAG (x) != 0.0)
3222 return SCM_BOOL_F;
3223 xx = SCM_COMPLEX_REAL (x);
3224 if (xisnan (xx))
3225 return SCM_BOOL_F;
3226 if (xisinf (xx))
73e4de09 3227 return scm_from_bool (xx < 0.0);
d8b95e27
KR
3228 x = scm_inexact_to_exact (x); /* with x as frac or int */
3229 goto again;
3230 }
f92e85f7
MV
3231 else
3232 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
3233 }
3234 else if (SCM_FRACTIONP (x))
3235 {
e11e83f3 3236 if (SCM_I_INUMP (y))
f92e85f7
MV
3237 return SCM_BOOL_F;
3238 else if (SCM_BIGP (y))
3239 return SCM_BOOL_F;
3240 else if (SCM_REALP (y))
d8b95e27
KR
3241 {
3242 double yy = SCM_REAL_VALUE (y);
3243 if (xisnan (yy))
3244 return SCM_BOOL_F;
3245 if (xisinf (yy))
73e4de09 3246 return scm_from_bool (0.0 < yy);
d8b95e27
KR
3247 y = scm_inexact_to_exact (y); /* with y as frac or int */
3248 goto again;
3249 }
f92e85f7 3250 else if (SCM_COMPLEXP (y))
d8b95e27
KR
3251 {
3252 double yy;
3253 if (SCM_COMPLEX_IMAG (y) != 0.0)
3254 return SCM_BOOL_F;
3255 yy = SCM_COMPLEX_REAL (y);
3256 if (xisnan (yy))
3257 return SCM_BOOL_F;
3258 if (xisinf (yy))
73e4de09 3259 return scm_from_bool (0.0 < yy);
d8b95e27
KR
3260 y = scm_inexact_to_exact (y); /* with y as frac or int */
3261 goto again;
3262 }
f92e85f7
MV
3263 else if (SCM_FRACTIONP (y))
3264 return scm_i_fraction_equalp (x, y);
0aacf84e
MD
3265 else
3266 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARGn, s_eq_p);
f4c627b3 3267 }
0aacf84e 3268 else
f4c627b3 3269 SCM_WTA_DISPATCH_2 (g_eq_p, x, y, SCM_ARG1, s_eq_p);
0f2d19dd
JB
3270}
3271
3272
a5f0b599
KR
3273/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
3274 done are good for inums, but for bignums an answer can almost always be
3275 had by just examining a few high bits of the operands, as done by GMP in
3276 mpq_cmp. flonum/frac compares likewise, but with the slight complication
3277 of the float exponent to take into account. */
3278
152f82bf 3279SCM_GPROC1 (s_less_p, "<", scm_tc7_rpsubr, scm_less_p, g_less_p);
942e5b91
MG
3280/* "Return @code{#t} if the list of parameters is monotonically\n"
3281 * "increasing."
3282 */
0f2d19dd 3283SCM
6e8d25a6 3284scm_less_p (SCM x, SCM y)
0f2d19dd 3285{
a5f0b599 3286 again:
e11e83f3 3287 if (SCM_I_INUMP (x))
0aacf84e 3288 {
e11e83f3
MV
3289 long xx = SCM_I_INUM (x);
3290 if (SCM_I_INUMP (y))
0aacf84e 3291 {
e11e83f3 3292 long yy = SCM_I_INUM (y);
73e4de09 3293 return scm_from_bool (xx < yy);
0aacf84e
MD
3294 }
3295 else if (SCM_BIGP (y))
3296 {
3297 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3298 scm_remember_upto_here_1 (y);
73e4de09 3299 return scm_from_bool (sgn > 0);
0aacf84e
MD
3300 }
3301 else if (SCM_REALP (y))
73e4de09 3302 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 3303 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3304 {
3305 /* "x < a/b" becomes "x*b < a" */
3306 int_frac:
3307 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
3308 y = SCM_FRACTION_NUMERATOR (y);
3309 goto again;
3310 }
0aacf84e
MD
3311 else
3312 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3313 }
0aacf84e
MD
3314 else if (SCM_BIGP (x))
3315 {
e11e83f3 3316 if (SCM_I_INUMP (y))
0aacf84e
MD
3317 {
3318 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3319 scm_remember_upto_here_1 (x);
73e4de09 3320 return scm_from_bool (sgn < 0);
0aacf84e
MD
3321 }
3322 else if (SCM_BIGP (y))
3323 {
3324 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3325 scm_remember_upto_here_2 (x, y);
73e4de09 3326 return scm_from_bool (cmp < 0);
0aacf84e
MD
3327 }
3328 else if (SCM_REALP (y))
3329 {
3330 int cmp;
3331 if (xisnan (SCM_REAL_VALUE (y)))
3332 return SCM_BOOL_F;
3333 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
3334 scm_remember_upto_here_1 (x);
73e4de09 3335 return scm_from_bool (cmp < 0);
0aacf84e 3336 }
f92e85f7 3337 else if (SCM_FRACTIONP (y))
a5f0b599 3338 goto int_frac;
0aacf84e
MD
3339 else
3340 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f4c627b3 3341 }
0aacf84e
MD
3342 else if (SCM_REALP (x))
3343 {
e11e83f3
MV
3344 if (SCM_I_INUMP (y))
3345 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
3346 else if (SCM_BIGP (y))
3347 {
3348 int cmp;
3349 if (xisnan (SCM_REAL_VALUE (x)))
3350 return SCM_BOOL_F;
3351 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
3352 scm_remember_upto_here_1 (y);
73e4de09 3353 return scm_from_bool (cmp > 0);
0aacf84e
MD
3354 }
3355 else if (SCM_REALP (y))
73e4de09 3356 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 3357 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3358 {
3359 double xx = SCM_REAL_VALUE (x);
3360 if (xisnan (xx))
3361 return SCM_BOOL_F;
3362 if (xisinf (xx))
73e4de09 3363 return scm_from_bool (xx < 0.0);
a5f0b599
KR
3364 x = scm_inexact_to_exact (x); /* with x as frac or int */
3365 goto again;
3366 }
f92e85f7
MV
3367 else
3368 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
3369 }
3370 else if (SCM_FRACTIONP (x))
3371 {
e11e83f3 3372 if (SCM_I_INUMP (y) || SCM_BIGP (y))
a5f0b599
KR
3373 {
3374 /* "a/b < y" becomes "a < y*b" */
3375 y = scm_product (y, SCM_FRACTION_DENOMINATOR (x));
3376 x = SCM_FRACTION_NUMERATOR (x);
3377 goto again;
3378 }
f92e85f7 3379 else if (SCM_REALP (y))
a5f0b599
KR
3380 {
3381 double yy = SCM_REAL_VALUE (y);
3382 if (xisnan (yy))
3383 return SCM_BOOL_F;
3384 if (xisinf (yy))
73e4de09 3385 return scm_from_bool (0.0 < yy);
a5f0b599
KR
3386 y = scm_inexact_to_exact (y); /* with y as frac or int */
3387 goto again;
3388 }
f92e85f7 3389 else if (SCM_FRACTIONP (y))
a5f0b599
KR
3390 {
3391 /* "a/b < c/d" becomes "a*d < c*b" */
3392 SCM new_x = scm_product (SCM_FRACTION_NUMERATOR (x),
3393 SCM_FRACTION_DENOMINATOR (y));
3394 SCM new_y = scm_product (SCM_FRACTION_NUMERATOR (y),
3395 SCM_FRACTION_DENOMINATOR (x));
3396 x = new_x;
3397 y = new_y;
3398 goto again;
3399 }
0aacf84e
MD
3400 else
3401 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARGn, s_less_p);
f872b822 3402 }
0aacf84e 3403 else
f4c627b3 3404 SCM_WTA_DISPATCH_2 (g_less_p, x, y, SCM_ARG1, s_less_p);
0f2d19dd
JB
3405}
3406
3407
c76b1eaf 3408SCM_GPROC1 (s_scm_gr_p, ">", scm_tc7_rpsubr, scm_gr_p, g_gr_p);
942e5b91
MG
3409/* "Return @code{#t} if the list of parameters is monotonically\n"
3410 * "decreasing."
c76b1eaf 3411 */
1bbd0b84 3412#define FUNC_NAME s_scm_gr_p
c76b1eaf
MD
3413SCM
3414scm_gr_p (SCM x, SCM y)
0f2d19dd 3415{
c76b1eaf
MD
3416 if (!SCM_NUMBERP (x))
3417 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG1, FUNC_NAME);
3418 else if (!SCM_NUMBERP (y))
3419 SCM_WTA_DISPATCH_2 (g_gr_p, x, y, SCM_ARG2, FUNC_NAME);
3420 else
3421 return scm_less_p (y, x);
0f2d19dd 3422}
1bbd0b84 3423#undef FUNC_NAME
0f2d19dd
JB
3424
3425
c76b1eaf 3426SCM_GPROC1 (s_scm_leq_p, "<=", scm_tc7_rpsubr, scm_leq_p, g_leq_p);
942e5b91 3427/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3428 * "non-decreasing."
3429 */
1bbd0b84 3430#define FUNC_NAME s_scm_leq_p
c76b1eaf
MD
3431SCM
3432scm_leq_p (SCM x, SCM y)
0f2d19dd 3433{
c76b1eaf
MD
3434 if (!SCM_NUMBERP (x))
3435 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG1, FUNC_NAME);
3436 else if (!SCM_NUMBERP (y))
3437 SCM_WTA_DISPATCH_2 (g_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 3438 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 3439 return SCM_BOOL_F;
c76b1eaf 3440 else
73e4de09 3441 return scm_not (scm_less_p (y, x));
0f2d19dd 3442}
1bbd0b84 3443#undef FUNC_NAME
0f2d19dd
JB
3444
3445
c76b1eaf 3446SCM_GPROC1 (s_scm_geq_p, ">=", scm_tc7_rpsubr, scm_geq_p, g_geq_p);
942e5b91 3447/* "Return @code{#t} if the list of parameters is monotonically\n"
c76b1eaf
MD
3448 * "non-increasing."
3449 */
1bbd0b84 3450#define FUNC_NAME s_scm_geq_p
c76b1eaf
MD
3451SCM
3452scm_geq_p (SCM x, SCM y)
0f2d19dd 3453{
c76b1eaf
MD
3454 if (!SCM_NUMBERP (x))
3455 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG1, FUNC_NAME);
3456 else if (!SCM_NUMBERP (y))
3457 SCM_WTA_DISPATCH_2 (g_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 3458 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 3459 return SCM_BOOL_F;
c76b1eaf 3460 else
73e4de09 3461 return scm_not (scm_less_p (x, y));
0f2d19dd 3462}
1bbd0b84 3463#undef FUNC_NAME
0f2d19dd
JB
3464
3465
152f82bf 3466SCM_GPROC (s_zero_p, "zero?", 1, 0, 0, scm_zero_p, g_zero_p);
942e5b91
MG
3467/* "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
3468 * "zero."
3469 */
0f2d19dd 3470SCM
6e8d25a6 3471scm_zero_p (SCM z)
0f2d19dd 3472{
e11e83f3 3473 if (SCM_I_INUMP (z))
bc36d050 3474 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 3475 else if (SCM_BIGP (z))
c2ff8ab0 3476 return SCM_BOOL_F;
0aacf84e 3477 else if (SCM_REALP (z))
73e4de09 3478 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 3479 else if (SCM_COMPLEXP (z))
73e4de09 3480 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 3481 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
3482 else if (SCM_FRACTIONP (z))
3483 return SCM_BOOL_F;
0aacf84e 3484 else
c2ff8ab0 3485 SCM_WTA_DISPATCH_1 (g_zero_p, z, SCM_ARG1, s_zero_p);
0f2d19dd
JB
3486}
3487
3488
152f82bf 3489SCM_GPROC (s_positive_p, "positive?", 1, 0, 0, scm_positive_p, g_positive_p);
942e5b91
MG
3490/* "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
3491 * "zero."
3492 */
0f2d19dd 3493SCM
6e8d25a6 3494scm_positive_p (SCM x)
0f2d19dd 3495{
e11e83f3
MV
3496 if (SCM_I_INUMP (x))
3497 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
3498 else if (SCM_BIGP (x))
3499 {
3500 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3501 scm_remember_upto_here_1 (x);
73e4de09 3502 return scm_from_bool (sgn > 0);
0aacf84e
MD
3503 }
3504 else if (SCM_REALP (x))
73e4de09 3505 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
3506 else if (SCM_FRACTIONP (x))
3507 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 3508 else
c2ff8ab0 3509 SCM_WTA_DISPATCH_1 (g_positive_p, x, SCM_ARG1, s_positive_p);
0f2d19dd
JB
3510}
3511
3512
152f82bf 3513SCM_GPROC (s_negative_p, "negative?", 1, 0, 0, scm_negative_p, g_negative_p);
942e5b91
MG
3514/* "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
3515 * "zero."
3516 */
0f2d19dd 3517SCM
6e8d25a6 3518scm_negative_p (SCM x)
0f2d19dd 3519{
e11e83f3
MV
3520 if (SCM_I_INUMP (x))
3521 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
3522 else if (SCM_BIGP (x))
3523 {
3524 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3525 scm_remember_upto_here_1 (x);
73e4de09 3526 return scm_from_bool (sgn < 0);
0aacf84e
MD
3527 }
3528 else if (SCM_REALP (x))
73e4de09 3529 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
3530 else if (SCM_FRACTIONP (x))
3531 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 3532 else
c2ff8ab0 3533 SCM_WTA_DISPATCH_1 (g_negative_p, x, SCM_ARG1, s_negative_p);
0f2d19dd
JB
3534}
3535
3536
2a06f791
KR
3537/* scm_min and scm_max return an inexact when either argument is inexact, as
3538 required by r5rs. On that basis, for exact/inexact combinations the
3539 exact is converted to inexact to compare and possibly return. This is
3540 unlike scm_less_p above which takes some trouble to preserve all bits in
3541 its test, such trouble is not required for min and max. */
3542
9de33deb 3543SCM_GPROC1 (s_max, "max", scm_tc7_asubr, scm_max, g_max);
942e5b91
MG
3544/* "Return the maximum of all parameter values."
3545 */
0f2d19dd 3546SCM
6e8d25a6 3547scm_max (SCM x, SCM y)
0f2d19dd 3548{
0aacf84e
MD
3549 if (SCM_UNBNDP (y))
3550 {
3551 if (SCM_UNBNDP (x))
3552 SCM_WTA_DISPATCH_0 (g_max, s_max);
e11e83f3 3553 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
3554 return x;
3555 else
3556 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 3557 }
f4c627b3 3558
e11e83f3 3559 if (SCM_I_INUMP (x))
0aacf84e 3560 {
e11e83f3
MV
3561 long xx = SCM_I_INUM (x);
3562 if (SCM_I_INUMP (y))
0aacf84e 3563 {
e11e83f3 3564 long yy = SCM_I_INUM (y);
0aacf84e
MD
3565 return (xx < yy) ? y : x;
3566 }
3567 else if (SCM_BIGP (y))
3568 {
3569 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3570 scm_remember_upto_here_1 (y);
3571 return (sgn < 0) ? x : y;
3572 }
3573 else if (SCM_REALP (y))
3574 {
3575 double z = xx;
3576 /* if y==NaN then ">" is false and we return NaN */
55f26379 3577 return (z > SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 3578 }
f92e85f7
MV
3579 else if (SCM_FRACTIONP (y))
3580 {
e4bc5d6c 3581 use_less:
73e4de09 3582 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 3583 }
0aacf84e
MD
3584 else
3585 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3586 }
0aacf84e
MD
3587 else if (SCM_BIGP (x))
3588 {
e11e83f3 3589 if (SCM_I_INUMP (y))
0aacf84e
MD
3590 {
3591 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3592 scm_remember_upto_here_1 (x);
3593 return (sgn < 0) ? y : x;
3594 }
3595 else if (SCM_BIGP (y))
3596 {
3597 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3598 scm_remember_upto_here_2 (x, y);
3599 return (cmp > 0) ? x : y;
3600 }
3601 else if (SCM_REALP (y))
3602 {
2a06f791
KR
3603 /* if y==NaN then xx>yy is false, so we return the NaN y */
3604 double xx, yy;
3605 big_real:
3606 xx = scm_i_big2dbl (x);
3607 yy = SCM_REAL_VALUE (y);
55f26379 3608 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 3609 }
f92e85f7
MV
3610 else if (SCM_FRACTIONP (y))
3611 {
e4bc5d6c 3612 goto use_less;
f92e85f7 3613 }
0aacf84e
MD
3614 else
3615 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 3616 }
0aacf84e
MD
3617 else if (SCM_REALP (x))
3618 {
e11e83f3 3619 if (SCM_I_INUMP (y))
0aacf84e 3620 {
e11e83f3 3621 double z = SCM_I_INUM (y);
0aacf84e 3622 /* if x==NaN then "<" is false and we return NaN */
55f26379 3623 return (SCM_REAL_VALUE (x) < z) ? scm_from_double (z) : x;
0aacf84e
MD
3624 }
3625 else if (SCM_BIGP (y))
3626 {
b6f8f763 3627 SCM_SWAP (x, y);
2a06f791 3628 goto big_real;
0aacf84e
MD
3629 }
3630 else if (SCM_REALP (y))
3631 {
3632 /* if x==NaN then our explicit check means we return NaN
3633 if y==NaN then ">" is false and we return NaN
3634 calling isnan is unavoidable, since it's the only way to know
3635 which of x or y causes any compares to be false */
3636 double xx = SCM_REAL_VALUE (x);
3637 return (xisnan (xx) || xx > SCM_REAL_VALUE (y)) ? x : y;
3638 }
f92e85f7
MV
3639 else if (SCM_FRACTIONP (y))
3640 {
3641 double yy = scm_i_fraction2double (y);
3642 double xx = SCM_REAL_VALUE (x);
55f26379 3643 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
3644 }
3645 else
3646 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3647 }
3648 else if (SCM_FRACTIONP (x))
3649 {
e11e83f3 3650 if (SCM_I_INUMP (y))
f92e85f7 3651 {
e4bc5d6c 3652 goto use_less;
f92e85f7
MV
3653 }
3654 else if (SCM_BIGP (y))
3655 {
e4bc5d6c 3656 goto use_less;
f92e85f7
MV
3657 }
3658 else if (SCM_REALP (y))
3659 {
3660 double xx = scm_i_fraction2double (x);
55f26379 3661 return (xx < SCM_REAL_VALUE (y)) ? y : scm_from_double (xx);
f92e85f7
MV
3662 }
3663 else if (SCM_FRACTIONP (y))
3664 {
e4bc5d6c 3665 goto use_less;
f92e85f7 3666 }
0aacf84e
MD
3667 else
3668 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 3669 }
0aacf84e 3670 else
f4c627b3 3671 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
3672}
3673
3674
9de33deb 3675SCM_GPROC1 (s_min, "min", scm_tc7_asubr, scm_min, g_min);
942e5b91
MG
3676/* "Return the minium of all parameter values."
3677 */
0f2d19dd 3678SCM
6e8d25a6 3679scm_min (SCM x, SCM y)
0f2d19dd 3680{
0aacf84e
MD
3681 if (SCM_UNBNDP (y))
3682 {
3683 if (SCM_UNBNDP (x))
3684 SCM_WTA_DISPATCH_0 (g_min, s_min);
e11e83f3 3685 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
3686 return x;
3687 else
3688 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 3689 }
f4c627b3 3690
e11e83f3 3691 if (SCM_I_INUMP (x))
0aacf84e 3692 {
e11e83f3
MV
3693 long xx = SCM_I_INUM (x);
3694 if (SCM_I_INUMP (y))
0aacf84e 3695 {
e11e83f3 3696 long yy = SCM_I_INUM (y);
0aacf84e
MD
3697 return (xx < yy) ? x : y;
3698 }
3699 else if (SCM_BIGP (y))
3700 {
3701 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
3702 scm_remember_upto_here_1 (y);
3703 return (sgn < 0) ? y : x;
3704 }
3705 else if (SCM_REALP (y))
3706 {
3707 double z = xx;
3708 /* if y==NaN then "<" is false and we return NaN */
55f26379 3709 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 3710 }
f92e85f7
MV
3711 else if (SCM_FRACTIONP (y))
3712 {
e4bc5d6c 3713 use_less:
73e4de09 3714 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 3715 }
0aacf84e
MD
3716 else
3717 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3718 }
0aacf84e
MD
3719 else if (SCM_BIGP (x))
3720 {
e11e83f3 3721 if (SCM_I_INUMP (y))
0aacf84e
MD
3722 {
3723 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3724 scm_remember_upto_here_1 (x);
3725 return (sgn < 0) ? x : y;
3726 }
3727 else if (SCM_BIGP (y))
3728 {
3729 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3730 scm_remember_upto_here_2 (x, y);
3731 return (cmp > 0) ? y : x;
3732 }
3733 else if (SCM_REALP (y))
3734 {
2a06f791
KR
3735 /* if y==NaN then xx<yy is false, so we return the NaN y */
3736 double xx, yy;
3737 big_real:
3738 xx = scm_i_big2dbl (x);
3739 yy = SCM_REAL_VALUE (y);
55f26379 3740 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 3741 }
f92e85f7
MV
3742 else if (SCM_FRACTIONP (y))
3743 {
e4bc5d6c 3744 goto use_less;
f92e85f7 3745 }
0aacf84e
MD
3746 else
3747 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 3748 }
0aacf84e
MD
3749 else if (SCM_REALP (x))
3750 {
e11e83f3 3751 if (SCM_I_INUMP (y))
0aacf84e 3752 {
e11e83f3 3753 double z = SCM_I_INUM (y);
0aacf84e 3754 /* if x==NaN then "<" is false and we return NaN */
55f26379 3755 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
3756 }
3757 else if (SCM_BIGP (y))
3758 {
b6f8f763 3759 SCM_SWAP (x, y);
2a06f791 3760 goto big_real;
0aacf84e
MD
3761 }
3762 else if (SCM_REALP (y))
3763 {
3764 /* if x==NaN then our explicit check means we return NaN
3765 if y==NaN then "<" is false and we return NaN
3766 calling isnan is unavoidable, since it's the only way to know
3767 which of x or y causes any compares to be false */
3768 double xx = SCM_REAL_VALUE (x);
3769 return (xisnan (xx) || xx < SCM_REAL_VALUE (y)) ? x : y;
3770 }
f92e85f7
MV
3771 else if (SCM_FRACTIONP (y))
3772 {
3773 double yy = scm_i_fraction2double (y);
3774 double xx = SCM_REAL_VALUE (x);
55f26379 3775 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 3776 }
0aacf84e
MD
3777 else
3778 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 3779 }
f92e85f7
MV
3780 else if (SCM_FRACTIONP (x))
3781 {
e11e83f3 3782 if (SCM_I_INUMP (y))
f92e85f7 3783 {
e4bc5d6c 3784 goto use_less;
f92e85f7
MV
3785 }
3786 else if (SCM_BIGP (y))
3787 {
e4bc5d6c 3788 goto use_less;
f92e85f7
MV
3789 }
3790 else if (SCM_REALP (y))
3791 {
3792 double xx = scm_i_fraction2double (x);
55f26379 3793 return (SCM_REAL_VALUE (y) < xx) ? y : scm_from_double (xx);
f92e85f7
MV
3794 }
3795 else if (SCM_FRACTIONP (y))
3796 {
e4bc5d6c 3797 goto use_less;
f92e85f7
MV
3798 }
3799 else
3800 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
3801 }
0aacf84e 3802 else
f4c627b3 3803 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
3804}
3805
3806
9de33deb 3807SCM_GPROC1 (s_sum, "+", scm_tc7_asubr, scm_sum, g_sum);
942e5b91
MG
3808/* "Return the sum of all parameter values. Return 0 if called without\n"
3809 * "any parameters."
3810 */
0f2d19dd 3811SCM
6e8d25a6 3812scm_sum (SCM x, SCM y)
0f2d19dd 3813{
ca46fb90
RB
3814 if (SCM_UNBNDP (y))
3815 {
3816 if (SCM_NUMBERP (x)) return x;
3817 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 3818 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 3819 }
c209c88e 3820
e11e83f3 3821 if (SCM_I_INUMP (x))
ca46fb90 3822 {
e11e83f3 3823 if (SCM_I_INUMP (y))
ca46fb90 3824 {
e11e83f3
MV
3825 long xx = SCM_I_INUM (x);
3826 long yy = SCM_I_INUM (y);
ca46fb90 3827 long int z = xx + yy;
d956fa6f 3828 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_long2big (z);
ca46fb90
RB
3829 }
3830 else if (SCM_BIGP (y))
3831 {
3832 SCM_SWAP (x, y);
3833 goto add_big_inum;
3834 }
3835 else if (SCM_REALP (y))
3836 {
e11e83f3 3837 long int xx = SCM_I_INUM (x);
55f26379 3838 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
3839 }
3840 else if (SCM_COMPLEXP (y))
3841 {
e11e83f3 3842 long int xx = SCM_I_INUM (x);
8507ec80 3843 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
3844 SCM_COMPLEX_IMAG (y));
3845 }
f92e85f7 3846 else if (SCM_FRACTIONP (y))
cba42c93 3847 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
3848 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
3849 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
3850 else
3851 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
3852 } else if (SCM_BIGP (x))
3853 {
e11e83f3 3854 if (SCM_I_INUMP (y))
0aacf84e
MD
3855 {
3856 long int inum;
3857 int bigsgn;
3858 add_big_inum:
e11e83f3 3859 inum = SCM_I_INUM (y);
0aacf84e
MD
3860 if (inum == 0)
3861 return x;
3862 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
3863 if (inum < 0)
3864 {
3865 SCM result = scm_i_mkbig ();
3866 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
3867 scm_remember_upto_here_1 (x);
3868 /* we know the result will have to be a bignum */
3869 if (bigsgn == -1)
3870 return result;
3871 return scm_i_normbig (result);
3872 }
3873 else
3874 {
3875 SCM result = scm_i_mkbig ();
3876 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
3877 scm_remember_upto_here_1 (x);
3878 /* we know the result will have to be a bignum */
3879 if (bigsgn == 1)
3880 return result;
3881 return scm_i_normbig (result);
3882 }
3883 }
3884 else if (SCM_BIGP (y))
3885 {
3886 SCM result = scm_i_mkbig ();
3887 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
3888 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
3889 mpz_add (SCM_I_BIG_MPZ (result),
3890 SCM_I_BIG_MPZ (x),
3891 SCM_I_BIG_MPZ (y));
3892 scm_remember_upto_here_2 (x, y);
3893 /* we know the result will have to be a bignum */
3894 if (sgn_x == sgn_y)
3895 return result;
3896 return scm_i_normbig (result);
3897 }
3898 else if (SCM_REALP (y))
3899 {
3900 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
3901 scm_remember_upto_here_1 (x);
55f26379 3902 return scm_from_double (result);
0aacf84e
MD
3903 }
3904 else if (SCM_COMPLEXP (y))
3905 {
3906 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
3907 + SCM_COMPLEX_REAL (y));
3908 scm_remember_upto_here_1 (x);
8507ec80 3909 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 3910 }
f92e85f7 3911 else if (SCM_FRACTIONP (y))
cba42c93 3912 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
3913 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
3914 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
3915 else
3916 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 3917 }
0aacf84e
MD
3918 else if (SCM_REALP (x))
3919 {
e11e83f3 3920 if (SCM_I_INUMP (y))
55f26379 3921 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
3922 else if (SCM_BIGP (y))
3923 {
3924 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
3925 scm_remember_upto_here_1 (y);
55f26379 3926 return scm_from_double (result);
0aacf84e
MD
3927 }
3928 else if (SCM_REALP (y))
55f26379 3929 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 3930 else if (SCM_COMPLEXP (y))
8507ec80 3931 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 3932 SCM_COMPLEX_IMAG (y));
f92e85f7 3933 else if (SCM_FRACTIONP (y))
55f26379 3934 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
3935 else
3936 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 3937 }
0aacf84e
MD
3938 else if (SCM_COMPLEXP (x))
3939 {
e11e83f3 3940 if (SCM_I_INUMP (y))
8507ec80 3941 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
3942 SCM_COMPLEX_IMAG (x));
3943 else if (SCM_BIGP (y))
3944 {
3945 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
3946 + SCM_COMPLEX_REAL (x));
3947 scm_remember_upto_here_1 (y);
8507ec80 3948 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
3949 }
3950 else if (SCM_REALP (y))
8507ec80 3951 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
3952 SCM_COMPLEX_IMAG (x));
3953 else if (SCM_COMPLEXP (y))
8507ec80 3954 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 3955 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 3956 else if (SCM_FRACTIONP (y))
8507ec80 3957 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
3958 SCM_COMPLEX_IMAG (x));
3959 else
3960 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
3961 }
3962 else if (SCM_FRACTIONP (x))
3963 {
e11e83f3 3964 if (SCM_I_INUMP (y))
cba42c93 3965 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
3966 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
3967 SCM_FRACTION_DENOMINATOR (x));
3968 else if (SCM_BIGP (y))
cba42c93 3969 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
3970 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
3971 SCM_FRACTION_DENOMINATOR (x));
3972 else if (SCM_REALP (y))
55f26379 3973 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 3974 else if (SCM_COMPLEXP (y))
8507ec80 3975 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
3976 SCM_COMPLEX_IMAG (y));
3977 else if (SCM_FRACTIONP (y))
3978 /* a/b + c/d = (ad + bc) / bd */
cba42c93 3979 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
3980 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
3981 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
3982 else
3983 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 3984 }
0aacf84e 3985 else
98cb6e75 3986 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
3987}
3988
3989
9de33deb 3990SCM_GPROC1 (s_difference, "-", scm_tc7_asubr, scm_difference, g_difference);
609c3d30
MG
3991/* If called with one argument @var{z1}, -@var{z1} returned. Otherwise
3992 * the sum of all but the first argument are subtracted from the first
3993 * argument. */
c05e97b7 3994#define FUNC_NAME s_difference
0f2d19dd 3995SCM
6e8d25a6 3996scm_difference (SCM x, SCM y)
0f2d19dd 3997{
ca46fb90
RB
3998 if (SCM_UNBNDP (y))
3999 {
4000 if (SCM_UNBNDP (x))
4001 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
4002 else
e11e83f3 4003 if (SCM_I_INUMP (x))
ca46fb90 4004 {
e11e83f3 4005 long xx = -SCM_I_INUM (x);
ca46fb90 4006 if (SCM_FIXABLE (xx))
d956fa6f 4007 return SCM_I_MAKINUM (xx);
ca46fb90
RB
4008 else
4009 return scm_i_long2big (xx);
4010 }
4011 else if (SCM_BIGP (x))
4012 /* FIXME: do we really need to normalize here? */
4013 return scm_i_normbig (scm_i_clonebig (x, 0));
4014 else if (SCM_REALP (x))
55f26379 4015 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 4016 else if (SCM_COMPLEXP (x))
8507ec80 4017 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 4018 -SCM_COMPLEX_IMAG (x));
f92e85f7 4019 else if (SCM_FRACTIONP (x))
cba42c93 4020 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 4021 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
4022 else
4023 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 4024 }
ca46fb90 4025
e11e83f3 4026 if (SCM_I_INUMP (x))
0aacf84e 4027 {
e11e83f3 4028 if (SCM_I_INUMP (y))
0aacf84e 4029 {
e11e83f3
MV
4030 long int xx = SCM_I_INUM (x);
4031 long int yy = SCM_I_INUM (y);
0aacf84e
MD
4032 long int z = xx - yy;
4033 if (SCM_FIXABLE (z))
d956fa6f 4034 return SCM_I_MAKINUM (z);
0aacf84e
MD
4035 else
4036 return scm_i_long2big (z);
4037 }
4038 else if (SCM_BIGP (y))
4039 {
4040 /* inum-x - big-y */
e11e83f3 4041 long xx = SCM_I_INUM (x);
ca46fb90 4042
0aacf84e
MD
4043 if (xx == 0)
4044 return scm_i_clonebig (y, 0);
4045 else
4046 {
4047 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
4048 SCM result = scm_i_mkbig ();
ca46fb90 4049
0aacf84e
MD
4050 if (xx >= 0)
4051 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
4052 else
4053 {
4054 /* x - y == -(y + -x) */
4055 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
4056 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
4057 }
4058 scm_remember_upto_here_1 (y);
ca46fb90 4059
0aacf84e
MD
4060 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
4061 /* we know the result will have to be a bignum */
4062 return result;
4063 else
4064 return scm_i_normbig (result);
4065 }
4066 }
4067 else if (SCM_REALP (y))
4068 {
e11e83f3 4069 long int xx = SCM_I_INUM (x);
55f26379 4070 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
4071 }
4072 else if (SCM_COMPLEXP (y))
4073 {
e11e83f3 4074 long int xx = SCM_I_INUM (x);
8507ec80 4075 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
0aacf84e
MD
4076 - SCM_COMPLEX_IMAG (y));
4077 }
f92e85f7
MV
4078 else if (SCM_FRACTIONP (y))
4079 /* a - b/c = (ac - b) / c */
cba42c93 4080 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4081 SCM_FRACTION_NUMERATOR (y)),
4082 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4083 else
4084 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 4085 }
0aacf84e
MD
4086 else if (SCM_BIGP (x))
4087 {
e11e83f3 4088 if (SCM_I_INUMP (y))
0aacf84e
MD
4089 {
4090 /* big-x - inum-y */
e11e83f3 4091 long yy = SCM_I_INUM (y);
0aacf84e 4092 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 4093
0aacf84e
MD
4094 scm_remember_upto_here_1 (x);
4095 if (sgn_x == 0)
c71b0706
MV
4096 return (SCM_FIXABLE (-yy) ?
4097 SCM_I_MAKINUM (-yy) : scm_from_long (-yy));
0aacf84e
MD
4098 else
4099 {
4100 SCM result = scm_i_mkbig ();
ca46fb90 4101
708f22c6
KR
4102 if (yy >= 0)
4103 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
4104 else
4105 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 4106 scm_remember_upto_here_1 (x);
ca46fb90 4107
0aacf84e
MD
4108 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
4109 /* we know the result will have to be a bignum */
4110 return result;
4111 else
4112 return scm_i_normbig (result);
4113 }
4114 }
4115 else if (SCM_BIGP (y))
4116 {
4117 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
4118 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
4119 SCM result = scm_i_mkbig ();
4120 mpz_sub (SCM_I_BIG_MPZ (result),
4121 SCM_I_BIG_MPZ (x),
4122 SCM_I_BIG_MPZ (y));
4123 scm_remember_upto_here_2 (x, y);
4124 /* we know the result will have to be a bignum */
4125 if ((sgn_x == 1) && (sgn_y == -1))
4126 return result;
4127 if ((sgn_x == -1) && (sgn_y == 1))
4128 return result;
4129 return scm_i_normbig (result);
4130 }
4131 else if (SCM_REALP (y))
4132 {
4133 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
4134 scm_remember_upto_here_1 (x);
55f26379 4135 return scm_from_double (result);
0aacf84e
MD
4136 }
4137 else if (SCM_COMPLEXP (y))
4138 {
4139 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
4140 - SCM_COMPLEX_REAL (y));
4141 scm_remember_upto_here_1 (x);
8507ec80 4142 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 4143 }
f92e85f7 4144 else if (SCM_FRACTIONP (y))
cba42c93 4145 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4146 SCM_FRACTION_NUMERATOR (y)),
4147 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 4148 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 4149 }
0aacf84e
MD
4150 else if (SCM_REALP (x))
4151 {
e11e83f3 4152 if (SCM_I_INUMP (y))
55f26379 4153 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
4154 else if (SCM_BIGP (y))
4155 {
4156 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
4157 scm_remember_upto_here_1 (x);
55f26379 4158 return scm_from_double (result);
0aacf84e
MD
4159 }
4160 else if (SCM_REALP (y))
55f26379 4161 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 4162 else if (SCM_COMPLEXP (y))
8507ec80 4163 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 4164 -SCM_COMPLEX_IMAG (y));
f92e85f7 4165 else if (SCM_FRACTIONP (y))
55f26379 4166 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
4167 else
4168 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 4169 }
0aacf84e
MD
4170 else if (SCM_COMPLEXP (x))
4171 {
e11e83f3 4172 if (SCM_I_INUMP (y))
8507ec80 4173 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
4174 SCM_COMPLEX_IMAG (x));
4175 else if (SCM_BIGP (y))
4176 {
4177 double real_part = (SCM_COMPLEX_REAL (x)
4178 - mpz_get_d (SCM_I_BIG_MPZ (y)));
4179 scm_remember_upto_here_1 (x);
8507ec80 4180 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
4181 }
4182 else if (SCM_REALP (y))
8507ec80 4183 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
4184 SCM_COMPLEX_IMAG (x));
4185 else if (SCM_COMPLEXP (y))
8507ec80 4186 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 4187 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 4188 else if (SCM_FRACTIONP (y))
8507ec80 4189 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
4190 SCM_COMPLEX_IMAG (x));
4191 else
4192 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
4193 }
4194 else if (SCM_FRACTIONP (x))
4195 {
e11e83f3 4196 if (SCM_I_INUMP (y))
f92e85f7 4197 /* a/b - c = (a - cb) / b */
cba42c93 4198 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4199 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
4200 SCM_FRACTION_DENOMINATOR (x));
4201 else if (SCM_BIGP (y))
cba42c93 4202 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4203 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
4204 SCM_FRACTION_DENOMINATOR (x));
4205 else if (SCM_REALP (y))
55f26379 4206 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 4207 else if (SCM_COMPLEXP (y))
8507ec80 4208 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
4209 -SCM_COMPLEX_IMAG (y));
4210 else if (SCM_FRACTIONP (y))
4211 /* a/b - c/d = (ad - bc) / bd */
cba42c93 4212 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4213 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
4214 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4215 else
4216 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 4217 }
0aacf84e 4218 else
98cb6e75 4219 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 4220}
c05e97b7 4221#undef FUNC_NAME
0f2d19dd 4222
ca46fb90 4223
9de33deb 4224SCM_GPROC1 (s_product, "*", scm_tc7_asubr, scm_product, g_product);
942e5b91
MG
4225/* "Return the product of all arguments. If called without arguments,\n"
4226 * "1 is returned."
4227 */
0f2d19dd 4228SCM
6e8d25a6 4229scm_product (SCM x, SCM y)
0f2d19dd 4230{
0aacf84e
MD
4231 if (SCM_UNBNDP (y))
4232 {
4233 if (SCM_UNBNDP (x))
d956fa6f 4234 return SCM_I_MAKINUM (1L);
0aacf84e
MD
4235 else if (SCM_NUMBERP (x))
4236 return x;
4237 else
4238 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 4239 }
ca46fb90 4240
e11e83f3 4241 if (SCM_I_INUMP (x))
0aacf84e
MD
4242 {
4243 long xx;
f4c627b3 4244
0aacf84e 4245 intbig:
e11e83f3 4246 xx = SCM_I_INUM (x);
f4c627b3 4247
0aacf84e
MD
4248 switch (xx)
4249 {
ca46fb90
RB
4250 case 0: return x; break;
4251 case 1: return y; break;
0aacf84e 4252 }
f4c627b3 4253
e11e83f3 4254 if (SCM_I_INUMP (y))
0aacf84e 4255 {
e11e83f3 4256 long yy = SCM_I_INUM (y);
0aacf84e 4257 long kk = xx * yy;
d956fa6f 4258 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 4259 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
4260 return k;
4261 else
4262 {
4263 SCM result = scm_i_long2big (xx);
4264 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
4265 return scm_i_normbig (result);
4266 }
4267 }
4268 else if (SCM_BIGP (y))
4269 {
4270 SCM result = scm_i_mkbig ();
4271 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
4272 scm_remember_upto_here_1 (y);
4273 return result;
4274 }
4275 else if (SCM_REALP (y))
55f26379 4276 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 4277 else if (SCM_COMPLEXP (y))
8507ec80 4278 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 4279 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 4280 else if (SCM_FRACTIONP (y))
cba42c93 4281 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 4282 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4283 else
4284 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4285 }
0aacf84e
MD
4286 else if (SCM_BIGP (x))
4287 {
e11e83f3 4288 if (SCM_I_INUMP (y))
0aacf84e
MD
4289 {
4290 SCM_SWAP (x, y);
4291 goto intbig;
4292 }
4293 else if (SCM_BIGP (y))
4294 {
4295 SCM result = scm_i_mkbig ();
4296 mpz_mul (SCM_I_BIG_MPZ (result),
4297 SCM_I_BIG_MPZ (x),
4298 SCM_I_BIG_MPZ (y));
4299 scm_remember_upto_here_2 (x, y);
4300 return result;
4301 }
4302 else if (SCM_REALP (y))
4303 {
4304 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
4305 scm_remember_upto_here_1 (x);
55f26379 4306 return scm_from_double (result);
0aacf84e
MD
4307 }
4308 else if (SCM_COMPLEXP (y))
4309 {
4310 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
4311 scm_remember_upto_here_1 (x);
8507ec80 4312 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
4313 z * SCM_COMPLEX_IMAG (y));
4314 }
f92e85f7 4315 else if (SCM_FRACTIONP (y))
cba42c93 4316 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 4317 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
4318 else
4319 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4320 }
0aacf84e
MD
4321 else if (SCM_REALP (x))
4322 {
e11e83f3 4323 if (SCM_I_INUMP (y))
55f26379 4324 return scm_from_double (SCM_I_INUM (y) * SCM_REAL_VALUE (x));
0aacf84e
MD
4325 else if (SCM_BIGP (y))
4326 {
4327 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
4328 scm_remember_upto_here_1 (y);
55f26379 4329 return scm_from_double (result);
0aacf84e
MD
4330 }
4331 else if (SCM_REALP (y))
55f26379 4332 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 4333 else if (SCM_COMPLEXP (y))
8507ec80 4334 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 4335 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 4336 else if (SCM_FRACTIONP (y))
55f26379 4337 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
4338 else
4339 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4340 }
0aacf84e
MD
4341 else if (SCM_COMPLEXP (x))
4342 {
e11e83f3 4343 if (SCM_I_INUMP (y))
8507ec80 4344 return scm_c_make_rectangular (SCM_I_INUM (y) * SCM_COMPLEX_REAL (x),
e11e83f3 4345 SCM_I_INUM (y) * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
4346 else if (SCM_BIGP (y))
4347 {
4348 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
4349 scm_remember_upto_here_1 (y);
8507ec80 4350 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 4351 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
4352 }
4353 else if (SCM_REALP (y))
8507ec80 4354 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
4355 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
4356 else if (SCM_COMPLEXP (y))
4357 {
8507ec80 4358 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
4359 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
4360 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
4361 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
4362 }
f92e85f7
MV
4363 else if (SCM_FRACTIONP (y))
4364 {
4365 double yy = scm_i_fraction2double (y);
8507ec80 4366 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
4367 yy * SCM_COMPLEX_IMAG (x));
4368 }
4369 else
4370 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
4371 }
4372 else if (SCM_FRACTIONP (x))
4373 {
e11e83f3 4374 if (SCM_I_INUMP (y))
cba42c93 4375 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
4376 SCM_FRACTION_DENOMINATOR (x));
4377 else if (SCM_BIGP (y))
cba42c93 4378 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
4379 SCM_FRACTION_DENOMINATOR (x));
4380 else if (SCM_REALP (y))
55f26379 4381 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
4382 else if (SCM_COMPLEXP (y))
4383 {
4384 double xx = scm_i_fraction2double (x);
8507ec80 4385 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
4386 xx * SCM_COMPLEX_IMAG (y));
4387 }
4388 else if (SCM_FRACTIONP (y))
4389 /* a/b * c/d = ac / bd */
cba42c93 4390 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4391 SCM_FRACTION_NUMERATOR (y)),
4392 scm_product (SCM_FRACTION_DENOMINATOR (x),
4393 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
4394 else
4395 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 4396 }
0aacf84e 4397 else
f4c627b3 4398 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
4399}
4400
7351e207
MV
4401#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
4402 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
4403#define ALLOW_DIVIDE_BY_ZERO
4404/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
4405#endif
0f2d19dd 4406
ba74ef4e
MV
4407/* The code below for complex division is adapted from the GNU
4408 libstdc++, which adapted it from f2c's libF77, and is subject to
4409 this copyright: */
4410
4411/****************************************************************
4412Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
4413
4414Permission to use, copy, modify, and distribute this software
4415and its documentation for any purpose and without fee is hereby
4416granted, provided that the above copyright notice appear in all
4417copies and that both that the copyright notice and this
4418permission notice and warranty disclaimer appear in supporting
4419documentation, and that the names of AT&T Bell Laboratories or
4420Bellcore or any of their entities not be used in advertising or
4421publicity pertaining to distribution of the software without
4422specific, written prior permission.
4423
4424AT&T and Bellcore disclaim all warranties with regard to this
4425software, including all implied warranties of merchantability
4426and fitness. In no event shall AT&T or Bellcore be liable for
4427any special, indirect or consequential damages or any damages
4428whatsoever resulting from loss of use, data or profits, whether
4429in an action of contract, negligence or other tortious action,
4430arising out of or in connection with the use or performance of
4431this software.
4432****************************************************************/
4433
9de33deb 4434SCM_GPROC1 (s_divide, "/", scm_tc7_asubr, scm_divide, g_divide);
609c3d30
MG
4435/* Divide the first argument by the product of the remaining
4436 arguments. If called with one argument @var{z1}, 1/@var{z1} is
4437 returned. */
c05e97b7 4438#define FUNC_NAME s_divide
f92e85f7
MV
4439static SCM
4440scm_i_divide (SCM x, SCM y, int inexact)
0f2d19dd 4441{
f8de44c1
DH
4442 double a;
4443
0aacf84e
MD
4444 if (SCM_UNBNDP (y))
4445 {
4446 if (SCM_UNBNDP (x))
4447 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 4448 else if (SCM_I_INUMP (x))
0aacf84e 4449 {
e11e83f3 4450 long xx = SCM_I_INUM (x);
0aacf84e
MD
4451 if (xx == 1 || xx == -1)
4452 return x;
7351e207 4453#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4454 else if (xx == 0)
4455 scm_num_overflow (s_divide);
7351e207 4456#endif
0aacf84e 4457 else
f92e85f7
MV
4458 {
4459 if (inexact)
55f26379 4460 return scm_from_double (1.0 / (double) xx);
cba42c93 4461 else return scm_i_make_ratio (SCM_I_MAKINUM(1), x);
f92e85f7 4462 }
0aacf84e
MD
4463 }
4464 else if (SCM_BIGP (x))
f92e85f7
MV
4465 {
4466 if (inexact)
55f26379 4467 return scm_from_double (1.0 / scm_i_big2dbl (x));
cba42c93 4468 else return scm_i_make_ratio (SCM_I_MAKINUM(1), x);
f92e85f7 4469 }
0aacf84e
MD
4470 else if (SCM_REALP (x))
4471 {
4472 double xx = SCM_REAL_VALUE (x);
7351e207 4473#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4474 if (xx == 0.0)
4475 scm_num_overflow (s_divide);
4476 else
7351e207 4477#endif
55f26379 4478 return scm_from_double (1.0 / xx);
0aacf84e
MD
4479 }
4480 else if (SCM_COMPLEXP (x))
4481 {
4482 double r = SCM_COMPLEX_REAL (x);
4483 double i = SCM_COMPLEX_IMAG (x);
4484 if (r <= i)
4485 {
4486 double t = r / i;
4487 double d = i * (1.0 + t * t);
8507ec80 4488 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
4489 }
4490 else
4491 {
4492 double t = i / r;
4493 double d = r * (1.0 + t * t);
8507ec80 4494 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
4495 }
4496 }
f92e85f7 4497 else if (SCM_FRACTIONP (x))
cba42c93 4498 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 4499 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
4500 else
4501 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 4502 }
f8de44c1 4503
e11e83f3 4504 if (SCM_I_INUMP (x))
0aacf84e 4505 {
e11e83f3
MV
4506 long xx = SCM_I_INUM (x);
4507 if (SCM_I_INUMP (y))
0aacf84e 4508 {
e11e83f3 4509 long yy = SCM_I_INUM (y);
0aacf84e
MD
4510 if (yy == 0)
4511 {
7351e207 4512#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4513 scm_num_overflow (s_divide);
7351e207 4514#else
55f26379 4515 return scm_from_double ((double) xx / (double) yy);
7351e207 4516#endif
0aacf84e
MD
4517 }
4518 else if (xx % yy != 0)
f92e85f7
MV
4519 {
4520 if (inexact)
55f26379 4521 return scm_from_double ((double) xx / (double) yy);
cba42c93 4522 else return scm_i_make_ratio (x, y);
f92e85f7 4523 }
0aacf84e
MD
4524 else
4525 {
4526 long z = xx / yy;
4527 if (SCM_FIXABLE (z))
d956fa6f 4528 return SCM_I_MAKINUM (z);
0aacf84e
MD
4529 else
4530 return scm_i_long2big (z);
4531 }
f872b822 4532 }
0aacf84e 4533 else if (SCM_BIGP (y))
f92e85f7
MV
4534 {
4535 if (inexact)
55f26379 4536 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 4537 else return scm_i_make_ratio (x, y);
f92e85f7 4538 }
0aacf84e
MD
4539 else if (SCM_REALP (y))
4540 {
4541 double yy = SCM_REAL_VALUE (y);
7351e207 4542#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4543 if (yy == 0.0)
4544 scm_num_overflow (s_divide);
4545 else
7351e207 4546#endif
55f26379 4547 return scm_from_double ((double) xx / yy);
ba74ef4e 4548 }
0aacf84e
MD
4549 else if (SCM_COMPLEXP (y))
4550 {
4551 a = xx;
4552 complex_div: /* y _must_ be a complex number */
4553 {
4554 double r = SCM_COMPLEX_REAL (y);
4555 double i = SCM_COMPLEX_IMAG (y);
4556 if (r <= i)
4557 {
4558 double t = r / i;
4559 double d = i * (1.0 + t * t);
8507ec80 4560 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
4561 }
4562 else
4563 {
4564 double t = i / r;
4565 double d = r * (1.0 + t * t);
8507ec80 4566 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
4567 }
4568 }
4569 }
f92e85f7
MV
4570 else if (SCM_FRACTIONP (y))
4571 /* a / b/c = ac / b */
cba42c93 4572 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 4573 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
4574 else
4575 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 4576 }
0aacf84e
MD
4577 else if (SCM_BIGP (x))
4578 {
e11e83f3 4579 if (SCM_I_INUMP (y))
0aacf84e 4580 {
e11e83f3 4581 long int yy = SCM_I_INUM (y);
0aacf84e
MD
4582 if (yy == 0)
4583 {
7351e207 4584#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4585 scm_num_overflow (s_divide);
7351e207 4586#else
0aacf84e
MD
4587 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4588 scm_remember_upto_here_1 (x);
4589 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 4590#endif
0aacf84e
MD
4591 }
4592 else if (yy == 1)
4593 return x;
4594 else
4595 {
4596 /* FIXME: HMM, what are the relative performance issues here?
4597 We need to test. Is it faster on average to test
4598 divisible_p, then perform whichever operation, or is it
4599 faster to perform the integer div opportunistically and
4600 switch to real if there's a remainder? For now we take the
4601 middle ground: test, then if divisible, use the faster div
4602 func. */
4603
4604 long abs_yy = yy < 0 ? -yy : yy;
4605 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
4606
4607 if (divisible_p)
4608 {
4609 SCM result = scm_i_mkbig ();
4610 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
4611 scm_remember_upto_here_1 (x);
4612 if (yy < 0)
4613 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
4614 return scm_i_normbig (result);
4615 }
4616 else
f92e85f7
MV
4617 {
4618 if (inexact)
55f26379 4619 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 4620 else return scm_i_make_ratio (x, y);
f92e85f7 4621 }
0aacf84e
MD
4622 }
4623 }
4624 else if (SCM_BIGP (y))
4625 {
4626 int y_is_zero = (mpz_sgn (SCM_I_BIG_MPZ (y)) == 0);
4627 if (y_is_zero)
4628 {
ca46fb90 4629#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 4630 scm_num_overflow (s_divide);
f872b822 4631#else
0aacf84e
MD
4632 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
4633 scm_remember_upto_here_1 (x);
4634 return (sgn == 0) ? scm_nan () : scm_inf ();
f872b822 4635#endif
0aacf84e
MD
4636 }
4637 else
4638 {
4639 /* big_x / big_y */
4640 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
4641 SCM_I_BIG_MPZ (y));
4642 if (divisible_p)
4643 {
4644 SCM result = scm_i_mkbig ();
4645 mpz_divexact (SCM_I_BIG_MPZ (result),
4646 SCM_I_BIG_MPZ (x),
4647 SCM_I_BIG_MPZ (y));
4648 scm_remember_upto_here_2 (x, y);
4649 return scm_i_normbig (result);
4650 }
4651 else
4652 {
f92e85f7
MV
4653 if (inexact)
4654 {
4655 double dbx = mpz_get_d (SCM_I_BIG_MPZ (x));
4656 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4657 scm_remember_upto_here_2 (x, y);
55f26379 4658 return scm_from_double (dbx / dby);
f92e85f7 4659 }
cba42c93 4660 else return scm_i_make_ratio (x, y);
0aacf84e
MD
4661 }
4662 }
4663 }
4664 else if (SCM_REALP (y))
4665 {
4666 double yy = SCM_REAL_VALUE (y);
7351e207 4667#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4668 if (yy == 0.0)
4669 scm_num_overflow (s_divide);
4670 else
7351e207 4671#endif
55f26379 4672 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
4673 }
4674 else if (SCM_COMPLEXP (y))
4675 {
4676 a = scm_i_big2dbl (x);
4677 goto complex_div;
4678 }
f92e85f7 4679 else if (SCM_FRACTIONP (y))
cba42c93 4680 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 4681 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
4682 else
4683 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4684 }
0aacf84e
MD
4685 else if (SCM_REALP (x))
4686 {
4687 double rx = SCM_REAL_VALUE (x);
e11e83f3 4688 if (SCM_I_INUMP (y))
0aacf84e 4689 {
e11e83f3 4690 long int yy = SCM_I_INUM (y);
7351e207 4691#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4692 if (yy == 0)
4693 scm_num_overflow (s_divide);
4694 else
7351e207 4695#endif
55f26379 4696 return scm_from_double (rx / (double) yy);
0aacf84e
MD
4697 }
4698 else if (SCM_BIGP (y))
4699 {
4700 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4701 scm_remember_upto_here_1 (y);
55f26379 4702 return scm_from_double (rx / dby);
0aacf84e
MD
4703 }
4704 else if (SCM_REALP (y))
4705 {
4706 double yy = SCM_REAL_VALUE (y);
7351e207 4707#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4708 if (yy == 0.0)
4709 scm_num_overflow (s_divide);
4710 else
7351e207 4711#endif
55f26379 4712 return scm_from_double (rx / yy);
0aacf84e
MD
4713 }
4714 else if (SCM_COMPLEXP (y))
4715 {
4716 a = rx;
4717 goto complex_div;
4718 }
f92e85f7 4719 else if (SCM_FRACTIONP (y))
55f26379 4720 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
4721 else
4722 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 4723 }
0aacf84e
MD
4724 else if (SCM_COMPLEXP (x))
4725 {
4726 double rx = SCM_COMPLEX_REAL (x);
4727 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 4728 if (SCM_I_INUMP (y))
0aacf84e 4729 {
e11e83f3 4730 long int yy = SCM_I_INUM (y);
7351e207 4731#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
4732 if (yy == 0)
4733 scm_num_overflow (s_divide);
4734 else
7351e207 4735#endif
0aacf84e
MD
4736 {
4737 double d = yy;
8507ec80 4738 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
4739 }
4740 }
4741 else if (SCM_BIGP (y))
4742 {
4743 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
4744 scm_remember_upto_here_1 (y);
8507ec80 4745 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
4746 }
4747 else if (SCM_REALP (y))
4748 {
4749 double yy = SCM_REAL_VALUE (y);
7351e207 4750#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
4751 if (yy == 0.0)
4752 scm_num_overflow (s_divide);
4753 else
7351e207 4754#endif
8507ec80 4755 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
4756 }
4757 else if (SCM_COMPLEXP (y))
4758 {
4759 double ry = SCM_COMPLEX_REAL (y);
4760 double iy = SCM_COMPLEX_IMAG (y);
4761 if (ry <= iy)
4762 {
4763 double t = ry / iy;
4764 double d = iy * (1.0 + t * t);
8507ec80 4765 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
4766 }
4767 else
4768 {
4769 double t = iy / ry;
4770 double d = ry * (1.0 + t * t);
8507ec80 4771 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
4772 }
4773 }
f92e85f7
MV
4774 else if (SCM_FRACTIONP (y))
4775 {
4776 double yy = scm_i_fraction2double (y);
8507ec80 4777 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 4778 }
0aacf84e
MD
4779 else
4780 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 4781 }
f92e85f7
MV
4782 else if (SCM_FRACTIONP (x))
4783 {
e11e83f3 4784 if (SCM_I_INUMP (y))
f92e85f7 4785 {
e11e83f3 4786 long int yy = SCM_I_INUM (y);
f92e85f7
MV
4787#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
4788 if (yy == 0)
4789 scm_num_overflow (s_divide);
4790 else
4791#endif
cba42c93 4792 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4793 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
4794 }
4795 else if (SCM_BIGP (y))
4796 {
cba42c93 4797 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
4798 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
4799 }
4800 else if (SCM_REALP (y))
4801 {
4802 double yy = SCM_REAL_VALUE (y);
4803#ifndef ALLOW_DIVIDE_BY_ZERO
4804 if (yy == 0.0)
4805 scm_num_overflow (s_divide);
4806 else
4807#endif
55f26379 4808 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
4809 }
4810 else if (SCM_COMPLEXP (y))
4811 {
4812 a = scm_i_fraction2double (x);
4813 goto complex_div;
4814 }
4815 else if (SCM_FRACTIONP (y))
cba42c93 4816 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
4817 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
4818 else
4819 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
4820 }
0aacf84e 4821 else
f8de44c1 4822 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 4823}
f92e85f7
MV
4824
4825SCM
4826scm_divide (SCM x, SCM y)
4827{
4828 return scm_i_divide (x, y, 0);
4829}
4830
4831static SCM scm_divide2real (SCM x, SCM y)
4832{
4833 return scm_i_divide (x, y, 1);
4834}
c05e97b7 4835#undef FUNC_NAME
0f2d19dd 4836
fa605590 4837
0f2d19dd 4838double
6e8d25a6 4839scm_asinh (double x)
0f2d19dd 4840{
fa605590
KR
4841#if HAVE_ASINH
4842 return asinh (x);
4843#else
4844#define asinh scm_asinh
f872b822 4845 return log (x + sqrt (x * x + 1));
fa605590 4846#endif
0f2d19dd 4847}
fa605590
KR
4848SCM_GPROC1 (s_asinh, "$asinh", scm_tc7_dsubr, (SCM (*)()) asinh, g_asinh);
4849/* "Return the inverse hyperbolic sine of @var{x}."
4850 */
0f2d19dd
JB
4851
4852
0f2d19dd 4853double
6e8d25a6 4854scm_acosh (double x)
0f2d19dd 4855{
fa605590
KR
4856#if HAVE_ACOSH
4857 return acosh (x);
4858#else
4859#define acosh scm_acosh
f872b822 4860 return log (x + sqrt (x * x - 1));
fa605590 4861#endif
0f2d19dd 4862}
fa605590
KR
4863SCM_GPROC1 (s_acosh, "$acosh", scm_tc7_dsubr, (SCM (*)()) acosh, g_acosh);
4864/* "Return the inverse hyperbolic cosine of @var{x}."
4865 */
0f2d19dd
JB
4866
4867
0f2d19dd 4868double
6e8d25a6 4869scm_atanh (double x)
0f2d19dd 4870{
fa605590
KR
4871#if HAVE_ATANH
4872 return atanh (x);
4873#else
4874#define atanh scm_atanh
f872b822 4875 return 0.5 * log ((1 + x) / (1 - x));
fa605590 4876#endif
0f2d19dd 4877}
fa605590
KR
4878SCM_GPROC1 (s_atanh, "$atanh", scm_tc7_dsubr, (SCM (*)()) atanh, g_atanh);
4879/* "Return the inverse hyperbolic tangent of @var{x}."
4880 */
0f2d19dd
JB
4881
4882
0f2d19dd 4883double
3101f40f 4884scm_c_truncate (double x)
0f2d19dd 4885{
fa605590
KR
4886#if HAVE_TRUNC
4887 return trunc (x);
4888#else
f872b822
MD
4889 if (x < 0.0)
4890 return -floor (-x);
4891 return floor (x);
fa605590 4892#endif
0f2d19dd 4893}
0f2d19dd 4894
3101f40f
MV
4895/* scm_c_round is done using floor(x+0.5) to round to nearest and with
4896 half-way case (ie. when x is an integer plus 0.5) going upwards.
4897 Then half-way cases are identified and adjusted down if the
4898 round-upwards didn't give the desired even integer.
6187f48b
KR
4899
4900 "plus_half == result" identifies a half-way case. If plus_half, which is
4901 x + 0.5, is an integer then x must be an integer plus 0.5.
4902
4903 An odd "result" value is identified with result/2 != floor(result/2).
4904 This is done with plus_half, since that value is ready for use sooner in
4905 a pipelined cpu, and we're already requiring plus_half == result.
4906
4907 Note however that we need to be careful when x is big and already an
4908 integer. In that case "x+0.5" may round to an adjacent integer, causing
4909 us to return such a value, incorrectly. For instance if the hardware is
4910 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
4911 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
4912 returned. Or if the hardware is in round-upwards mode, then other bigger
4913 values like say x == 2^128 will see x+0.5 rounding up to the next higher
4914 representable value, 2^128+2^76 (or whatever), again incorrect.
4915
4916 These bad roundings of x+0.5 are avoided by testing at the start whether
4917 x is already an integer. If it is then clearly that's the desired result
4918 already. And if it's not then the exponent must be small enough to allow
4919 an 0.5 to be represented, and hence added without a bad rounding. */
4920
0f2d19dd 4921double
3101f40f 4922scm_c_round (double x)
0f2d19dd 4923{
6187f48b
KR
4924 double plus_half, result;
4925
4926 if (x == floor (x))
4927 return x;
4928
4929 plus_half = x + 0.5;
4930 result = floor (plus_half);
3101f40f 4931 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
4932 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
4933 ? result - 1
4934 : result);
0f2d19dd
JB
4935}
4936
f92e85f7
MV
4937SCM_DEFINE (scm_truncate_number, "truncate", 1, 0, 0,
4938 (SCM x),
4939 "Round the number @var{x} towards zero.")
4940#define FUNC_NAME s_scm_truncate_number
4941{
73e4de09 4942 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
4943 return scm_floor (x);
4944 else
4945 return scm_ceiling (x);
4946}
4947#undef FUNC_NAME
4948
4949static SCM exactly_one_half;
4950
4951SCM_DEFINE (scm_round_number, "round", 1, 0, 0,
4952 (SCM x),
4953 "Round the number @var{x} towards the nearest integer. "
4954 "When it is exactly halfway between two integers, "
4955 "round towards the even one.")
4956#define FUNC_NAME s_scm_round_number
4957{
e11e83f3 4958 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
4959 return x;
4960 else if (SCM_REALP (x))
3101f40f 4961 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
f92e85f7 4962 else
bae30667
KR
4963 {
4964 /* OPTIMIZE-ME: Fraction case could be done more efficiently by a
4965 single quotient+remainder division then examining to see which way
4966 the rounding should go. */
4967 SCM plus_half = scm_sum (x, exactly_one_half);
4968 SCM result = scm_floor (plus_half);
3101f40f 4969 /* Adjust so that the rounding is towards even. */
73e4de09
MV
4970 if (scm_is_true (scm_num_eq_p (plus_half, result))
4971 && scm_is_true (scm_odd_p (result)))
d956fa6f 4972 return scm_difference (result, SCM_I_MAKINUM (1));
bae30667
KR
4973 else
4974 return result;
4975 }
f92e85f7
MV
4976}
4977#undef FUNC_NAME
4978
4979SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
4980 (SCM x),
4981 "Round the number @var{x} towards minus infinity.")
4982#define FUNC_NAME s_scm_floor
4983{
e11e83f3 4984 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
4985 return x;
4986 else if (SCM_REALP (x))
55f26379 4987 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7
MV
4988 else if (SCM_FRACTIONP (x))
4989 {
4990 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
4991 SCM_FRACTION_DENOMINATOR (x));
73e4de09 4992 if (scm_is_false (scm_negative_p (x)))
f92e85f7
MV
4993 {
4994 /* For positive x, rounding towards zero is correct. */
4995 return q;
4996 }
4997 else
4998 {
4999 /* For negative x, we need to return q-1 unless x is an
5000 integer. But fractions are never integer, per our
5001 assumptions. */
d956fa6f 5002 return scm_difference (q, SCM_I_MAKINUM (1));
f92e85f7
MV
5003 }
5004 }
5005 else
5006 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
5007}
5008#undef FUNC_NAME
5009
5010SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
5011 (SCM x),
5012 "Round the number @var{x} towards infinity.")
5013#define FUNC_NAME s_scm_ceiling
5014{
e11e83f3 5015 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
5016 return x;
5017 else if (SCM_REALP (x))
55f26379 5018 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7
MV
5019 else if (SCM_FRACTIONP (x))
5020 {
5021 SCM q = scm_quotient (SCM_FRACTION_NUMERATOR (x),
5022 SCM_FRACTION_DENOMINATOR (x));
73e4de09 5023 if (scm_is_false (scm_positive_p (x)))
f92e85f7
MV
5024 {
5025 /* For negative x, rounding towards zero is correct. */
5026 return q;
5027 }
5028 else
5029 {
5030 /* For positive x, we need to return q+1 unless x is an
5031 integer. But fractions are never integer, per our
5032 assumptions. */
d956fa6f 5033 return scm_sum (q, SCM_I_MAKINUM (1));
f92e85f7
MV
5034 }
5035 }
5036 else
5037 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
5038}
5039#undef FUNC_NAME
0f2d19dd 5040
14b18ed6 5041SCM_GPROC1 (s_i_sqrt, "$sqrt", scm_tc7_dsubr, (SCM (*)()) sqrt, g_i_sqrt);
942e5b91
MG
5042/* "Return the square root of the real number @var{x}."
5043 */
14b18ed6 5044SCM_GPROC1 (s_i_abs, "$abs", scm_tc7_dsubr, (SCM (*)()) fabs, g_i_abs);
942e5b91
MG
5045/* "Return the absolute value of the real number @var{x}."
5046 */
14b18ed6 5047SCM_GPROC1 (s_i_exp, "$exp", scm_tc7_dsubr, (SCM (*)()) exp, g_i_exp);
942e5b91
MG
5048/* "Return the @var{x}th power of e."
5049 */
14b18ed6 5050SCM_GPROC1 (s_i_log, "$log", scm_tc7_dsubr, (SCM (*)()) log, g_i_log);
b3fcac34 5051/* "Return the natural logarithm of the real number @var{x}."
942e5b91 5052 */
14b18ed6 5053SCM_GPROC1 (s_i_sin, "$sin", scm_tc7_dsubr, (SCM (*)()) sin, g_i_sin);
942e5b91
MG
5054/* "Return the sine of the real number @var{x}."
5055 */
14b18ed6 5056SCM_GPROC1 (s_i_cos, "$cos", scm_tc7_dsubr, (SCM (*)()) cos, g_i_cos);
942e5b91
MG
5057/* "Return the cosine of the real number @var{x}."
5058 */
14b18ed6 5059SCM_GPROC1 (s_i_tan, "$tan", scm_tc7_dsubr, (SCM (*)()) tan, g_i_tan);
942e5b91
MG
5060/* "Return the tangent of the real number @var{x}."
5061 */
14b18ed6 5062SCM_GPROC1 (s_i_asin, "$asin", scm_tc7_dsubr, (SCM (*)()) asin, g_i_asin);
942e5b91
MG
5063/* "Return the arc sine of the real number @var{x}."
5064 */
14b18ed6 5065SCM_GPROC1 (s_i_acos, "$acos", scm_tc7_dsubr, (SCM (*)()) acos, g_i_acos);
942e5b91
MG
5066/* "Return the arc cosine of the real number @var{x}."
5067 */
14b18ed6 5068SCM_GPROC1 (s_i_atan, "$atan", scm_tc7_dsubr, (SCM (*)()) atan, g_i_atan);
942e5b91
MG
5069/* "Return the arc tangent of the real number @var{x}."
5070 */
14b18ed6 5071SCM_GPROC1 (s_i_sinh, "$sinh", scm_tc7_dsubr, (SCM (*)()) sinh, g_i_sinh);
942e5b91
MG
5072/* "Return the hyperbolic sine of the real number @var{x}."
5073 */
14b18ed6 5074SCM_GPROC1 (s_i_cosh, "$cosh", scm_tc7_dsubr, (SCM (*)()) cosh, g_i_cosh);
942e5b91
MG
5075/* "Return the hyperbolic cosine of the real number @var{x}."
5076 */
14b18ed6 5077SCM_GPROC1 (s_i_tanh, "$tanh", scm_tc7_dsubr, (SCM (*)()) tanh, g_i_tanh);
942e5b91
MG
5078/* "Return the hyperbolic tangent of the real number @var{x}."
5079 */
f872b822
MD
5080
5081struct dpair
5082{
5083 double x, y;
5084};
5085
27c37006
NJ
5086static void scm_two_doubles (SCM x,
5087 SCM y,
3eeba8d4
JB
5088 const char *sstring,
5089 struct dpair * xy);
f872b822
MD
5090
5091static void
27c37006
NJ
5092scm_two_doubles (SCM x, SCM y, const char *sstring, struct dpair *xy)
5093{
e11e83f3
MV
5094 if (SCM_I_INUMP (x))
5095 xy->x = SCM_I_INUM (x);
0aacf84e 5096 else if (SCM_BIGP (x))
1be6b49c 5097 xy->x = scm_i_big2dbl (x);
0aacf84e 5098 else if (SCM_REALP (x))
27c37006 5099 xy->x = SCM_REAL_VALUE (x);
f92e85f7
MV
5100 else if (SCM_FRACTIONP (x))
5101 xy->x = scm_i_fraction2double (x);
0aacf84e 5102 else
27c37006 5103 scm_wrong_type_arg (sstring, SCM_ARG1, x);
98cb6e75 5104
e11e83f3
MV
5105 if (SCM_I_INUMP (y))
5106 xy->y = SCM_I_INUM (y);
0aacf84e 5107 else if (SCM_BIGP (y))
1be6b49c 5108 xy->y = scm_i_big2dbl (y);
0aacf84e 5109 else if (SCM_REALP (y))
27c37006 5110 xy->y = SCM_REAL_VALUE (y);
f92e85f7
MV
5111 else if (SCM_FRACTIONP (y))
5112 xy->y = scm_i_fraction2double (y);
0aacf84e 5113 else
27c37006 5114 scm_wrong_type_arg (sstring, SCM_ARG2, y);
0f2d19dd
JB
5115}
5116
5117
a1ec6916 5118SCM_DEFINE (scm_sys_expt, "$expt", 2, 0, 0,
27c37006
NJ
5119 (SCM x, SCM y),
5120 "Return @var{x} raised to the power of @var{y}. This\n"
0137a31b 5121 "procedure does not accept complex arguments.")
1bbd0b84 5122#define FUNC_NAME s_scm_sys_expt
0f2d19dd
JB
5123{
5124 struct dpair xy;
27c37006 5125 scm_two_doubles (x, y, FUNC_NAME, &xy);
55f26379 5126 return scm_from_double (pow (xy.x, xy.y));
0f2d19dd 5127}
1bbd0b84 5128#undef FUNC_NAME
0f2d19dd
JB
5129
5130
a1ec6916 5131SCM_DEFINE (scm_sys_atan2, "$atan2", 2, 0, 0,
27c37006
NJ
5132 (SCM x, SCM y),
5133 "Return the arc tangent of the two arguments @var{x} and\n"
5134 "@var{y}. This is similar to calculating the arc tangent of\n"
5135 "@var{x} / @var{y}, except that the signs of both arguments\n"
0137a31b
MG
5136 "are used to determine the quadrant of the result. This\n"
5137 "procedure does not accept complex arguments.")
1bbd0b84 5138#define FUNC_NAME s_scm_sys_atan2
0f2d19dd
JB
5139{
5140 struct dpair xy;
27c37006 5141 scm_two_doubles (x, y, FUNC_NAME, &xy);
55f26379 5142 return scm_from_double (atan2 (xy.x, xy.y));
0f2d19dd 5143}
1bbd0b84 5144#undef FUNC_NAME
0f2d19dd 5145
8507ec80
MV
5146SCM
5147scm_c_make_rectangular (double re, double im)
5148{
5149 if (im == 0.0)
5150 return scm_from_double (re);
5151 else
5152 {
5153 SCM z;
5154 SCM_NEWSMOB (z, scm_tc16_complex, scm_gc_malloc (sizeof (scm_t_complex),
5155 "complex"));
5156 SCM_COMPLEX_REAL (z) = re;
5157 SCM_COMPLEX_IMAG (z) = im;
5158 return z;
5159 }
5160}
0f2d19dd 5161
a1ec6916 5162SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
bb628794 5163 (SCM real, SCM imaginary),
942e5b91
MG
5164 "Return a complex number constructed of the given @var{real} and\n"
5165 "@var{imaginary} parts.")
1bbd0b84 5166#define FUNC_NAME s_scm_make_rectangular
0f2d19dd
JB
5167{
5168 struct dpair xy;
bb628794 5169 scm_two_doubles (real, imaginary, FUNC_NAME, &xy);
8507ec80 5170 return scm_c_make_rectangular (xy.x, xy.y);
0f2d19dd 5171}
1bbd0b84 5172#undef FUNC_NAME
0f2d19dd 5173
8507ec80
MV
5174SCM
5175scm_c_make_polar (double mag, double ang)
5176{
5177 double s, c;
5178#if HAVE_SINCOS
5179 sincos (ang, &s, &c);
5180#else
5181 s = sin (ang);
5182 c = cos (ang);
5183#endif
5184 return scm_c_make_rectangular (mag * c, mag * s);
5185}
0f2d19dd 5186
a1ec6916 5187SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
27c37006 5188 (SCM x, SCM y),
942e5b91 5189 "Return the complex number @var{x} * e^(i * @var{y}).")
1bbd0b84 5190#define FUNC_NAME s_scm_make_polar
0f2d19dd
JB
5191{
5192 struct dpair xy;
27c37006 5193 scm_two_doubles (x, y, FUNC_NAME, &xy);
8507ec80 5194 return scm_c_make_polar (xy.x, xy.y);
0f2d19dd 5195}
1bbd0b84 5196#undef FUNC_NAME
0f2d19dd
JB
5197
5198
152f82bf 5199SCM_GPROC (s_real_part, "real-part", 1, 0, 0, scm_real_part, g_real_part);
942e5b91
MG
5200/* "Return the real part of the number @var{z}."
5201 */
0f2d19dd 5202SCM
6e8d25a6 5203scm_real_part (SCM z)
0f2d19dd 5204{
e11e83f3 5205 if (SCM_I_INUMP (z))
c2ff8ab0 5206 return z;
0aacf84e 5207 else if (SCM_BIGP (z))
c2ff8ab0 5208 return z;
0aacf84e 5209 else if (SCM_REALP (z))
c2ff8ab0 5210 return z;
0aacf84e 5211 else if (SCM_COMPLEXP (z))
55f26379 5212 return scm_from_double (SCM_COMPLEX_REAL (z));
f92e85f7 5213 else if (SCM_FRACTIONP (z))
2fa2d879 5214 return z;
0aacf84e 5215 else
c2ff8ab0 5216 SCM_WTA_DISPATCH_1 (g_real_part, z, SCM_ARG1, s_real_part);
0f2d19dd
JB
5217}
5218
5219
152f82bf 5220SCM_GPROC (s_imag_part, "imag-part", 1, 0, 0, scm_imag_part, g_imag_part);
942e5b91
MG
5221/* "Return the imaginary part of the number @var{z}."
5222 */
0f2d19dd 5223SCM
6e8d25a6 5224scm_imag_part (SCM z)
0f2d19dd 5225{
e11e83f3 5226 if (SCM_I_INUMP (z))
f872b822 5227 return SCM_INUM0;
0aacf84e 5228 else if (SCM_BIGP (z))
f872b822 5229 return SCM_INUM0;
0aacf84e 5230 else if (SCM_REALP (z))
c2ff8ab0 5231 return scm_flo0;
0aacf84e 5232 else if (SCM_COMPLEXP (z))
55f26379 5233 return scm_from_double (SCM_COMPLEX_IMAG (z));
f92e85f7
MV
5234 else if (SCM_FRACTIONP (z))
5235 return SCM_INUM0;
0aacf84e 5236 else
c2ff8ab0 5237 SCM_WTA_DISPATCH_1 (g_imag_part, z, SCM_ARG1, s_imag_part);
0f2d19dd
JB
5238}
5239
f92e85f7
MV
5240SCM_GPROC (s_numerator, "numerator", 1, 0, 0, scm_numerator, g_numerator);
5241/* "Return the numerator of the number @var{z}."
5242 */
5243SCM
5244scm_numerator (SCM z)
5245{
e11e83f3 5246 if (SCM_I_INUMP (z))
f92e85f7
MV
5247 return z;
5248 else if (SCM_BIGP (z))
5249 return z;
5250 else if (SCM_FRACTIONP (z))
5251 {
5252 scm_i_fraction_reduce (z);
5253 return SCM_FRACTION_NUMERATOR (z);
5254 }
5255 else if (SCM_REALP (z))
5256 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
5257 else
5258 SCM_WTA_DISPATCH_1 (g_numerator, z, SCM_ARG1, s_numerator);
5259}
5260
5261
5262SCM_GPROC (s_denominator, "denominator", 1, 0, 0, scm_denominator, g_denominator);
5263/* "Return the denominator of the number @var{z}."
5264 */
5265SCM
5266scm_denominator (SCM z)
5267{
e11e83f3 5268 if (SCM_I_INUMP (z))
d956fa6f 5269 return SCM_I_MAKINUM (1);
f92e85f7 5270 else if (SCM_BIGP (z))
d956fa6f 5271 return SCM_I_MAKINUM (1);
f92e85f7
MV
5272 else if (SCM_FRACTIONP (z))
5273 {
5274 scm_i_fraction_reduce (z);
5275 return SCM_FRACTION_DENOMINATOR (z);
5276 }
5277 else if (SCM_REALP (z))
5278 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
5279 else
5280 SCM_WTA_DISPATCH_1 (g_denominator, z, SCM_ARG1, s_denominator);
5281}
0f2d19dd 5282
9de33deb 5283SCM_GPROC (s_magnitude, "magnitude", 1, 0, 0, scm_magnitude, g_magnitude);
942e5b91
MG
5284/* "Return the magnitude of the number @var{z}. This is the same as\n"
5285 * "@code{abs} for real arguments, but also allows complex numbers."
5286 */
0f2d19dd 5287SCM
6e8d25a6 5288scm_magnitude (SCM z)
0f2d19dd 5289{
e11e83f3 5290 if (SCM_I_INUMP (z))
0aacf84e 5291 {
e11e83f3 5292 long int zz = SCM_I_INUM (z);
0aacf84e
MD
5293 if (zz >= 0)
5294 return z;
5295 else if (SCM_POSFIXABLE (-zz))
d956fa6f 5296 return SCM_I_MAKINUM (-zz);
0aacf84e
MD
5297 else
5298 return scm_i_long2big (-zz);
5986c47d 5299 }
0aacf84e
MD
5300 else if (SCM_BIGP (z))
5301 {
5302 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
5303 scm_remember_upto_here_1 (z);
5304 if (sgn < 0)
5305 return scm_i_clonebig (z, 0);
5306 else
5307 return z;
5986c47d 5308 }
0aacf84e 5309 else if (SCM_REALP (z))
55f26379 5310 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 5311 else if (SCM_COMPLEXP (z))
55f26379 5312 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
5313 else if (SCM_FRACTIONP (z))
5314 {
73e4de09 5315 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 5316 return z;
cba42c93 5317 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
5318 SCM_FRACTION_DENOMINATOR (z));
5319 }
0aacf84e 5320 else
c2ff8ab0 5321 SCM_WTA_DISPATCH_1 (g_magnitude, z, SCM_ARG1, s_magnitude);
0f2d19dd
JB
5322}
5323
5324
9de33deb 5325SCM_GPROC (s_angle, "angle", 1, 0, 0, scm_angle, g_angle);
942e5b91
MG
5326/* "Return the angle of the complex number @var{z}."
5327 */
0f2d19dd 5328SCM
6e8d25a6 5329scm_angle (SCM z)
0f2d19dd 5330{
c8ae173e 5331 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
55f26379 5332 scm_flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
5333 But if atan2 follows the floating point rounding mode, then the value
5334 is not a constant. Maybe it'd be close enough though. */
e11e83f3 5335 if (SCM_I_INUMP (z))
0aacf84e 5336 {
e11e83f3 5337 if (SCM_I_INUM (z) >= 0)
c8ae173e 5338 return scm_flo0;
0aacf84e 5339 else
55f26379 5340 return scm_from_double (atan2 (0.0, -1.0));
f872b822 5341 }
0aacf84e
MD
5342 else if (SCM_BIGP (z))
5343 {
5344 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
5345 scm_remember_upto_here_1 (z);
5346 if (sgn < 0)
55f26379 5347 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 5348 else
c8ae173e 5349 return scm_flo0;
0f2d19dd 5350 }
0aacf84e 5351 else if (SCM_REALP (z))
c8ae173e
KR
5352 {
5353 if (SCM_REAL_VALUE (z) >= 0)
5354 return scm_flo0;
5355 else
55f26379 5356 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 5357 }
0aacf84e 5358 else if (SCM_COMPLEXP (z))
55f26379 5359 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
5360 else if (SCM_FRACTIONP (z))
5361 {
73e4de09 5362 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 5363 return scm_flo0;
55f26379 5364 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 5365 }
0aacf84e 5366 else
f4c627b3 5367 SCM_WTA_DISPATCH_1 (g_angle, z, SCM_ARG1, s_angle);
0f2d19dd
JB
5368}
5369
5370
3c9a524f
DH
5371SCM_GPROC (s_exact_to_inexact, "exact->inexact", 1, 0, 0, scm_exact_to_inexact, g_exact_to_inexact);
5372/* Convert the number @var{x} to its inexact representation.\n"
5373 */
5374SCM
5375scm_exact_to_inexact (SCM z)
5376{
e11e83f3 5377 if (SCM_I_INUMP (z))
55f26379 5378 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 5379 else if (SCM_BIGP (z))
55f26379 5380 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 5381 else if (SCM_FRACTIONP (z))
55f26379 5382 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
5383 else if (SCM_INEXACTP (z))
5384 return z;
5385 else
5386 SCM_WTA_DISPATCH_1 (g_exact_to_inexact, z, 1, s_exact_to_inexact);
5387}
5388
5389
a1ec6916 5390SCM_DEFINE (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
1bbd0b84 5391 (SCM z),
1e6808ea 5392 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 5393#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 5394{
e11e83f3 5395 if (SCM_I_INUMP (z))
f872b822 5396 return z;
0aacf84e 5397 else if (SCM_BIGP (z))
f872b822 5398 return z;
0aacf84e
MD
5399 else if (SCM_REALP (z))
5400 {
f92e85f7
MV
5401 if (xisinf (SCM_REAL_VALUE (z)) || xisnan (SCM_REAL_VALUE (z)))
5402 SCM_OUT_OF_RANGE (1, z);
2be24db4 5403 else
f92e85f7
MV
5404 {
5405 mpq_t frac;
5406 SCM q;
5407
5408 mpq_init (frac);
5409 mpq_set_d (frac, SCM_REAL_VALUE (z));
cba42c93 5410 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
f92e85f7
MV
5411 scm_i_mpz2num (mpq_denref (frac)));
5412
cba42c93 5413 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
5414 for frac...
5415 */
5416 mpq_clear (frac);
5417 return q;
5418 }
c2ff8ab0 5419 }
f92e85f7
MV
5420 else if (SCM_FRACTIONP (z))
5421 return z;
0aacf84e 5422 else
c2ff8ab0 5423 SCM_WRONG_TYPE_ARG (1, z);
0f2d19dd 5424}
1bbd0b84 5425#undef FUNC_NAME
0f2d19dd 5426
f92e85f7
MV
5427SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
5428 (SCM x, SCM err),
5429 "Return an exact number that is within @var{err} of @var{x}.")
5430#define FUNC_NAME s_scm_rationalize
5431{
e11e83f3 5432 if (SCM_I_INUMP (x))
f92e85f7
MV
5433 return x;
5434 else if (SCM_BIGP (x))
5435 return x;
5436 else if ((SCM_REALP (x)) || SCM_FRACTIONP (x))
5437 {
5438 /* Use continued fractions to find closest ratio. All
5439 arithmetic is done with exact numbers.
5440 */
5441
5442 SCM ex = scm_inexact_to_exact (x);
5443 SCM int_part = scm_floor (ex);
d956fa6f
MV
5444 SCM tt = SCM_I_MAKINUM (1);
5445 SCM a1 = SCM_I_MAKINUM (0), a2 = SCM_I_MAKINUM (1), a = SCM_I_MAKINUM (0);
5446 SCM b1 = SCM_I_MAKINUM (1), b2 = SCM_I_MAKINUM (0), b = SCM_I_MAKINUM (0);
f92e85f7
MV
5447 SCM rx;
5448 int i = 0;
5449
73e4de09 5450 if (scm_is_true (scm_num_eq_p (ex, int_part)))
f92e85f7
MV
5451 return ex;
5452
5453 ex = scm_difference (ex, int_part); /* x = x-int_part */
5454 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
5455
5456 /* We stop after a million iterations just to be absolutely sure
5457 that we don't go into an infinite loop. The process normally
5458 converges after less than a dozen iterations.
5459 */
5460
5461 err = scm_abs (err);
5462 while (++i < 1000000)
5463 {
5464 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
5465 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
5466 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
5467 scm_is_false
f92e85f7
MV
5468 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
5469 err))) /* abs(x-a/b) <= err */
02164269
MV
5470 {
5471 SCM res = scm_sum (int_part, scm_divide (a, b));
73e4de09
MV
5472 if (scm_is_false (scm_exact_p (x))
5473 || scm_is_false (scm_exact_p (err)))
02164269
MV
5474 return scm_exact_to_inexact (res);
5475 else
5476 return res;
5477 }
f92e85f7
MV
5478 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
5479 SCM_UNDEFINED);
5480 tt = scm_floor (rx); /* tt = floor (rx) */
5481 a2 = a1;
5482 b2 = b1;
5483 a1 = a;
5484 b1 = b;
5485 }
5486 scm_num_overflow (s_scm_rationalize);
5487 }
5488 else
5489 SCM_WRONG_TYPE_ARG (1, x);
5490}
5491#undef FUNC_NAME
5492
73e4de09
MV
5493/* conversion functions */
5494
5495int
5496scm_is_integer (SCM val)
5497{
5498 return scm_is_true (scm_integer_p (val));
5499}
5500
5501int
5502scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
5503{
e11e83f3 5504 if (SCM_I_INUMP (val))
73e4de09 5505 {
e11e83f3 5506 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
5507 return n >= min && n <= max;
5508 }
5509 else if (SCM_BIGP (val))
5510 {
5511 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
5512 return 0;
5513 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
5514 {
5515 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
5516 {
5517 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
5518 return n >= min && n <= max;
5519 }
5520 else
5521 return 0;
5522 }
73e4de09
MV
5523 else
5524 {
d956fa6f
MV
5525 scm_t_intmax n;
5526 size_t count;
73e4de09 5527
d956fa6f
MV
5528 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
5529 > CHAR_BIT*sizeof (scm_t_uintmax))
5530 return 0;
5531
5532 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
5533 SCM_I_BIG_MPZ (val));
73e4de09 5534
d956fa6f 5535 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 5536 {
d956fa6f
MV
5537 if (n < 0)
5538 return 0;
73e4de09 5539 }
73e4de09
MV
5540 else
5541 {
d956fa6f
MV
5542 n = -n;
5543 if (n >= 0)
5544 return 0;
73e4de09 5545 }
d956fa6f
MV
5546
5547 return n >= min && n <= max;
73e4de09
MV
5548 }
5549 }
73e4de09
MV
5550 else
5551 return 0;
5552}
5553
5554int
5555scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
5556{
e11e83f3 5557 if (SCM_I_INUMP (val))
73e4de09 5558 {
e11e83f3 5559 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
5560 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
5561 }
5562 else if (SCM_BIGP (val))
5563 {
5564 if (max <= SCM_MOST_POSITIVE_FIXNUM)
5565 return 0;
5566 else if (max <= ULONG_MAX)
d956fa6f
MV
5567 {
5568 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
5569 {
5570 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
5571 return n >= min && n <= max;
5572 }
5573 else
5574 return 0;
5575 }
73e4de09
MV
5576 else
5577 {
d956fa6f
MV
5578 scm_t_uintmax n;
5579 size_t count;
73e4de09 5580
d956fa6f
MV
5581 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
5582 return 0;
73e4de09 5583
d956fa6f
MV
5584 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
5585 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 5586 return 0;
d956fa6f
MV
5587
5588 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
5589 SCM_I_BIG_MPZ (val));
73e4de09 5590
d956fa6f 5591 return n >= min && n <= max;
73e4de09
MV
5592 }
5593 }
73e4de09
MV
5594 else
5595 return 0;
5596}
5597
bfd7932e
MV
5598#define TYPE scm_t_intmax
5599#define TYPE_MIN min
5600#define TYPE_MAX max
5601#define SIZEOF_TYPE 0
5602#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
5603#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
5604#include "libguile/conv-integer.i.c"
5605
5606#define TYPE scm_t_uintmax
5607#define TYPE_MIN min
5608#define TYPE_MAX max
5609#define SIZEOF_TYPE 0
5610#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
5611#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
5612#include "libguile/conv-uinteger.i.c"
5613
5614#define TYPE scm_t_int8
5615#define TYPE_MIN SCM_T_INT8_MIN
5616#define TYPE_MAX SCM_T_INT8_MAX
5617#define SIZEOF_TYPE 1
5618#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
5619#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
5620#include "libguile/conv-integer.i.c"
5621
5622#define TYPE scm_t_uint8
5623#define TYPE_MIN 0
5624#define TYPE_MAX SCM_T_UINT8_MAX
5625#define SIZEOF_TYPE 1
5626#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
5627#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
5628#include "libguile/conv-uinteger.i.c"
5629
5630#define TYPE scm_t_int16
5631#define TYPE_MIN SCM_T_INT16_MIN
5632#define TYPE_MAX SCM_T_INT16_MAX
5633#define SIZEOF_TYPE 2
5634#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
5635#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
5636#include "libguile/conv-integer.i.c"
5637
5638#define TYPE scm_t_uint16
5639#define TYPE_MIN 0
5640#define TYPE_MAX SCM_T_UINT16_MAX
5641#define SIZEOF_TYPE 2
5642#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
5643#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
5644#include "libguile/conv-uinteger.i.c"
5645
5646#define TYPE scm_t_int32
5647#define TYPE_MIN SCM_T_INT32_MIN
5648#define TYPE_MAX SCM_T_INT32_MAX
5649#define SIZEOF_TYPE 4
5650#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
5651#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
5652#include "libguile/conv-integer.i.c"
5653
5654#define TYPE scm_t_uint32
5655#define TYPE_MIN 0
5656#define TYPE_MAX SCM_T_UINT32_MAX
5657#define SIZEOF_TYPE 4
5658#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
5659#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
5660#include "libguile/conv-uinteger.i.c"
5661
5662#if SCM_HAVE_T_INT64
5663
5664#define TYPE scm_t_int64
5665#define TYPE_MIN SCM_T_INT64_MIN
5666#define TYPE_MAX SCM_T_INT64_MAX
5667#define SIZEOF_TYPE 8
5668#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
5669#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
5670#include "libguile/conv-integer.i.c"
5671
5672#define TYPE scm_t_uint64
5673#define TYPE_MIN 0
5674#define TYPE_MAX SCM_T_UINT64_MAX
5675#define SIZEOF_TYPE 8
5676#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
5677#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
5678#include "libguile/conv-uinteger.i.c"
73e4de09 5679
bfd7932e 5680#endif
73e4de09 5681
cd036260
MV
5682void
5683scm_to_mpz (SCM val, mpz_t rop)
5684{
5685 if (SCM_I_INUMP (val))
5686 mpz_set_si (rop, SCM_I_INUM (val));
5687 else if (SCM_BIGP (val))
5688 mpz_set (rop, SCM_I_BIG_MPZ (val));
5689 else
5690 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
5691}
5692
5693SCM
5694scm_from_mpz (mpz_t val)
5695{
5696 return scm_i_mpz2num (val);
5697}
5698
73e4de09
MV
5699int
5700scm_is_real (SCM val)
5701{
5702 return scm_is_true (scm_real_p (val));
5703}
5704
55f26379
MV
5705int
5706scm_is_rational (SCM val)
5707{
5708 return scm_is_true (scm_rational_p (val));
5709}
5710
73e4de09
MV
5711double
5712scm_to_double (SCM val)
5713{
55f26379
MV
5714 if (SCM_I_INUMP (val))
5715 return SCM_I_INUM (val);
5716 else if (SCM_BIGP (val))
5717 return scm_i_big2dbl (val);
5718 else if (SCM_FRACTIONP (val))
5719 return scm_i_fraction2double (val);
5720 else if (SCM_REALP (val))
5721 return SCM_REAL_VALUE (val);
5722 else
5723 scm_wrong_type_arg (NULL, 0, val);
73e4de09
MV
5724}
5725
5726SCM
5727scm_from_double (double val)
5728{
55f26379
MV
5729 SCM z = scm_double_cell (scm_tc16_real, 0, 0, 0);
5730 SCM_REAL_VALUE (z) = val;
5731 return z;
73e4de09
MV
5732}
5733
55f26379
MV
5734#if SCM_ENABLE_DISCOURAGED == 1
5735
5736float
5737scm_num2float (SCM num, unsigned long int pos, const char *s_caller)
5738{
5739 if (SCM_BIGP (num))
5740 {
5741 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
5742 if (!xisinf (res))
5743 return res;
5744 else
5745 scm_out_of_range (NULL, num);
5746 }
5747 else
5748 return scm_to_double (num);
5749}
5750
5751double
5752scm_num2double (SCM num, unsigned long int pos, const char *s_caller)
5753{
5754 if (SCM_BIGP (num))
5755 {
5756 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
5757 if (!xisinf (res))
5758 return res;
5759 else
5760 scm_out_of_range (NULL, num);
5761 }
5762 else
5763 return scm_to_double (num);
5764}
5765
5766#endif
5767
8507ec80
MV
5768int
5769scm_is_complex (SCM val)
5770{
5771 return scm_is_true (scm_complex_p (val));
5772}
5773
5774double
5775scm_c_real_part (SCM z)
5776{
5777 if (SCM_COMPLEXP (z))
5778 return SCM_COMPLEX_REAL (z);
5779 else
5780 {
5781 /* Use the scm_real_part to get proper error checking and
5782 dispatching.
5783 */
5784 return scm_to_double (scm_real_part (z));
5785 }
5786}
5787
5788double
5789scm_c_imag_part (SCM z)
5790{
5791 if (SCM_COMPLEXP (z))
5792 return SCM_COMPLEX_IMAG (z);
5793 else
5794 {
5795 /* Use the scm_imag_part to get proper error checking and
5796 dispatching. The result will almost always be 0.0, but not
5797 always.
5798 */
5799 return scm_to_double (scm_imag_part (z));
5800 }
5801}
5802
5803double
5804scm_c_magnitude (SCM z)
5805{
5806 return scm_to_double (scm_magnitude (z));
5807}
5808
5809double
5810scm_c_angle (SCM z)
5811{
5812 return scm_to_double (scm_angle (z));
5813}
5814
5815int
5816scm_is_number (SCM z)
5817{
5818 return scm_is_true (scm_number_p (z));
5819}
5820
0f2d19dd
JB
5821void
5822scm_init_numbers ()
0f2d19dd 5823{
0b799eea
MV
5824 int i;
5825
713a4259
KR
5826 mpz_init_set_si (z_negative_one, -1);
5827
a261c0e9
DH
5828 /* It may be possible to tune the performance of some algorithms by using
5829 * the following constants to avoid the creation of bignums. Please, before
5830 * using these values, remember the two rules of program optimization:
5831 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 5832 scm_c_define ("most-positive-fixnum",
d956fa6f 5833 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 5834 scm_c_define ("most-negative-fixnum",
d956fa6f 5835 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 5836
f3ae5d60
MD
5837 scm_add_feature ("complex");
5838 scm_add_feature ("inexact");
55f26379 5839 scm_flo0 = scm_from_double (0.0);
0b799eea
MV
5840
5841 /* determine floating point precision */
55f26379 5842 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
5843 {
5844 init_dblprec(&scm_dblprec[i-2],i);
5845 init_fx_radix(fx_per_radix[i-2],i);
5846 }
f872b822 5847#ifdef DBL_DIG
0b799eea
MV
5848 /* hard code precision for base 10 if the preprocessor tells us to... */
5849 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
5850#endif
1be6b49c 5851
d956fa6f
MV
5852 exactly_one_half = scm_permanent_object (scm_divide (SCM_I_MAKINUM (1),
5853 SCM_I_MAKINUM (2)));
a0599745 5854#include "libguile/numbers.x"
0f2d19dd 5855}
89e00824
ML
5856
5857/*
5858 Local Variables:
5859 c-file-style: "gnu"
5860 End:
5861*/