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