allow iflags to be constant expressions with typing-strictness==2
[bpt/guile.git] / libguile / numbers.c
CommitLineData
8e43ed5d 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005, 2006, 2007, 2008, 2009, 2010, 2011 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 7 * This library is free software; you can redistribute it and/or
53befeb7
NJ
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 3 of
10 * the License, or (at your option) any later version.
0f2d19dd 11 *
53befeb7
NJ
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
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
53befeb7
NJ
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA
73be1d9e 21 */
1bbd0b84 22
0f2d19dd 23\f
ca46fb90 24/* General assumptions:
ca46fb90
RB
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.
c7218482 28 * XXX What about infinities? They are equal to their own floor! -mhw
f92e85f7 29 * All objects satisfying SCM_FRACTIONP are never an integer.
ca46fb90
RB
30 */
31
32/* TODO:
33
34 - see if special casing bignums and reals in integer-exponent when
35 possible (to use mpz_pow and mpf_pow_ui) is faster.
36
37 - look in to better short-circuiting of common cases in
38 integer-expt and elsewhere.
39
40 - see if direct mpz operations can help in ash and elsewhere.
41
42 */
0f2d19dd 43
dbb605f5 44#ifdef HAVE_CONFIG_H
ee33d62a
RB
45# include <config.h>
46#endif
47
bbec4602
LC
48#include <verify.h>
49
0f2d19dd 50#include <math.h>
fc194577 51#include <string.h>
3f47e526
MG
52#include <unicase.h>
53#include <unictype.h>
f92e85f7 54
8ab3d8a0
KR
55#if HAVE_COMPLEX_H
56#include <complex.h>
57#endif
58
a0599745 59#include "libguile/_scm.h"
a0599745
MD
60#include "libguile/feature.h"
61#include "libguile/ports.h"
62#include "libguile/root.h"
63#include "libguile/smob.h"
64#include "libguile/strings.h"
864e7d42 65#include "libguile/bdw-gc.h"
a0599745
MD
66
67#include "libguile/validate.h"
68#include "libguile/numbers.h"
1be6b49c 69#include "libguile/deprecation.h"
f4c627b3 70
f92e85f7
MV
71#include "libguile/eq.h"
72
8ab3d8a0
KR
73/* values per glibc, if not already defined */
74#ifndef M_LOG10E
75#define M_LOG10E 0.43429448190325182765
76#endif
85bdb6ac
MW
77#ifndef M_LN2
78#define M_LN2 0.69314718055994530942
79#endif
8ab3d8a0
KR
80#ifndef M_PI
81#define M_PI 3.14159265358979323846
82#endif
83
e25f3727
AW
84typedef scm_t_signed_bits scm_t_inum;
85#define scm_from_inum(x) (scm_from_signed_integer (x))
86
7112615f
MW
87/* Tests to see if a C double is neither infinite nor a NaN.
88 TODO: if it's available, use C99's isfinite(x) instead */
89#define DOUBLE_IS_FINITE(x) (!isinf(x) && !isnan(x))
90
041fccf6
MW
91/* On some platforms, isinf(x) returns 0, 1 or -1, indicating the sign
92 of the infinity, but other platforms return a boolean only. */
93#define DOUBLE_IS_POSITIVE_INFINITY(x) (isinf(x) && ((x) > 0))
94#define DOUBLE_IS_NEGATIVE_INFINITY(x) (isinf(x) && ((x) < 0))
95
0f2d19dd 96\f
f4c627b3 97
ca46fb90
RB
98/*
99 Wonder if this might be faster for some of our code? A switch on
100 the numtag would jump directly to the right case, and the
101 SCM_I_NUMTAG code might be faster than repeated SCM_FOOP tests...
102
103 #define SCM_I_NUMTAG_NOTNUM 0
104 #define SCM_I_NUMTAG_INUM 1
105 #define SCM_I_NUMTAG_BIG scm_tc16_big
106 #define SCM_I_NUMTAG_REAL scm_tc16_real
107 #define SCM_I_NUMTAG_COMPLEX scm_tc16_complex
108 #define SCM_I_NUMTAG(x) \
e11e83f3 109 (SCM_I_INUMP(x) ? SCM_I_NUMTAG_INUM \
ca46fb90 110 : (SCM_IMP(x) ? SCM_I_NUMTAG_NOTNUM \
534c55a9 111 : (((0xfcff & SCM_CELL_TYPE (x)) == scm_tc7_number) ? SCM_TYP16(x) \
ca46fb90
RB
112 : SCM_I_NUMTAG_NOTNUM)))
113*/
f92e85f7 114/* the macro above will not work as is with fractions */
f4c627b3
DH
115
116
e7efe8e7 117static SCM flo0;
ff62c168 118static SCM exactly_one_half;
a5f6b751 119static SCM flo_log10e;
e7efe8e7 120
34d19ef6 121#define SCM_SWAP(x, y) do { SCM __t = x; x = y; y = __t; } while (0)
09fb7599 122
56e55ac7 123/* FLOBUFLEN is the maximum number of characters neccessary for the
3a9809df
DH
124 * printed or scm_string representation of an inexact number.
125 */
0b799eea 126#define FLOBUFLEN (40+2*(sizeof(double)/sizeof(char)*SCM_CHAR_BIT*3+9)/10)
3a9809df 127
b127c712 128
ad79736c
AW
129#if !defined (HAVE_ASINH)
130static double asinh (double x) { return log (x + sqrt (x * x + 1)); }
131#endif
132#if !defined (HAVE_ACOSH)
133static double acosh (double x) { return log (x + sqrt (x * x - 1)); }
134#endif
135#if !defined (HAVE_ATANH)
136static double atanh (double x) { return 0.5 * log ((1 + x) / (1 - x)); }
137#endif
138
18d78c5e
MW
139/* mpz_cmp_d in GMP before 4.2 didn't recognise infinities, so
140 xmpz_cmp_d uses an explicit check. Starting with GMP 4.2 (released
141 in March 2006), mpz_cmp_d now handles infinities properly. */
f8a8200b 142#if 1
b127c712 143#define xmpz_cmp_d(z, d) \
2e65b52f 144 (isinf (d) ? (d < 0.0 ? 1 : -1) : mpz_cmp_d (z, d))
b127c712
KR
145#else
146#define xmpz_cmp_d(z, d) mpz_cmp_d (z, d)
147#endif
148
f92e85f7 149
4b26c03e 150#if defined (GUILE_I)
03976fee 151#if defined HAVE_COMPLEX_DOUBLE
8ab3d8a0
KR
152
153/* For an SCM object Z which is a complex number (ie. satisfies
154 SCM_COMPLEXP), return its value as a C level "complex double". */
155#define SCM_COMPLEX_VALUE(z) \
4b26c03e 156 (SCM_COMPLEX_REAL (z) + GUILE_I * SCM_COMPLEX_IMAG (z))
8ab3d8a0 157
7a35784c 158static inline SCM scm_from_complex_double (complex double z) SCM_UNUSED;
8ab3d8a0
KR
159
160/* Convert a C "complex double" to an SCM value. */
7a35784c 161static inline SCM
8ab3d8a0
KR
162scm_from_complex_double (complex double z)
163{
164 return scm_c_make_rectangular (creal (z), cimag (z));
165}
bca69a9f 166
8ab3d8a0 167#endif /* HAVE_COMPLEX_DOUBLE */
bca69a9f 168#endif /* GUILE_I */
8ab3d8a0 169
0f2d19dd
JB
170\f
171
713a4259 172static mpz_t z_negative_one;
ac0c002c
DH
173
174\f
864e7d42
LC
175/* Clear the `mpz_t' embedded in bignum PTR. */
176static void
177finalize_bignum (GC_PTR ptr, GC_PTR data)
178{
179 SCM bignum;
180
181 bignum = PTR2SCM (ptr);
182 mpz_clear (SCM_I_BIG_MPZ (bignum));
183}
184
d017fcdf
LC
185/* Return a new uninitialized bignum. */
186static inline SCM
187make_bignum (void)
188{
189 scm_t_bits *p;
864e7d42
LC
190 GC_finalization_proc prev_finalizer;
191 GC_PTR prev_finalizer_data;
d017fcdf
LC
192
193 /* Allocate one word for the type tag and enough room for an `mpz_t'. */
194 p = scm_gc_malloc_pointerless (sizeof (scm_t_bits) + sizeof (mpz_t),
195 "bignum");
196 p[0] = scm_tc16_big;
197
864e7d42
LC
198 GC_REGISTER_FINALIZER_NO_ORDER (p, finalize_bignum, NULL,
199 &prev_finalizer,
200 &prev_finalizer_data);
201
d017fcdf
LC
202 return SCM_PACK (p);
203}
ac0c002c 204
864e7d42 205
189171c5 206SCM
ca46fb90
RB
207scm_i_mkbig ()
208{
209 /* Return a newly created bignum. */
d017fcdf 210 SCM z = make_bignum ();
ca46fb90
RB
211 mpz_init (SCM_I_BIG_MPZ (z));
212 return z;
213}
214
e25f3727
AW
215static SCM
216scm_i_inum2big (scm_t_inum x)
217{
218 /* Return a newly created bignum initialized to X. */
219 SCM z = make_bignum ();
220#if SIZEOF_VOID_P == SIZEOF_LONG
221 mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
222#else
223 /* Note that in this case, you'll also have to check all mpz_*_ui and
224 mpz_*_si invocations in Guile. */
225#error creation of mpz not implemented for this inum size
226#endif
227 return z;
228}
229
189171c5 230SCM
c71b0706
MV
231scm_i_long2big (long x)
232{
233 /* Return a newly created bignum initialized to X. */
d017fcdf 234 SCM z = make_bignum ();
c71b0706
MV
235 mpz_init_set_si (SCM_I_BIG_MPZ (z), x);
236 return z;
237}
238
189171c5 239SCM
c71b0706
MV
240scm_i_ulong2big (unsigned long x)
241{
242 /* Return a newly created bignum initialized to X. */
d017fcdf 243 SCM z = make_bignum ();
c71b0706
MV
244 mpz_init_set_ui (SCM_I_BIG_MPZ (z), x);
245 return z;
246}
247
189171c5 248SCM
ca46fb90
RB
249scm_i_clonebig (SCM src_big, int same_sign_p)
250{
251 /* Copy src_big's value, negate it if same_sign_p is false, and return. */
d017fcdf 252 SCM z = make_bignum ();
ca46fb90 253 mpz_init_set (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (src_big));
0aacf84e
MD
254 if (!same_sign_p)
255 mpz_neg (SCM_I_BIG_MPZ (z), SCM_I_BIG_MPZ (z));
ca46fb90
RB
256 return z;
257}
258
189171c5 259int
ca46fb90
RB
260scm_i_bigcmp (SCM x, SCM y)
261{
262 /* Return neg if x < y, pos if x > y, and 0 if x == y */
263 /* presume we already know x and y are bignums */
264 int result = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
265 scm_remember_upto_here_2 (x, y);
266 return result;
267}
268
189171c5 269SCM
ca46fb90
RB
270scm_i_dbl2big (double d)
271{
272 /* results are only defined if d is an integer */
d017fcdf 273 SCM z = make_bignum ();
ca46fb90
RB
274 mpz_init_set_d (SCM_I_BIG_MPZ (z), d);
275 return z;
276}
277
f92e85f7
MV
278/* Convert a integer in double representation to a SCM number. */
279
189171c5 280SCM
f92e85f7
MV
281scm_i_dbl2num (double u)
282{
283 /* SCM_MOST_POSITIVE_FIXNUM+1 and SCM_MOST_NEGATIVE_FIXNUM are both
284 powers of 2, so there's no rounding when making "double" values
285 from them. If plain SCM_MOST_POSITIVE_FIXNUM was used it could
286 get rounded on a 64-bit machine, hence the "+1".
287
288 The use of floor() to force to an integer value ensures we get a
289 "numerically closest" value without depending on how a
290 double->long cast or how mpz_set_d will round. For reference,
291 double->long probably follows the hardware rounding mode,
292 mpz_set_d truncates towards zero. */
293
294 /* XXX - what happens when SCM_MOST_POSITIVE_FIXNUM etc is not
295 representable as a double? */
296
297 if (u < (double) (SCM_MOST_POSITIVE_FIXNUM+1)
298 && u >= (double) SCM_MOST_NEGATIVE_FIXNUM)
e25f3727 299 return SCM_I_MAKINUM ((scm_t_inum) u);
f92e85f7
MV
300 else
301 return scm_i_dbl2big (u);
302}
303
089c9a59
KR
304/* scm_i_big2dbl() rounds to the closest representable double, in accordance
305 with R5RS exact->inexact.
306
307 The approach is to use mpz_get_d to pick out the high DBL_MANT_DIG bits
f8a8200b
KR
308 (ie. truncate towards zero), then adjust to get the closest double by
309 examining the next lower bit and adding 1 (to the absolute value) if
310 necessary.
311
312 Bignums exactly half way between representable doubles are rounded to the
313 next higher absolute value (ie. away from zero). This seems like an
314 adequate interpretation of R5RS "numerically closest", and it's easier
315 and faster than a full "nearest-even" style.
316
317 The bit test must be done on the absolute value of the mpz_t, which means
318 we need to use mpz_getlimbn. mpz_tstbit is not right, it treats
319 negatives as twos complement.
320
18d78c5e
MW
321 In GMP before 4.2, mpz_get_d rounding was unspecified. It ended up
322 following the hardware rounding mode, but applied to the absolute
323 value of the mpz_t operand. This is not what we want so we put the
324 high DBL_MANT_DIG bits into a temporary. Starting with GMP 4.2
325 (released in March 2006) mpz_get_d now always truncates towards zero.
f8a8200b 326
18d78c5e
MW
327 ENHANCE-ME: The temporary init+clear to force the rounding in GMP
328 before 4.2 is a slowdown. It'd be faster to pick out the relevant
329 high bits with mpz_getlimbn. */
089c9a59
KR
330
331double
ca46fb90
RB
332scm_i_big2dbl (SCM b)
333{
089c9a59
KR
334 double result;
335 size_t bits;
336
337 bits = mpz_sizeinbase (SCM_I_BIG_MPZ (b), 2);
338
f8a8200b 339#if 1
089c9a59 340 {
18d78c5e
MW
341 /* For GMP earlier than 4.2, force truncation towards zero */
342
343 /* FIXME: DBL_MANT_DIG is the number of base-`FLT_RADIX' digits,
344 _not_ the number of bits, so this code will break badly on a
345 system with non-binary doubles. */
346
089c9a59
KR
347 mpz_t tmp;
348 if (bits > DBL_MANT_DIG)
349 {
350 size_t shift = bits - DBL_MANT_DIG;
351 mpz_init2 (tmp, DBL_MANT_DIG);
352 mpz_tdiv_q_2exp (tmp, SCM_I_BIG_MPZ (b), shift);
353 result = ldexp (mpz_get_d (tmp), shift);
354 mpz_clear (tmp);
355 }
356 else
357 {
358 result = mpz_get_d (SCM_I_BIG_MPZ (b));
359 }
360 }
361#else
18d78c5e 362 /* GMP 4.2 or later */
089c9a59
KR
363 result = mpz_get_d (SCM_I_BIG_MPZ (b));
364#endif
365
366 if (bits > DBL_MANT_DIG)
367 {
368 unsigned long pos = bits - DBL_MANT_DIG - 1;
369 /* test bit number "pos" in absolute value */
370 if (mpz_getlimbn (SCM_I_BIG_MPZ (b), pos / GMP_NUMB_BITS)
371 & ((mp_limb_t) 1 << (pos % GMP_NUMB_BITS)))
372 {
373 result += ldexp ((double) mpz_sgn (SCM_I_BIG_MPZ (b)), pos + 1);
374 }
375 }
376
ca46fb90
RB
377 scm_remember_upto_here_1 (b);
378 return result;
379}
380
189171c5 381SCM
ca46fb90
RB
382scm_i_normbig (SCM b)
383{
384 /* convert a big back to a fixnum if it'll fit */
385 /* presume b is a bignum */
386 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (b)))
387 {
e25f3727 388 scm_t_inum val = mpz_get_si (SCM_I_BIG_MPZ (b));
ca46fb90 389 if (SCM_FIXABLE (val))
d956fa6f 390 b = SCM_I_MAKINUM (val);
ca46fb90
RB
391 }
392 return b;
393}
f872b822 394
f92e85f7
MV
395static SCM_C_INLINE_KEYWORD SCM
396scm_i_mpz2num (mpz_t b)
397{
398 /* convert a mpz number to a SCM number. */
399 if (mpz_fits_slong_p (b))
400 {
e25f3727 401 scm_t_inum val = mpz_get_si (b);
f92e85f7 402 if (SCM_FIXABLE (val))
d956fa6f 403 return SCM_I_MAKINUM (val);
f92e85f7
MV
404 }
405
406 {
d017fcdf 407 SCM z = make_bignum ();
f92e85f7
MV
408 mpz_init_set (SCM_I_BIG_MPZ (z), b);
409 return z;
410 }
411}
412
413/* this is needed when we want scm_divide to make a float, not a ratio, even if passed two ints */
414static SCM scm_divide2real (SCM x, SCM y);
415
cba42c93
MV
416static SCM
417scm_i_make_ratio (SCM numerator, SCM denominator)
c60e130c 418#define FUNC_NAME "make-ratio"
f92e85f7 419{
c60e130c
MV
420 /* First make sure the arguments are proper.
421 */
e11e83f3 422 if (SCM_I_INUMP (denominator))
f92e85f7 423 {
bc36d050 424 if (scm_is_eq (denominator, SCM_INUM0))
f92e85f7 425 scm_num_overflow ("make-ratio");
cff5fa33 426 if (scm_is_eq (denominator, SCM_INUM1))
f92e85f7
MV
427 return numerator;
428 }
429 else
430 {
431 if (!(SCM_BIGP(denominator)))
432 SCM_WRONG_TYPE_ARG (2, denominator);
433 }
e11e83f3 434 if (!SCM_I_INUMP (numerator) && !SCM_BIGP (numerator))
c60e130c
MV
435 SCM_WRONG_TYPE_ARG (1, numerator);
436
437 /* Then flip signs so that the denominator is positive.
438 */
73e4de09 439 if (scm_is_true (scm_negative_p (denominator)))
c60e130c
MV
440 {
441 numerator = scm_difference (numerator, SCM_UNDEFINED);
442 denominator = scm_difference (denominator, SCM_UNDEFINED);
443 }
444
445 /* Now consider for each of the four fixnum/bignum combinations
446 whether the rational number is really an integer.
447 */
e11e83f3 448 if (SCM_I_INUMP (numerator))
f92e85f7 449 {
e25f3727 450 scm_t_inum x = SCM_I_INUM (numerator);
bc36d050 451 if (scm_is_eq (numerator, SCM_INUM0))
f92e85f7 452 return SCM_INUM0;
e11e83f3 453 if (SCM_I_INUMP (denominator))
f92e85f7 454 {
e25f3727 455 scm_t_inum y;
e11e83f3 456 y = SCM_I_INUM (denominator);
f92e85f7 457 if (x == y)
cff5fa33 458 return SCM_INUM1;
f92e85f7 459 if ((x % y) == 0)
d956fa6f 460 return SCM_I_MAKINUM (x / y);
f92e85f7 461 }
dd5130ca
KR
462 else
463 {
464 /* When x == SCM_MOST_NEGATIVE_FIXNUM we could have the negative
3271a325
KR
465 of that value for the denominator, as a bignum. Apart from
466 that case, abs(bignum) > abs(inum) so inum/bignum is not an
467 integer. */
468 if (x == SCM_MOST_NEGATIVE_FIXNUM
469 && mpz_cmp_ui (SCM_I_BIG_MPZ (denominator),
470 - SCM_MOST_NEGATIVE_FIXNUM) == 0)
d956fa6f 471 return SCM_I_MAKINUM(-1);
dd5130ca 472 }
f92e85f7 473 }
c60e130c 474 else if (SCM_BIGP (numerator))
f92e85f7 475 {
e11e83f3 476 if (SCM_I_INUMP (denominator))
c60e130c 477 {
e25f3727 478 scm_t_inum yy = SCM_I_INUM (denominator);
c60e130c
MV
479 if (mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), yy))
480 return scm_divide (numerator, denominator);
481 }
482 else
f92e85f7 483 {
bc36d050 484 if (scm_is_eq (numerator, denominator))
cff5fa33 485 return SCM_INUM1;
c60e130c
MV
486 if (mpz_divisible_p (SCM_I_BIG_MPZ (numerator),
487 SCM_I_BIG_MPZ (denominator)))
488 return scm_divide(numerator, denominator);
f92e85f7 489 }
f92e85f7 490 }
c60e130c
MV
491
492 /* No, it's a proper fraction.
493 */
e2bf3b19
HWN
494 {
495 SCM divisor = scm_gcd (numerator, denominator);
cff5fa33 496 if (!(scm_is_eq (divisor, SCM_INUM1)))
e2bf3b19
HWN
497 {
498 numerator = scm_divide (numerator, divisor);
499 denominator = scm_divide (denominator, divisor);
500 }
501
502 return scm_double_cell (scm_tc16_fraction,
503 SCM_UNPACK (numerator),
504 SCM_UNPACK (denominator), 0);
505 }
f92e85f7 506}
c60e130c 507#undef FUNC_NAME
f92e85f7 508
f92e85f7
MV
509double
510scm_i_fraction2double (SCM z)
511{
55f26379
MV
512 return scm_to_double (scm_divide2real (SCM_FRACTION_NUMERATOR (z),
513 SCM_FRACTION_DENOMINATOR (z)));
f92e85f7
MV
514}
515
2e274311
MW
516static int
517double_is_non_negative_zero (double x)
518{
519 static double zero = 0.0;
520
521 return !memcmp (&x, &zero, sizeof(double));
522}
523
2519490c
MW
524SCM_PRIMITIVE_GENERIC (scm_exact_p, "exact?", 1, 0, 0,
525 (SCM x),
942e5b91
MG
526 "Return @code{#t} if @var{x} is an exact number, @code{#f}\n"
527 "otherwise.")
1bbd0b84 528#define FUNC_NAME s_scm_exact_p
0f2d19dd 529{
41df63cf
MW
530 if (SCM_INEXACTP (x))
531 return SCM_BOOL_F;
532 else if (SCM_NUMBERP (x))
0aacf84e 533 return SCM_BOOL_T;
41df63cf 534 else
2519490c 535 SCM_WTA_DISPATCH_1 (g_scm_exact_p, x, 1, s_scm_exact_p);
41df63cf
MW
536}
537#undef FUNC_NAME
538
539
2519490c 540SCM_PRIMITIVE_GENERIC (scm_inexact_p, "inexact?", 1, 0, 0,
41df63cf
MW
541 (SCM x),
542 "Return @code{#t} if @var{x} is an inexact number, @code{#f}\n"
543 "else.")
544#define FUNC_NAME s_scm_inexact_p
545{
546 if (SCM_INEXACTP (x))
f92e85f7 547 return SCM_BOOL_T;
41df63cf 548 else if (SCM_NUMBERP (x))
eb927cb9 549 return SCM_BOOL_F;
41df63cf 550 else
2519490c 551 SCM_WTA_DISPATCH_1 (g_scm_inexact_p, x, 1, s_scm_inexact_p);
0f2d19dd 552}
1bbd0b84 553#undef FUNC_NAME
0f2d19dd 554
4219f20d 555
2519490c 556SCM_PRIMITIVE_GENERIC (scm_odd_p, "odd?", 1, 0, 0,
1bbd0b84 557 (SCM n),
942e5b91
MG
558 "Return @code{#t} if @var{n} is an odd number, @code{#f}\n"
559 "otherwise.")
1bbd0b84 560#define FUNC_NAME s_scm_odd_p
0f2d19dd 561{
e11e83f3 562 if (SCM_I_INUMP (n))
0aacf84e 563 {
e25f3727 564 scm_t_inum val = SCM_I_INUM (n);
73e4de09 565 return scm_from_bool ((val & 1L) != 0);
0aacf84e
MD
566 }
567 else if (SCM_BIGP (n))
568 {
569 int odd_p = mpz_odd_p (SCM_I_BIG_MPZ (n));
570 scm_remember_upto_here_1 (n);
73e4de09 571 return scm_from_bool (odd_p);
0aacf84e 572 }
f92e85f7
MV
573 else if (SCM_REALP (n))
574 {
2519490c
MW
575 double val = SCM_REAL_VALUE (n);
576 if (DOUBLE_IS_FINITE (val))
577 {
578 double rem = fabs (fmod (val, 2.0));
579 if (rem == 1.0)
580 return SCM_BOOL_T;
581 else if (rem == 0.0)
582 return SCM_BOOL_F;
583 }
f92e85f7 584 }
2519490c 585 SCM_WTA_DISPATCH_1 (g_scm_odd_p, n, 1, s_scm_odd_p);
0f2d19dd 586}
1bbd0b84 587#undef FUNC_NAME
0f2d19dd 588
4219f20d 589
2519490c 590SCM_PRIMITIVE_GENERIC (scm_even_p, "even?", 1, 0, 0,
1bbd0b84 591 (SCM n),
942e5b91
MG
592 "Return @code{#t} if @var{n} is an even number, @code{#f}\n"
593 "otherwise.")
1bbd0b84 594#define FUNC_NAME s_scm_even_p
0f2d19dd 595{
e11e83f3 596 if (SCM_I_INUMP (n))
0aacf84e 597 {
e25f3727 598 scm_t_inum val = SCM_I_INUM (n);
73e4de09 599 return scm_from_bool ((val & 1L) == 0);
0aacf84e
MD
600 }
601 else if (SCM_BIGP (n))
602 {
603 int even_p = mpz_even_p (SCM_I_BIG_MPZ (n));
604 scm_remember_upto_here_1 (n);
73e4de09 605 return scm_from_bool (even_p);
0aacf84e 606 }
f92e85f7
MV
607 else if (SCM_REALP (n))
608 {
2519490c
MW
609 double val = SCM_REAL_VALUE (n);
610 if (DOUBLE_IS_FINITE (val))
611 {
612 double rem = fabs (fmod (val, 2.0));
613 if (rem == 1.0)
614 return SCM_BOOL_F;
615 else if (rem == 0.0)
616 return SCM_BOOL_T;
617 }
f92e85f7 618 }
2519490c 619 SCM_WTA_DISPATCH_1 (g_scm_even_p, n, 1, s_scm_even_p);
0f2d19dd 620}
1bbd0b84 621#undef FUNC_NAME
0f2d19dd 622
2519490c
MW
623SCM_PRIMITIVE_GENERIC (scm_finite_p, "finite?", 1, 0, 0,
624 (SCM x),
10391e06
AW
625 "Return @code{#t} if the real number @var{x} is neither\n"
626 "infinite nor a NaN, @code{#f} otherwise.")
7112615f
MW
627#define FUNC_NAME s_scm_finite_p
628{
629 if (SCM_REALP (x))
630 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
10391e06 631 else if (scm_is_real (x))
7112615f
MW
632 return SCM_BOOL_T;
633 else
2519490c 634 SCM_WTA_DISPATCH_1 (g_scm_finite_p, x, 1, s_scm_finite_p);
7112615f
MW
635}
636#undef FUNC_NAME
637
2519490c
MW
638SCM_PRIMITIVE_GENERIC (scm_inf_p, "inf?", 1, 0, 0,
639 (SCM x),
640 "Return @code{#t} if the real number @var{x} is @samp{+inf.0} or\n"
641 "@samp{-inf.0}. Otherwise return @code{#f}.")
7351e207
MV
642#define FUNC_NAME s_scm_inf_p
643{
b1092b3a 644 if (SCM_REALP (x))
2e65b52f 645 return scm_from_bool (isinf (SCM_REAL_VALUE (x)));
10391e06 646 else if (scm_is_real (x))
7351e207 647 return SCM_BOOL_F;
10391e06 648 else
2519490c 649 SCM_WTA_DISPATCH_1 (g_scm_inf_p, x, 1, s_scm_inf_p);
7351e207
MV
650}
651#undef FUNC_NAME
652
2519490c
MW
653SCM_PRIMITIVE_GENERIC (scm_nan_p, "nan?", 1, 0, 0,
654 (SCM x),
10391e06
AW
655 "Return @code{#t} if the real number @var{x} is a NaN,\n"
656 "or @code{#f} otherwise.")
7351e207
MV
657#define FUNC_NAME s_scm_nan_p
658{
10391e06
AW
659 if (SCM_REALP (x))
660 return scm_from_bool (isnan (SCM_REAL_VALUE (x)));
661 else if (scm_is_real (x))
7351e207 662 return SCM_BOOL_F;
10391e06 663 else
2519490c 664 SCM_WTA_DISPATCH_1 (g_scm_nan_p, x, 1, s_scm_nan_p);
7351e207
MV
665}
666#undef FUNC_NAME
667
668/* Guile's idea of infinity. */
669static double guile_Inf;
670
671/* Guile's idea of not a number. */
672static double guile_NaN;
673
674static void
675guile_ieee_init (void)
676{
7351e207
MV
677/* Some version of gcc on some old version of Linux used to crash when
678 trying to make Inf and NaN. */
679
240a27d2
KR
680#ifdef INFINITY
681 /* C99 INFINITY, when available.
682 FIXME: The standard allows for INFINITY to be something that overflows
683 at compile time. We ought to have a configure test to check for that
684 before trying to use it. (But in practice we believe this is not a
685 problem on any system guile is likely to target.) */
686 guile_Inf = INFINITY;
56a3dcd4 687#elif defined HAVE_DINFINITY
240a27d2 688 /* OSF */
7351e207 689 extern unsigned int DINFINITY[2];
eaa94eaa 690 guile_Inf = (*((double *) (DINFINITY)));
7351e207
MV
691#else
692 double tmp = 1e+10;
693 guile_Inf = tmp;
694 for (;;)
695 {
696 guile_Inf *= 1e+10;
697 if (guile_Inf == tmp)
698 break;
699 tmp = guile_Inf;
700 }
701#endif
702
240a27d2
KR
703#ifdef NAN
704 /* C99 NAN, when available */
705 guile_NaN = NAN;
56a3dcd4 706#elif defined HAVE_DQNAN
eaa94eaa
LC
707 {
708 /* OSF */
709 extern unsigned int DQNAN[2];
710 guile_NaN = (*((double *)(DQNAN)));
711 }
7351e207
MV
712#else
713 guile_NaN = guile_Inf / guile_Inf;
714#endif
7351e207
MV
715}
716
717SCM_DEFINE (scm_inf, "inf", 0, 0, 0,
718 (void),
719 "Return Inf.")
720#define FUNC_NAME s_scm_inf
721{
722 static int initialized = 0;
723 if (! initialized)
724 {
725 guile_ieee_init ();
726 initialized = 1;
727 }
55f26379 728 return scm_from_double (guile_Inf);
7351e207
MV
729}
730#undef FUNC_NAME
731
732SCM_DEFINE (scm_nan, "nan", 0, 0, 0,
733 (void),
734 "Return NaN.")
735#define FUNC_NAME s_scm_nan
736{
737 static int initialized = 0;
0aacf84e 738 if (!initialized)
7351e207
MV
739 {
740 guile_ieee_init ();
741 initialized = 1;
742 }
55f26379 743 return scm_from_double (guile_NaN);
7351e207
MV
744}
745#undef FUNC_NAME
746
4219f20d 747
a48d60b1
MD
748SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
749 (SCM x),
750 "Return the absolute value of @var{x}.")
2519490c 751#define FUNC_NAME s_scm_abs
0f2d19dd 752{
e11e83f3 753 if (SCM_I_INUMP (x))
0aacf84e 754 {
e25f3727 755 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
756 if (xx >= 0)
757 return x;
758 else if (SCM_POSFIXABLE (-xx))
d956fa6f 759 return SCM_I_MAKINUM (-xx);
0aacf84e 760 else
e25f3727 761 return scm_i_inum2big (-xx);
4219f20d 762 }
9b9ef10c
MW
763 else if (SCM_LIKELY (SCM_REALP (x)))
764 {
765 double xx = SCM_REAL_VALUE (x);
766 /* If x is a NaN then xx<0 is false so we return x unchanged */
767 if (xx < 0.0)
768 return scm_from_double (-xx);
769 /* Handle signed zeroes properly */
770 else if (SCM_UNLIKELY (xx == 0.0))
771 return flo0;
772 else
773 return x;
774 }
0aacf84e
MD
775 else if (SCM_BIGP (x))
776 {
777 const int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
778 if (sgn < 0)
779 return scm_i_clonebig (x, 0);
780 else
781 return x;
4219f20d 782 }
f92e85f7
MV
783 else if (SCM_FRACTIONP (x))
784 {
73e4de09 785 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (x))))
f92e85f7 786 return x;
cba42c93 787 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7
MV
788 SCM_FRACTION_DENOMINATOR (x));
789 }
0aacf84e 790 else
a48d60b1 791 SCM_WTA_DISPATCH_1 (g_scm_abs, x, 1, s_scm_abs);
0f2d19dd 792}
a48d60b1 793#undef FUNC_NAME
0f2d19dd 794
4219f20d 795
2519490c
MW
796SCM_PRIMITIVE_GENERIC (scm_quotient, "quotient", 2, 0, 0,
797 (SCM x, SCM y),
798 "Return the quotient of the numbers @var{x} and @var{y}.")
799#define FUNC_NAME s_scm_quotient
0f2d19dd 800{
495a39c4 801 if (SCM_LIKELY (scm_is_integer (x)))
0aacf84e 802 {
495a39c4 803 if (SCM_LIKELY (scm_is_integer (y)))
a8da6d93 804 return scm_truncate_quotient (x, y);
0aacf84e 805 else
2519490c 806 SCM_WTA_DISPATCH_2 (g_scm_quotient, x, y, SCM_ARG2, s_scm_quotient);
f872b822 807 }
0aacf84e 808 else
2519490c 809 SCM_WTA_DISPATCH_2 (g_scm_quotient, x, y, SCM_ARG1, s_scm_quotient);
0f2d19dd 810}
2519490c 811#undef FUNC_NAME
0f2d19dd 812
2519490c
MW
813SCM_PRIMITIVE_GENERIC (scm_remainder, "remainder", 2, 0, 0,
814 (SCM x, SCM y),
815 "Return the remainder of the numbers @var{x} and @var{y}.\n"
816 "@lisp\n"
817 "(remainder 13 4) @result{} 1\n"
818 "(remainder -13 4) @result{} -1\n"
819 "@end lisp")
820#define FUNC_NAME s_scm_remainder
0f2d19dd 821{
495a39c4 822 if (SCM_LIKELY (scm_is_integer (x)))
0aacf84e 823 {
495a39c4 824 if (SCM_LIKELY (scm_is_integer (y)))
a8da6d93 825 return scm_truncate_remainder (x, y);
0aacf84e 826 else
2519490c 827 SCM_WTA_DISPATCH_2 (g_scm_remainder, x, y, SCM_ARG2, s_scm_remainder);
f872b822 828 }
0aacf84e 829 else
2519490c 830 SCM_WTA_DISPATCH_2 (g_scm_remainder, x, y, SCM_ARG1, s_scm_remainder);
0f2d19dd 831}
2519490c 832#undef FUNC_NAME
0f2d19dd 833
89a7e495 834
2519490c
MW
835SCM_PRIMITIVE_GENERIC (scm_modulo, "modulo", 2, 0, 0,
836 (SCM x, SCM y),
837 "Return the modulo of the numbers @var{x} and @var{y}.\n"
838 "@lisp\n"
839 "(modulo 13 4) @result{} 1\n"
840 "(modulo -13 4) @result{} 3\n"
841 "@end lisp")
842#define FUNC_NAME s_scm_modulo
0f2d19dd 843{
495a39c4 844 if (SCM_LIKELY (scm_is_integer (x)))
0aacf84e 845 {
495a39c4 846 if (SCM_LIKELY (scm_is_integer (y)))
a8da6d93 847 return scm_floor_remainder (x, y);
0aacf84e 848 else
2519490c 849 SCM_WTA_DISPATCH_2 (g_scm_modulo, x, y, SCM_ARG2, s_scm_modulo);
828865c3 850 }
0aacf84e 851 else
2519490c 852 SCM_WTA_DISPATCH_2 (g_scm_modulo, x, y, SCM_ARG1, s_scm_modulo);
0f2d19dd 853}
2519490c 854#undef FUNC_NAME
0f2d19dd 855
5fbf680b
MW
856/* two_valued_wta_dispatch_2 is a version of SCM_WTA_DISPATCH_2 for
857 two-valued functions. It is called from primitive generics that take
858 two arguments and return two values, when the core procedure is
859 unable to handle the given argument types. If there are GOOPS
860 methods for this primitive generic, it dispatches to GOOPS and, if
861 successful, expects two values to be returned, which are placed in
862 *rp1 and *rp2. If there are no GOOPS methods, it throws a
863 wrong-type-arg exception.
864
865 FIXME: This obviously belongs somewhere else, but until we decide on
866 the right API, it is here as a static function, because it is needed
867 by the *_divide functions below.
868*/
869static void
870two_valued_wta_dispatch_2 (SCM gf, SCM a1, SCM a2, int pos,
871 const char *subr, SCM *rp1, SCM *rp2)
872{
873 if (SCM_UNPACK (gf))
874 scm_i_extract_values_2 (scm_call_generic_2 (gf, a1, a2), rp1, rp2);
875 else
876 scm_wrong_type_arg (subr, pos, (pos == SCM_ARG1) ? a1 : a2);
877}
878
a8da6d93
MW
879SCM_DEFINE (scm_euclidean_quotient, "euclidean-quotient", 2, 0, 0,
880 (SCM x, SCM y),
881 "Return the integer @var{q} such that\n"
882 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
883 "where @math{0 <= @var{r} < abs(@var{y})}.\n"
884 "@lisp\n"
885 "(euclidean-quotient 123 10) @result{} 12\n"
886 "(euclidean-quotient 123 -10) @result{} -12\n"
887 "(euclidean-quotient -123 10) @result{} -13\n"
888 "(euclidean-quotient -123 -10) @result{} 13\n"
889 "(euclidean-quotient -123.2 -63.5) @result{} 2.0\n"
890 "(euclidean-quotient 16/3 -10/7) @result{} -3\n"
891 "@end lisp")
ff62c168
MW
892#define FUNC_NAME s_scm_euclidean_quotient
893{
a8da6d93
MW
894 if (scm_is_false (scm_negative_p (y)))
895 return scm_floor_quotient (x, y);
ff62c168 896 else
a8da6d93 897 return scm_ceiling_quotient (x, y);
ff62c168
MW
898}
899#undef FUNC_NAME
900
a8da6d93
MW
901SCM_DEFINE (scm_euclidean_remainder, "euclidean-remainder", 2, 0, 0,
902 (SCM x, SCM y),
903 "Return the real number @var{r} such that\n"
904 "@math{0 <= @var{r} < abs(@var{y})} and\n"
905 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
906 "for some integer @var{q}.\n"
907 "@lisp\n"
908 "(euclidean-remainder 123 10) @result{} 3\n"
909 "(euclidean-remainder 123 -10) @result{} 3\n"
910 "(euclidean-remainder -123 10) @result{} 7\n"
911 "(euclidean-remainder -123 -10) @result{} 7\n"
912 "(euclidean-remainder -123.2 -63.5) @result{} 3.8\n"
913 "(euclidean-remainder 16/3 -10/7) @result{} 22/21\n"
914 "@end lisp")
ff62c168
MW
915#define FUNC_NAME s_scm_euclidean_remainder
916{
a8da6d93
MW
917 if (scm_is_false (scm_negative_p (y)))
918 return scm_floor_remainder (x, y);
ff62c168 919 else
a8da6d93 920 return scm_ceiling_remainder (x, y);
ff62c168
MW
921}
922#undef FUNC_NAME
923
a8da6d93
MW
924SCM_DEFINE (scm_i_euclidean_divide, "euclidean/", 2, 0, 0,
925 (SCM x, SCM y),
926 "Return the integer @var{q} and the real number @var{r}\n"
927 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
928 "and @math{0 <= @var{r} < abs(@var{y})}.\n"
929 "@lisp\n"
930 "(euclidean/ 123 10) @result{} 12 and 3\n"
931 "(euclidean/ 123 -10) @result{} -12 and 3\n"
932 "(euclidean/ -123 10) @result{} -13 and 7\n"
933 "(euclidean/ -123 -10) @result{} 13 and 7\n"
934 "(euclidean/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
935 "(euclidean/ 16/3 -10/7) @result{} -3 and 22/21\n"
936 "@end lisp")
5fbf680b
MW
937#define FUNC_NAME s_scm_i_euclidean_divide
938{
a8da6d93
MW
939 if (scm_is_false (scm_negative_p (y)))
940 return scm_i_floor_divide (x, y);
941 else
942 return scm_i_ceiling_divide (x, y);
5fbf680b
MW
943}
944#undef FUNC_NAME
945
5fbf680b
MW
946void
947scm_euclidean_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 948{
a8da6d93
MW
949 if (scm_is_false (scm_negative_p (y)))
950 return scm_floor_divide (x, y, qp, rp);
ff62c168 951 else
a8da6d93 952 return scm_ceiling_divide (x, y, qp, rp);
ff62c168
MW
953}
954
8f9da340
MW
955static SCM scm_i_inexact_floor_quotient (double x, double y);
956static SCM scm_i_exact_rational_floor_quotient (SCM x, SCM y);
957
958SCM_PRIMITIVE_GENERIC (scm_floor_quotient, "floor-quotient", 2, 0, 0,
959 (SCM x, SCM y),
960 "Return the floor of @math{@var{x} / @var{y}}.\n"
961 "@lisp\n"
962 "(floor-quotient 123 10) @result{} 12\n"
963 "(floor-quotient 123 -10) @result{} -13\n"
964 "(floor-quotient -123 10) @result{} -13\n"
965 "(floor-quotient -123 -10) @result{} 12\n"
966 "(floor-quotient -123.2 -63.5) @result{} 1.0\n"
967 "(floor-quotient 16/3 -10/7) @result{} -4\n"
968 "@end lisp")
969#define FUNC_NAME s_scm_floor_quotient
970{
971 if (SCM_LIKELY (SCM_I_INUMP (x)))
972 {
973 scm_t_inum xx = SCM_I_INUM (x);
974 if (SCM_LIKELY (SCM_I_INUMP (y)))
975 {
976 scm_t_inum yy = SCM_I_INUM (y);
977 scm_t_inum xx1 = xx;
978 scm_t_inum qq;
979 if (SCM_LIKELY (yy > 0))
980 {
981 if (SCM_UNLIKELY (xx < 0))
982 xx1 = xx - yy + 1;
983 }
984 else if (SCM_UNLIKELY (yy == 0))
985 scm_num_overflow (s_scm_floor_quotient);
986 else if (xx > 0)
987 xx1 = xx - yy - 1;
988 qq = xx1 / yy;
989 if (SCM_LIKELY (SCM_FIXABLE (qq)))
990 return SCM_I_MAKINUM (qq);
991 else
992 return scm_i_inum2big (qq);
993 }
994 else if (SCM_BIGP (y))
995 {
996 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
997 scm_remember_upto_here_1 (y);
998 if (sign > 0)
999 return SCM_I_MAKINUM ((xx < 0) ? -1 : 0);
1000 else
1001 return SCM_I_MAKINUM ((xx > 0) ? -1 : 0);
1002 }
1003 else if (SCM_REALP (y))
1004 return scm_i_inexact_floor_quotient (xx, SCM_REAL_VALUE (y));
1005 else if (SCM_FRACTIONP (y))
1006 return scm_i_exact_rational_floor_quotient (x, y);
1007 else
1008 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1009 s_scm_floor_quotient);
1010 }
1011 else if (SCM_BIGP (x))
1012 {
1013 if (SCM_LIKELY (SCM_I_INUMP (y)))
1014 {
1015 scm_t_inum yy = SCM_I_INUM (y);
1016 if (SCM_UNLIKELY (yy == 0))
1017 scm_num_overflow (s_scm_floor_quotient);
1018 else if (SCM_UNLIKELY (yy == 1))
1019 return x;
1020 else
1021 {
1022 SCM q = scm_i_mkbig ();
1023 if (yy > 0)
1024 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1025 else
1026 {
1027 mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1028 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1029 }
1030 scm_remember_upto_here_1 (x);
1031 return scm_i_normbig (q);
1032 }
1033 }
1034 else if (SCM_BIGP (y))
1035 {
1036 SCM q = scm_i_mkbig ();
1037 mpz_fdiv_q (SCM_I_BIG_MPZ (q),
1038 SCM_I_BIG_MPZ (x),
1039 SCM_I_BIG_MPZ (y));
1040 scm_remember_upto_here_2 (x, y);
1041 return scm_i_normbig (q);
1042 }
1043 else if (SCM_REALP (y))
1044 return scm_i_inexact_floor_quotient
1045 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1046 else if (SCM_FRACTIONP (y))
1047 return scm_i_exact_rational_floor_quotient (x, y);
1048 else
1049 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1050 s_scm_floor_quotient);
1051 }
1052 else if (SCM_REALP (x))
1053 {
1054 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1055 SCM_BIGP (y) || SCM_FRACTIONP (y))
1056 return scm_i_inexact_floor_quotient
1057 (SCM_REAL_VALUE (x), scm_to_double (y));
1058 else
1059 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1060 s_scm_floor_quotient);
1061 }
1062 else if (SCM_FRACTIONP (x))
1063 {
1064 if (SCM_REALP (y))
1065 return scm_i_inexact_floor_quotient
1066 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1067 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1068 return scm_i_exact_rational_floor_quotient (x, y);
1069 else
1070 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1071 s_scm_floor_quotient);
1072 }
1073 else
1074 SCM_WTA_DISPATCH_2 (g_scm_floor_quotient, x, y, SCM_ARG1,
1075 s_scm_floor_quotient);
1076}
1077#undef FUNC_NAME
1078
1079static SCM
1080scm_i_inexact_floor_quotient (double x, double y)
1081{
1082 if (SCM_UNLIKELY (y == 0))
1083 scm_num_overflow (s_scm_floor_quotient); /* or return a NaN? */
1084 else
1085 return scm_from_double (floor (x / y));
1086}
1087
1088static SCM
1089scm_i_exact_rational_floor_quotient (SCM x, SCM y)
1090{
1091 return scm_floor_quotient
1092 (scm_product (scm_numerator (x), scm_denominator (y)),
1093 scm_product (scm_numerator (y), scm_denominator (x)));
1094}
1095
1096static SCM scm_i_inexact_floor_remainder (double x, double y);
1097static SCM scm_i_exact_rational_floor_remainder (SCM x, SCM y);
1098
1099SCM_PRIMITIVE_GENERIC (scm_floor_remainder, "floor-remainder", 2, 0, 0,
1100 (SCM x, SCM y),
1101 "Return the real number @var{r} such that\n"
1102 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1103 "where @math{@var{q} = floor(@var{x} / @var{y})}.\n"
1104 "@lisp\n"
1105 "(floor-remainder 123 10) @result{} 3\n"
1106 "(floor-remainder 123 -10) @result{} -7\n"
1107 "(floor-remainder -123 10) @result{} 7\n"
1108 "(floor-remainder -123 -10) @result{} -3\n"
1109 "(floor-remainder -123.2 -63.5) @result{} -59.7\n"
1110 "(floor-remainder 16/3 -10/7) @result{} -8/21\n"
1111 "@end lisp")
1112#define FUNC_NAME s_scm_floor_remainder
1113{
1114 if (SCM_LIKELY (SCM_I_INUMP (x)))
1115 {
1116 scm_t_inum xx = SCM_I_INUM (x);
1117 if (SCM_LIKELY (SCM_I_INUMP (y)))
1118 {
1119 scm_t_inum yy = SCM_I_INUM (y);
1120 if (SCM_UNLIKELY (yy == 0))
1121 scm_num_overflow (s_scm_floor_remainder);
1122 else
1123 {
1124 scm_t_inum rr = xx % yy;
1125 int needs_adjustment;
1126
1127 if (SCM_LIKELY (yy > 0))
1128 needs_adjustment = (rr < 0);
1129 else
1130 needs_adjustment = (rr > 0);
1131
1132 if (needs_adjustment)
1133 rr += yy;
1134 return SCM_I_MAKINUM (rr);
1135 }
1136 }
1137 else if (SCM_BIGP (y))
1138 {
1139 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1140 scm_remember_upto_here_1 (y);
1141 if (sign > 0)
1142 {
1143 if (xx < 0)
1144 {
1145 SCM r = scm_i_mkbig ();
1146 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1147 scm_remember_upto_here_1 (y);
1148 return scm_i_normbig (r);
1149 }
1150 else
1151 return x;
1152 }
1153 else if (xx <= 0)
1154 return x;
1155 else
1156 {
1157 SCM r = scm_i_mkbig ();
1158 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1159 scm_remember_upto_here_1 (y);
1160 return scm_i_normbig (r);
1161 }
1162 }
1163 else if (SCM_REALP (y))
1164 return scm_i_inexact_floor_remainder (xx, SCM_REAL_VALUE (y));
1165 else if (SCM_FRACTIONP (y))
1166 return scm_i_exact_rational_floor_remainder (x, y);
1167 else
1168 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1169 s_scm_floor_remainder);
1170 }
1171 else if (SCM_BIGP (x))
1172 {
1173 if (SCM_LIKELY (SCM_I_INUMP (y)))
1174 {
1175 scm_t_inum yy = SCM_I_INUM (y);
1176 if (SCM_UNLIKELY (yy == 0))
1177 scm_num_overflow (s_scm_floor_remainder);
1178 else
1179 {
1180 scm_t_inum rr;
1181 if (yy > 0)
1182 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), yy);
1183 else
1184 rr = -mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1185 scm_remember_upto_here_1 (x);
1186 return SCM_I_MAKINUM (rr);
1187 }
1188 }
1189 else if (SCM_BIGP (y))
1190 {
1191 SCM r = scm_i_mkbig ();
1192 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
1193 SCM_I_BIG_MPZ (x),
1194 SCM_I_BIG_MPZ (y));
1195 scm_remember_upto_here_2 (x, y);
1196 return scm_i_normbig (r);
1197 }
1198 else if (SCM_REALP (y))
1199 return scm_i_inexact_floor_remainder
1200 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1201 else if (SCM_FRACTIONP (y))
1202 return scm_i_exact_rational_floor_remainder (x, y);
1203 else
1204 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1205 s_scm_floor_remainder);
1206 }
1207 else if (SCM_REALP (x))
1208 {
1209 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1210 SCM_BIGP (y) || SCM_FRACTIONP (y))
1211 return scm_i_inexact_floor_remainder
1212 (SCM_REAL_VALUE (x), scm_to_double (y));
1213 else
1214 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1215 s_scm_floor_remainder);
1216 }
1217 else if (SCM_FRACTIONP (x))
1218 {
1219 if (SCM_REALP (y))
1220 return scm_i_inexact_floor_remainder
1221 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1222 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1223 return scm_i_exact_rational_floor_remainder (x, y);
1224 else
1225 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1226 s_scm_floor_remainder);
1227 }
1228 else
1229 SCM_WTA_DISPATCH_2 (g_scm_floor_remainder, x, y, SCM_ARG1,
1230 s_scm_floor_remainder);
1231}
1232#undef FUNC_NAME
1233
1234static SCM
1235scm_i_inexact_floor_remainder (double x, double y)
1236{
1237 /* Although it would be more efficient to use fmod here, we can't
1238 because it would in some cases produce results inconsistent with
1239 scm_i_inexact_floor_quotient, such that x != q * y + r (not even
1240 close). In particular, when x is very close to a multiple of y,
1241 then r might be either 0.0 or y, but those two cases must
1242 correspond to different choices of q. If r = 0.0 then q must be
1243 x/y, and if r = y then q must be x/y-1. If quotient chooses one
1244 and remainder chooses the other, it would be bad. */
1245 if (SCM_UNLIKELY (y == 0))
1246 scm_num_overflow (s_scm_floor_remainder); /* or return a NaN? */
1247 else
1248 return scm_from_double (x - y * floor (x / y));
1249}
1250
1251static SCM
1252scm_i_exact_rational_floor_remainder (SCM x, SCM y)
1253{
1254 SCM xd = scm_denominator (x);
1255 SCM yd = scm_denominator (y);
1256 SCM r1 = scm_floor_remainder (scm_product (scm_numerator (x), yd),
1257 scm_product (scm_numerator (y), xd));
1258 return scm_divide (r1, scm_product (xd, yd));
1259}
1260
1261
1262static void scm_i_inexact_floor_divide (double x, double y,
1263 SCM *qp, SCM *rp);
1264static void scm_i_exact_rational_floor_divide (SCM x, SCM y,
1265 SCM *qp, SCM *rp);
1266
1267SCM_PRIMITIVE_GENERIC (scm_i_floor_divide, "floor/", 2, 0, 0,
1268 (SCM x, SCM y),
1269 "Return the integer @var{q} and the real number @var{r}\n"
1270 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1271 "and @math{@var{q} = floor(@var{x} / @var{y})}.\n"
1272 "@lisp\n"
1273 "(floor/ 123 10) @result{} 12 and 3\n"
1274 "(floor/ 123 -10) @result{} -13 and -7\n"
1275 "(floor/ -123 10) @result{} -13 and 7\n"
1276 "(floor/ -123 -10) @result{} 12 and -3\n"
1277 "(floor/ -123.2 -63.5) @result{} 1.0 and -59.7\n"
1278 "(floor/ 16/3 -10/7) @result{} -4 and -8/21\n"
1279 "@end lisp")
1280#define FUNC_NAME s_scm_i_floor_divide
1281{
1282 SCM q, r;
1283
1284 scm_floor_divide(x, y, &q, &r);
1285 return scm_values (scm_list_2 (q, r));
1286}
1287#undef FUNC_NAME
1288
1289#define s_scm_floor_divide s_scm_i_floor_divide
1290#define g_scm_floor_divide g_scm_i_floor_divide
1291
1292void
1293scm_floor_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1294{
1295 if (SCM_LIKELY (SCM_I_INUMP (x)))
1296 {
1297 scm_t_inum xx = SCM_I_INUM (x);
1298 if (SCM_LIKELY (SCM_I_INUMP (y)))
1299 {
1300 scm_t_inum yy = SCM_I_INUM (y);
1301 if (SCM_UNLIKELY (yy == 0))
1302 scm_num_overflow (s_scm_floor_divide);
1303 else
1304 {
1305 scm_t_inum qq = xx / yy;
1306 scm_t_inum rr = xx % yy;
1307 int needs_adjustment;
1308
1309 if (SCM_LIKELY (yy > 0))
1310 needs_adjustment = (rr < 0);
1311 else
1312 needs_adjustment = (rr > 0);
1313
1314 if (needs_adjustment)
1315 {
1316 rr += yy;
1317 qq--;
1318 }
1319
1320 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1321 *qp = SCM_I_MAKINUM (qq);
1322 else
1323 *qp = scm_i_inum2big (qq);
1324 *rp = SCM_I_MAKINUM (rr);
1325 }
1326 return;
1327 }
1328 else if (SCM_BIGP (y))
1329 {
1330 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1331 scm_remember_upto_here_1 (y);
1332 if (sign > 0)
1333 {
1334 if (xx < 0)
1335 {
1336 SCM r = scm_i_mkbig ();
1337 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1338 scm_remember_upto_here_1 (y);
1339 *qp = SCM_I_MAKINUM (-1);
1340 *rp = scm_i_normbig (r);
1341 }
1342 else
1343 {
1344 *qp = SCM_INUM0;
1345 *rp = x;
1346 }
1347 }
1348 else if (xx <= 0)
1349 {
1350 *qp = SCM_INUM0;
1351 *rp = x;
1352 }
1353 else
1354 {
1355 SCM r = scm_i_mkbig ();
1356 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1357 scm_remember_upto_here_1 (y);
1358 *qp = SCM_I_MAKINUM (-1);
1359 *rp = scm_i_normbig (r);
1360 }
1361 return;
1362 }
1363 else if (SCM_REALP (y))
1364 return scm_i_inexact_floor_divide (xx, SCM_REAL_VALUE (y), qp, rp);
1365 else if (SCM_FRACTIONP (y))
1366 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1367 else
1368 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1369 s_scm_floor_divide, qp, rp);
1370 }
1371 else if (SCM_BIGP (x))
1372 {
1373 if (SCM_LIKELY (SCM_I_INUMP (y)))
1374 {
1375 scm_t_inum yy = SCM_I_INUM (y);
1376 if (SCM_UNLIKELY (yy == 0))
1377 scm_num_overflow (s_scm_floor_divide);
1378 else
1379 {
1380 SCM q = scm_i_mkbig ();
1381 SCM r = scm_i_mkbig ();
1382 if (yy > 0)
1383 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1384 SCM_I_BIG_MPZ (x), yy);
1385 else
1386 {
1387 mpz_cdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1388 SCM_I_BIG_MPZ (x), -yy);
1389 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1390 }
1391 scm_remember_upto_here_1 (x);
1392 *qp = scm_i_normbig (q);
1393 *rp = scm_i_normbig (r);
1394 }
1395 return;
1396 }
1397 else if (SCM_BIGP (y))
1398 {
1399 SCM q = scm_i_mkbig ();
1400 SCM r = scm_i_mkbig ();
1401 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1402 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1403 scm_remember_upto_here_2 (x, y);
1404 *qp = scm_i_normbig (q);
1405 *rp = scm_i_normbig (r);
1406 return;
1407 }
1408 else if (SCM_REALP (y))
1409 return scm_i_inexact_floor_divide
1410 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
1411 else if (SCM_FRACTIONP (y))
1412 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1413 else
1414 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1415 s_scm_floor_divide, qp, rp);
1416 }
1417 else if (SCM_REALP (x))
1418 {
1419 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1420 SCM_BIGP (y) || SCM_FRACTIONP (y))
1421 return scm_i_inexact_floor_divide
1422 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
1423 else
1424 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1425 s_scm_floor_divide, qp, rp);
1426 }
1427 else if (SCM_FRACTIONP (x))
1428 {
1429 if (SCM_REALP (y))
1430 return scm_i_inexact_floor_divide
1431 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
1432 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1433 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1434 else
1435 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1436 s_scm_floor_divide, qp, rp);
1437 }
1438 else
1439 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG1,
1440 s_scm_floor_divide, qp, rp);
1441}
1442
1443static void
1444scm_i_inexact_floor_divide (double x, double y, SCM *qp, SCM *rp)
1445{
1446 if (SCM_UNLIKELY (y == 0))
1447 scm_num_overflow (s_scm_floor_divide); /* or return a NaN? */
1448 else
1449 {
1450 double q = floor (x / y);
1451 double r = x - q * y;
1452 *qp = scm_from_double (q);
1453 *rp = scm_from_double (r);
1454 }
1455}
1456
1457static void
1458scm_i_exact_rational_floor_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1459{
1460 SCM r1;
1461 SCM xd = scm_denominator (x);
1462 SCM yd = scm_denominator (y);
1463
1464 scm_floor_divide (scm_product (scm_numerator (x), yd),
1465 scm_product (scm_numerator (y), xd),
1466 qp, &r1);
1467 *rp = scm_divide (r1, scm_product (xd, yd));
1468}
1469
1470static SCM scm_i_inexact_ceiling_quotient (double x, double y);
1471static SCM scm_i_exact_rational_ceiling_quotient (SCM x, SCM y);
1472
1473SCM_PRIMITIVE_GENERIC (scm_ceiling_quotient, "ceiling-quotient", 2, 0, 0,
1474 (SCM x, SCM y),
1475 "Return the ceiling of @math{@var{x} / @var{y}}.\n"
1476 "@lisp\n"
1477 "(ceiling-quotient 123 10) @result{} 13\n"
1478 "(ceiling-quotient 123 -10) @result{} -12\n"
1479 "(ceiling-quotient -123 10) @result{} -12\n"
1480 "(ceiling-quotient -123 -10) @result{} 13\n"
1481 "(ceiling-quotient -123.2 -63.5) @result{} 2.0\n"
1482 "(ceiling-quotient 16/3 -10/7) @result{} -3\n"
1483 "@end lisp")
1484#define FUNC_NAME s_scm_ceiling_quotient
1485{
1486 if (SCM_LIKELY (SCM_I_INUMP (x)))
1487 {
1488 scm_t_inum xx = SCM_I_INUM (x);
1489 if (SCM_LIKELY (SCM_I_INUMP (y)))
1490 {
1491 scm_t_inum yy = SCM_I_INUM (y);
1492 if (SCM_UNLIKELY (yy == 0))
1493 scm_num_overflow (s_scm_ceiling_quotient);
1494 else
1495 {
1496 scm_t_inum xx1 = xx;
1497 scm_t_inum qq;
1498 if (SCM_LIKELY (yy > 0))
1499 {
1500 if (SCM_LIKELY (xx >= 0))
1501 xx1 = xx + yy - 1;
1502 }
1503 else if (SCM_UNLIKELY (yy == 0))
1504 scm_num_overflow (s_scm_ceiling_quotient);
1505 else if (xx < 0)
1506 xx1 = xx + yy + 1;
1507 qq = xx1 / yy;
1508 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1509 return SCM_I_MAKINUM (qq);
1510 else
1511 return scm_i_inum2big (qq);
1512 }
1513 }
1514 else if (SCM_BIGP (y))
1515 {
1516 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1517 scm_remember_upto_here_1 (y);
1518 if (SCM_LIKELY (sign > 0))
1519 {
1520 if (SCM_LIKELY (xx > 0))
1521 return SCM_INUM1;
1522 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1523 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1524 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1525 {
1526 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1527 scm_remember_upto_here_1 (y);
1528 return SCM_I_MAKINUM (-1);
1529 }
1530 else
1531 return SCM_INUM0;
1532 }
1533 else if (xx >= 0)
1534 return SCM_INUM0;
1535 else
1536 return SCM_INUM1;
1537 }
1538 else if (SCM_REALP (y))
1539 return scm_i_inexact_ceiling_quotient (xx, SCM_REAL_VALUE (y));
1540 else if (SCM_FRACTIONP (y))
1541 return scm_i_exact_rational_ceiling_quotient (x, y);
1542 else
1543 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1544 s_scm_ceiling_quotient);
1545 }
1546 else if (SCM_BIGP (x))
1547 {
1548 if (SCM_LIKELY (SCM_I_INUMP (y)))
1549 {
1550 scm_t_inum yy = SCM_I_INUM (y);
1551 if (SCM_UNLIKELY (yy == 0))
1552 scm_num_overflow (s_scm_ceiling_quotient);
1553 else if (SCM_UNLIKELY (yy == 1))
1554 return x;
1555 else
1556 {
1557 SCM q = scm_i_mkbig ();
1558 if (yy > 0)
1559 mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1560 else
1561 {
1562 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1563 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1564 }
1565 scm_remember_upto_here_1 (x);
1566 return scm_i_normbig (q);
1567 }
1568 }
1569 else if (SCM_BIGP (y))
1570 {
1571 SCM q = scm_i_mkbig ();
1572 mpz_cdiv_q (SCM_I_BIG_MPZ (q),
1573 SCM_I_BIG_MPZ (x),
1574 SCM_I_BIG_MPZ (y));
1575 scm_remember_upto_here_2 (x, y);
1576 return scm_i_normbig (q);
1577 }
1578 else if (SCM_REALP (y))
1579 return scm_i_inexact_ceiling_quotient
1580 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1581 else if (SCM_FRACTIONP (y))
1582 return scm_i_exact_rational_ceiling_quotient (x, y);
1583 else
1584 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1585 s_scm_ceiling_quotient);
1586 }
1587 else if (SCM_REALP (x))
1588 {
1589 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1590 SCM_BIGP (y) || SCM_FRACTIONP (y))
1591 return scm_i_inexact_ceiling_quotient
1592 (SCM_REAL_VALUE (x), scm_to_double (y));
1593 else
1594 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1595 s_scm_ceiling_quotient);
1596 }
1597 else if (SCM_FRACTIONP (x))
1598 {
1599 if (SCM_REALP (y))
1600 return scm_i_inexact_ceiling_quotient
1601 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1602 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1603 return scm_i_exact_rational_ceiling_quotient (x, y);
1604 else
1605 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1606 s_scm_ceiling_quotient);
1607 }
1608 else
1609 SCM_WTA_DISPATCH_2 (g_scm_ceiling_quotient, x, y, SCM_ARG1,
1610 s_scm_ceiling_quotient);
1611}
1612#undef FUNC_NAME
1613
1614static SCM
1615scm_i_inexact_ceiling_quotient (double x, double y)
1616{
1617 if (SCM_UNLIKELY (y == 0))
1618 scm_num_overflow (s_scm_ceiling_quotient); /* or return a NaN? */
1619 else
1620 return scm_from_double (ceil (x / y));
1621}
1622
1623static SCM
1624scm_i_exact_rational_ceiling_quotient (SCM x, SCM y)
1625{
1626 return scm_ceiling_quotient
1627 (scm_product (scm_numerator (x), scm_denominator (y)),
1628 scm_product (scm_numerator (y), scm_denominator (x)));
1629}
1630
1631static SCM scm_i_inexact_ceiling_remainder (double x, double y);
1632static SCM scm_i_exact_rational_ceiling_remainder (SCM x, SCM y);
1633
1634SCM_PRIMITIVE_GENERIC (scm_ceiling_remainder, "ceiling-remainder", 2, 0, 0,
1635 (SCM x, SCM y),
1636 "Return the real number @var{r} such that\n"
1637 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1638 "where @math{@var{q} = ceiling(@var{x} / @var{y})}.\n"
1639 "@lisp\n"
1640 "(ceiling-remainder 123 10) @result{} -7\n"
1641 "(ceiling-remainder 123 -10) @result{} 3\n"
1642 "(ceiling-remainder -123 10) @result{} -3\n"
1643 "(ceiling-remainder -123 -10) @result{} 7\n"
1644 "(ceiling-remainder -123.2 -63.5) @result{} 3.8\n"
1645 "(ceiling-remainder 16/3 -10/7) @result{} 22/21\n"
1646 "@end lisp")
1647#define FUNC_NAME s_scm_ceiling_remainder
1648{
1649 if (SCM_LIKELY (SCM_I_INUMP (x)))
1650 {
1651 scm_t_inum xx = SCM_I_INUM (x);
1652 if (SCM_LIKELY (SCM_I_INUMP (y)))
1653 {
1654 scm_t_inum yy = SCM_I_INUM (y);
1655 if (SCM_UNLIKELY (yy == 0))
1656 scm_num_overflow (s_scm_ceiling_remainder);
1657 else
1658 {
1659 scm_t_inum rr = xx % yy;
1660 int needs_adjustment;
1661
1662 if (SCM_LIKELY (yy > 0))
1663 needs_adjustment = (rr > 0);
1664 else
1665 needs_adjustment = (rr < 0);
1666
1667 if (needs_adjustment)
1668 rr -= yy;
1669 return SCM_I_MAKINUM (rr);
1670 }
1671 }
1672 else if (SCM_BIGP (y))
1673 {
1674 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1675 scm_remember_upto_here_1 (y);
1676 if (SCM_LIKELY (sign > 0))
1677 {
1678 if (SCM_LIKELY (xx > 0))
1679 {
1680 SCM r = scm_i_mkbig ();
1681 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1682 scm_remember_upto_here_1 (y);
1683 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1684 return scm_i_normbig (r);
1685 }
1686 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1687 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1688 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1689 {
1690 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1691 scm_remember_upto_here_1 (y);
1692 return SCM_INUM0;
1693 }
1694 else
1695 return x;
1696 }
1697 else if (xx >= 0)
1698 return x;
1699 else
1700 {
1701 SCM r = scm_i_mkbig ();
1702 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1703 scm_remember_upto_here_1 (y);
1704 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1705 return scm_i_normbig (r);
1706 }
1707 }
1708 else if (SCM_REALP (y))
1709 return scm_i_inexact_ceiling_remainder (xx, SCM_REAL_VALUE (y));
1710 else if (SCM_FRACTIONP (y))
1711 return scm_i_exact_rational_ceiling_remainder (x, y);
1712 else
1713 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1714 s_scm_ceiling_remainder);
1715 }
1716 else if (SCM_BIGP (x))
1717 {
1718 if (SCM_LIKELY (SCM_I_INUMP (y)))
1719 {
1720 scm_t_inum yy = SCM_I_INUM (y);
1721 if (SCM_UNLIKELY (yy == 0))
1722 scm_num_overflow (s_scm_ceiling_remainder);
1723 else
1724 {
1725 scm_t_inum rr;
1726 if (yy > 0)
1727 rr = -mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
1728 else
1729 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1730 scm_remember_upto_here_1 (x);
1731 return SCM_I_MAKINUM (rr);
1732 }
1733 }
1734 else if (SCM_BIGP (y))
1735 {
1736 SCM r = scm_i_mkbig ();
1737 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
1738 SCM_I_BIG_MPZ (x),
1739 SCM_I_BIG_MPZ (y));
1740 scm_remember_upto_here_2 (x, y);
1741 return scm_i_normbig (r);
1742 }
1743 else if (SCM_REALP (y))
1744 return scm_i_inexact_ceiling_remainder
1745 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1746 else if (SCM_FRACTIONP (y))
1747 return scm_i_exact_rational_ceiling_remainder (x, y);
1748 else
1749 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1750 s_scm_ceiling_remainder);
1751 }
1752 else if (SCM_REALP (x))
1753 {
1754 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1755 SCM_BIGP (y) || SCM_FRACTIONP (y))
1756 return scm_i_inexact_ceiling_remainder
1757 (SCM_REAL_VALUE (x), scm_to_double (y));
1758 else
1759 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1760 s_scm_ceiling_remainder);
1761 }
1762 else if (SCM_FRACTIONP (x))
1763 {
1764 if (SCM_REALP (y))
1765 return scm_i_inexact_ceiling_remainder
1766 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1767 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1768 return scm_i_exact_rational_ceiling_remainder (x, y);
1769 else
1770 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1771 s_scm_ceiling_remainder);
1772 }
1773 else
1774 SCM_WTA_DISPATCH_2 (g_scm_ceiling_remainder, x, y, SCM_ARG1,
1775 s_scm_ceiling_remainder);
1776}
1777#undef FUNC_NAME
1778
1779static SCM
1780scm_i_inexact_ceiling_remainder (double x, double y)
1781{
1782 /* Although it would be more efficient to use fmod here, we can't
1783 because it would in some cases produce results inconsistent with
1784 scm_i_inexact_ceiling_quotient, such that x != q * y + r (not even
1785 close). In particular, when x is very close to a multiple of y,
1786 then r might be either 0.0 or -y, but those two cases must
1787 correspond to different choices of q. If r = 0.0 then q must be
1788 x/y, and if r = -y then q must be x/y+1. If quotient chooses one
1789 and remainder chooses the other, it would be bad. */
1790 if (SCM_UNLIKELY (y == 0))
1791 scm_num_overflow (s_scm_ceiling_remainder); /* or return a NaN? */
1792 else
1793 return scm_from_double (x - y * ceil (x / y));
1794}
1795
1796static SCM
1797scm_i_exact_rational_ceiling_remainder (SCM x, SCM y)
1798{
1799 SCM xd = scm_denominator (x);
1800 SCM yd = scm_denominator (y);
1801 SCM r1 = scm_ceiling_remainder (scm_product (scm_numerator (x), yd),
1802 scm_product (scm_numerator (y), xd));
1803 return scm_divide (r1, scm_product (xd, yd));
1804}
1805
1806static void scm_i_inexact_ceiling_divide (double x, double y,
1807 SCM *qp, SCM *rp);
1808static void scm_i_exact_rational_ceiling_divide (SCM x, SCM y,
1809 SCM *qp, SCM *rp);
1810
1811SCM_PRIMITIVE_GENERIC (scm_i_ceiling_divide, "ceiling/", 2, 0, 0,
1812 (SCM x, SCM y),
1813 "Return the integer @var{q} and the real number @var{r}\n"
1814 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1815 "and @math{@var{q} = ceiling(@var{x} / @var{y})}.\n"
1816 "@lisp\n"
1817 "(ceiling/ 123 10) @result{} 13 and -7\n"
1818 "(ceiling/ 123 -10) @result{} -12 and 3\n"
1819 "(ceiling/ -123 10) @result{} -12 and -3\n"
1820 "(ceiling/ -123 -10) @result{} 13 and 7\n"
1821 "(ceiling/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
1822 "(ceiling/ 16/3 -10/7) @result{} -3 and 22/21\n"
1823 "@end lisp")
1824#define FUNC_NAME s_scm_i_ceiling_divide
1825{
1826 SCM q, r;
1827
1828 scm_ceiling_divide(x, y, &q, &r);
1829 return scm_values (scm_list_2 (q, r));
1830}
1831#undef FUNC_NAME
1832
1833#define s_scm_ceiling_divide s_scm_i_ceiling_divide
1834#define g_scm_ceiling_divide g_scm_i_ceiling_divide
1835
1836void
1837scm_ceiling_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1838{
1839 if (SCM_LIKELY (SCM_I_INUMP (x)))
1840 {
1841 scm_t_inum xx = SCM_I_INUM (x);
1842 if (SCM_LIKELY (SCM_I_INUMP (y)))
1843 {
1844 scm_t_inum yy = SCM_I_INUM (y);
1845 if (SCM_UNLIKELY (yy == 0))
1846 scm_num_overflow (s_scm_ceiling_divide);
1847 else
1848 {
1849 scm_t_inum qq = xx / yy;
1850 scm_t_inum rr = xx % yy;
1851 int needs_adjustment;
1852
1853 if (SCM_LIKELY (yy > 0))
1854 needs_adjustment = (rr > 0);
1855 else
1856 needs_adjustment = (rr < 0);
1857
1858 if (needs_adjustment)
1859 {
1860 rr -= yy;
1861 qq++;
1862 }
1863 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1864 *qp = SCM_I_MAKINUM (qq);
1865 else
1866 *qp = scm_i_inum2big (qq);
1867 *rp = SCM_I_MAKINUM (rr);
1868 }
1869 return;
1870 }
1871 else if (SCM_BIGP (y))
1872 {
1873 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1874 scm_remember_upto_here_1 (y);
1875 if (SCM_LIKELY (sign > 0))
1876 {
1877 if (SCM_LIKELY (xx > 0))
1878 {
1879 SCM r = scm_i_mkbig ();
1880 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1881 scm_remember_upto_here_1 (y);
1882 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1883 *qp = SCM_INUM1;
1884 *rp = scm_i_normbig (r);
1885 }
1886 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1887 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1888 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1889 {
1890 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1891 scm_remember_upto_here_1 (y);
1892 *qp = SCM_I_MAKINUM (-1);
1893 *rp = SCM_INUM0;
1894 }
1895 else
1896 {
1897 *qp = SCM_INUM0;
1898 *rp = x;
1899 }
1900 }
1901 else if (xx >= 0)
1902 {
1903 *qp = SCM_INUM0;
1904 *rp = x;
1905 }
1906 else
1907 {
1908 SCM r = scm_i_mkbig ();
1909 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1910 scm_remember_upto_here_1 (y);
1911 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1912 *qp = SCM_INUM1;
1913 *rp = scm_i_normbig (r);
1914 }
1915 return;
1916 }
1917 else if (SCM_REALP (y))
1918 return scm_i_inexact_ceiling_divide (xx, SCM_REAL_VALUE (y), qp, rp);
1919 else if (SCM_FRACTIONP (y))
1920 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1921 else
1922 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1923 s_scm_ceiling_divide, qp, rp);
1924 }
1925 else if (SCM_BIGP (x))
1926 {
1927 if (SCM_LIKELY (SCM_I_INUMP (y)))
1928 {
1929 scm_t_inum yy = SCM_I_INUM (y);
1930 if (SCM_UNLIKELY (yy == 0))
1931 scm_num_overflow (s_scm_ceiling_divide);
1932 else
1933 {
1934 SCM q = scm_i_mkbig ();
1935 SCM r = scm_i_mkbig ();
1936 if (yy > 0)
1937 mpz_cdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1938 SCM_I_BIG_MPZ (x), yy);
1939 else
1940 {
1941 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1942 SCM_I_BIG_MPZ (x), -yy);
1943 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1944 }
1945 scm_remember_upto_here_1 (x);
1946 *qp = scm_i_normbig (q);
1947 *rp = scm_i_normbig (r);
1948 }
1949 return;
1950 }
1951 else if (SCM_BIGP (y))
1952 {
1953 SCM q = scm_i_mkbig ();
1954 SCM r = scm_i_mkbig ();
1955 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1956 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1957 scm_remember_upto_here_2 (x, y);
1958 *qp = scm_i_normbig (q);
1959 *rp = scm_i_normbig (r);
1960 return;
1961 }
1962 else if (SCM_REALP (y))
1963 return scm_i_inexact_ceiling_divide
1964 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
1965 else if (SCM_FRACTIONP (y))
1966 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1967 else
1968 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1969 s_scm_ceiling_divide, qp, rp);
1970 }
1971 else if (SCM_REALP (x))
1972 {
1973 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1974 SCM_BIGP (y) || SCM_FRACTIONP (y))
1975 return scm_i_inexact_ceiling_divide
1976 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
1977 else
1978 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1979 s_scm_ceiling_divide, qp, rp);
1980 }
1981 else if (SCM_FRACTIONP (x))
1982 {
1983 if (SCM_REALP (y))
1984 return scm_i_inexact_ceiling_divide
1985 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
1986 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1987 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1988 else
1989 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1990 s_scm_ceiling_divide, qp, rp);
1991 }
1992 else
1993 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG1,
1994 s_scm_ceiling_divide, qp, rp);
1995}
1996
1997static void
1998scm_i_inexact_ceiling_divide (double x, double y, SCM *qp, SCM *rp)
1999{
2000 if (SCM_UNLIKELY (y == 0))
2001 scm_num_overflow (s_scm_ceiling_divide); /* or return a NaN? */
2002 else
2003 {
2004 double q = ceil (x / y);
2005 double r = x - q * y;
2006 *qp = scm_from_double (q);
2007 *rp = scm_from_double (r);
2008 }
2009}
2010
2011static void
2012scm_i_exact_rational_ceiling_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2013{
2014 SCM r1;
2015 SCM xd = scm_denominator (x);
2016 SCM yd = scm_denominator (y);
2017
2018 scm_ceiling_divide (scm_product (scm_numerator (x), yd),
2019 scm_product (scm_numerator (y), xd),
2020 qp, &r1);
2021 *rp = scm_divide (r1, scm_product (xd, yd));
2022}
2023
2024static SCM scm_i_inexact_truncate_quotient (double x, double y);
2025static SCM scm_i_exact_rational_truncate_quotient (SCM x, SCM y);
2026
2027SCM_PRIMITIVE_GENERIC (scm_truncate_quotient, "truncate-quotient", 2, 0, 0,
2028 (SCM x, SCM y),
2029 "Return @math{@var{x} / @var{y}} rounded toward zero.\n"
2030 "@lisp\n"
2031 "(truncate-quotient 123 10) @result{} 12\n"
2032 "(truncate-quotient 123 -10) @result{} -12\n"
2033 "(truncate-quotient -123 10) @result{} -12\n"
2034 "(truncate-quotient -123 -10) @result{} 12\n"
2035 "(truncate-quotient -123.2 -63.5) @result{} 1.0\n"
2036 "(truncate-quotient 16/3 -10/7) @result{} -3\n"
2037 "@end lisp")
2038#define FUNC_NAME s_scm_truncate_quotient
2039{
2040 if (SCM_LIKELY (SCM_I_INUMP (x)))
2041 {
2042 scm_t_inum xx = SCM_I_INUM (x);
2043 if (SCM_LIKELY (SCM_I_INUMP (y)))
2044 {
2045 scm_t_inum yy = SCM_I_INUM (y);
2046 if (SCM_UNLIKELY (yy == 0))
2047 scm_num_overflow (s_scm_truncate_quotient);
2048 else
2049 {
2050 scm_t_inum qq = xx / yy;
2051 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2052 return SCM_I_MAKINUM (qq);
2053 else
2054 return scm_i_inum2big (qq);
2055 }
2056 }
2057 else if (SCM_BIGP (y))
2058 {
2059 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2060 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2061 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2062 {
2063 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2064 scm_remember_upto_here_1 (y);
2065 return SCM_I_MAKINUM (-1);
2066 }
2067 else
2068 return SCM_INUM0;
2069 }
2070 else if (SCM_REALP (y))
2071 return scm_i_inexact_truncate_quotient (xx, SCM_REAL_VALUE (y));
2072 else if (SCM_FRACTIONP (y))
2073 return scm_i_exact_rational_truncate_quotient (x, y);
2074 else
2075 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2076 s_scm_truncate_quotient);
2077 }
2078 else if (SCM_BIGP (x))
2079 {
2080 if (SCM_LIKELY (SCM_I_INUMP (y)))
2081 {
2082 scm_t_inum yy = SCM_I_INUM (y);
2083 if (SCM_UNLIKELY (yy == 0))
2084 scm_num_overflow (s_scm_truncate_quotient);
2085 else if (SCM_UNLIKELY (yy == 1))
2086 return x;
2087 else
2088 {
2089 SCM q = scm_i_mkbig ();
2090 if (yy > 0)
2091 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
2092 else
2093 {
2094 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
2095 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2096 }
2097 scm_remember_upto_here_1 (x);
2098 return scm_i_normbig (q);
2099 }
2100 }
2101 else if (SCM_BIGP (y))
2102 {
2103 SCM q = scm_i_mkbig ();
2104 mpz_tdiv_q (SCM_I_BIG_MPZ (q),
2105 SCM_I_BIG_MPZ (x),
2106 SCM_I_BIG_MPZ (y));
2107 scm_remember_upto_here_2 (x, y);
2108 return scm_i_normbig (q);
2109 }
2110 else if (SCM_REALP (y))
2111 return scm_i_inexact_truncate_quotient
2112 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2113 else if (SCM_FRACTIONP (y))
2114 return scm_i_exact_rational_truncate_quotient (x, y);
2115 else
2116 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2117 s_scm_truncate_quotient);
2118 }
2119 else if (SCM_REALP (x))
2120 {
2121 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2122 SCM_BIGP (y) || SCM_FRACTIONP (y))
2123 return scm_i_inexact_truncate_quotient
2124 (SCM_REAL_VALUE (x), scm_to_double (y));
2125 else
2126 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2127 s_scm_truncate_quotient);
2128 }
2129 else if (SCM_FRACTIONP (x))
2130 {
2131 if (SCM_REALP (y))
2132 return scm_i_inexact_truncate_quotient
2133 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2134 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2135 return scm_i_exact_rational_truncate_quotient (x, y);
2136 else
2137 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2138 s_scm_truncate_quotient);
2139 }
2140 else
2141 SCM_WTA_DISPATCH_2 (g_scm_truncate_quotient, x, y, SCM_ARG1,
2142 s_scm_truncate_quotient);
2143}
2144#undef FUNC_NAME
2145
2146static SCM
2147scm_i_inexact_truncate_quotient (double x, double y)
2148{
2149 if (SCM_UNLIKELY (y == 0))
2150 scm_num_overflow (s_scm_truncate_quotient); /* or return a NaN? */
2151 else
c251ab63 2152 return scm_from_double (trunc (x / y));
8f9da340
MW
2153}
2154
2155static SCM
2156scm_i_exact_rational_truncate_quotient (SCM x, SCM y)
2157{
2158 return scm_truncate_quotient
2159 (scm_product (scm_numerator (x), scm_denominator (y)),
2160 scm_product (scm_numerator (y), scm_denominator (x)));
2161}
2162
2163static SCM scm_i_inexact_truncate_remainder (double x, double y);
2164static SCM scm_i_exact_rational_truncate_remainder (SCM x, SCM y);
2165
2166SCM_PRIMITIVE_GENERIC (scm_truncate_remainder, "truncate-remainder", 2, 0, 0,
2167 (SCM x, SCM y),
2168 "Return the real number @var{r} such that\n"
2169 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2170 "where @math{@var{q} = truncate(@var{x} / @var{y})}.\n"
2171 "@lisp\n"
2172 "(truncate-remainder 123 10) @result{} 3\n"
2173 "(truncate-remainder 123 -10) @result{} 3\n"
2174 "(truncate-remainder -123 10) @result{} -3\n"
2175 "(truncate-remainder -123 -10) @result{} -3\n"
2176 "(truncate-remainder -123.2 -63.5) @result{} -59.7\n"
2177 "(truncate-remainder 16/3 -10/7) @result{} 22/21\n"
2178 "@end lisp")
2179#define FUNC_NAME s_scm_truncate_remainder
2180{
2181 if (SCM_LIKELY (SCM_I_INUMP (x)))
2182 {
2183 scm_t_inum xx = SCM_I_INUM (x);
2184 if (SCM_LIKELY (SCM_I_INUMP (y)))
2185 {
2186 scm_t_inum yy = SCM_I_INUM (y);
2187 if (SCM_UNLIKELY (yy == 0))
2188 scm_num_overflow (s_scm_truncate_remainder);
2189 else
2190 return SCM_I_MAKINUM (xx % yy);
2191 }
2192 else if (SCM_BIGP (y))
2193 {
2194 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2195 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2196 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2197 {
2198 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2199 scm_remember_upto_here_1 (y);
2200 return SCM_INUM0;
2201 }
2202 else
2203 return x;
2204 }
2205 else if (SCM_REALP (y))
2206 return scm_i_inexact_truncate_remainder (xx, SCM_REAL_VALUE (y));
2207 else if (SCM_FRACTIONP (y))
2208 return scm_i_exact_rational_truncate_remainder (x, y);
2209 else
2210 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2211 s_scm_truncate_remainder);
2212 }
2213 else if (SCM_BIGP (x))
2214 {
2215 if (SCM_LIKELY (SCM_I_INUMP (y)))
2216 {
2217 scm_t_inum yy = SCM_I_INUM (y);
2218 if (SCM_UNLIKELY (yy == 0))
2219 scm_num_overflow (s_scm_truncate_remainder);
2220 else
2221 {
2222 scm_t_inum rr = (mpz_tdiv_ui (SCM_I_BIG_MPZ (x),
2223 (yy > 0) ? yy : -yy)
2224 * mpz_sgn (SCM_I_BIG_MPZ (x)));
2225 scm_remember_upto_here_1 (x);
2226 return SCM_I_MAKINUM (rr);
2227 }
2228 }
2229 else if (SCM_BIGP (y))
2230 {
2231 SCM r = scm_i_mkbig ();
2232 mpz_tdiv_r (SCM_I_BIG_MPZ (r),
2233 SCM_I_BIG_MPZ (x),
2234 SCM_I_BIG_MPZ (y));
2235 scm_remember_upto_here_2 (x, y);
2236 return scm_i_normbig (r);
2237 }
2238 else if (SCM_REALP (y))
2239 return scm_i_inexact_truncate_remainder
2240 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2241 else if (SCM_FRACTIONP (y))
2242 return scm_i_exact_rational_truncate_remainder (x, y);
2243 else
2244 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2245 s_scm_truncate_remainder);
2246 }
2247 else if (SCM_REALP (x))
2248 {
2249 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2250 SCM_BIGP (y) || SCM_FRACTIONP (y))
2251 return scm_i_inexact_truncate_remainder
2252 (SCM_REAL_VALUE (x), scm_to_double (y));
2253 else
2254 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2255 s_scm_truncate_remainder);
2256 }
2257 else if (SCM_FRACTIONP (x))
2258 {
2259 if (SCM_REALP (y))
2260 return scm_i_inexact_truncate_remainder
2261 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2262 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2263 return scm_i_exact_rational_truncate_remainder (x, y);
2264 else
2265 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2266 s_scm_truncate_remainder);
2267 }
2268 else
2269 SCM_WTA_DISPATCH_2 (g_scm_truncate_remainder, x, y, SCM_ARG1,
2270 s_scm_truncate_remainder);
2271}
2272#undef FUNC_NAME
2273
2274static SCM
2275scm_i_inexact_truncate_remainder (double x, double y)
2276{
2277 /* Although it would be more efficient to use fmod here, we can't
2278 because it would in some cases produce results inconsistent with
2279 scm_i_inexact_truncate_quotient, such that x != q * y + r (not even
2280 close). In particular, when x is very close to a multiple of y,
2281 then r might be either 0.0 or sgn(x)*|y|, but those two cases must
2282 correspond to different choices of q. If quotient chooses one and
2283 remainder chooses the other, it would be bad. */
2284 if (SCM_UNLIKELY (y == 0))
2285 scm_num_overflow (s_scm_truncate_remainder); /* or return a NaN? */
2286 else
c251ab63 2287 return scm_from_double (x - y * trunc (x / y));
8f9da340
MW
2288}
2289
2290static SCM
2291scm_i_exact_rational_truncate_remainder (SCM x, SCM y)
2292{
2293 SCM xd = scm_denominator (x);
2294 SCM yd = scm_denominator (y);
2295 SCM r1 = scm_truncate_remainder (scm_product (scm_numerator (x), yd),
2296 scm_product (scm_numerator (y), xd));
2297 return scm_divide (r1, scm_product (xd, yd));
2298}
2299
2300
2301static void scm_i_inexact_truncate_divide (double x, double y,
2302 SCM *qp, SCM *rp);
2303static void scm_i_exact_rational_truncate_divide (SCM x, SCM y,
2304 SCM *qp, SCM *rp);
2305
2306SCM_PRIMITIVE_GENERIC (scm_i_truncate_divide, "truncate/", 2, 0, 0,
2307 (SCM x, SCM y),
2308 "Return the integer @var{q} and the real number @var{r}\n"
2309 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2310 "and @math{@var{q} = truncate(@var{x} / @var{y})}.\n"
2311 "@lisp\n"
2312 "(truncate/ 123 10) @result{} 12 and 3\n"
2313 "(truncate/ 123 -10) @result{} -12 and 3\n"
2314 "(truncate/ -123 10) @result{} -12 and -3\n"
2315 "(truncate/ -123 -10) @result{} 12 and -3\n"
2316 "(truncate/ -123.2 -63.5) @result{} 1.0 and -59.7\n"
2317 "(truncate/ 16/3 -10/7) @result{} -3 and 22/21\n"
2318 "@end lisp")
2319#define FUNC_NAME s_scm_i_truncate_divide
2320{
2321 SCM q, r;
2322
2323 scm_truncate_divide(x, y, &q, &r);
2324 return scm_values (scm_list_2 (q, r));
2325}
2326#undef FUNC_NAME
2327
2328#define s_scm_truncate_divide s_scm_i_truncate_divide
2329#define g_scm_truncate_divide g_scm_i_truncate_divide
2330
2331void
2332scm_truncate_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2333{
2334 if (SCM_LIKELY (SCM_I_INUMP (x)))
2335 {
2336 scm_t_inum xx = SCM_I_INUM (x);
2337 if (SCM_LIKELY (SCM_I_INUMP (y)))
2338 {
2339 scm_t_inum yy = SCM_I_INUM (y);
2340 if (SCM_UNLIKELY (yy == 0))
2341 scm_num_overflow (s_scm_truncate_divide);
2342 else
2343 {
2344 scm_t_inum qq = xx / yy;
2345 scm_t_inum rr = xx % yy;
2346 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2347 *qp = SCM_I_MAKINUM (qq);
2348 else
2349 *qp = scm_i_inum2big (qq);
2350 *rp = SCM_I_MAKINUM (rr);
2351 }
2352 return;
2353 }
2354 else if (SCM_BIGP (y))
2355 {
2356 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2357 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2358 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2359 {
2360 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2361 scm_remember_upto_here_1 (y);
2362 *qp = SCM_I_MAKINUM (-1);
2363 *rp = SCM_INUM0;
2364 }
2365 else
2366 {
2367 *qp = SCM_INUM0;
2368 *rp = x;
2369 }
2370 return;
2371 }
2372 else if (SCM_REALP (y))
2373 return scm_i_inexact_truncate_divide (xx, SCM_REAL_VALUE (y), qp, rp);
2374 else if (SCM_FRACTIONP (y))
2375 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2376 else
2377 return two_valued_wta_dispatch_2
2378 (g_scm_truncate_divide, x, y, SCM_ARG2,
2379 s_scm_truncate_divide, qp, rp);
2380 }
2381 else if (SCM_BIGP (x))
2382 {
2383 if (SCM_LIKELY (SCM_I_INUMP (y)))
2384 {
2385 scm_t_inum yy = SCM_I_INUM (y);
2386 if (SCM_UNLIKELY (yy == 0))
2387 scm_num_overflow (s_scm_truncate_divide);
2388 else
2389 {
2390 SCM q = scm_i_mkbig ();
2391 scm_t_inum rr;
2392 if (yy > 0)
2393 rr = mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q),
2394 SCM_I_BIG_MPZ (x), yy);
2395 else
2396 {
2397 rr = mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q),
2398 SCM_I_BIG_MPZ (x), -yy);
2399 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2400 }
2401 rr *= mpz_sgn (SCM_I_BIG_MPZ (x));
2402 scm_remember_upto_here_1 (x);
2403 *qp = scm_i_normbig (q);
2404 *rp = SCM_I_MAKINUM (rr);
2405 }
2406 return;
2407 }
2408 else if (SCM_BIGP (y))
2409 {
2410 SCM q = scm_i_mkbig ();
2411 SCM r = scm_i_mkbig ();
2412 mpz_tdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2413 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2414 scm_remember_upto_here_2 (x, y);
2415 *qp = scm_i_normbig (q);
2416 *rp = scm_i_normbig (r);
2417 }
2418 else if (SCM_REALP (y))
2419 return scm_i_inexact_truncate_divide
2420 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
2421 else if (SCM_FRACTIONP (y))
2422 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2423 else
2424 return two_valued_wta_dispatch_2
2425 (g_scm_truncate_divide, x, y, SCM_ARG2,
2426 s_scm_truncate_divide, qp, rp);
2427 }
2428 else if (SCM_REALP (x))
2429 {
2430 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2431 SCM_BIGP (y) || SCM_FRACTIONP (y))
2432 return scm_i_inexact_truncate_divide
2433 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
2434 else
2435 return two_valued_wta_dispatch_2
2436 (g_scm_truncate_divide, x, y, SCM_ARG2,
2437 s_scm_truncate_divide, qp, rp);
2438 }
2439 else if (SCM_FRACTIONP (x))
2440 {
2441 if (SCM_REALP (y))
2442 return scm_i_inexact_truncate_divide
2443 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
2444 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2445 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2446 else
2447 return two_valued_wta_dispatch_2
2448 (g_scm_truncate_divide, x, y, SCM_ARG2,
2449 s_scm_truncate_divide, qp, rp);
2450 }
2451 else
2452 return two_valued_wta_dispatch_2 (g_scm_truncate_divide, x, y, SCM_ARG1,
2453 s_scm_truncate_divide, qp, rp);
2454}
2455
2456static void
2457scm_i_inexact_truncate_divide (double x, double y, SCM *qp, SCM *rp)
2458{
2459 if (SCM_UNLIKELY (y == 0))
2460 scm_num_overflow (s_scm_truncate_divide); /* or return a NaN? */
2461 else
2462 {
c15fe499
MW
2463 double q = trunc (x / y);
2464 double r = x - q * y;
8f9da340
MW
2465 *qp = scm_from_double (q);
2466 *rp = scm_from_double (r);
2467 }
2468}
2469
2470static void
2471scm_i_exact_rational_truncate_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2472{
2473 SCM r1;
2474 SCM xd = scm_denominator (x);
2475 SCM yd = scm_denominator (y);
2476
2477 scm_truncate_divide (scm_product (scm_numerator (x), yd),
2478 scm_product (scm_numerator (y), xd),
2479 qp, &r1);
2480 *rp = scm_divide (r1, scm_product (xd, yd));
2481}
2482
ff62c168
MW
2483static SCM scm_i_inexact_centered_quotient (double x, double y);
2484static SCM scm_i_bigint_centered_quotient (SCM x, SCM y);
03ddd15b 2485static SCM scm_i_exact_rational_centered_quotient (SCM x, SCM y);
ff62c168 2486
8f9da340
MW
2487SCM_PRIMITIVE_GENERIC (scm_centered_quotient, "centered-quotient", 2, 0, 0,
2488 (SCM x, SCM y),
2489 "Return the integer @var{q} such that\n"
2490 "@math{@var{x} = @var{q}*@var{y} + @var{r}} where\n"
2491 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2492 "@lisp\n"
2493 "(centered-quotient 123 10) @result{} 12\n"
2494 "(centered-quotient 123 -10) @result{} -12\n"
2495 "(centered-quotient -123 10) @result{} -12\n"
2496 "(centered-quotient -123 -10) @result{} 12\n"
2497 "(centered-quotient -123.2 -63.5) @result{} 2.0\n"
2498 "(centered-quotient 16/3 -10/7) @result{} -4\n"
2499 "@end lisp")
2500#define FUNC_NAME s_scm_centered_quotient
2501{
2502 if (SCM_LIKELY (SCM_I_INUMP (x)))
2503 {
2504 scm_t_inum xx = SCM_I_INUM (x);
2505 if (SCM_LIKELY (SCM_I_INUMP (y)))
2506 {
2507 scm_t_inum yy = SCM_I_INUM (y);
2508 if (SCM_UNLIKELY (yy == 0))
2509 scm_num_overflow (s_scm_centered_quotient);
2510 else
2511 {
2512 scm_t_inum qq = xx / yy;
2513 scm_t_inum rr = xx % yy;
2514 if (SCM_LIKELY (xx > 0))
2515 {
2516 if (SCM_LIKELY (yy > 0))
2517 {
2518 if (rr >= (yy + 1) / 2)
2519 qq++;
2520 }
2521 else
2522 {
2523 if (rr >= (1 - yy) / 2)
2524 qq--;
2525 }
2526 }
2527 else
2528 {
2529 if (SCM_LIKELY (yy > 0))
2530 {
2531 if (rr < -yy / 2)
2532 qq--;
2533 }
2534 else
2535 {
2536 if (rr < yy / 2)
2537 qq++;
2538 }
2539 }
2540 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2541 return SCM_I_MAKINUM (qq);
2542 else
2543 return scm_i_inum2big (qq);
2544 }
2545 }
2546 else if (SCM_BIGP (y))
2547 {
2548 /* Pass a denormalized bignum version of x (even though it
2549 can fit in a fixnum) to scm_i_bigint_centered_quotient */
2550 return scm_i_bigint_centered_quotient (scm_i_long2big (xx), y);
2551 }
2552 else if (SCM_REALP (y))
2553 return scm_i_inexact_centered_quotient (xx, SCM_REAL_VALUE (y));
2554 else if (SCM_FRACTIONP (y))
2555 return scm_i_exact_rational_centered_quotient (x, y);
2556 else
2557 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2558 s_scm_centered_quotient);
2559 }
2560 else if (SCM_BIGP (x))
2561 {
2562 if (SCM_LIKELY (SCM_I_INUMP (y)))
2563 {
2564 scm_t_inum yy = SCM_I_INUM (y);
2565 if (SCM_UNLIKELY (yy == 0))
2566 scm_num_overflow (s_scm_centered_quotient);
2567 else if (SCM_UNLIKELY (yy == 1))
2568 return x;
2569 else
2570 {
2571 SCM q = scm_i_mkbig ();
2572 scm_t_inum rr;
2573 /* Arrange for rr to initially be non-positive,
2574 because that simplifies the test to see
2575 if it is within the needed bounds. */
2576 if (yy > 0)
2577 {
2578 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2579 SCM_I_BIG_MPZ (x), yy);
2580 scm_remember_upto_here_1 (x);
2581 if (rr < -yy / 2)
2582 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2583 SCM_I_BIG_MPZ (q), 1);
2584 }
2585 else
2586 {
2587 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2588 SCM_I_BIG_MPZ (x), -yy);
2589 scm_remember_upto_here_1 (x);
2590 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2591 if (rr < yy / 2)
2592 mpz_add_ui (SCM_I_BIG_MPZ (q),
2593 SCM_I_BIG_MPZ (q), 1);
2594 }
2595 return scm_i_normbig (q);
2596 }
2597 }
2598 else if (SCM_BIGP (y))
2599 return scm_i_bigint_centered_quotient (x, y);
2600 else if (SCM_REALP (y))
2601 return scm_i_inexact_centered_quotient
2602 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2603 else if (SCM_FRACTIONP (y))
2604 return scm_i_exact_rational_centered_quotient (x, y);
2605 else
2606 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2607 s_scm_centered_quotient);
2608 }
2609 else if (SCM_REALP (x))
2610 {
2611 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2612 SCM_BIGP (y) || SCM_FRACTIONP (y))
2613 return scm_i_inexact_centered_quotient
2614 (SCM_REAL_VALUE (x), scm_to_double (y));
2615 else
2616 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2617 s_scm_centered_quotient);
2618 }
2619 else if (SCM_FRACTIONP (x))
2620 {
2621 if (SCM_REALP (y))
2622 return scm_i_inexact_centered_quotient
2623 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2624 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2625 return scm_i_exact_rational_centered_quotient (x, y);
2626 else
2627 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2628 s_scm_centered_quotient);
2629 }
2630 else
2631 SCM_WTA_DISPATCH_2 (g_scm_centered_quotient, x, y, SCM_ARG1,
2632 s_scm_centered_quotient);
2633}
2634#undef FUNC_NAME
2635
2636static SCM
2637scm_i_inexact_centered_quotient (double x, double y)
2638{
2639 if (SCM_LIKELY (y > 0))
2640 return scm_from_double (floor (x/y + 0.5));
2641 else if (SCM_LIKELY (y < 0))
2642 return scm_from_double (ceil (x/y - 0.5));
2643 else if (y == 0)
2644 scm_num_overflow (s_scm_centered_quotient); /* or return a NaN? */
2645 else
2646 return scm_nan ();
2647}
2648
2649/* Assumes that both x and y are bigints, though
2650 x might be able to fit into a fixnum. */
2651static SCM
2652scm_i_bigint_centered_quotient (SCM x, SCM y)
2653{
2654 SCM q, r, min_r;
2655
2656 /* Note that x might be small enough to fit into a
2657 fixnum, so we must not let it escape into the wild */
2658 q = scm_i_mkbig ();
2659 r = scm_i_mkbig ();
2660
2661 /* min_r will eventually become -abs(y)/2 */
2662 min_r = scm_i_mkbig ();
2663 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2664 SCM_I_BIG_MPZ (y), 1);
2665
2666 /* Arrange for rr to initially be non-positive,
2667 because that simplifies the test to see
2668 if it is within the needed bounds. */
2669 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2670 {
2671 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2672 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2673 scm_remember_upto_here_2 (x, y);
2674 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2675 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2676 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2677 SCM_I_BIG_MPZ (q), 1);
2678 }
2679 else
2680 {
2681 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2682 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2683 scm_remember_upto_here_2 (x, y);
2684 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2685 mpz_add_ui (SCM_I_BIG_MPZ (q),
2686 SCM_I_BIG_MPZ (q), 1);
2687 }
2688 scm_remember_upto_here_2 (r, min_r);
2689 return scm_i_normbig (q);
2690}
2691
2692static SCM
2693scm_i_exact_rational_centered_quotient (SCM x, SCM y)
2694{
2695 return scm_centered_quotient
2696 (scm_product (scm_numerator (x), scm_denominator (y)),
2697 scm_product (scm_numerator (y), scm_denominator (x)));
2698}
2699
2700static SCM scm_i_inexact_centered_remainder (double x, double y);
2701static SCM scm_i_bigint_centered_remainder (SCM x, SCM y);
2702static SCM scm_i_exact_rational_centered_remainder (SCM x, SCM y);
2703
2704SCM_PRIMITIVE_GENERIC (scm_centered_remainder, "centered-remainder", 2, 0, 0,
2705 (SCM x, SCM y),
2706 "Return the real number @var{r} such that\n"
2707 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}\n"
2708 "and @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2709 "for some integer @var{q}.\n"
2710 "@lisp\n"
2711 "(centered-remainder 123 10) @result{} 3\n"
2712 "(centered-remainder 123 -10) @result{} 3\n"
2713 "(centered-remainder -123 10) @result{} -3\n"
2714 "(centered-remainder -123 -10) @result{} -3\n"
2715 "(centered-remainder -123.2 -63.5) @result{} 3.8\n"
2716 "(centered-remainder 16/3 -10/7) @result{} -8/21\n"
2717 "@end lisp")
2718#define FUNC_NAME s_scm_centered_remainder
2719{
2720 if (SCM_LIKELY (SCM_I_INUMP (x)))
2721 {
2722 scm_t_inum xx = SCM_I_INUM (x);
2723 if (SCM_LIKELY (SCM_I_INUMP (y)))
2724 {
2725 scm_t_inum yy = SCM_I_INUM (y);
2726 if (SCM_UNLIKELY (yy == 0))
2727 scm_num_overflow (s_scm_centered_remainder);
2728 else
2729 {
2730 scm_t_inum rr = xx % yy;
2731 if (SCM_LIKELY (xx > 0))
2732 {
2733 if (SCM_LIKELY (yy > 0))
2734 {
2735 if (rr >= (yy + 1) / 2)
2736 rr -= yy;
2737 }
2738 else
2739 {
2740 if (rr >= (1 - yy) / 2)
2741 rr += yy;
2742 }
2743 }
2744 else
2745 {
2746 if (SCM_LIKELY (yy > 0))
2747 {
2748 if (rr < -yy / 2)
2749 rr += yy;
2750 }
2751 else
2752 {
2753 if (rr < yy / 2)
2754 rr -= yy;
2755 }
2756 }
2757 return SCM_I_MAKINUM (rr);
2758 }
2759 }
2760 else if (SCM_BIGP (y))
2761 {
2762 /* Pass a denormalized bignum version of x (even though it
2763 can fit in a fixnum) to scm_i_bigint_centered_remainder */
2764 return scm_i_bigint_centered_remainder (scm_i_long2big (xx), y);
2765 }
2766 else if (SCM_REALP (y))
2767 return scm_i_inexact_centered_remainder (xx, SCM_REAL_VALUE (y));
2768 else if (SCM_FRACTIONP (y))
2769 return scm_i_exact_rational_centered_remainder (x, y);
2770 else
2771 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2772 s_scm_centered_remainder);
2773 }
2774 else if (SCM_BIGP (x))
2775 {
2776 if (SCM_LIKELY (SCM_I_INUMP (y)))
2777 {
2778 scm_t_inum yy = SCM_I_INUM (y);
2779 if (SCM_UNLIKELY (yy == 0))
2780 scm_num_overflow (s_scm_centered_remainder);
2781 else
2782 {
2783 scm_t_inum rr;
2784 /* Arrange for rr to initially be non-positive,
2785 because that simplifies the test to see
2786 if it is within the needed bounds. */
2787 if (yy > 0)
2788 {
2789 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
2790 scm_remember_upto_here_1 (x);
2791 if (rr < -yy / 2)
2792 rr += yy;
2793 }
2794 else
2795 {
2796 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
2797 scm_remember_upto_here_1 (x);
2798 if (rr < yy / 2)
2799 rr -= yy;
2800 }
2801 return SCM_I_MAKINUM (rr);
2802 }
2803 }
2804 else if (SCM_BIGP (y))
2805 return scm_i_bigint_centered_remainder (x, y);
2806 else if (SCM_REALP (y))
2807 return scm_i_inexact_centered_remainder
2808 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2809 else if (SCM_FRACTIONP (y))
2810 return scm_i_exact_rational_centered_remainder (x, y);
2811 else
2812 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2813 s_scm_centered_remainder);
2814 }
2815 else if (SCM_REALP (x))
2816 {
2817 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2818 SCM_BIGP (y) || SCM_FRACTIONP (y))
2819 return scm_i_inexact_centered_remainder
2820 (SCM_REAL_VALUE (x), scm_to_double (y));
2821 else
2822 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2823 s_scm_centered_remainder);
2824 }
2825 else if (SCM_FRACTIONP (x))
2826 {
2827 if (SCM_REALP (y))
2828 return scm_i_inexact_centered_remainder
2829 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2830 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2831 return scm_i_exact_rational_centered_remainder (x, y);
2832 else
2833 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2834 s_scm_centered_remainder);
2835 }
2836 else
2837 SCM_WTA_DISPATCH_2 (g_scm_centered_remainder, x, y, SCM_ARG1,
2838 s_scm_centered_remainder);
2839}
2840#undef FUNC_NAME
2841
2842static SCM
2843scm_i_inexact_centered_remainder (double x, double y)
2844{
2845 double q;
2846
2847 /* Although it would be more efficient to use fmod here, we can't
2848 because it would in some cases produce results inconsistent with
2849 scm_i_inexact_centered_quotient, such that x != r + q * y (not even
2850 close). In particular, when x-y/2 is very close to a multiple of
2851 y, then r might be either -abs(y/2) or abs(y/2)-epsilon, but those
2852 two cases must correspond to different choices of q. If quotient
2853 chooses one and remainder chooses the other, it would be bad. */
2854 if (SCM_LIKELY (y > 0))
2855 q = floor (x/y + 0.5);
2856 else if (SCM_LIKELY (y < 0))
2857 q = ceil (x/y - 0.5);
2858 else if (y == 0)
2859 scm_num_overflow (s_scm_centered_remainder); /* or return a NaN? */
2860 else
2861 return scm_nan ();
2862 return scm_from_double (x - q * y);
2863}
2864
2865/* Assumes that both x and y are bigints, though
2866 x might be able to fit into a fixnum. */
2867static SCM
2868scm_i_bigint_centered_remainder (SCM x, SCM y)
2869{
2870 SCM r, min_r;
2871
2872 /* Note that x might be small enough to fit into a
2873 fixnum, so we must not let it escape into the wild */
2874 r = scm_i_mkbig ();
2875
2876 /* min_r will eventually become -abs(y)/2 */
2877 min_r = scm_i_mkbig ();
2878 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2879 SCM_I_BIG_MPZ (y), 1);
2880
2881 /* Arrange for rr to initially be non-positive,
2882 because that simplifies the test to see
2883 if it is within the needed bounds. */
2884 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2885 {
2886 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
2887 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2888 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2889 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2890 mpz_add (SCM_I_BIG_MPZ (r),
2891 SCM_I_BIG_MPZ (r),
2892 SCM_I_BIG_MPZ (y));
2893 }
2894 else
2895 {
2896 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
2897 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2898 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2899 mpz_sub (SCM_I_BIG_MPZ (r),
2900 SCM_I_BIG_MPZ (r),
2901 SCM_I_BIG_MPZ (y));
2902 }
2903 scm_remember_upto_here_2 (x, y);
2904 return scm_i_normbig (r);
2905}
2906
2907static SCM
2908scm_i_exact_rational_centered_remainder (SCM x, SCM y)
2909{
2910 SCM xd = scm_denominator (x);
2911 SCM yd = scm_denominator (y);
2912 SCM r1 = scm_centered_remainder (scm_product (scm_numerator (x), yd),
2913 scm_product (scm_numerator (y), xd));
2914 return scm_divide (r1, scm_product (xd, yd));
2915}
2916
2917
2918static void scm_i_inexact_centered_divide (double x, double y,
2919 SCM *qp, SCM *rp);
2920static void scm_i_bigint_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp);
2921static void scm_i_exact_rational_centered_divide (SCM x, SCM y,
2922 SCM *qp, SCM *rp);
2923
2924SCM_PRIMITIVE_GENERIC (scm_i_centered_divide, "centered/", 2, 0, 0,
2925 (SCM x, SCM y),
2926 "Return the integer @var{q} and the real number @var{r}\n"
2927 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2928 "and @math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2929 "@lisp\n"
2930 "(centered/ 123 10) @result{} 12 and 3\n"
2931 "(centered/ 123 -10) @result{} -12 and 3\n"
2932 "(centered/ -123 10) @result{} -12 and -3\n"
2933 "(centered/ -123 -10) @result{} 12 and -3\n"
2934 "(centered/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
2935 "(centered/ 16/3 -10/7) @result{} -4 and -8/21\n"
2936 "@end lisp")
2937#define FUNC_NAME s_scm_i_centered_divide
2938{
2939 SCM q, r;
2940
2941 scm_centered_divide(x, y, &q, &r);
2942 return scm_values (scm_list_2 (q, r));
2943}
2944#undef FUNC_NAME
2945
2946#define s_scm_centered_divide s_scm_i_centered_divide
2947#define g_scm_centered_divide g_scm_i_centered_divide
2948
2949void
2950scm_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2951{
2952 if (SCM_LIKELY (SCM_I_INUMP (x)))
2953 {
2954 scm_t_inum xx = SCM_I_INUM (x);
2955 if (SCM_LIKELY (SCM_I_INUMP (y)))
2956 {
2957 scm_t_inum yy = SCM_I_INUM (y);
2958 if (SCM_UNLIKELY (yy == 0))
2959 scm_num_overflow (s_scm_centered_divide);
2960 else
2961 {
2962 scm_t_inum qq = xx / yy;
2963 scm_t_inum rr = xx % yy;
2964 if (SCM_LIKELY (xx > 0))
2965 {
2966 if (SCM_LIKELY (yy > 0))
2967 {
2968 if (rr >= (yy + 1) / 2)
2969 { qq++; rr -= yy; }
2970 }
2971 else
2972 {
2973 if (rr >= (1 - yy) / 2)
2974 { qq--; rr += yy; }
2975 }
2976 }
2977 else
2978 {
2979 if (SCM_LIKELY (yy > 0))
2980 {
2981 if (rr < -yy / 2)
2982 { qq--; rr += yy; }
2983 }
2984 else
2985 {
2986 if (rr < yy / 2)
2987 { qq++; rr -= yy; }
2988 }
2989 }
2990 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2991 *qp = SCM_I_MAKINUM (qq);
2992 else
2993 *qp = scm_i_inum2big (qq);
2994 *rp = SCM_I_MAKINUM (rr);
2995 }
2996 return;
2997 }
2998 else if (SCM_BIGP (y))
2999 {
3000 /* Pass a denormalized bignum version of x (even though it
3001 can fit in a fixnum) to scm_i_bigint_centered_divide */
3002 return scm_i_bigint_centered_divide (scm_i_long2big (xx), y, qp, rp);
3003 }
3004 else if (SCM_REALP (y))
3005 return scm_i_inexact_centered_divide (xx, SCM_REAL_VALUE (y), qp, rp);
3006 else if (SCM_FRACTIONP (y))
3007 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3008 else
3009 return two_valued_wta_dispatch_2
3010 (g_scm_centered_divide, x, y, SCM_ARG2,
3011 s_scm_centered_divide, qp, rp);
3012 }
3013 else if (SCM_BIGP (x))
3014 {
3015 if (SCM_LIKELY (SCM_I_INUMP (y)))
3016 {
3017 scm_t_inum yy = SCM_I_INUM (y);
3018 if (SCM_UNLIKELY (yy == 0))
3019 scm_num_overflow (s_scm_centered_divide);
3020 else
3021 {
3022 SCM q = scm_i_mkbig ();
3023 scm_t_inum rr;
3024 /* Arrange for rr to initially be non-positive,
3025 because that simplifies the test to see
3026 if it is within the needed bounds. */
3027 if (yy > 0)
3028 {
3029 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3030 SCM_I_BIG_MPZ (x), yy);
3031 scm_remember_upto_here_1 (x);
3032 if (rr < -yy / 2)
3033 {
3034 mpz_sub_ui (SCM_I_BIG_MPZ (q),
3035 SCM_I_BIG_MPZ (q), 1);
3036 rr += yy;
3037 }
3038 }
3039 else
3040 {
3041 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3042 SCM_I_BIG_MPZ (x), -yy);
3043 scm_remember_upto_here_1 (x);
3044 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
3045 if (rr < yy / 2)
3046 {
3047 mpz_add_ui (SCM_I_BIG_MPZ (q),
3048 SCM_I_BIG_MPZ (q), 1);
3049 rr -= yy;
3050 }
3051 }
3052 *qp = scm_i_normbig (q);
3053 *rp = SCM_I_MAKINUM (rr);
3054 }
3055 return;
3056 }
3057 else if (SCM_BIGP (y))
3058 return scm_i_bigint_centered_divide (x, y, qp, rp);
3059 else if (SCM_REALP (y))
3060 return scm_i_inexact_centered_divide
3061 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
3062 else if (SCM_FRACTIONP (y))
3063 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3064 else
3065 return two_valued_wta_dispatch_2
3066 (g_scm_centered_divide, x, y, SCM_ARG2,
3067 s_scm_centered_divide, qp, rp);
3068 }
3069 else if (SCM_REALP (x))
3070 {
3071 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3072 SCM_BIGP (y) || SCM_FRACTIONP (y))
3073 return scm_i_inexact_centered_divide
3074 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
3075 else
3076 return two_valued_wta_dispatch_2
3077 (g_scm_centered_divide, x, y, SCM_ARG2,
3078 s_scm_centered_divide, qp, rp);
3079 }
3080 else if (SCM_FRACTIONP (x))
3081 {
3082 if (SCM_REALP (y))
3083 return scm_i_inexact_centered_divide
3084 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
3085 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
3086 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3087 else
3088 return two_valued_wta_dispatch_2
3089 (g_scm_centered_divide, x, y, SCM_ARG2,
3090 s_scm_centered_divide, qp, rp);
3091 }
3092 else
3093 return two_valued_wta_dispatch_2 (g_scm_centered_divide, x, y, SCM_ARG1,
3094 s_scm_centered_divide, qp, rp);
3095}
3096
3097static void
3098scm_i_inexact_centered_divide (double x, double y, SCM *qp, SCM *rp)
3099{
3100 double q, r;
3101
3102 if (SCM_LIKELY (y > 0))
3103 q = floor (x/y + 0.5);
3104 else if (SCM_LIKELY (y < 0))
3105 q = ceil (x/y - 0.5);
3106 else if (y == 0)
3107 scm_num_overflow (s_scm_centered_divide); /* or return a NaN? */
3108 else
3109 q = guile_NaN;
3110 r = x - q * y;
3111 *qp = scm_from_double (q);
3112 *rp = scm_from_double (r);
3113}
3114
3115/* Assumes that both x and y are bigints, though
3116 x might be able to fit into a fixnum. */
3117static void
3118scm_i_bigint_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
3119{
3120 SCM q, r, min_r;
3121
3122 /* Note that x might be small enough to fit into a
3123 fixnum, so we must not let it escape into the wild */
3124 q = scm_i_mkbig ();
3125 r = scm_i_mkbig ();
3126
3127 /* min_r will eventually become -abs(y/2) */
3128 min_r = scm_i_mkbig ();
3129 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
3130 SCM_I_BIG_MPZ (y), 1);
3131
3132 /* Arrange for rr to initially be non-positive,
3133 because that simplifies the test to see
3134 if it is within the needed bounds. */
3135 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
3136 {
3137 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3138 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3139 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
3140 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
3141 {
3142 mpz_sub_ui (SCM_I_BIG_MPZ (q),
3143 SCM_I_BIG_MPZ (q), 1);
3144 mpz_add (SCM_I_BIG_MPZ (r),
3145 SCM_I_BIG_MPZ (r),
3146 SCM_I_BIG_MPZ (y));
3147 }
3148 }
3149 else
3150 {
3151 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3152 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3153 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
3154 {
3155 mpz_add_ui (SCM_I_BIG_MPZ (q),
3156 SCM_I_BIG_MPZ (q), 1);
3157 mpz_sub (SCM_I_BIG_MPZ (r),
3158 SCM_I_BIG_MPZ (r),
3159 SCM_I_BIG_MPZ (y));
3160 }
3161 }
3162 scm_remember_upto_here_2 (x, y);
3163 *qp = scm_i_normbig (q);
3164 *rp = scm_i_normbig (r);
3165}
3166
3167static void
3168scm_i_exact_rational_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
3169{
3170 SCM r1;
3171 SCM xd = scm_denominator (x);
3172 SCM yd = scm_denominator (y);
3173
3174 scm_centered_divide (scm_product (scm_numerator (x), yd),
3175 scm_product (scm_numerator (y), xd),
3176 qp, &r1);
3177 *rp = scm_divide (r1, scm_product (xd, yd));
3178}
3179
3180static SCM scm_i_inexact_round_quotient (double x, double y);
3181static SCM scm_i_bigint_round_quotient (SCM x, SCM y);
3182static SCM scm_i_exact_rational_round_quotient (SCM x, SCM y);
3183
3184SCM_PRIMITIVE_GENERIC (scm_round_quotient, "round-quotient", 2, 0, 0,
ff62c168 3185 (SCM x, SCM y),
8f9da340
MW
3186 "Return @math{@var{x} / @var{y}} to the nearest integer,\n"
3187 "with ties going to the nearest even integer.\n"
ff62c168 3188 "@lisp\n"
8f9da340
MW
3189 "(round-quotient 123 10) @result{} 12\n"
3190 "(round-quotient 123 -10) @result{} -12\n"
3191 "(round-quotient -123 10) @result{} -12\n"
3192 "(round-quotient -123 -10) @result{} 12\n"
3193 "(round-quotient 125 10) @result{} 12\n"
3194 "(round-quotient 127 10) @result{} 13\n"
3195 "(round-quotient 135 10) @result{} 14\n"
3196 "(round-quotient -123.2 -63.5) @result{} 2.0\n"
3197 "(round-quotient 16/3 -10/7) @result{} -4\n"
ff62c168 3198 "@end lisp")
8f9da340 3199#define FUNC_NAME s_scm_round_quotient
ff62c168
MW
3200{
3201 if (SCM_LIKELY (SCM_I_INUMP (x)))
3202 {
4a46bc2a 3203 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3204 if (SCM_LIKELY (SCM_I_INUMP (y)))
3205 {
3206 scm_t_inum yy = SCM_I_INUM (y);
3207 if (SCM_UNLIKELY (yy == 0))
8f9da340 3208 scm_num_overflow (s_scm_round_quotient);
ff62c168
MW
3209 else
3210 {
ff62c168 3211 scm_t_inum qq = xx / yy;
4a46bc2a 3212 scm_t_inum rr = xx % yy;
8f9da340
MW
3213 scm_t_inum ay = yy;
3214 scm_t_inum r2 = 2 * rr;
3215
3216 if (SCM_LIKELY (yy < 0))
ff62c168 3217 {
8f9da340
MW
3218 ay = -ay;
3219 r2 = -r2;
3220 }
3221
3222 if (qq & 1L)
3223 {
3224 if (r2 >= ay)
3225 qq++;
3226 else if (r2 <= -ay)
3227 qq--;
ff62c168
MW
3228 }
3229 else
3230 {
8f9da340
MW
3231 if (r2 > ay)
3232 qq++;
3233 else if (r2 < -ay)
3234 qq--;
ff62c168 3235 }
4a46bc2a
MW
3236 if (SCM_LIKELY (SCM_FIXABLE (qq)))
3237 return SCM_I_MAKINUM (qq);
3238 else
3239 return scm_i_inum2big (qq);
ff62c168
MW
3240 }
3241 }
3242 else if (SCM_BIGP (y))
3243 {
3244 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3245 can fit in a fixnum) to scm_i_bigint_round_quotient */
3246 return scm_i_bigint_round_quotient (scm_i_long2big (xx), y);
ff62c168
MW
3247 }
3248 else if (SCM_REALP (y))
8f9da340 3249 return scm_i_inexact_round_quotient (xx, SCM_REAL_VALUE (y));
ff62c168 3250 else if (SCM_FRACTIONP (y))
8f9da340 3251 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3252 else
8f9da340
MW
3253 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3254 s_scm_round_quotient);
ff62c168
MW
3255 }
3256 else if (SCM_BIGP (x))
3257 {
3258 if (SCM_LIKELY (SCM_I_INUMP (y)))
3259 {
3260 scm_t_inum yy = SCM_I_INUM (y);
3261 if (SCM_UNLIKELY (yy == 0))
8f9da340 3262 scm_num_overflow (s_scm_round_quotient);
4a46bc2a
MW
3263 else if (SCM_UNLIKELY (yy == 1))
3264 return x;
ff62c168
MW
3265 else
3266 {
3267 SCM q = scm_i_mkbig ();
3268 scm_t_inum rr;
8f9da340
MW
3269 int needs_adjustment;
3270
ff62c168
MW
3271 if (yy > 0)
3272 {
8f9da340
MW
3273 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3274 SCM_I_BIG_MPZ (x), yy);
3275 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3276 needs_adjustment = (2*rr >= yy);
3277 else
3278 needs_adjustment = (2*rr > yy);
ff62c168
MW
3279 }
3280 else
3281 {
3282 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3283 SCM_I_BIG_MPZ (x), -yy);
ff62c168 3284 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
8f9da340
MW
3285 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3286 needs_adjustment = (2*rr <= yy);
3287 else
3288 needs_adjustment = (2*rr < yy);
ff62c168 3289 }
8f9da340
MW
3290 scm_remember_upto_here_1 (x);
3291 if (needs_adjustment)
3292 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
ff62c168
MW
3293 return scm_i_normbig (q);
3294 }
3295 }
3296 else if (SCM_BIGP (y))
8f9da340 3297 return scm_i_bigint_round_quotient (x, y);
ff62c168 3298 else if (SCM_REALP (y))
8f9da340 3299 return scm_i_inexact_round_quotient
ff62c168
MW
3300 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
3301 else if (SCM_FRACTIONP (y))
8f9da340 3302 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3303 else
8f9da340
MW
3304 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3305 s_scm_round_quotient);
ff62c168
MW
3306 }
3307 else if (SCM_REALP (x))
3308 {
3309 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3310 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3311 return scm_i_inexact_round_quotient
ff62c168
MW
3312 (SCM_REAL_VALUE (x), scm_to_double (y));
3313 else
8f9da340
MW
3314 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3315 s_scm_round_quotient);
ff62c168
MW
3316 }
3317 else if (SCM_FRACTIONP (x))
3318 {
3319 if (SCM_REALP (y))
8f9da340 3320 return scm_i_inexact_round_quotient
ff62c168 3321 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
03ddd15b 3322 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3323 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3324 else
8f9da340
MW
3325 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3326 s_scm_round_quotient);
ff62c168
MW
3327 }
3328 else
8f9da340
MW
3329 SCM_WTA_DISPATCH_2 (g_scm_round_quotient, x, y, SCM_ARG1,
3330 s_scm_round_quotient);
ff62c168
MW
3331}
3332#undef FUNC_NAME
3333
3334static SCM
8f9da340 3335scm_i_inexact_round_quotient (double x, double y)
ff62c168 3336{
8f9da340
MW
3337 if (SCM_UNLIKELY (y == 0))
3338 scm_num_overflow (s_scm_round_quotient); /* or return a NaN? */
ff62c168 3339 else
8f9da340 3340 return scm_from_double (scm_c_round (x / y));
ff62c168
MW
3341}
3342
3343/* Assumes that both x and y are bigints, though
3344 x might be able to fit into a fixnum. */
3345static SCM
8f9da340 3346scm_i_bigint_round_quotient (SCM x, SCM y)
ff62c168 3347{
8f9da340
MW
3348 SCM q, r, r2;
3349 int cmp, needs_adjustment;
ff62c168
MW
3350
3351 /* Note that x might be small enough to fit into a
3352 fixnum, so we must not let it escape into the wild */
3353 q = scm_i_mkbig ();
3354 r = scm_i_mkbig ();
8f9da340 3355 r2 = scm_i_mkbig ();
ff62c168 3356
8f9da340
MW
3357 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3358 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3359 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
3360 scm_remember_upto_here_2 (x, r);
ff62c168 3361
8f9da340
MW
3362 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3363 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3364 needs_adjustment = (cmp >= 0);
ff62c168 3365 else
8f9da340
MW
3366 needs_adjustment = (cmp > 0);
3367 scm_remember_upto_here_2 (r2, y);
3368
3369 if (needs_adjustment)
3370 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3371
ff62c168
MW
3372 return scm_i_normbig (q);
3373}
3374
ff62c168 3375static SCM
8f9da340 3376scm_i_exact_rational_round_quotient (SCM x, SCM y)
ff62c168 3377{
8f9da340 3378 return scm_round_quotient
03ddd15b
MW
3379 (scm_product (scm_numerator (x), scm_denominator (y)),
3380 scm_product (scm_numerator (y), scm_denominator (x)));
ff62c168
MW
3381}
3382
8f9da340
MW
3383static SCM scm_i_inexact_round_remainder (double x, double y);
3384static SCM scm_i_bigint_round_remainder (SCM x, SCM y);
3385static SCM scm_i_exact_rational_round_remainder (SCM x, SCM y);
ff62c168 3386
8f9da340 3387SCM_PRIMITIVE_GENERIC (scm_round_remainder, "round-remainder", 2, 0, 0,
ff62c168
MW
3388 (SCM x, SCM y),
3389 "Return the real number @var{r} such that\n"
8f9da340
MW
3390 "@math{@var{x} = @var{q}*@var{y} + @var{r}}, where\n"
3391 "@var{q} is @math{@var{x} / @var{y}} rounded to the\n"
3392 "nearest integer, with ties going to the nearest\n"
3393 "even integer.\n"
ff62c168 3394 "@lisp\n"
8f9da340
MW
3395 "(round-remainder 123 10) @result{} 3\n"
3396 "(round-remainder 123 -10) @result{} 3\n"
3397 "(round-remainder -123 10) @result{} -3\n"
3398 "(round-remainder -123 -10) @result{} -3\n"
3399 "(round-remainder 125 10) @result{} 5\n"
3400 "(round-remainder 127 10) @result{} -3\n"
3401 "(round-remainder 135 10) @result{} -5\n"
3402 "(round-remainder -123.2 -63.5) @result{} 3.8\n"
3403 "(round-remainder 16/3 -10/7) @result{} -8/21\n"
ff62c168 3404 "@end lisp")
8f9da340 3405#define FUNC_NAME s_scm_round_remainder
ff62c168
MW
3406{
3407 if (SCM_LIKELY (SCM_I_INUMP (x)))
3408 {
4a46bc2a 3409 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3410 if (SCM_LIKELY (SCM_I_INUMP (y)))
3411 {
3412 scm_t_inum yy = SCM_I_INUM (y);
3413 if (SCM_UNLIKELY (yy == 0))
8f9da340 3414 scm_num_overflow (s_scm_round_remainder);
ff62c168
MW
3415 else
3416 {
8f9da340 3417 scm_t_inum qq = xx / yy;
ff62c168 3418 scm_t_inum rr = xx % yy;
8f9da340
MW
3419 scm_t_inum ay = yy;
3420 scm_t_inum r2 = 2 * rr;
3421
3422 if (SCM_LIKELY (yy < 0))
ff62c168 3423 {
8f9da340
MW
3424 ay = -ay;
3425 r2 = -r2;
3426 }
3427
3428 if (qq & 1L)
3429 {
3430 if (r2 >= ay)
3431 rr -= yy;
3432 else if (r2 <= -ay)
3433 rr += yy;
ff62c168
MW
3434 }
3435 else
3436 {
8f9da340
MW
3437 if (r2 > ay)
3438 rr -= yy;
3439 else if (r2 < -ay)
3440 rr += yy;
ff62c168
MW
3441 }
3442 return SCM_I_MAKINUM (rr);
3443 }
3444 }
3445 else if (SCM_BIGP (y))
3446 {
3447 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3448 can fit in a fixnum) to scm_i_bigint_round_remainder */
3449 return scm_i_bigint_round_remainder
3450 (scm_i_long2big (xx), y);
ff62c168
MW
3451 }
3452 else if (SCM_REALP (y))
8f9da340 3453 return scm_i_inexact_round_remainder (xx, SCM_REAL_VALUE (y));
ff62c168 3454 else if (SCM_FRACTIONP (y))
8f9da340 3455 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3456 else
8f9da340
MW
3457 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3458 s_scm_round_remainder);
ff62c168
MW
3459 }
3460 else if (SCM_BIGP (x))
3461 {
3462 if (SCM_LIKELY (SCM_I_INUMP (y)))
3463 {
3464 scm_t_inum yy = SCM_I_INUM (y);
3465 if (SCM_UNLIKELY (yy == 0))
8f9da340 3466 scm_num_overflow (s_scm_round_remainder);
ff62c168
MW
3467 else
3468 {
8f9da340 3469 SCM q = scm_i_mkbig ();
ff62c168 3470 scm_t_inum rr;
8f9da340
MW
3471 int needs_adjustment;
3472
ff62c168
MW
3473 if (yy > 0)
3474 {
8f9da340
MW
3475 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3476 SCM_I_BIG_MPZ (x), yy);
3477 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3478 needs_adjustment = (2*rr >= yy);
3479 else
3480 needs_adjustment = (2*rr > yy);
ff62c168
MW
3481 }
3482 else
3483 {
8f9da340
MW
3484 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3485 SCM_I_BIG_MPZ (x), -yy);
3486 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3487 needs_adjustment = (2*rr <= yy);
3488 else
3489 needs_adjustment = (2*rr < yy);
ff62c168 3490 }
8f9da340
MW
3491 scm_remember_upto_here_2 (x, q);
3492 if (needs_adjustment)
3493 rr -= yy;
ff62c168
MW
3494 return SCM_I_MAKINUM (rr);
3495 }
3496 }
3497 else if (SCM_BIGP (y))
8f9da340 3498 return scm_i_bigint_round_remainder (x, y);
ff62c168 3499 else if (SCM_REALP (y))
8f9da340 3500 return scm_i_inexact_round_remainder
ff62c168
MW
3501 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
3502 else if (SCM_FRACTIONP (y))
8f9da340 3503 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3504 else
8f9da340
MW
3505 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3506 s_scm_round_remainder);
ff62c168
MW
3507 }
3508 else if (SCM_REALP (x))
3509 {
3510 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3511 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3512 return scm_i_inexact_round_remainder
ff62c168
MW
3513 (SCM_REAL_VALUE (x), scm_to_double (y));
3514 else
8f9da340
MW
3515 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3516 s_scm_round_remainder);
ff62c168
MW
3517 }
3518 else if (SCM_FRACTIONP (x))
3519 {
3520 if (SCM_REALP (y))
8f9da340 3521 return scm_i_inexact_round_remainder
ff62c168 3522 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
03ddd15b 3523 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3524 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3525 else
8f9da340
MW
3526 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3527 s_scm_round_remainder);
ff62c168
MW
3528 }
3529 else
8f9da340
MW
3530 SCM_WTA_DISPATCH_2 (g_scm_round_remainder, x, y, SCM_ARG1,
3531 s_scm_round_remainder);
ff62c168
MW
3532}
3533#undef FUNC_NAME
3534
3535static SCM
8f9da340 3536scm_i_inexact_round_remainder (double x, double y)
ff62c168 3537{
ff62c168
MW
3538 /* Although it would be more efficient to use fmod here, we can't
3539 because it would in some cases produce results inconsistent with
8f9da340 3540 scm_i_inexact_round_quotient, such that x != r + q * y (not even
ff62c168 3541 close). In particular, when x-y/2 is very close to a multiple of
8f9da340
MW
3542 y, then r might be either -abs(y/2) or abs(y/2), but those two
3543 cases must correspond to different choices of q. If quotient
ff62c168 3544 chooses one and remainder chooses the other, it would be bad. */
8f9da340
MW
3545
3546 if (SCM_UNLIKELY (y == 0))
3547 scm_num_overflow (s_scm_round_remainder); /* or return a NaN? */
ff62c168 3548 else
8f9da340
MW
3549 {
3550 double q = scm_c_round (x / y);
3551 return scm_from_double (x - q * y);
3552 }
ff62c168
MW
3553}
3554
3555/* Assumes that both x and y are bigints, though
3556 x might be able to fit into a fixnum. */
3557static SCM
8f9da340 3558scm_i_bigint_round_remainder (SCM x, SCM y)
ff62c168 3559{
8f9da340
MW
3560 SCM q, r, r2;
3561 int cmp, needs_adjustment;
ff62c168
MW
3562
3563 /* Note that x might be small enough to fit into a
3564 fixnum, so we must not let it escape into the wild */
8f9da340 3565 q = scm_i_mkbig ();
ff62c168 3566 r = scm_i_mkbig ();
8f9da340 3567 r2 = scm_i_mkbig ();
ff62c168 3568
8f9da340
MW
3569 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3570 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3571 scm_remember_upto_here_1 (x);
3572 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
ff62c168 3573
8f9da340
MW
3574 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3575 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3576 needs_adjustment = (cmp >= 0);
ff62c168 3577 else
8f9da340
MW
3578 needs_adjustment = (cmp > 0);
3579 scm_remember_upto_here_2 (q, r2);
3580
3581 if (needs_adjustment)
3582 mpz_sub (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y));
3583
3584 scm_remember_upto_here_1 (y);
ff62c168
MW
3585 return scm_i_normbig (r);
3586}
3587
ff62c168 3588static SCM
8f9da340 3589scm_i_exact_rational_round_remainder (SCM x, SCM y)
ff62c168 3590{
03ddd15b
MW
3591 SCM xd = scm_denominator (x);
3592 SCM yd = scm_denominator (y);
8f9da340
MW
3593 SCM r1 = scm_round_remainder (scm_product (scm_numerator (x), yd),
3594 scm_product (scm_numerator (y), xd));
03ddd15b 3595 return scm_divide (r1, scm_product (xd, yd));
ff62c168
MW
3596}
3597
3598
8f9da340
MW
3599static void scm_i_inexact_round_divide (double x, double y, SCM *qp, SCM *rp);
3600static void scm_i_bigint_round_divide (SCM x, SCM y, SCM *qp, SCM *rp);
3601static void scm_i_exact_rational_round_divide (SCM x, SCM y, SCM *qp, SCM *rp);
ff62c168 3602
8f9da340 3603SCM_PRIMITIVE_GENERIC (scm_i_round_divide, "round/", 2, 0, 0,
ff62c168
MW
3604 (SCM x, SCM y),
3605 "Return the integer @var{q} and the real number @var{r}\n"
3606 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
8f9da340
MW
3607 "and @var{q} is @math{@var{x} / @var{y}} rounded to the\n"
3608 "nearest integer, with ties going to the nearest even integer.\n"
ff62c168 3609 "@lisp\n"
8f9da340
MW
3610 "(round/ 123 10) @result{} 12 and 3\n"
3611 "(round/ 123 -10) @result{} -12 and 3\n"
3612 "(round/ -123 10) @result{} -12 and -3\n"
3613 "(round/ -123 -10) @result{} 12 and -3\n"
3614 "(round/ 125 10) @result{} 12 and 5\n"
3615 "(round/ 127 10) @result{} 13 and -3\n"
3616 "(round/ 135 10) @result{} 14 and -5\n"
3617 "(round/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
3618 "(round/ 16/3 -10/7) @result{} -4 and -8/21\n"
ff62c168 3619 "@end lisp")
8f9da340 3620#define FUNC_NAME s_scm_i_round_divide
5fbf680b
MW
3621{
3622 SCM q, r;
3623
8f9da340 3624 scm_round_divide(x, y, &q, &r);
5fbf680b
MW
3625 return scm_values (scm_list_2 (q, r));
3626}
3627#undef FUNC_NAME
3628
8f9da340
MW
3629#define s_scm_round_divide s_scm_i_round_divide
3630#define g_scm_round_divide g_scm_i_round_divide
5fbf680b
MW
3631
3632void
8f9da340 3633scm_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168
MW
3634{
3635 if (SCM_LIKELY (SCM_I_INUMP (x)))
3636 {
4a46bc2a 3637 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3638 if (SCM_LIKELY (SCM_I_INUMP (y)))
3639 {
3640 scm_t_inum yy = SCM_I_INUM (y);
3641 if (SCM_UNLIKELY (yy == 0))
8f9da340 3642 scm_num_overflow (s_scm_round_divide);
ff62c168
MW
3643 else
3644 {
ff62c168 3645 scm_t_inum qq = xx / yy;
4a46bc2a 3646 scm_t_inum rr = xx % yy;
8f9da340
MW
3647 scm_t_inum ay = yy;
3648 scm_t_inum r2 = 2 * rr;
3649
3650 if (SCM_LIKELY (yy < 0))
ff62c168 3651 {
8f9da340
MW
3652 ay = -ay;
3653 r2 = -r2;
3654 }
3655
3656 if (qq & 1L)
3657 {
3658 if (r2 >= ay)
3659 { qq++; rr -= yy; }
3660 else if (r2 <= -ay)
3661 { qq--; rr += yy; }
ff62c168
MW
3662 }
3663 else
3664 {
8f9da340
MW
3665 if (r2 > ay)
3666 { qq++; rr -= yy; }
3667 else if (r2 < -ay)
3668 { qq--; rr += yy; }
ff62c168 3669 }
4a46bc2a 3670 if (SCM_LIKELY (SCM_FIXABLE (qq)))
5fbf680b 3671 *qp = SCM_I_MAKINUM (qq);
4a46bc2a 3672 else
5fbf680b
MW
3673 *qp = scm_i_inum2big (qq);
3674 *rp = SCM_I_MAKINUM (rr);
ff62c168 3675 }
5fbf680b 3676 return;
ff62c168
MW
3677 }
3678 else if (SCM_BIGP (y))
3679 {
3680 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3681 can fit in a fixnum) to scm_i_bigint_round_divide */
3682 return scm_i_bigint_round_divide
3683 (scm_i_long2big (SCM_I_INUM (x)), y, qp, rp);
ff62c168
MW
3684 }
3685 else if (SCM_REALP (y))
8f9da340 3686 return scm_i_inexact_round_divide (xx, SCM_REAL_VALUE (y), qp, rp);
ff62c168 3687 else if (SCM_FRACTIONP (y))
8f9da340 3688 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3689 else
8f9da340
MW
3690 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3691 s_scm_round_divide, qp, rp);
ff62c168
MW
3692 }
3693 else if (SCM_BIGP (x))
3694 {
3695 if (SCM_LIKELY (SCM_I_INUMP (y)))
3696 {
3697 scm_t_inum yy = SCM_I_INUM (y);
3698 if (SCM_UNLIKELY (yy == 0))
8f9da340 3699 scm_num_overflow (s_scm_round_divide);
ff62c168
MW
3700 else
3701 {
3702 SCM q = scm_i_mkbig ();
3703 scm_t_inum rr;
8f9da340
MW
3704 int needs_adjustment;
3705
ff62c168
MW
3706 if (yy > 0)
3707 {
8f9da340
MW
3708 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3709 SCM_I_BIG_MPZ (x), yy);
3710 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3711 needs_adjustment = (2*rr >= yy);
3712 else
3713 needs_adjustment = (2*rr > yy);
ff62c168
MW
3714 }
3715 else
3716 {
3717 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3718 SCM_I_BIG_MPZ (x), -yy);
ff62c168 3719 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
8f9da340
MW
3720 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3721 needs_adjustment = (2*rr <= yy);
3722 else
3723 needs_adjustment = (2*rr < yy);
3724 }
3725 scm_remember_upto_here_1 (x);
3726 if (needs_adjustment)
3727 {
3728 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3729 rr -= yy;
ff62c168 3730 }
5fbf680b
MW
3731 *qp = scm_i_normbig (q);
3732 *rp = SCM_I_MAKINUM (rr);
ff62c168 3733 }
5fbf680b 3734 return;
ff62c168
MW
3735 }
3736 else if (SCM_BIGP (y))
8f9da340 3737 return scm_i_bigint_round_divide (x, y, qp, rp);
ff62c168 3738 else if (SCM_REALP (y))
8f9da340 3739 return scm_i_inexact_round_divide
5fbf680b 3740 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
ff62c168 3741 else if (SCM_FRACTIONP (y))
8f9da340 3742 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3743 else
8f9da340
MW
3744 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3745 s_scm_round_divide, qp, rp);
ff62c168
MW
3746 }
3747 else if (SCM_REALP (x))
3748 {
3749 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3750 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3751 return scm_i_inexact_round_divide
5fbf680b 3752 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
03ddd15b 3753 else
8f9da340
MW
3754 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3755 s_scm_round_divide, qp, rp);
ff62c168
MW
3756 }
3757 else if (SCM_FRACTIONP (x))
3758 {
3759 if (SCM_REALP (y))
8f9da340 3760 return scm_i_inexact_round_divide
5fbf680b 3761 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
03ddd15b 3762 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3763 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3764 else
8f9da340
MW
3765 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3766 s_scm_round_divide, qp, rp);
ff62c168
MW
3767 }
3768 else
8f9da340
MW
3769 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG1,
3770 s_scm_round_divide, qp, rp);
ff62c168 3771}
ff62c168 3772
5fbf680b 3773static void
8f9da340 3774scm_i_inexact_round_divide (double x, double y, SCM *qp, SCM *rp)
ff62c168 3775{
8f9da340
MW
3776 if (SCM_UNLIKELY (y == 0))
3777 scm_num_overflow (s_scm_round_divide); /* or return a NaN? */
ff62c168 3778 else
8f9da340
MW
3779 {
3780 double q = scm_c_round (x / y);
3781 double r = x - q * y;
3782 *qp = scm_from_double (q);
3783 *rp = scm_from_double (r);
3784 }
ff62c168
MW
3785}
3786
3787/* Assumes that both x and y are bigints, though
3788 x might be able to fit into a fixnum. */
5fbf680b 3789static void
8f9da340 3790scm_i_bigint_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 3791{
8f9da340
MW
3792 SCM q, r, r2;
3793 int cmp, needs_adjustment;
ff62c168
MW
3794
3795 /* Note that x might be small enough to fit into a
3796 fixnum, so we must not let it escape into the wild */
3797 q = scm_i_mkbig ();
3798 r = scm_i_mkbig ();
8f9da340 3799 r2 = scm_i_mkbig ();
ff62c168 3800
8f9da340
MW
3801 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3802 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3803 scm_remember_upto_here_1 (x);
3804 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
ff62c168 3805
8f9da340
MW
3806 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3807 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3808 needs_adjustment = (cmp >= 0);
ff62c168 3809 else
8f9da340
MW
3810 needs_adjustment = (cmp > 0);
3811
3812 if (needs_adjustment)
ff62c168 3813 {
8f9da340
MW
3814 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3815 mpz_sub (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y));
ff62c168 3816 }
8f9da340
MW
3817
3818 scm_remember_upto_here_2 (r2, y);
5fbf680b
MW
3819 *qp = scm_i_normbig (q);
3820 *rp = scm_i_normbig (r);
ff62c168
MW
3821}
3822
5fbf680b 3823static void
8f9da340 3824scm_i_exact_rational_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 3825{
03ddd15b
MW
3826 SCM r1;
3827 SCM xd = scm_denominator (x);
3828 SCM yd = scm_denominator (y);
3829
8f9da340
MW
3830 scm_round_divide (scm_product (scm_numerator (x), yd),
3831 scm_product (scm_numerator (y), xd),
3832 qp, &r1);
03ddd15b 3833 *rp = scm_divide (r1, scm_product (xd, yd));
ff62c168
MW
3834}
3835
3836
78d3deb1
AW
3837SCM_PRIMITIVE_GENERIC (scm_i_gcd, "gcd", 0, 2, 1,
3838 (SCM x, SCM y, SCM rest),
3839 "Return the greatest common divisor of all parameter values.\n"
3840 "If called without arguments, 0 is returned.")
3841#define FUNC_NAME s_scm_i_gcd
3842{
3843 while (!scm_is_null (rest))
3844 { x = scm_gcd (x, y);
3845 y = scm_car (rest);
3846 rest = scm_cdr (rest);
3847 }
3848 return scm_gcd (x, y);
3849}
3850#undef FUNC_NAME
3851
3852#define s_gcd s_scm_i_gcd
3853#define g_gcd g_scm_i_gcd
3854
0f2d19dd 3855SCM
6e8d25a6 3856scm_gcd (SCM x, SCM y)
0f2d19dd 3857{
ca46fb90 3858 if (SCM_UNBNDP (y))
1dd79792 3859 return SCM_UNBNDP (x) ? SCM_INUM0 : scm_abs (x);
ca46fb90 3860
e11e83f3 3861 if (SCM_I_INUMP (x))
ca46fb90 3862 {
e11e83f3 3863 if (SCM_I_INUMP (y))
ca46fb90 3864 {
e25f3727
AW
3865 scm_t_inum xx = SCM_I_INUM (x);
3866 scm_t_inum yy = SCM_I_INUM (y);
3867 scm_t_inum u = xx < 0 ? -xx : xx;
3868 scm_t_inum v = yy < 0 ? -yy : yy;
3869 scm_t_inum result;
0aacf84e
MD
3870 if (xx == 0)
3871 result = v;
3872 else if (yy == 0)
3873 result = u;
3874 else
3875 {
e25f3727
AW
3876 scm_t_inum k = 1;
3877 scm_t_inum t;
0aacf84e
MD
3878 /* Determine a common factor 2^k */
3879 while (!(1 & (u | v)))
3880 {
3881 k <<= 1;
3882 u >>= 1;
3883 v >>= 1;
3884 }
3885 /* Now, any factor 2^n can be eliminated */
3886 if (u & 1)
3887 t = -v;
3888 else
3889 {
3890 t = u;
3891 b3:
3892 t = SCM_SRS (t, 1);
3893 }
3894 if (!(1 & t))
3895 goto b3;
3896 if (t > 0)
3897 u = t;
3898 else
3899 v = -t;
3900 t = u - v;
3901 if (t != 0)
3902 goto b3;
3903 result = u * k;
3904 }
3905 return (SCM_POSFIXABLE (result)
d956fa6f 3906 ? SCM_I_MAKINUM (result)
e25f3727 3907 : scm_i_inum2big (result));
ca46fb90
RB
3908 }
3909 else if (SCM_BIGP (y))
3910 {
0bff4dce
KR
3911 SCM_SWAP (x, y);
3912 goto big_inum;
ca46fb90
RB
3913 }
3914 else
3915 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 3916 }
ca46fb90
RB
3917 else if (SCM_BIGP (x))
3918 {
e11e83f3 3919 if (SCM_I_INUMP (y))
ca46fb90 3920 {
e25f3727
AW
3921 scm_t_bits result;
3922 scm_t_inum yy;
0bff4dce 3923 big_inum:
e11e83f3 3924 yy = SCM_I_INUM (y);
8c5b0afc
KR
3925 if (yy == 0)
3926 return scm_abs (x);
0aacf84e
MD
3927 if (yy < 0)
3928 yy = -yy;
ca46fb90
RB
3929 result = mpz_gcd_ui (NULL, SCM_I_BIG_MPZ (x), yy);
3930 scm_remember_upto_here_1 (x);
0aacf84e 3931 return (SCM_POSFIXABLE (result)
d956fa6f 3932 ? SCM_I_MAKINUM (result)
e25f3727 3933 : scm_from_unsigned_integer (result));
ca46fb90
RB
3934 }
3935 else if (SCM_BIGP (y))
3936 {
3937 SCM result = scm_i_mkbig ();
0aacf84e
MD
3938 mpz_gcd (SCM_I_BIG_MPZ (result),
3939 SCM_I_BIG_MPZ (x),
3940 SCM_I_BIG_MPZ (y));
3941 scm_remember_upto_here_2 (x, y);
ca46fb90
RB
3942 return scm_i_normbig (result);
3943 }
3944 else
3945 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
09fb7599 3946 }
ca46fb90 3947 else
09fb7599 3948 SCM_WTA_DISPATCH_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
0f2d19dd
JB
3949}
3950
78d3deb1
AW
3951SCM_PRIMITIVE_GENERIC (scm_i_lcm, "lcm", 0, 2, 1,
3952 (SCM x, SCM y, SCM rest),
3953 "Return the least common multiple of the arguments.\n"
3954 "If called without arguments, 1 is returned.")
3955#define FUNC_NAME s_scm_i_lcm
3956{
3957 while (!scm_is_null (rest))
3958 { x = scm_lcm (x, y);
3959 y = scm_car (rest);
3960 rest = scm_cdr (rest);
3961 }
3962 return scm_lcm (x, y);
3963}
3964#undef FUNC_NAME
3965
3966#define s_lcm s_scm_i_lcm
3967#define g_lcm g_scm_i_lcm
3968
0f2d19dd 3969SCM
6e8d25a6 3970scm_lcm (SCM n1, SCM n2)
0f2d19dd 3971{
ca46fb90
RB
3972 if (SCM_UNBNDP (n2))
3973 {
3974 if (SCM_UNBNDP (n1))
d956fa6f
MV
3975 return SCM_I_MAKINUM (1L);
3976 n2 = SCM_I_MAKINUM (1L);
09fb7599 3977 }
09fb7599 3978
e11e83f3 3979 SCM_GASSERT2 (SCM_I_INUMP (n1) || SCM_BIGP (n1),
ca46fb90 3980 g_lcm, n1, n2, SCM_ARG1, s_lcm);
e11e83f3 3981 SCM_GASSERT2 (SCM_I_INUMP (n2) || SCM_BIGP (n2),
ca46fb90 3982 g_lcm, n1, n2, SCM_ARGn, s_lcm);
09fb7599 3983
e11e83f3 3984 if (SCM_I_INUMP (n1))
ca46fb90 3985 {
e11e83f3 3986 if (SCM_I_INUMP (n2))
ca46fb90
RB
3987 {
3988 SCM d = scm_gcd (n1, n2);
bc36d050 3989 if (scm_is_eq (d, SCM_INUM0))
ca46fb90
RB
3990 return d;
3991 else
3992 return scm_abs (scm_product (n1, scm_quotient (n2, d)));
3993 }
3994 else
3995 {
3996 /* inum n1, big n2 */
3997 inumbig:
3998 {
3999 SCM result = scm_i_mkbig ();
e25f3727 4000 scm_t_inum nn1 = SCM_I_INUM (n1);
ca46fb90
RB
4001 if (nn1 == 0) return SCM_INUM0;
4002 if (nn1 < 0) nn1 = - nn1;
4003 mpz_lcm_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n2), nn1);
4004 scm_remember_upto_here_1 (n2);
4005 return result;
4006 }
4007 }
4008 }
4009 else
4010 {
4011 /* big n1 */
e11e83f3 4012 if (SCM_I_INUMP (n2))
ca46fb90
RB
4013 {
4014 SCM_SWAP (n1, n2);
4015 goto inumbig;
4016 }
4017 else
4018 {
4019 SCM result = scm_i_mkbig ();
4020 mpz_lcm(SCM_I_BIG_MPZ (result),
4021 SCM_I_BIG_MPZ (n1),
4022 SCM_I_BIG_MPZ (n2));
4023 scm_remember_upto_here_2(n1, n2);
4024 /* shouldn't need to normalize b/c lcm of 2 bigs should be big */
4025 return result;
4026 }
f872b822 4027 }
0f2d19dd
JB
4028}
4029
8a525303
GB
4030/* Emulating 2's complement bignums with sign magnitude arithmetic:
4031
4032 Logand:
4033 X Y Result Method:
4034 (len)
4035 + + + x (map digit:logand X Y)
4036 + - + x (map digit:logand X (lognot (+ -1 Y)))
4037 - + + y (map digit:logand (lognot (+ -1 X)) Y)
4038 - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y)))
4039
4040 Logior:
4041 X Y Result Method:
4042
4043 + + + (map digit:logior X Y)
4044 + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y)))
4045 - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y)))
4046 - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y)))
4047
4048 Logxor:
4049 X Y Result Method:
4050
4051 + + + (map digit:logxor X Y)
4052 + - - (+ 1 (map digit:logxor X (+ -1 Y)))
4053 - + - (+ 1 (map digit:logxor (+ -1 X) Y))
4054 - - + (map digit:logxor (+ -1 X) (+ -1 Y))
4055
4056 Logtest:
4057 X Y Result
4058
4059 + + (any digit:logand X Y)
4060 + - (any digit:logand X (lognot (+ -1 Y)))
4061 - + (any digit:logand (lognot (+ -1 X)) Y)
4062 - - #t
4063
4064*/
4065
78d3deb1
AW
4066SCM_DEFINE (scm_i_logand, "logand", 0, 2, 1,
4067 (SCM x, SCM y, SCM rest),
4068 "Return the bitwise AND of the integer arguments.\n\n"
4069 "@lisp\n"
4070 "(logand) @result{} -1\n"
4071 "(logand 7) @result{} 7\n"
4072 "(logand #b111 #b011 #b001) @result{} 1\n"
4073 "@end lisp")
4074#define FUNC_NAME s_scm_i_logand
4075{
4076 while (!scm_is_null (rest))
4077 { x = scm_logand (x, y);
4078 y = scm_car (rest);
4079 rest = scm_cdr (rest);
4080 }
4081 return scm_logand (x, y);
4082}
4083#undef FUNC_NAME
4084
4085#define s_scm_logand s_scm_i_logand
4086
4087SCM scm_logand (SCM n1, SCM n2)
1bbd0b84 4088#define FUNC_NAME s_scm_logand
0f2d19dd 4089{
e25f3727 4090 scm_t_inum nn1;
9a00c9fc 4091
0aacf84e
MD
4092 if (SCM_UNBNDP (n2))
4093 {
4094 if (SCM_UNBNDP (n1))
d956fa6f 4095 return SCM_I_MAKINUM (-1);
0aacf84e
MD
4096 else if (!SCM_NUMBERP (n1))
4097 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
4098 else if (SCM_NUMBERP (n1))
4099 return n1;
4100 else
4101 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 4102 }
09fb7599 4103
e11e83f3 4104 if (SCM_I_INUMP (n1))
0aacf84e 4105 {
e11e83f3
MV
4106 nn1 = SCM_I_INUM (n1);
4107 if (SCM_I_INUMP (n2))
0aacf84e 4108 {
e25f3727 4109 scm_t_inum nn2 = SCM_I_INUM (n2);
d956fa6f 4110 return SCM_I_MAKINUM (nn1 & nn2);
0aacf84e
MD
4111 }
4112 else if SCM_BIGP (n2)
4113 {
4114 intbig:
4115 if (n1 == 0)
4116 return SCM_INUM0;
4117 {
4118 SCM result_z = scm_i_mkbig ();
4119 mpz_t nn1_z;
4120 mpz_init_set_si (nn1_z, nn1);
4121 mpz_and (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
4122 scm_remember_upto_here_1 (n2);
4123 mpz_clear (nn1_z);
4124 return scm_i_normbig (result_z);
4125 }
4126 }
4127 else
4128 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
4129 }
4130 else if (SCM_BIGP (n1))
4131 {
e11e83f3 4132 if (SCM_I_INUMP (n2))
0aacf84e
MD
4133 {
4134 SCM_SWAP (n1, n2);
e11e83f3 4135 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
4136 goto intbig;
4137 }
4138 else if (SCM_BIGP (n2))
4139 {
4140 SCM result_z = scm_i_mkbig ();
4141 mpz_and (SCM_I_BIG_MPZ (result_z),
4142 SCM_I_BIG_MPZ (n1),
4143 SCM_I_BIG_MPZ (n2));
4144 scm_remember_upto_here_2 (n1, n2);
4145 return scm_i_normbig (result_z);
4146 }
4147 else
4148 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 4149 }
0aacf84e 4150 else
09fb7599 4151 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 4152}
1bbd0b84 4153#undef FUNC_NAME
0f2d19dd 4154
09fb7599 4155
78d3deb1
AW
4156SCM_DEFINE (scm_i_logior, "logior", 0, 2, 1,
4157 (SCM x, SCM y, SCM rest),
4158 "Return the bitwise OR of the integer arguments.\n\n"
4159 "@lisp\n"
4160 "(logior) @result{} 0\n"
4161 "(logior 7) @result{} 7\n"
4162 "(logior #b000 #b001 #b011) @result{} 3\n"
4163 "@end lisp")
4164#define FUNC_NAME s_scm_i_logior
4165{
4166 while (!scm_is_null (rest))
4167 { x = scm_logior (x, y);
4168 y = scm_car (rest);
4169 rest = scm_cdr (rest);
4170 }
4171 return scm_logior (x, y);
4172}
4173#undef FUNC_NAME
4174
4175#define s_scm_logior s_scm_i_logior
4176
4177SCM scm_logior (SCM n1, SCM n2)
1bbd0b84 4178#define FUNC_NAME s_scm_logior
0f2d19dd 4179{
e25f3727 4180 scm_t_inum nn1;
9a00c9fc 4181
0aacf84e
MD
4182 if (SCM_UNBNDP (n2))
4183 {
4184 if (SCM_UNBNDP (n1))
4185 return SCM_INUM0;
4186 else if (SCM_NUMBERP (n1))
4187 return n1;
4188 else
4189 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 4190 }
09fb7599 4191
e11e83f3 4192 if (SCM_I_INUMP (n1))
0aacf84e 4193 {
e11e83f3
MV
4194 nn1 = SCM_I_INUM (n1);
4195 if (SCM_I_INUMP (n2))
0aacf84e 4196 {
e11e83f3 4197 long nn2 = SCM_I_INUM (n2);
d956fa6f 4198 return SCM_I_MAKINUM (nn1 | nn2);
0aacf84e
MD
4199 }
4200 else if (SCM_BIGP (n2))
4201 {
4202 intbig:
4203 if (nn1 == 0)
4204 return n2;
4205 {
4206 SCM result_z = scm_i_mkbig ();
4207 mpz_t nn1_z;
4208 mpz_init_set_si (nn1_z, nn1);
4209 mpz_ior (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
4210 scm_remember_upto_here_1 (n2);
4211 mpz_clear (nn1_z);
9806de0d 4212 return scm_i_normbig (result_z);
0aacf84e
MD
4213 }
4214 }
4215 else
4216 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
4217 }
4218 else if (SCM_BIGP (n1))
4219 {
e11e83f3 4220 if (SCM_I_INUMP (n2))
0aacf84e
MD
4221 {
4222 SCM_SWAP (n1, n2);
e11e83f3 4223 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
4224 goto intbig;
4225 }
4226 else if (SCM_BIGP (n2))
4227 {
4228 SCM result_z = scm_i_mkbig ();
4229 mpz_ior (SCM_I_BIG_MPZ (result_z),
4230 SCM_I_BIG_MPZ (n1),
4231 SCM_I_BIG_MPZ (n2));
4232 scm_remember_upto_here_2 (n1, n2);
9806de0d 4233 return scm_i_normbig (result_z);
0aacf84e
MD
4234 }
4235 else
4236 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 4237 }
0aacf84e 4238 else
09fb7599 4239 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 4240}
1bbd0b84 4241#undef FUNC_NAME
0f2d19dd 4242
09fb7599 4243
78d3deb1
AW
4244SCM_DEFINE (scm_i_logxor, "logxor", 0, 2, 1,
4245 (SCM x, SCM y, SCM rest),
3c3db128
GH
4246 "Return the bitwise XOR of the integer arguments. A bit is\n"
4247 "set in the result if it is set in an odd number of arguments.\n"
4248 "@lisp\n"
4249 "(logxor) @result{} 0\n"
4250 "(logxor 7) @result{} 7\n"
4251 "(logxor #b000 #b001 #b011) @result{} 2\n"
4252 "(logxor #b000 #b001 #b011 #b011) @result{} 1\n"
1e6808ea 4253 "@end lisp")
78d3deb1
AW
4254#define FUNC_NAME s_scm_i_logxor
4255{
4256 while (!scm_is_null (rest))
4257 { x = scm_logxor (x, y);
4258 y = scm_car (rest);
4259 rest = scm_cdr (rest);
4260 }
4261 return scm_logxor (x, y);
4262}
4263#undef FUNC_NAME
4264
4265#define s_scm_logxor s_scm_i_logxor
4266
4267SCM scm_logxor (SCM n1, SCM n2)
1bbd0b84 4268#define FUNC_NAME s_scm_logxor
0f2d19dd 4269{
e25f3727 4270 scm_t_inum nn1;
9a00c9fc 4271
0aacf84e
MD
4272 if (SCM_UNBNDP (n2))
4273 {
4274 if (SCM_UNBNDP (n1))
4275 return SCM_INUM0;
4276 else if (SCM_NUMBERP (n1))
4277 return n1;
4278 else
4279 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
d28da049 4280 }
09fb7599 4281
e11e83f3 4282 if (SCM_I_INUMP (n1))
0aacf84e 4283 {
e11e83f3
MV
4284 nn1 = SCM_I_INUM (n1);
4285 if (SCM_I_INUMP (n2))
0aacf84e 4286 {
e25f3727 4287 scm_t_inum nn2 = SCM_I_INUM (n2);
d956fa6f 4288 return SCM_I_MAKINUM (nn1 ^ nn2);
0aacf84e
MD
4289 }
4290 else if (SCM_BIGP (n2))
4291 {
4292 intbig:
4293 {
4294 SCM result_z = scm_i_mkbig ();
4295 mpz_t nn1_z;
4296 mpz_init_set_si (nn1_z, nn1);
4297 mpz_xor (SCM_I_BIG_MPZ (result_z), nn1_z, SCM_I_BIG_MPZ (n2));
4298 scm_remember_upto_here_1 (n2);
4299 mpz_clear (nn1_z);
4300 return scm_i_normbig (result_z);
4301 }
4302 }
4303 else
4304 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
4305 }
4306 else if (SCM_BIGP (n1))
4307 {
e11e83f3 4308 if (SCM_I_INUMP (n2))
0aacf84e
MD
4309 {
4310 SCM_SWAP (n1, n2);
e11e83f3 4311 nn1 = SCM_I_INUM (n1);
0aacf84e
MD
4312 goto intbig;
4313 }
4314 else if (SCM_BIGP (n2))
4315 {
4316 SCM result_z = scm_i_mkbig ();
4317 mpz_xor (SCM_I_BIG_MPZ (result_z),
4318 SCM_I_BIG_MPZ (n1),
4319 SCM_I_BIG_MPZ (n2));
4320 scm_remember_upto_here_2 (n1, n2);
4321 return scm_i_normbig (result_z);
4322 }
4323 else
4324 SCM_WRONG_TYPE_ARG (SCM_ARG2, n2);
09fb7599 4325 }
0aacf84e 4326 else
09fb7599 4327 SCM_WRONG_TYPE_ARG (SCM_ARG1, n1);
0f2d19dd 4328}
1bbd0b84 4329#undef FUNC_NAME
0f2d19dd 4330
09fb7599 4331
a1ec6916 4332SCM_DEFINE (scm_logtest, "logtest", 2, 0, 0,
1e6808ea 4333 (SCM j, SCM k),
ba6e7231
KR
4334 "Test whether @var{j} and @var{k} have any 1 bits in common.\n"
4335 "This is equivalent to @code{(not (zero? (logand j k)))}, but\n"
4336 "without actually calculating the @code{logand}, just testing\n"
4337 "for non-zero.\n"
4338 "\n"
1e6808ea 4339 "@lisp\n"
b380b885
MD
4340 "(logtest #b0100 #b1011) @result{} #f\n"
4341 "(logtest #b0100 #b0111) @result{} #t\n"
1e6808ea 4342 "@end lisp")
1bbd0b84 4343#define FUNC_NAME s_scm_logtest
0f2d19dd 4344{
e25f3727 4345 scm_t_inum nj;
9a00c9fc 4346
e11e83f3 4347 if (SCM_I_INUMP (j))
0aacf84e 4348 {
e11e83f3
MV
4349 nj = SCM_I_INUM (j);
4350 if (SCM_I_INUMP (k))
0aacf84e 4351 {
e25f3727 4352 scm_t_inum nk = SCM_I_INUM (k);
73e4de09 4353 return scm_from_bool (nj & nk);
0aacf84e
MD
4354 }
4355 else if (SCM_BIGP (k))
4356 {
4357 intbig:
4358 if (nj == 0)
4359 return SCM_BOOL_F;
4360 {
4361 SCM result;
4362 mpz_t nj_z;
4363 mpz_init_set_si (nj_z, nj);
4364 mpz_and (nj_z, nj_z, SCM_I_BIG_MPZ (k));
4365 scm_remember_upto_here_1 (k);
73e4de09 4366 result = scm_from_bool (mpz_sgn (nj_z) != 0);
0aacf84e
MD
4367 mpz_clear (nj_z);
4368 return result;
4369 }
4370 }
4371 else
4372 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
4373 }
4374 else if (SCM_BIGP (j))
4375 {
e11e83f3 4376 if (SCM_I_INUMP (k))
0aacf84e
MD
4377 {
4378 SCM_SWAP (j, k);
e11e83f3 4379 nj = SCM_I_INUM (j);
0aacf84e
MD
4380 goto intbig;
4381 }
4382 else if (SCM_BIGP (k))
4383 {
4384 SCM result;
4385 mpz_t result_z;
4386 mpz_init (result_z);
4387 mpz_and (result_z,
4388 SCM_I_BIG_MPZ (j),
4389 SCM_I_BIG_MPZ (k));
4390 scm_remember_upto_here_2 (j, k);
73e4de09 4391 result = scm_from_bool (mpz_sgn (result_z) != 0);
0aacf84e
MD
4392 mpz_clear (result_z);
4393 return result;
4394 }
4395 else
4396 SCM_WRONG_TYPE_ARG (SCM_ARG2, k);
4397 }
4398 else
4399 SCM_WRONG_TYPE_ARG (SCM_ARG1, j);
0f2d19dd 4400}
1bbd0b84 4401#undef FUNC_NAME
0f2d19dd 4402
c1bfcf60 4403
a1ec6916 4404SCM_DEFINE (scm_logbit_p, "logbit?", 2, 0, 0,
2cd04b42 4405 (SCM index, SCM j),
ba6e7231
KR
4406 "Test whether bit number @var{index} in @var{j} is set.\n"
4407 "@var{index} starts from 0 for the least significant bit.\n"
4408 "\n"
1e6808ea 4409 "@lisp\n"
b380b885
MD
4410 "(logbit? 0 #b1101) @result{} #t\n"
4411 "(logbit? 1 #b1101) @result{} #f\n"
4412 "(logbit? 2 #b1101) @result{} #t\n"
4413 "(logbit? 3 #b1101) @result{} #t\n"
4414 "(logbit? 4 #b1101) @result{} #f\n"
1e6808ea 4415 "@end lisp")
1bbd0b84 4416#define FUNC_NAME s_scm_logbit_p
0f2d19dd 4417{
78166ad5 4418 unsigned long int iindex;
5efd3c7d 4419 iindex = scm_to_ulong (index);
78166ad5 4420
e11e83f3 4421 if (SCM_I_INUMP (j))
0d75f6d8
KR
4422 {
4423 /* bits above what's in an inum follow the sign bit */
20fcc8ed 4424 iindex = min (iindex, SCM_LONG_BIT - 1);
e11e83f3 4425 return scm_from_bool ((1L << iindex) & SCM_I_INUM (j));
0d75f6d8 4426 }
0aacf84e
MD
4427 else if (SCM_BIGP (j))
4428 {
4429 int val = mpz_tstbit (SCM_I_BIG_MPZ (j), iindex);
4430 scm_remember_upto_here_1 (j);
73e4de09 4431 return scm_from_bool (val);
0aacf84e
MD
4432 }
4433 else
78166ad5 4434 SCM_WRONG_TYPE_ARG (SCM_ARG2, j);
0f2d19dd 4435}
1bbd0b84 4436#undef FUNC_NAME
0f2d19dd 4437
78166ad5 4438
a1ec6916 4439SCM_DEFINE (scm_lognot, "lognot", 1, 0, 0,
1bbd0b84 4440 (SCM n),
4d814788 4441 "Return the integer which is the ones-complement of the integer\n"
1e6808ea
MG
4442 "argument.\n"
4443 "\n"
b380b885
MD
4444 "@lisp\n"
4445 "(number->string (lognot #b10000000) 2)\n"
4446 " @result{} \"-10000001\"\n"
4447 "(number->string (lognot #b0) 2)\n"
4448 " @result{} \"-1\"\n"
1e6808ea 4449 "@end lisp")
1bbd0b84 4450#define FUNC_NAME s_scm_lognot
0f2d19dd 4451{
e11e83f3 4452 if (SCM_I_INUMP (n)) {
f9811f9f
KR
4453 /* No overflow here, just need to toggle all the bits making up the inum.
4454 Enhancement: No need to strip the tag and add it back, could just xor
4455 a block of 1 bits, if that worked with the various debug versions of
4456 the SCM typedef. */
e11e83f3 4457 return SCM_I_MAKINUM (~ SCM_I_INUM (n));
f9811f9f
KR
4458
4459 } else if (SCM_BIGP (n)) {
4460 SCM result = scm_i_mkbig ();
4461 mpz_com (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n));
4462 scm_remember_upto_here_1 (n);
4463 return result;
4464
4465 } else {
4466 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
4467 }
0f2d19dd 4468}
1bbd0b84 4469#undef FUNC_NAME
0f2d19dd 4470
518b7508
KR
4471/* returns 0 if IN is not an integer. OUT must already be
4472 initialized. */
4473static int
4474coerce_to_big (SCM in, mpz_t out)
4475{
4476 if (SCM_BIGP (in))
4477 mpz_set (out, SCM_I_BIG_MPZ (in));
e11e83f3
MV
4478 else if (SCM_I_INUMP (in))
4479 mpz_set_si (out, SCM_I_INUM (in));
518b7508
KR
4480 else
4481 return 0;
4482
4483 return 1;
4484}
4485
d885e204 4486SCM_DEFINE (scm_modulo_expt, "modulo-expt", 3, 0, 0,
518b7508
KR
4487 (SCM n, SCM k, SCM m),
4488 "Return @var{n} raised to the integer exponent\n"
4489 "@var{k}, modulo @var{m}.\n"
4490 "\n"
4491 "@lisp\n"
4492 "(modulo-expt 2 3 5)\n"
4493 " @result{} 3\n"
4494 "@end lisp")
d885e204 4495#define FUNC_NAME s_scm_modulo_expt
518b7508
KR
4496{
4497 mpz_t n_tmp;
4498 mpz_t k_tmp;
4499 mpz_t m_tmp;
4500
4501 /* There are two classes of error we might encounter --
4502 1) Math errors, which we'll report by calling scm_num_overflow,
4503 and
4504 2) wrong-type errors, which of course we'll report by calling
4505 SCM_WRONG_TYPE_ARG.
4506 We don't report those errors immediately, however; instead we do
4507 some cleanup first. These variables tell us which error (if
4508 any) we should report after cleaning up.
4509 */
4510 int report_overflow = 0;
4511
4512 int position_of_wrong_type = 0;
4513 SCM value_of_wrong_type = SCM_INUM0;
4514
4515 SCM result = SCM_UNDEFINED;
4516
4517 mpz_init (n_tmp);
4518 mpz_init (k_tmp);
4519 mpz_init (m_tmp);
4520
bc36d050 4521 if (scm_is_eq (m, SCM_INUM0))
518b7508
KR
4522 {
4523 report_overflow = 1;
4524 goto cleanup;
4525 }
4526
4527 if (!coerce_to_big (n, n_tmp))
4528 {
4529 value_of_wrong_type = n;
4530 position_of_wrong_type = 1;
4531 goto cleanup;
4532 }
4533
4534 if (!coerce_to_big (k, k_tmp))
4535 {
4536 value_of_wrong_type = k;
4537 position_of_wrong_type = 2;
4538 goto cleanup;
4539 }
4540
4541 if (!coerce_to_big (m, m_tmp))
4542 {
4543 value_of_wrong_type = m;
4544 position_of_wrong_type = 3;
4545 goto cleanup;
4546 }
4547
4548 /* if the exponent K is negative, and we simply call mpz_powm, we
4549 will get a divide-by-zero exception when an inverse 1/n mod m
4550 doesn't exist (or is not unique). Since exceptions are hard to
4551 handle, we'll attempt the inversion "by hand" -- that way, we get
4552 a simple failure code, which is easy to handle. */
4553
4554 if (-1 == mpz_sgn (k_tmp))
4555 {
4556 if (!mpz_invert (n_tmp, n_tmp, m_tmp))
4557 {
4558 report_overflow = 1;
4559 goto cleanup;
4560 }
4561 mpz_neg (k_tmp, k_tmp);
4562 }
4563
4564 result = scm_i_mkbig ();
4565 mpz_powm (SCM_I_BIG_MPZ (result),
4566 n_tmp,
4567 k_tmp,
4568 m_tmp);
b7b8c575
KR
4569
4570 if (mpz_sgn (m_tmp) < 0 && mpz_sgn (SCM_I_BIG_MPZ (result)) != 0)
4571 mpz_add (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), m_tmp);
4572
518b7508
KR
4573 cleanup:
4574 mpz_clear (m_tmp);
4575 mpz_clear (k_tmp);
4576 mpz_clear (n_tmp);
4577
4578 if (report_overflow)
4579 scm_num_overflow (FUNC_NAME);
4580
4581 if (position_of_wrong_type)
4582 SCM_WRONG_TYPE_ARG (position_of_wrong_type,
4583 value_of_wrong_type);
4584
4585 return scm_i_normbig (result);
4586}
4587#undef FUNC_NAME
4588
a1ec6916 4589SCM_DEFINE (scm_integer_expt, "integer-expt", 2, 0, 0,
2cd04b42 4590 (SCM n, SCM k),
ba6e7231
KR
4591 "Return @var{n} raised to the power @var{k}. @var{k} must be an\n"
4592 "exact integer, @var{n} can be any number.\n"
4593 "\n"
2519490c
MW
4594 "Negative @var{k} is supported, and results in\n"
4595 "@math{1/@var{n}^abs(@var{k})} in the usual way.\n"
4596 "@math{@var{n}^0} is 1, as usual, and that\n"
ba6e7231 4597 "includes @math{0^0} is 1.\n"
1e6808ea 4598 "\n"
b380b885 4599 "@lisp\n"
ba6e7231
KR
4600 "(integer-expt 2 5) @result{} 32\n"
4601 "(integer-expt -3 3) @result{} -27\n"
4602 "(integer-expt 5 -3) @result{} 1/125\n"
4603 "(integer-expt 0 0) @result{} 1\n"
b380b885 4604 "@end lisp")
1bbd0b84 4605#define FUNC_NAME s_scm_integer_expt
0f2d19dd 4606{
e25f3727 4607 scm_t_inum i2 = 0;
1c35cb19
RB
4608 SCM z_i2 = SCM_BOOL_F;
4609 int i2_is_big = 0;
d956fa6f 4610 SCM acc = SCM_I_MAKINUM (1L);
ca46fb90 4611
bfe1f03a
MW
4612 /* Specifically refrain from checking the type of the first argument.
4613 This allows us to exponentiate any object that can be multiplied.
4614 If we must raise to a negative power, we must also be able to
4615 take its reciprocal. */
4616 if (!SCM_LIKELY (SCM_I_INUMP (k)) && !SCM_LIKELY (SCM_BIGP (k)))
01c7284a 4617 SCM_WRONG_TYPE_ARG (2, k);
5a8fc758 4618
bfe1f03a
MW
4619 if (SCM_UNLIKELY (scm_is_eq (k, SCM_INUM0)))
4620 return SCM_INUM1; /* n^(exact0) is exact 1, regardless of n */
4621 else if (SCM_UNLIKELY (scm_is_eq (n, SCM_I_MAKINUM (-1L))))
4622 return scm_is_false (scm_even_p (k)) ? n : SCM_INUM1;
4623 /* The next check is necessary only because R6RS specifies different
4624 behavior for 0^(-k) than for (/ 0). If n is not a scheme number,
4625 we simply skip this case and move on. */
4626 else if (SCM_NUMBERP (n) && scm_is_true (scm_zero_p (n)))
4627 {
4628 /* k cannot be 0 at this point, because we
4629 have already checked for that case above */
4630 if (scm_is_true (scm_positive_p (k)))
01c7284a
MW
4631 return n;
4632 else /* return NaN for (0 ^ k) for negative k per R6RS */
4633 return scm_nan ();
4634 }
ca46fb90 4635
e11e83f3
MV
4636 if (SCM_I_INUMP (k))
4637 i2 = SCM_I_INUM (k);
ca46fb90
RB
4638 else if (SCM_BIGP (k))
4639 {
4640 z_i2 = scm_i_clonebig (k, 1);
ca46fb90
RB
4641 scm_remember_upto_here_1 (k);
4642 i2_is_big = 1;
4643 }
2830fd91 4644 else
ca46fb90
RB
4645 SCM_WRONG_TYPE_ARG (2, k);
4646
4647 if (i2_is_big)
f872b822 4648 {
ca46fb90
RB
4649 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == -1)
4650 {
4651 mpz_neg (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2));
4652 n = scm_divide (n, SCM_UNDEFINED);
4653 }
4654 while (1)
4655 {
4656 if (mpz_sgn(SCM_I_BIG_MPZ (z_i2)) == 0)
4657 {
ca46fb90
RB
4658 return acc;
4659 }
4660 if (mpz_cmp_ui(SCM_I_BIG_MPZ (z_i2), 1) == 0)
4661 {
ca46fb90
RB
4662 return scm_product (acc, n);
4663 }
4664 if (mpz_tstbit(SCM_I_BIG_MPZ (z_i2), 0))
4665 acc = scm_product (acc, n);
4666 n = scm_product (n, n);
4667 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (z_i2), SCM_I_BIG_MPZ (z_i2), 1);
4668 }
f872b822 4669 }
ca46fb90 4670 else
f872b822 4671 {
ca46fb90
RB
4672 if (i2 < 0)
4673 {
4674 i2 = -i2;
4675 n = scm_divide (n, SCM_UNDEFINED);
4676 }
4677 while (1)
4678 {
4679 if (0 == i2)
4680 return acc;
4681 if (1 == i2)
4682 return scm_product (acc, n);
4683 if (i2 & 1)
4684 acc = scm_product (acc, n);
4685 n = scm_product (n, n);
4686 i2 >>= 1;
4687 }
f872b822 4688 }
0f2d19dd 4689}
1bbd0b84 4690#undef FUNC_NAME
0f2d19dd 4691
a1ec6916 4692SCM_DEFINE (scm_ash, "ash", 2, 0, 0,
1bbd0b84 4693 (SCM n, SCM cnt),
32f19569
KR
4694 "Return @var{n} shifted left by @var{cnt} bits, or shifted right\n"
4695 "if @var{cnt} is negative. This is an ``arithmetic'' shift.\n"
1e6808ea 4696 "\n"
e7644cb2 4697 "This is effectively a multiplication by 2^@var{cnt}, and when\n"
32f19569
KR
4698 "@var{cnt} is negative it's a division, rounded towards negative\n"
4699 "infinity. (Note that this is not the same rounding as\n"
4700 "@code{quotient} does.)\n"
4701 "\n"
4702 "With @var{n} viewed as an infinite precision twos complement,\n"
4703 "@code{ash} means a left shift introducing zero bits, or a right\n"
4704 "shift dropping bits.\n"
1e6808ea 4705 "\n"
b380b885 4706 "@lisp\n"
1e6808ea
MG
4707 "(number->string (ash #b1 3) 2) @result{} \"1000\"\n"
4708 "(number->string (ash #b1010 -1) 2) @result{} \"101\"\n"
32f19569
KR
4709 "\n"
4710 ";; -23 is bits ...11101001, -6 is bits ...111010\n"
4711 "(ash -23 -2) @result{} -6\n"
a3c8b9fc 4712 "@end lisp")
1bbd0b84 4713#define FUNC_NAME s_scm_ash
0f2d19dd 4714{
3ab9f56e 4715 long bits_to_shift;
5efd3c7d 4716 bits_to_shift = scm_to_long (cnt);
ca46fb90 4717
788aca27
KR
4718 if (SCM_I_INUMP (n))
4719 {
e25f3727 4720 scm_t_inum nn = SCM_I_INUM (n);
788aca27
KR
4721
4722 if (bits_to_shift > 0)
4723 {
4724 /* Left shift of bits_to_shift >= SCM_I_FIXNUM_BIT-1 will always
4725 overflow a non-zero fixnum. For smaller shifts we check the
4726 bits going into positions above SCM_I_FIXNUM_BIT-1. If they're
4727 all 0s for nn>=0, or all 1s for nn<0 then there's no overflow.
4728 Those bits are "nn >> (SCM_I_FIXNUM_BIT-1 -
4729 bits_to_shift)". */
4730
4731 if (nn == 0)
4732 return n;
4733
4734 if (bits_to_shift < SCM_I_FIXNUM_BIT-1
e25f3727 4735 && ((scm_t_bits)
788aca27
KR
4736 (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
4737 <= 1))
4738 {
4739 return SCM_I_MAKINUM (nn << bits_to_shift);
4740 }
4741 else
4742 {
e25f3727 4743 SCM result = scm_i_inum2big (nn);
788aca27
KR
4744 mpz_mul_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
4745 bits_to_shift);
4746 return result;
4747 }
4748 }
4749 else
4750 {
4751 bits_to_shift = -bits_to_shift;
4752 if (bits_to_shift >= SCM_LONG_BIT)
cff5fa33 4753 return (nn >= 0 ? SCM_INUM0 : SCM_I_MAKINUM(-1));
788aca27
KR
4754 else
4755 return SCM_I_MAKINUM (SCM_SRS (nn, bits_to_shift));
4756 }
4757
4758 }
4759 else if (SCM_BIGP (n))
ca46fb90 4760 {
788aca27
KR
4761 SCM result;
4762
4763 if (bits_to_shift == 0)
4764 return n;
4765
4766 result = scm_i_mkbig ();
4767 if (bits_to_shift >= 0)
4768 {
4769 mpz_mul_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n),
4770 bits_to_shift);
4771 return result;
4772 }
ca46fb90 4773 else
788aca27
KR
4774 {
4775 /* GMP doesn't have an fdiv_q_2exp variant returning just a long, so
4776 we have to allocate a bignum even if the result is going to be a
4777 fixnum. */
4778 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (n),
4779 -bits_to_shift);
4780 return scm_i_normbig (result);
4781 }
4782
ca46fb90
RB
4783 }
4784 else
788aca27
KR
4785 {
4786 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
4787 }
0f2d19dd 4788}
1bbd0b84 4789#undef FUNC_NAME
0f2d19dd 4790
3c9f20f8 4791
a1ec6916 4792SCM_DEFINE (scm_bit_extract, "bit-extract", 3, 0, 0,
1bbd0b84 4793 (SCM n, SCM start, SCM end),
1e6808ea
MG
4794 "Return the integer composed of the @var{start} (inclusive)\n"
4795 "through @var{end} (exclusive) bits of @var{n}. The\n"
4796 "@var{start}th bit becomes the 0-th bit in the result.\n"
4797 "\n"
b380b885
MD
4798 "@lisp\n"
4799 "(number->string (bit-extract #b1101101010 0 4) 2)\n"
4800 " @result{} \"1010\"\n"
4801 "(number->string (bit-extract #b1101101010 4 9) 2)\n"
4802 " @result{} \"10110\"\n"
4803 "@end lisp")
1bbd0b84 4804#define FUNC_NAME s_scm_bit_extract
0f2d19dd 4805{
7f848242 4806 unsigned long int istart, iend, bits;
5efd3c7d
MV
4807 istart = scm_to_ulong (start);
4808 iend = scm_to_ulong (end);
c1bfcf60 4809 SCM_ASSERT_RANGE (3, end, (iend >= istart));
78166ad5 4810
7f848242
KR
4811 /* how many bits to keep */
4812 bits = iend - istart;
4813
e11e83f3 4814 if (SCM_I_INUMP (n))
0aacf84e 4815 {
e25f3727 4816 scm_t_inum in = SCM_I_INUM (n);
7f848242
KR
4817
4818 /* When istart>=SCM_I_FIXNUM_BIT we can just limit the shift to
d77ad560 4819 SCM_I_FIXNUM_BIT-1 to get either 0 or -1 per the sign of "in". */
857ae6af 4820 in = SCM_SRS (in, min (istart, SCM_I_FIXNUM_BIT-1));
ac0c002c 4821
0aacf84e
MD
4822 if (in < 0 && bits >= SCM_I_FIXNUM_BIT)
4823 {
4824 /* Since we emulate two's complement encoded numbers, this
4825 * special case requires us to produce a result that has
7f848242 4826 * more bits than can be stored in a fixnum.
0aacf84e 4827 */
e25f3727 4828 SCM result = scm_i_inum2big (in);
7f848242
KR
4829 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result),
4830 bits);
4831 return result;
0aacf84e 4832 }
ac0c002c 4833
7f848242 4834 /* mask down to requisite bits */
857ae6af 4835 bits = min (bits, SCM_I_FIXNUM_BIT);
d956fa6f 4836 return SCM_I_MAKINUM (in & ((1L << bits) - 1));
0aacf84e
MD
4837 }
4838 else if (SCM_BIGP (n))
ac0c002c 4839 {
7f848242
KR
4840 SCM result;
4841 if (bits == 1)
4842 {
d956fa6f 4843 result = SCM_I_MAKINUM (mpz_tstbit (SCM_I_BIG_MPZ (n), istart));
7f848242
KR
4844 }
4845 else
4846 {
4847 /* ENHANCE-ME: It'd be nice not to allocate a new bignum when
4848 bits<SCM_I_FIXNUM_BIT. Would want some help from GMP to get
4849 such bits into a ulong. */
4850 result = scm_i_mkbig ();
4851 mpz_fdiv_q_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(n), istart);
4852 mpz_fdiv_r_2exp (SCM_I_BIG_MPZ(result), SCM_I_BIG_MPZ(result), bits);
4853 result = scm_i_normbig (result);
4854 }
4855 scm_remember_upto_here_1 (n);
4856 return result;
ac0c002c 4857 }
0aacf84e 4858 else
78166ad5 4859 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 4860}
1bbd0b84 4861#undef FUNC_NAME
0f2d19dd 4862
7f848242 4863
e4755e5c
JB
4864static const char scm_logtab[] = {
4865 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
4866};
1cc91f1b 4867
a1ec6916 4868SCM_DEFINE (scm_logcount, "logcount", 1, 0, 0,
1bbd0b84 4869 (SCM n),
1e6808ea
MG
4870 "Return the number of bits in integer @var{n}. If integer is\n"
4871 "positive, the 1-bits in its binary representation are counted.\n"
4872 "If negative, the 0-bits in its two's-complement binary\n"
4873 "representation are counted. If 0, 0 is returned.\n"
4874 "\n"
b380b885
MD
4875 "@lisp\n"
4876 "(logcount #b10101010)\n"
ca46fb90
RB
4877 " @result{} 4\n"
4878 "(logcount 0)\n"
4879 " @result{} 0\n"
4880 "(logcount -2)\n"
4881 " @result{} 1\n"
4882 "@end lisp")
4883#define FUNC_NAME s_scm_logcount
4884{
e11e83f3 4885 if (SCM_I_INUMP (n))
f872b822 4886 {
e25f3727
AW
4887 unsigned long c = 0;
4888 scm_t_inum nn = SCM_I_INUM (n);
ca46fb90
RB
4889 if (nn < 0)
4890 nn = -1 - nn;
4891 while (nn)
4892 {
4893 c += scm_logtab[15 & nn];
4894 nn >>= 4;
4895 }
d956fa6f 4896 return SCM_I_MAKINUM (c);
f872b822 4897 }
ca46fb90 4898 else if (SCM_BIGP (n))
f872b822 4899 {
ca46fb90 4900 unsigned long count;
713a4259
KR
4901 if (mpz_sgn (SCM_I_BIG_MPZ (n)) >= 0)
4902 count = mpz_popcount (SCM_I_BIG_MPZ (n));
ca46fb90 4903 else
713a4259
KR
4904 count = mpz_hamdist (SCM_I_BIG_MPZ (n), z_negative_one);
4905 scm_remember_upto_here_1 (n);
d956fa6f 4906 return SCM_I_MAKINUM (count);
f872b822 4907 }
ca46fb90
RB
4908 else
4909 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
0f2d19dd 4910}
ca46fb90 4911#undef FUNC_NAME
0f2d19dd
JB
4912
4913
ca46fb90
RB
4914static const char scm_ilentab[] = {
4915 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
4916};
4917
0f2d19dd 4918
ca46fb90
RB
4919SCM_DEFINE (scm_integer_length, "integer-length", 1, 0, 0,
4920 (SCM n),
4921 "Return the number of bits necessary to represent @var{n}.\n"
4922 "\n"
4923 "@lisp\n"
4924 "(integer-length #b10101010)\n"
4925 " @result{} 8\n"
4926 "(integer-length 0)\n"
4927 " @result{} 0\n"
4928 "(integer-length #b1111)\n"
4929 " @result{} 4\n"
4930 "@end lisp")
4931#define FUNC_NAME s_scm_integer_length
4932{
e11e83f3 4933 if (SCM_I_INUMP (n))
0aacf84e 4934 {
e25f3727 4935 unsigned long c = 0;
0aacf84e 4936 unsigned int l = 4;
e25f3727 4937 scm_t_inum nn = SCM_I_INUM (n);
0aacf84e
MD
4938 if (nn < 0)
4939 nn = -1 - nn;
4940 while (nn)
4941 {
4942 c += 4;
4943 l = scm_ilentab [15 & nn];
4944 nn >>= 4;
4945 }
d956fa6f 4946 return SCM_I_MAKINUM (c - 4 + l);
0aacf84e
MD
4947 }
4948 else if (SCM_BIGP (n))
4949 {
4950 /* mpz_sizeinbase looks at the absolute value of negatives, whereas we
4951 want a ones-complement. If n is ...111100..00 then mpz_sizeinbase is
4952 1 too big, so check for that and adjust. */
4953 size_t size = mpz_sizeinbase (SCM_I_BIG_MPZ (n), 2);
4954 if (mpz_sgn (SCM_I_BIG_MPZ (n)) < 0
4955 && mpz_scan0 (SCM_I_BIG_MPZ (n), /* no 0 bits above the lowest 1 */
4956 mpz_scan1 (SCM_I_BIG_MPZ (n), 0)) == ULONG_MAX)
4957 size--;
4958 scm_remember_upto_here_1 (n);
d956fa6f 4959 return SCM_I_MAKINUM (size);
0aacf84e
MD
4960 }
4961 else
ca46fb90 4962 SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
ca46fb90
RB
4963}
4964#undef FUNC_NAME
0f2d19dd
JB
4965
4966/*** NUMBERS -> STRINGS ***/
0b799eea
MV
4967#define SCM_MAX_DBL_PREC 60
4968#define SCM_MAX_DBL_RADIX 36
4969
4970/* this is an array starting with radix 2, and ending with radix SCM_MAX_DBL_RADIX */
4971static int scm_dblprec[SCM_MAX_DBL_RADIX - 1];
4972static double fx_per_radix[SCM_MAX_DBL_RADIX - 1][SCM_MAX_DBL_PREC];
4973
4974static
4975void init_dblprec(int *prec, int radix) {
4976 /* determine floating point precision by adding successively
4977 smaller increments to 1.0 until it is considered == 1.0 */
4978 double f = ((double)1.0)/radix;
4979 double fsum = 1.0 + f;
4980
4981 *prec = 0;
4982 while (fsum != 1.0)
4983 {
4984 if (++(*prec) > SCM_MAX_DBL_PREC)
4985 fsum = 1.0;
4986 else
4987 {
4988 f /= radix;
4989 fsum = f + 1.0;
4990 }
4991 }
4992 (*prec) -= 1;
4993}
4994
4995static
4996void init_fx_radix(double *fx_list, int radix)
4997{
4998 /* initialize a per-radix list of tolerances. When added
4999 to a number < 1.0, we can determine if we should raund
5000 up and quit converting a number to a string. */
5001 int i;
5002 fx_list[0] = 0.0;
5003 fx_list[1] = 0.5;
5004 for( i = 2 ; i < SCM_MAX_DBL_PREC; ++i )
5005 fx_list[i] = (fx_list[i-1] / radix);
5006}
5007
5008/* use this array as a way to generate a single digit */
9b5fcde6 5009static const char number_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
0f2d19dd 5010
1be6b49c 5011static size_t
0b799eea 5012idbl2str (double f, char *a, int radix)
0f2d19dd 5013{
0b799eea
MV
5014 int efmt, dpt, d, i, wp;
5015 double *fx;
5016#ifdef DBL_MIN_10_EXP
5017 double f_cpy;
5018 int exp_cpy;
5019#endif /* DBL_MIN_10_EXP */
5020 size_t ch = 0;
5021 int exp = 0;
5022
5023 if(radix < 2 ||
5024 radix > SCM_MAX_DBL_RADIX)
5025 {
5026 /* revert to existing behavior */
5027 radix = 10;
5028 }
5029
5030 wp = scm_dblprec[radix-2];
5031 fx = fx_per_radix[radix-2];
0f2d19dd 5032
f872b822 5033 if (f == 0.0)
abb7e44d
MV
5034 {
5035#ifdef HAVE_COPYSIGN
5036 double sgn = copysign (1.0, f);
5037
5038 if (sgn < 0.0)
5039 a[ch++] = '-';
5040#endif
abb7e44d
MV
5041 goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;} */
5042 }
7351e207 5043
2e65b52f 5044 if (isinf (f))
7351e207
MV
5045 {
5046 if (f < 0)
5047 strcpy (a, "-inf.0");
5048 else
5049 strcpy (a, "+inf.0");
5050 return ch+6;
5051 }
2e65b52f 5052 else if (isnan (f))
7351e207
MV
5053 {
5054 strcpy (a, "+nan.0");
5055 return ch+6;
5056 }
5057
f872b822
MD
5058 if (f < 0.0)
5059 {
5060 f = -f;
5061 a[ch++] = '-';
5062 }
7351e207 5063
f872b822
MD
5064#ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from
5065 make-uniform-vector, from causing infinite loops. */
0b799eea
MV
5066 /* just do the checking...if it passes, we do the conversion for our
5067 radix again below */
5068 f_cpy = f;
5069 exp_cpy = exp;
5070
5071 while (f_cpy < 1.0)
f872b822 5072 {
0b799eea
MV
5073 f_cpy *= 10.0;
5074 if (exp_cpy-- < DBL_MIN_10_EXP)
7351e207
MV
5075 {
5076 a[ch++] = '#';
5077 a[ch++] = '.';
5078 a[ch++] = '#';
5079 return ch;
5080 }
f872b822 5081 }
0b799eea 5082 while (f_cpy > 10.0)
f872b822 5083 {
0b799eea
MV
5084 f_cpy *= 0.10;
5085 if (exp_cpy++ > DBL_MAX_10_EXP)
7351e207
MV
5086 {
5087 a[ch++] = '#';
5088 a[ch++] = '.';
5089 a[ch++] = '#';
5090 return ch;
5091 }
f872b822 5092 }
0b799eea
MV
5093#endif
5094
f872b822
MD
5095 while (f < 1.0)
5096 {
0b799eea 5097 f *= radix;
f872b822
MD
5098 exp--;
5099 }
0b799eea 5100 while (f > radix)
f872b822 5101 {
0b799eea 5102 f /= radix;
f872b822
MD
5103 exp++;
5104 }
0b799eea
MV
5105
5106 if (f + fx[wp] >= radix)
f872b822
MD
5107 {
5108 f = 1.0;
5109 exp++;
5110 }
0f2d19dd 5111 zero:
0b799eea
MV
5112#ifdef ENGNOT
5113 /* adding 9999 makes this equivalent to abs(x) % 3 */
f872b822 5114 dpt = (exp + 9999) % 3;
0f2d19dd
JB
5115 exp -= dpt++;
5116 efmt = 1;
f872b822
MD
5117#else
5118 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 5119 if (!efmt)
cda139a7
MD
5120 {
5121 if (exp < 0)
5122 {
5123 a[ch++] = '0';
5124 a[ch++] = '.';
5125 dpt = exp;
f872b822
MD
5126 while (++dpt)
5127 a[ch++] = '0';
cda139a7
MD
5128 }
5129 else
f872b822 5130 dpt = exp + 1;
cda139a7 5131 }
0f2d19dd
JB
5132 else
5133 dpt = 1;
f872b822
MD
5134#endif
5135
5136 do
5137 {
5138 d = f;
5139 f -= d;
0b799eea 5140 a[ch++] = number_chars[d];
f872b822
MD
5141 if (f < fx[wp])
5142 break;
5143 if (f + fx[wp] >= 1.0)
5144 {
0b799eea 5145 a[ch - 1] = number_chars[d+1];
f872b822
MD
5146 break;
5147 }
0b799eea 5148 f *= radix;
f872b822
MD
5149 if (!(--dpt))
5150 a[ch++] = '.';
0f2d19dd 5151 }
f872b822 5152 while (wp--);
0f2d19dd
JB
5153
5154 if (dpt > 0)
cda139a7 5155 {
f872b822 5156#ifndef ENGNOT
cda139a7
MD
5157 if ((dpt > 4) && (exp > 6))
5158 {
f872b822 5159 d = (a[0] == '-' ? 2 : 1);
cda139a7 5160 for (i = ch++; i > d; i--)
f872b822 5161 a[i] = a[i - 1];
cda139a7
MD
5162 a[d] = '.';
5163 efmt = 1;
5164 }
5165 else
f872b822 5166#endif
cda139a7 5167 {
f872b822
MD
5168 while (--dpt)
5169 a[ch++] = '0';
cda139a7
MD
5170 a[ch++] = '.';
5171 }
5172 }
f872b822
MD
5173 if (a[ch - 1] == '.')
5174 a[ch++] = '0'; /* trailing zero */
5175 if (efmt && exp)
5176 {
5177 a[ch++] = 'e';
5178 if (exp < 0)
5179 {
5180 exp = -exp;
5181 a[ch++] = '-';
5182 }
0b799eea
MV
5183 for (i = radix; i <= exp; i *= radix);
5184 for (i /= radix; i; i /= radix)
f872b822 5185 {
0b799eea 5186 a[ch++] = number_chars[exp / i];
f872b822
MD
5187 exp %= i;
5188 }
0f2d19dd 5189 }
0f2d19dd
JB
5190 return ch;
5191}
5192
7a1aba42
MV
5193
5194static size_t
5195icmplx2str (double real, double imag, char *str, int radix)
5196{
5197 size_t i;
c7218482 5198 double sgn;
7a1aba42
MV
5199
5200 i = idbl2str (real, str, radix);
c7218482
MW
5201#ifdef HAVE_COPYSIGN
5202 sgn = copysign (1.0, imag);
5203#else
5204 sgn = imag;
5205#endif
5206 /* Don't output a '+' for negative numbers or for Inf and
5207 NaN. They will provide their own sign. */
5208 if (sgn >= 0 && DOUBLE_IS_FINITE (imag))
5209 str[i++] = '+';
5210 i += idbl2str (imag, &str[i], radix);
5211 str[i++] = 'i';
7a1aba42
MV
5212 return i;
5213}
5214
1be6b49c 5215static size_t
0b799eea 5216iflo2str (SCM flt, char *str, int radix)
0f2d19dd 5217{
1be6b49c 5218 size_t i;
3c9a524f 5219 if (SCM_REALP (flt))
0b799eea 5220 i = idbl2str (SCM_REAL_VALUE (flt), str, radix);
0f2d19dd 5221 else
7a1aba42
MV
5222 i = icmplx2str (SCM_COMPLEX_REAL (flt), SCM_COMPLEX_IMAG (flt),
5223 str, radix);
0f2d19dd
JB
5224 return i;
5225}
0f2d19dd 5226
2881e77b 5227/* convert a scm_t_intmax to a string (unterminated). returns the number of
1bbd0b84
GB
5228 characters in the result.
5229 rad is output base
5230 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 5231size_t
2881e77b
MV
5232scm_iint2str (scm_t_intmax num, int rad, char *p)
5233{
5234 if (num < 0)
5235 {
5236 *p++ = '-';
5237 return scm_iuint2str (-num, rad, p) + 1;
5238 }
5239 else
5240 return scm_iuint2str (num, rad, p);
5241}
5242
5243/* convert a scm_t_intmax to a string (unterminated). returns the number of
5244 characters in the result.
5245 rad is output base
5246 p is destination: worst case (base 2) is SCM_INTBUFLEN */
5247size_t
5248scm_iuint2str (scm_t_uintmax num, int rad, char *p)
0f2d19dd 5249{
1be6b49c
ML
5250 size_t j = 1;
5251 size_t i;
2881e77b 5252 scm_t_uintmax n = num;
5c11cc9d 5253
a6f3af16
AW
5254 if (rad < 2 || rad > 36)
5255 scm_out_of_range ("scm_iuint2str", scm_from_int (rad));
5256
f872b822 5257 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
5258 j++;
5259
5260 i = j;
2881e77b 5261 n = num;
f872b822
MD
5262 while (i--)
5263 {
5c11cc9d
GH
5264 int d = n % rad;
5265
f872b822 5266 n /= rad;
a6f3af16 5267 p[i] = number_chars[d];
f872b822 5268 }
0f2d19dd
JB
5269 return j;
5270}
5271
a1ec6916 5272SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
5273 (SCM n, SCM radix),
5274 "Return a string holding the external representation of the\n"
942e5b91
MG
5275 "number @var{n} in the given @var{radix}. If @var{n} is\n"
5276 "inexact, a radix of 10 will be used.")
1bbd0b84 5277#define FUNC_NAME s_scm_number_to_string
0f2d19dd 5278{
1bbd0b84 5279 int base;
98cb6e75 5280
0aacf84e 5281 if (SCM_UNBNDP (radix))
98cb6e75 5282 base = 10;
0aacf84e 5283 else
5efd3c7d 5284 base = scm_to_signed_integer (radix, 2, 36);
98cb6e75 5285
e11e83f3 5286 if (SCM_I_INUMP (n))
0aacf84e
MD
5287 {
5288 char num_buf [SCM_INTBUFLEN];
e11e83f3 5289 size_t length = scm_iint2str (SCM_I_INUM (n), base, num_buf);
cc95e00a 5290 return scm_from_locale_stringn (num_buf, length);
0aacf84e
MD
5291 }
5292 else if (SCM_BIGP (n))
5293 {
5294 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
5295 scm_remember_upto_here_1 (n);
cc95e00a 5296 return scm_take_locale_string (str);
0aacf84e 5297 }
f92e85f7
MV
5298 else if (SCM_FRACTIONP (n))
5299 {
f92e85f7 5300 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
cc95e00a 5301 scm_from_locale_string ("/"),
f92e85f7
MV
5302 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
5303 }
0aacf84e
MD
5304 else if (SCM_INEXACTP (n))
5305 {
5306 char num_buf [FLOBUFLEN];
cc95e00a 5307 return scm_from_locale_stringn (num_buf, iflo2str (n, num_buf, base));
0aacf84e
MD
5308 }
5309 else
bb628794 5310 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 5311}
1bbd0b84 5312#undef FUNC_NAME
0f2d19dd
JB
5313
5314
ca46fb90
RB
5315/* These print routines used to be stubbed here so that scm_repl.c
5316 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 5317
0f2d19dd 5318int
e81d98ec 5319scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 5320{
56e55ac7 5321 char num_buf[FLOBUFLEN];
0b799eea 5322 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
0f2d19dd
JB
5323 return !0;
5324}
5325
b479fe9a
MV
5326void
5327scm_i_print_double (double val, SCM port)
5328{
5329 char num_buf[FLOBUFLEN];
5330 scm_lfwrite (num_buf, idbl2str (val, num_buf, 10), port);
5331}
5332
f3ae5d60 5333int
e81d98ec 5334scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 5335
f3ae5d60 5336{
56e55ac7 5337 char num_buf[FLOBUFLEN];
0b799eea 5338 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
f3ae5d60
MD
5339 return !0;
5340}
1cc91f1b 5341
7a1aba42
MV
5342void
5343scm_i_print_complex (double real, double imag, SCM port)
5344{
5345 char num_buf[FLOBUFLEN];
5346 scm_lfwrite (num_buf, icmplx2str (real, imag, num_buf, 10), port);
5347}
5348
f92e85f7
MV
5349int
5350scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
5351{
5352 SCM str;
f92e85f7 5353 str = scm_number_to_string (sexp, SCM_UNDEFINED);
a9178715 5354 scm_display (str, port);
f92e85f7
MV
5355 scm_remember_upto_here_1 (str);
5356 return !0;
5357}
5358
0f2d19dd 5359int
e81d98ec 5360scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 5361{
ca46fb90
RB
5362 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
5363 scm_remember_upto_here_1 (exp);
5364 scm_lfwrite (str, (size_t) strlen (str), port);
5365 free (str);
0f2d19dd
JB
5366 return !0;
5367}
5368/*** END nums->strs ***/
5369
3c9a524f 5370
0f2d19dd 5371/*** STRINGS -> NUMBERS ***/
2a8fecee 5372
3c9a524f
DH
5373/* The following functions implement the conversion from strings to numbers.
5374 * The implementation somehow follows the grammar for numbers as it is given
5375 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
5376 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
5377 * points should be noted about the implementation:
bc3d34f5 5378 *
3c9a524f
DH
5379 * * Each function keeps a local index variable 'idx' that points at the
5380 * current position within the parsed string. The global index is only
5381 * updated if the function could parse the corresponding syntactic unit
5382 * successfully.
bc3d34f5 5383 *
3c9a524f 5384 * * Similarly, the functions keep track of indicators of inexactness ('#',
bc3d34f5
MW
5385 * '.' or exponents) using local variables ('hash_seen', 'x').
5386 *
3c9a524f
DH
5387 * * Sequences of digits are parsed into temporary variables holding fixnums.
5388 * Only if these fixnums would overflow, the result variables are updated
5389 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
5390 * the temporary variables holding the fixnums are cleared, and the process
5391 * starts over again. If for example fixnums were able to store five decimal
5392 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
5393 * and the result was computed as 12345 * 100000 + 67890. In other words,
5394 * only every five digits two bignum operations were performed.
bc3d34f5
MW
5395 *
5396 * Notes on the handling of exactness specifiers:
5397 *
5398 * When parsing non-real complex numbers, we apply exactness specifiers on
5399 * per-component basis, as is done in PLT Scheme. For complex numbers
5400 * written in rectangular form, exactness specifiers are applied to the
5401 * real and imaginary parts before calling scm_make_rectangular. For
5402 * complex numbers written in polar form, exactness specifiers are applied
5403 * to the magnitude and angle before calling scm_make_polar.
5404 *
5405 * There are two kinds of exactness specifiers: forced and implicit. A
5406 * forced exactness specifier is a "#e" or "#i" prefix at the beginning of
5407 * the entire number, and applies to both components of a complex number.
5408 * "#e" causes each component to be made exact, and "#i" causes each
5409 * component to be made inexact. If no forced exactness specifier is
5410 * present, then the exactness of each component is determined
5411 * independently by the presence or absence of a decimal point or hash mark
5412 * within that component. If a decimal point or hash mark is present, the
5413 * component is made inexact, otherwise it is made exact.
5414 *
5415 * After the exactness specifiers have been applied to each component, they
5416 * are passed to either scm_make_rectangular or scm_make_polar to produce
5417 * the final result. Note that this will result in a real number if the
5418 * imaginary part, magnitude, or angle is an exact 0.
5419 *
5420 * For example, (string->number "#i5.0+0i") does the equivalent of:
5421 *
5422 * (make-rectangular (exact->inexact 5) (exact->inexact 0))
3c9a524f
DH
5423 */
5424
5425enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
5426
5427/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
5428
a6f3af16
AW
5429/* Caller is responsible for checking that the return value is in range
5430 for the given radix, which should be <= 36. */
5431static unsigned int
5432char_decimal_value (scm_t_uint32 c)
5433{
5434 /* uc_decimal_value returns -1 on error. When cast to an unsigned int,
5435 that's certainly above any valid decimal, so we take advantage of
5436 that to elide some tests. */
5437 unsigned int d = (unsigned int) uc_decimal_value (c);
5438
5439 /* If that failed, try extended hexadecimals, then. Only accept ascii
5440 hexadecimals. */
5441 if (d >= 10U)
5442 {
5443 c = uc_tolower (c);
5444 if (c >= (scm_t_uint32) 'a')
5445 d = c - (scm_t_uint32)'a' + 10U;
5446 }
5447 return d;
5448}
3c9a524f 5449
2a8fecee 5450static SCM
3f47e526 5451mem2uinteger (SCM mem, unsigned int *p_idx,
3c9a524f 5452 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 5453{
3c9a524f
DH
5454 unsigned int idx = *p_idx;
5455 unsigned int hash_seen = 0;
5456 scm_t_bits shift = 1;
5457 scm_t_bits add = 0;
5458 unsigned int digit_value;
5459 SCM result;
5460 char c;
3f47e526 5461 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5462
5463 if (idx == len)
5464 return SCM_BOOL_F;
2a8fecee 5465
3f47e526 5466 c = scm_i_string_ref (mem, idx);
a6f3af16 5467 digit_value = char_decimal_value (c);
3c9a524f
DH
5468 if (digit_value >= radix)
5469 return SCM_BOOL_F;
5470
5471 idx++;
d956fa6f 5472 result = SCM_I_MAKINUM (digit_value);
3c9a524f 5473 while (idx != len)
f872b822 5474 {
3f47e526 5475 scm_t_wchar c = scm_i_string_ref (mem, idx);
a6f3af16 5476 if (c == '#')
3c9a524f
DH
5477 {
5478 hash_seen = 1;
5479 digit_value = 0;
5480 }
a6f3af16
AW
5481 else if (hash_seen)
5482 break;
3c9a524f 5483 else
a6f3af16
AW
5484 {
5485 digit_value = char_decimal_value (c);
5486 /* This check catches non-decimals in addition to out-of-range
5487 decimals. */
5488 if (digit_value >= radix)
5489 break;
5490 }
3c9a524f
DH
5491
5492 idx++;
5493 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
5494 {
d956fa6f 5495 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5496 if (add > 0)
d956fa6f 5497 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5498
5499 shift = radix;
5500 add = digit_value;
5501 }
5502 else
5503 {
5504 shift = shift * radix;
5505 add = add * radix + digit_value;
5506 }
5507 };
5508
5509 if (shift > 1)
d956fa6f 5510 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5511 if (add > 0)
d956fa6f 5512 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5513
5514 *p_idx = idx;
5515 if (hash_seen)
5516 *p_exactness = INEXACT;
5517
5518 return result;
2a8fecee
JB
5519}
5520
5521
3c9a524f
DH
5522/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
5523 * covers the parts of the rules that start at a potential point. The value
5524 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
5525 * in variable result. The content of *p_exactness indicates, whether a hash
5526 * has already been seen in the digits before the point.
3c9a524f 5527 */
1cc91f1b 5528
3f47e526 5529#define DIGIT2UINT(d) (uc_numeric_value(d).numerator)
3c9a524f
DH
5530
5531static SCM
3f47e526 5532mem2decimal_from_point (SCM result, SCM mem,
3c9a524f 5533 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 5534{
3c9a524f
DH
5535 unsigned int idx = *p_idx;
5536 enum t_exactness x = *p_exactness;
3f47e526 5537 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5538
5539 if (idx == len)
79d34f68 5540 return result;
3c9a524f 5541
3f47e526 5542 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
5543 {
5544 scm_t_bits shift = 1;
5545 scm_t_bits add = 0;
5546 unsigned int digit_value;
cff5fa33 5547 SCM big_shift = SCM_INUM1;
3c9a524f
DH
5548
5549 idx++;
5550 while (idx != len)
5551 {
3f47e526
MG
5552 scm_t_wchar c = scm_i_string_ref (mem, idx);
5553 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5554 {
5555 if (x == INEXACT)
5556 return SCM_BOOL_F;
5557 else
5558 digit_value = DIGIT2UINT (c);
5559 }
5560 else if (c == '#')
5561 {
5562 x = INEXACT;
5563 digit_value = 0;
5564 }
5565 else
5566 break;
5567
5568 idx++;
5569 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
5570 {
d956fa6f
MV
5571 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
5572 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5573 if (add > 0)
d956fa6f 5574 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5575
5576 shift = 10;
5577 add = digit_value;
5578 }
5579 else
5580 {
5581 shift = shift * 10;
5582 add = add * 10 + digit_value;
5583 }
5584 };
5585
5586 if (add > 0)
5587 {
d956fa6f
MV
5588 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
5589 result = scm_product (result, SCM_I_MAKINUM (shift));
5590 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5591 }
5592
d8592269 5593 result = scm_divide (result, big_shift);
79d34f68 5594
3c9a524f
DH
5595 /* We've seen a decimal point, thus the value is implicitly inexact. */
5596 x = INEXACT;
f872b822 5597 }
3c9a524f 5598
3c9a524f 5599 if (idx != len)
f872b822 5600 {
3c9a524f
DH
5601 int sign = 1;
5602 unsigned int start;
3f47e526 5603 scm_t_wchar c;
3c9a524f
DH
5604 int exponent;
5605 SCM e;
5606
5607 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
5608
3f47e526 5609 switch (scm_i_string_ref (mem, idx))
f872b822 5610 {
3c9a524f
DH
5611 case 'd': case 'D':
5612 case 'e': case 'E':
5613 case 'f': case 'F':
5614 case 'l': case 'L':
5615 case 's': case 'S':
5616 idx++;
ee0ddd21
AW
5617 if (idx == len)
5618 return SCM_BOOL_F;
5619
3c9a524f 5620 start = idx;
3f47e526 5621 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5622 if (c == '-')
5623 {
5624 idx++;
ee0ddd21
AW
5625 if (idx == len)
5626 return SCM_BOOL_F;
5627
3c9a524f 5628 sign = -1;
3f47e526 5629 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5630 }
5631 else if (c == '+')
5632 {
5633 idx++;
ee0ddd21
AW
5634 if (idx == len)
5635 return SCM_BOOL_F;
5636
3c9a524f 5637 sign = 1;
3f47e526 5638 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5639 }
5640 else
5641 sign = 1;
5642
3f47e526 5643 if (!uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5644 return SCM_BOOL_F;
5645
5646 idx++;
5647 exponent = DIGIT2UINT (c);
5648 while (idx != len)
f872b822 5649 {
3f47e526
MG
5650 scm_t_wchar c = scm_i_string_ref (mem, idx);
5651 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5652 {
5653 idx++;
5654 if (exponent <= SCM_MAXEXP)
5655 exponent = exponent * 10 + DIGIT2UINT (c);
5656 }
5657 else
5658 break;
f872b822 5659 }
3c9a524f
DH
5660
5661 if (exponent > SCM_MAXEXP)
f872b822 5662 {
3c9a524f 5663 size_t exp_len = idx - start;
3f47e526 5664 SCM exp_string = scm_i_substring_copy (mem, start, start + exp_len);
3c9a524f
DH
5665 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
5666 scm_out_of_range ("string->number", exp_num);
f872b822 5667 }
3c9a524f 5668
d956fa6f 5669 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
5670 if (sign == 1)
5671 result = scm_product (result, e);
5672 else
6ebecdeb 5673 result = scm_divide (result, e);
3c9a524f
DH
5674
5675 /* We've seen an exponent, thus the value is implicitly inexact. */
5676 x = INEXACT;
5677
f872b822 5678 break;
3c9a524f 5679
f872b822 5680 default:
3c9a524f 5681 break;
f872b822 5682 }
0f2d19dd 5683 }
3c9a524f
DH
5684
5685 *p_idx = idx;
5686 if (x == INEXACT)
5687 *p_exactness = x;
5688
5689 return result;
0f2d19dd 5690}
0f2d19dd 5691
3c9a524f
DH
5692
5693/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
5694
5695static SCM
3f47e526 5696mem2ureal (SCM mem, unsigned int *p_idx,
9d427b2c 5697 unsigned int radix, enum t_exactness forced_x)
0f2d19dd 5698{
3c9a524f 5699 unsigned int idx = *p_idx;
164d2481 5700 SCM result;
3f47e526 5701 size_t len = scm_i_string_length (mem);
3c9a524f 5702
40f89215
NJ
5703 /* Start off believing that the number will be exact. This changes
5704 to INEXACT if we see a decimal point or a hash. */
9d427b2c 5705 enum t_exactness implicit_x = EXACT;
40f89215 5706
3c9a524f
DH
5707 if (idx == len)
5708 return SCM_BOOL_F;
5709
3f47e526 5710 if (idx+5 <= len && !scm_i_string_strcmp (mem, idx, "inf.0"))
7351e207
MV
5711 {
5712 *p_idx = idx+5;
5713 return scm_inf ();
5714 }
5715
3f47e526 5716 if (idx+4 < len && !scm_i_string_strcmp (mem, idx, "nan."))
7351e207 5717 {
d8592269
MV
5718 /* Cobble up the fractional part. We might want to set the
5719 NaN's mantissa from it. */
7351e207 5720 idx += 4;
9d427b2c 5721 mem2uinteger (mem, &idx, 10, &implicit_x);
7351e207
MV
5722 *p_idx = idx;
5723 return scm_nan ();
5724 }
5725
3f47e526 5726 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
5727 {
5728 if (radix != 10)
5729 return SCM_BOOL_F;
5730 else if (idx + 1 == len)
5731 return SCM_BOOL_F;
3f47e526 5732 else if (!uc_is_property_decimal_digit ((scm_t_uint32) scm_i_string_ref (mem, idx+1)))
3c9a524f
DH
5733 return SCM_BOOL_F;
5734 else
cff5fa33 5735 result = mem2decimal_from_point (SCM_INUM0, mem,
9d427b2c 5736 p_idx, &implicit_x);
f872b822 5737 }
3c9a524f
DH
5738 else
5739 {
3c9a524f 5740 SCM uinteger;
3c9a524f 5741
9d427b2c 5742 uinteger = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 5743 if (scm_is_false (uinteger))
3c9a524f
DH
5744 return SCM_BOOL_F;
5745
5746 if (idx == len)
5747 result = uinteger;
3f47e526 5748 else if (scm_i_string_ref (mem, idx) == '/')
f872b822 5749 {
3c9a524f
DH
5750 SCM divisor;
5751
5752 idx++;
ee0ddd21
AW
5753 if (idx == len)
5754 return SCM_BOOL_F;
3c9a524f 5755
9d427b2c 5756 divisor = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 5757 if (scm_is_false (divisor))
3c9a524f
DH
5758 return SCM_BOOL_F;
5759
f92e85f7 5760 /* both are int/big here, I assume */
cba42c93 5761 result = scm_i_make_ratio (uinteger, divisor);
f872b822 5762 }
3c9a524f
DH
5763 else if (radix == 10)
5764 {
9d427b2c 5765 result = mem2decimal_from_point (uinteger, mem, &idx, &implicit_x);
73e4de09 5766 if (scm_is_false (result))
3c9a524f
DH
5767 return SCM_BOOL_F;
5768 }
5769 else
5770 result = uinteger;
5771
5772 *p_idx = idx;
f872b822 5773 }
164d2481 5774
9d427b2c
MW
5775 switch (forced_x)
5776 {
5777 case EXACT:
5778 if (SCM_INEXACTP (result))
5779 return scm_inexact_to_exact (result);
5780 else
5781 return result;
5782 case INEXACT:
5783 if (SCM_INEXACTP (result))
5784 return result;
5785 else
5786 return scm_exact_to_inexact (result);
5787 case NO_EXACTNESS:
5788 if (implicit_x == INEXACT)
5789 {
5790 if (SCM_INEXACTP (result))
5791 return result;
5792 else
5793 return scm_exact_to_inexact (result);
5794 }
5795 else
5796 return result;
5797 }
164d2481 5798
9d427b2c
MW
5799 /* We should never get here */
5800 scm_syserror ("mem2ureal");
3c9a524f 5801}
0f2d19dd 5802
0f2d19dd 5803
3c9a524f 5804/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 5805
3c9a524f 5806static SCM
3f47e526 5807mem2complex (SCM mem, unsigned int idx,
9d427b2c 5808 unsigned int radix, enum t_exactness forced_x)
3c9a524f 5809{
3f47e526 5810 scm_t_wchar c;
3c9a524f
DH
5811 int sign = 0;
5812 SCM ureal;
3f47e526 5813 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5814
5815 if (idx == len)
5816 return SCM_BOOL_F;
5817
3f47e526 5818 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5819 if (c == '+')
5820 {
5821 idx++;
5822 sign = 1;
5823 }
5824 else if (c == '-')
5825 {
5826 idx++;
5827 sign = -1;
0f2d19dd 5828 }
0f2d19dd 5829
3c9a524f
DH
5830 if (idx == len)
5831 return SCM_BOOL_F;
5832
9d427b2c 5833 ureal = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 5834 if (scm_is_false (ureal))
f872b822 5835 {
3c9a524f
DH
5836 /* input must be either +i or -i */
5837
5838 if (sign == 0)
5839 return SCM_BOOL_F;
5840
3f47e526
MG
5841 if (scm_i_string_ref (mem, idx) == 'i'
5842 || scm_i_string_ref (mem, idx) == 'I')
f872b822 5843 {
3c9a524f
DH
5844 idx++;
5845 if (idx != len)
5846 return SCM_BOOL_F;
5847
cff5fa33 5848 return scm_make_rectangular (SCM_INUM0, SCM_I_MAKINUM (sign));
f872b822 5849 }
3c9a524f
DH
5850 else
5851 return SCM_BOOL_F;
0f2d19dd 5852 }
3c9a524f
DH
5853 else
5854 {
73e4de09 5855 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 5856 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 5857
3c9a524f
DH
5858 if (idx == len)
5859 return ureal;
5860
3f47e526 5861 c = scm_i_string_ref (mem, idx);
3c9a524f 5862 switch (c)
f872b822 5863 {
3c9a524f
DH
5864 case 'i': case 'I':
5865 /* either +<ureal>i or -<ureal>i */
5866
5867 idx++;
5868 if (sign == 0)
5869 return SCM_BOOL_F;
5870 if (idx != len)
5871 return SCM_BOOL_F;
cff5fa33 5872 return scm_make_rectangular (SCM_INUM0, ureal);
3c9a524f
DH
5873
5874 case '@':
5875 /* polar input: <real>@<real>. */
5876
5877 idx++;
5878 if (idx == len)
5879 return SCM_BOOL_F;
5880 else
f872b822 5881 {
3c9a524f
DH
5882 int sign;
5883 SCM angle;
5884 SCM result;
5885
3f47e526 5886 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5887 if (c == '+')
5888 {
5889 idx++;
ee0ddd21
AW
5890 if (idx == len)
5891 return SCM_BOOL_F;
3c9a524f
DH
5892 sign = 1;
5893 }
5894 else if (c == '-')
5895 {
5896 idx++;
ee0ddd21
AW
5897 if (idx == len)
5898 return SCM_BOOL_F;
3c9a524f
DH
5899 sign = -1;
5900 }
5901 else
5902 sign = 1;
5903
9d427b2c 5904 angle = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 5905 if (scm_is_false (angle))
3c9a524f
DH
5906 return SCM_BOOL_F;
5907 if (idx != len)
5908 return SCM_BOOL_F;
5909
73e4de09 5910 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
5911 angle = scm_difference (angle, SCM_UNDEFINED);
5912
5913 result = scm_make_polar (ureal, angle);
5914 return result;
f872b822 5915 }
3c9a524f
DH
5916 case '+':
5917 case '-':
5918 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 5919
3c9a524f
DH
5920 idx++;
5921 if (idx == len)
5922 return SCM_BOOL_F;
5923 else
5924 {
5925 int sign = (c == '+') ? 1 : -1;
9d427b2c 5926 SCM imag = mem2ureal (mem, &idx, radix, forced_x);
0f2d19dd 5927
73e4de09 5928 if (scm_is_false (imag))
d956fa6f 5929 imag = SCM_I_MAKINUM (sign);
23295dc3 5930 else if (sign == -1 && scm_is_false (scm_nan_p (imag)))
1fe5e088 5931 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 5932
3c9a524f
DH
5933 if (idx == len)
5934 return SCM_BOOL_F;
3f47e526
MG
5935 if (scm_i_string_ref (mem, idx) != 'i'
5936 && scm_i_string_ref (mem, idx) != 'I')
3c9a524f 5937 return SCM_BOOL_F;
0f2d19dd 5938
3c9a524f
DH
5939 idx++;
5940 if (idx != len)
5941 return SCM_BOOL_F;
0f2d19dd 5942
1fe5e088 5943 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
5944 }
5945 default:
5946 return SCM_BOOL_F;
5947 }
5948 }
0f2d19dd 5949}
0f2d19dd
JB
5950
5951
3c9a524f
DH
5952/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
5953
5954enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 5955
0f2d19dd 5956SCM
3f47e526 5957scm_i_string_to_number (SCM mem, unsigned int default_radix)
0f2d19dd 5958{
3c9a524f
DH
5959 unsigned int idx = 0;
5960 unsigned int radix = NO_RADIX;
5961 enum t_exactness forced_x = NO_EXACTNESS;
3f47e526 5962 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5963
5964 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
3f47e526 5965 while (idx + 2 < len && scm_i_string_ref (mem, idx) == '#')
3c9a524f 5966 {
3f47e526 5967 switch (scm_i_string_ref (mem, idx + 1))
3c9a524f
DH
5968 {
5969 case 'b': case 'B':
5970 if (radix != NO_RADIX)
5971 return SCM_BOOL_F;
5972 radix = DUAL;
5973 break;
5974 case 'd': case 'D':
5975 if (radix != NO_RADIX)
5976 return SCM_BOOL_F;
5977 radix = DEC;
5978 break;
5979 case 'i': case 'I':
5980 if (forced_x != NO_EXACTNESS)
5981 return SCM_BOOL_F;
5982 forced_x = INEXACT;
5983 break;
5984 case 'e': case 'E':
5985 if (forced_x != NO_EXACTNESS)
5986 return SCM_BOOL_F;
5987 forced_x = EXACT;
5988 break;
5989 case 'o': case 'O':
5990 if (radix != NO_RADIX)
5991 return SCM_BOOL_F;
5992 radix = OCT;
5993 break;
5994 case 'x': case 'X':
5995 if (radix != NO_RADIX)
5996 return SCM_BOOL_F;
5997 radix = HEX;
5998 break;
5999 default:
f872b822 6000 return SCM_BOOL_F;
3c9a524f
DH
6001 }
6002 idx += 2;
6003 }
6004
6005 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
6006 if (radix == NO_RADIX)
9d427b2c 6007 radix = default_radix;
f872b822 6008
9d427b2c 6009 return mem2complex (mem, idx, radix, forced_x);
0f2d19dd
JB
6010}
6011
3f47e526
MG
6012SCM
6013scm_c_locale_stringn_to_number (const char* mem, size_t len,
6014 unsigned int default_radix)
6015{
6016 SCM str = scm_from_locale_stringn (mem, len);
6017
6018 return scm_i_string_to_number (str, default_radix);
6019}
6020
0f2d19dd 6021
a1ec6916 6022SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 6023 (SCM string, SCM radix),
1e6808ea 6024 "Return a number of the maximally precise representation\n"
942e5b91 6025 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
6026 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
6027 "is a default radix that may be overridden by an explicit radix\n"
6028 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
6029 "supplied, then the default radix is 10. If string is not a\n"
6030 "syntactically valid notation for a number, then\n"
6031 "@code{string->number} returns @code{#f}.")
1bbd0b84 6032#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
6033{
6034 SCM answer;
5efd3c7d 6035 unsigned int base;
a6d9e5ab 6036 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
6037
6038 if (SCM_UNBNDP (radix))
6039 base = 10;
6040 else
6041 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
6042
3f47e526 6043 answer = scm_i_string_to_number (string, base);
8824ac88
MV
6044 scm_remember_upto_here_1 (string);
6045 return answer;
0f2d19dd 6046}
1bbd0b84 6047#undef FUNC_NAME
3c9a524f
DH
6048
6049
0f2d19dd
JB
6050/*** END strs->nums ***/
6051
5986c47d 6052
8507ec80
MV
6053SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
6054 (SCM x),
6055 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
6056 "otherwise.")
6057#define FUNC_NAME s_scm_number_p
6058{
6059 return scm_from_bool (SCM_NUMBERP (x));
6060}
6061#undef FUNC_NAME
6062
6063SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 6064 (SCM x),
942e5b91 6065 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 6066 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
6067 "values form subsets of the set of complex numbers, i. e. the\n"
6068 "predicate will also be fulfilled if @var{x} is a real,\n"
6069 "rational or integer number.")
8507ec80 6070#define FUNC_NAME s_scm_complex_p
0f2d19dd 6071{
8507ec80
MV
6072 /* all numbers are complex. */
6073 return scm_number_p (x);
0f2d19dd 6074}
1bbd0b84 6075#undef FUNC_NAME
0f2d19dd 6076
f92e85f7
MV
6077SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
6078 (SCM x),
6079 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
6080 "otherwise. Note that the set of integer values forms a subset of\n"
6081 "the set of real numbers, i. e. the predicate will also be\n"
6082 "fulfilled if @var{x} is an integer number.")
6083#define FUNC_NAME s_scm_real_p
6084{
c960e556
MW
6085 return scm_from_bool
6086 (SCM_I_INUMP (x) || SCM_REALP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x));
f92e85f7
MV
6087}
6088#undef FUNC_NAME
6089
6090SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 6091 (SCM x),
942e5b91 6092 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 6093 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 6094 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
6095 "fulfilled if @var{x} is an integer number.")
6096#define FUNC_NAME s_scm_rational_p
0f2d19dd 6097{
c960e556 6098 if (SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x))
f92e85f7
MV
6099 return SCM_BOOL_T;
6100 else if (SCM_REALP (x))
c960e556
MW
6101 /* due to their limited precision, finite floating point numbers are
6102 rational as well. (finite means neither infinity nor a NaN) */
6103 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
0aacf84e 6104 else
bb628794 6105 return SCM_BOOL_F;
0f2d19dd 6106}
1bbd0b84 6107#undef FUNC_NAME
0f2d19dd 6108
a1ec6916 6109SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 6110 (SCM x),
942e5b91
MG
6111 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
6112 "else.")
1bbd0b84 6113#define FUNC_NAME s_scm_integer_p
0f2d19dd 6114{
c960e556 6115 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f872b822 6116 return SCM_BOOL_T;
c960e556
MW
6117 else if (SCM_REALP (x))
6118 {
6119 double val = SCM_REAL_VALUE (x);
6120 return scm_from_bool (!isinf (val) && (val == floor (val)));
6121 }
6122 else
8e43ed5d 6123 return SCM_BOOL_F;
0f2d19dd 6124}
1bbd0b84 6125#undef FUNC_NAME
0f2d19dd
JB
6126
6127
8a1f4f98
AW
6128SCM scm_i_num_eq_p (SCM, SCM, SCM);
6129SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
6130 (SCM x, SCM y, SCM rest),
6131 "Return @code{#t} if all parameters are numerically equal.")
6132#define FUNC_NAME s_scm_i_num_eq_p
6133{
6134 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6135 return SCM_BOOL_T;
6136 while (!scm_is_null (rest))
6137 {
6138 if (scm_is_false (scm_num_eq_p (x, y)))
6139 return SCM_BOOL_F;
6140 x = y;
6141 y = scm_car (rest);
6142 rest = scm_cdr (rest);
6143 }
6144 return scm_num_eq_p (x, y);
6145}
6146#undef FUNC_NAME
0f2d19dd 6147SCM
6e8d25a6 6148scm_num_eq_p (SCM x, SCM y)
0f2d19dd 6149{
d8b95e27 6150 again:
e11e83f3 6151 if (SCM_I_INUMP (x))
0aacf84e 6152 {
e25f3727 6153 scm_t_signed_bits xx = SCM_I_INUM (x);
e11e83f3 6154 if (SCM_I_INUMP (y))
0aacf84e 6155 {
e25f3727 6156 scm_t_signed_bits yy = SCM_I_INUM (y);
73e4de09 6157 return scm_from_bool (xx == yy);
0aacf84e
MD
6158 }
6159 else if (SCM_BIGP (y))
6160 return SCM_BOOL_F;
6161 else if (SCM_REALP (y))
e8c5b1f2
KR
6162 {
6163 /* On a 32-bit system an inum fits a double, we can cast the inum
6164 to a double and compare.
6165
6166 But on a 64-bit system an inum is bigger than a double and
6167 casting it to a double (call that dxx) will round. dxx is at
6168 worst 1 bigger or smaller than xx, so if dxx==yy we know yy is
6169 an integer and fits a long. So we cast yy to a long and
6170 compare with plain xx.
6171
6172 An alternative (for any size system actually) would be to check
6173 yy is an integer (with floor) and is in range of an inum
6174 (compare against appropriate powers of 2) then test
e25f3727
AW
6175 xx==(scm_t_signed_bits)yy. It's just a matter of which
6176 casts/comparisons might be fastest or easiest for the cpu. */
e8c5b1f2
KR
6177
6178 double yy = SCM_REAL_VALUE (y);
3a1b45fd
MV
6179 return scm_from_bool ((double) xx == yy
6180 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 6181 || xx == (scm_t_signed_bits) yy));
e8c5b1f2 6182 }
0aacf84e 6183 else if (SCM_COMPLEXP (y))
73e4de09 6184 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 6185 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
6186 else if (SCM_FRACTIONP (y))
6187 return SCM_BOOL_F;
0aacf84e 6188 else
8a1f4f98 6189 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 6190 }
0aacf84e
MD
6191 else if (SCM_BIGP (x))
6192 {
e11e83f3 6193 if (SCM_I_INUMP (y))
0aacf84e
MD
6194 return SCM_BOOL_F;
6195 else if (SCM_BIGP (y))
6196 {
6197 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6198 scm_remember_upto_here_2 (x, y);
73e4de09 6199 return scm_from_bool (0 == cmp);
0aacf84e
MD
6200 }
6201 else if (SCM_REALP (y))
6202 {
6203 int cmp;
2e65b52f 6204 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
6205 return SCM_BOOL_F;
6206 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
6207 scm_remember_upto_here_1 (x);
73e4de09 6208 return scm_from_bool (0 == cmp);
0aacf84e
MD
6209 }
6210 else if (SCM_COMPLEXP (y))
6211 {
6212 int cmp;
6213 if (0.0 != SCM_COMPLEX_IMAG (y))
6214 return SCM_BOOL_F;
2e65b52f 6215 if (isnan (SCM_COMPLEX_REAL (y)))
0aacf84e
MD
6216 return SCM_BOOL_F;
6217 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
6218 scm_remember_upto_here_1 (x);
73e4de09 6219 return scm_from_bool (0 == cmp);
0aacf84e 6220 }
f92e85f7
MV
6221 else if (SCM_FRACTIONP (y))
6222 return SCM_BOOL_F;
0aacf84e 6223 else
8a1f4f98 6224 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 6225 }
0aacf84e
MD
6226 else if (SCM_REALP (x))
6227 {
e8c5b1f2 6228 double xx = SCM_REAL_VALUE (x);
e11e83f3 6229 if (SCM_I_INUMP (y))
e8c5b1f2
KR
6230 {
6231 /* see comments with inum/real above */
e25f3727 6232 scm_t_signed_bits yy = SCM_I_INUM (y);
3a1b45fd
MV
6233 return scm_from_bool (xx == (double) yy
6234 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 6235 || (scm_t_signed_bits) xx == yy));
e8c5b1f2 6236 }
0aacf84e
MD
6237 else if (SCM_BIGP (y))
6238 {
6239 int cmp;
2e65b52f 6240 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
6241 return SCM_BOOL_F;
6242 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
6243 scm_remember_upto_here_1 (y);
73e4de09 6244 return scm_from_bool (0 == cmp);
0aacf84e
MD
6245 }
6246 else if (SCM_REALP (y))
73e4de09 6247 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 6248 else if (SCM_COMPLEXP (y))
73e4de09 6249 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 6250 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 6251 else if (SCM_FRACTIONP (y))
d8b95e27
KR
6252 {
6253 double xx = SCM_REAL_VALUE (x);
2e65b52f 6254 if (isnan (xx))
d8b95e27 6255 return SCM_BOOL_F;
2e65b52f 6256 if (isinf (xx))
73e4de09 6257 return scm_from_bool (xx < 0.0);
d8b95e27
KR
6258 x = scm_inexact_to_exact (x); /* with x as frac or int */
6259 goto again;
6260 }
0aacf84e 6261 else
8a1f4f98 6262 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f872b822 6263 }
0aacf84e
MD
6264 else if (SCM_COMPLEXP (x))
6265 {
e11e83f3
MV
6266 if (SCM_I_INUMP (y))
6267 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
6268 && (SCM_COMPLEX_IMAG (x) == 0.0));
6269 else if (SCM_BIGP (y))
6270 {
6271 int cmp;
6272 if (0.0 != SCM_COMPLEX_IMAG (x))
6273 return SCM_BOOL_F;
2e65b52f 6274 if (isnan (SCM_COMPLEX_REAL (x)))
0aacf84e
MD
6275 return SCM_BOOL_F;
6276 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
6277 scm_remember_upto_here_1 (y);
73e4de09 6278 return scm_from_bool (0 == cmp);
0aacf84e
MD
6279 }
6280 else if (SCM_REALP (y))
73e4de09 6281 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
6282 && (SCM_COMPLEX_IMAG (x) == 0.0));
6283 else if (SCM_COMPLEXP (y))
73e4de09 6284 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 6285 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 6286 else if (SCM_FRACTIONP (y))
d8b95e27
KR
6287 {
6288 double xx;
6289 if (SCM_COMPLEX_IMAG (x) != 0.0)
6290 return SCM_BOOL_F;
6291 xx = SCM_COMPLEX_REAL (x);
2e65b52f 6292 if (isnan (xx))
d8b95e27 6293 return SCM_BOOL_F;
2e65b52f 6294 if (isinf (xx))
73e4de09 6295 return scm_from_bool (xx < 0.0);
d8b95e27
KR
6296 x = scm_inexact_to_exact (x); /* with x as frac or int */
6297 goto again;
6298 }
f92e85f7 6299 else
8a1f4f98 6300 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f92e85f7
MV
6301 }
6302 else if (SCM_FRACTIONP (x))
6303 {
e11e83f3 6304 if (SCM_I_INUMP (y))
f92e85f7
MV
6305 return SCM_BOOL_F;
6306 else if (SCM_BIGP (y))
6307 return SCM_BOOL_F;
6308 else if (SCM_REALP (y))
d8b95e27
KR
6309 {
6310 double yy = SCM_REAL_VALUE (y);
2e65b52f 6311 if (isnan (yy))
d8b95e27 6312 return SCM_BOOL_F;
2e65b52f 6313 if (isinf (yy))
73e4de09 6314 return scm_from_bool (0.0 < yy);
d8b95e27
KR
6315 y = scm_inexact_to_exact (y); /* with y as frac or int */
6316 goto again;
6317 }
f92e85f7 6318 else if (SCM_COMPLEXP (y))
d8b95e27
KR
6319 {
6320 double yy;
6321 if (SCM_COMPLEX_IMAG (y) != 0.0)
6322 return SCM_BOOL_F;
6323 yy = SCM_COMPLEX_REAL (y);
2e65b52f 6324 if (isnan (yy))
d8b95e27 6325 return SCM_BOOL_F;
2e65b52f 6326 if (isinf (yy))
73e4de09 6327 return scm_from_bool (0.0 < yy);
d8b95e27
KR
6328 y = scm_inexact_to_exact (y); /* with y as frac or int */
6329 goto again;
6330 }
f92e85f7
MV
6331 else if (SCM_FRACTIONP (y))
6332 return scm_i_fraction_equalp (x, y);
0aacf84e 6333 else
8a1f4f98 6334 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn, s_scm_i_num_eq_p);
f4c627b3 6335 }
0aacf84e 6336 else
8a1f4f98 6337 SCM_WTA_DISPATCH_2 (g_scm_i_num_eq_p, x, y, SCM_ARG1, s_scm_i_num_eq_p);
0f2d19dd
JB
6338}
6339
6340
a5f0b599
KR
6341/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
6342 done are good for inums, but for bignums an answer can almost always be
6343 had by just examining a few high bits of the operands, as done by GMP in
6344 mpq_cmp. flonum/frac compares likewise, but with the slight complication
6345 of the float exponent to take into account. */
6346
8c93b597 6347SCM_INTERNAL SCM scm_i_num_less_p (SCM, SCM, SCM);
8a1f4f98
AW
6348SCM_PRIMITIVE_GENERIC (scm_i_num_less_p, "<", 0, 2, 1,
6349 (SCM x, SCM y, SCM rest),
6350 "Return @code{#t} if the list of parameters is monotonically\n"
6351 "increasing.")
6352#define FUNC_NAME s_scm_i_num_less_p
6353{
6354 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6355 return SCM_BOOL_T;
6356 while (!scm_is_null (rest))
6357 {
6358 if (scm_is_false (scm_less_p (x, y)))
6359 return SCM_BOOL_F;
6360 x = y;
6361 y = scm_car (rest);
6362 rest = scm_cdr (rest);
6363 }
6364 return scm_less_p (x, y);
6365}
6366#undef FUNC_NAME
0f2d19dd 6367SCM
6e8d25a6 6368scm_less_p (SCM x, SCM y)
0f2d19dd 6369{
a5f0b599 6370 again:
e11e83f3 6371 if (SCM_I_INUMP (x))
0aacf84e 6372 {
e25f3727 6373 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6374 if (SCM_I_INUMP (y))
0aacf84e 6375 {
e25f3727 6376 scm_t_inum yy = SCM_I_INUM (y);
73e4de09 6377 return scm_from_bool (xx < yy);
0aacf84e
MD
6378 }
6379 else if (SCM_BIGP (y))
6380 {
6381 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6382 scm_remember_upto_here_1 (y);
73e4de09 6383 return scm_from_bool (sgn > 0);
0aacf84e
MD
6384 }
6385 else if (SCM_REALP (y))
73e4de09 6386 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 6387 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6388 {
6389 /* "x < a/b" becomes "x*b < a" */
6390 int_frac:
6391 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
6392 y = SCM_FRACTION_NUMERATOR (y);
6393 goto again;
6394 }
0aacf84e 6395 else
8a1f4f98 6396 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 6397 }
0aacf84e
MD
6398 else if (SCM_BIGP (x))
6399 {
e11e83f3 6400 if (SCM_I_INUMP (y))
0aacf84e
MD
6401 {
6402 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6403 scm_remember_upto_here_1 (x);
73e4de09 6404 return scm_from_bool (sgn < 0);
0aacf84e
MD
6405 }
6406 else if (SCM_BIGP (y))
6407 {
6408 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6409 scm_remember_upto_here_2 (x, y);
73e4de09 6410 return scm_from_bool (cmp < 0);
0aacf84e
MD
6411 }
6412 else if (SCM_REALP (y))
6413 {
6414 int cmp;
2e65b52f 6415 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
6416 return SCM_BOOL_F;
6417 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
6418 scm_remember_upto_here_1 (x);
73e4de09 6419 return scm_from_bool (cmp < 0);
0aacf84e 6420 }
f92e85f7 6421 else if (SCM_FRACTIONP (y))
a5f0b599 6422 goto int_frac;
0aacf84e 6423 else
8a1f4f98 6424 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f4c627b3 6425 }
0aacf84e
MD
6426 else if (SCM_REALP (x))
6427 {
e11e83f3
MV
6428 if (SCM_I_INUMP (y))
6429 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
6430 else if (SCM_BIGP (y))
6431 {
6432 int cmp;
2e65b52f 6433 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
6434 return SCM_BOOL_F;
6435 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
6436 scm_remember_upto_here_1 (y);
73e4de09 6437 return scm_from_bool (cmp > 0);
0aacf84e
MD
6438 }
6439 else if (SCM_REALP (y))
73e4de09 6440 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 6441 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6442 {
6443 double xx = SCM_REAL_VALUE (x);
2e65b52f 6444 if (isnan (xx))
a5f0b599 6445 return SCM_BOOL_F;
2e65b52f 6446 if (isinf (xx))
73e4de09 6447 return scm_from_bool (xx < 0.0);
a5f0b599
KR
6448 x = scm_inexact_to_exact (x); /* with x as frac or int */
6449 goto again;
6450 }
f92e85f7 6451 else
8a1f4f98 6452 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f92e85f7
MV
6453 }
6454 else if (SCM_FRACTIONP (x))
6455 {
e11e83f3 6456 if (SCM_I_INUMP (y) || SCM_BIGP (y))
a5f0b599
KR
6457 {
6458 /* "a/b < y" becomes "a < y*b" */
6459 y = scm_product (y, SCM_FRACTION_DENOMINATOR (x));
6460 x = SCM_FRACTION_NUMERATOR (x);
6461 goto again;
6462 }
f92e85f7 6463 else if (SCM_REALP (y))
a5f0b599
KR
6464 {
6465 double yy = SCM_REAL_VALUE (y);
2e65b52f 6466 if (isnan (yy))
a5f0b599 6467 return SCM_BOOL_F;
2e65b52f 6468 if (isinf (yy))
73e4de09 6469 return scm_from_bool (0.0 < yy);
a5f0b599
KR
6470 y = scm_inexact_to_exact (y); /* with y as frac or int */
6471 goto again;
6472 }
f92e85f7 6473 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6474 {
6475 /* "a/b < c/d" becomes "a*d < c*b" */
6476 SCM new_x = scm_product (SCM_FRACTION_NUMERATOR (x),
6477 SCM_FRACTION_DENOMINATOR (y));
6478 SCM new_y = scm_product (SCM_FRACTION_NUMERATOR (y),
6479 SCM_FRACTION_DENOMINATOR (x));
6480 x = new_x;
6481 y = new_y;
6482 goto again;
6483 }
0aacf84e 6484 else
8a1f4f98 6485 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARGn, s_scm_i_num_less_p);
f872b822 6486 }
0aacf84e 6487 else
8a1f4f98 6488 SCM_WTA_DISPATCH_2 (g_scm_i_num_less_p, x, y, SCM_ARG1, s_scm_i_num_less_p);
0f2d19dd
JB
6489}
6490
6491
8a1f4f98
AW
6492SCM scm_i_num_gr_p (SCM, SCM, SCM);
6493SCM_PRIMITIVE_GENERIC (scm_i_num_gr_p, ">", 0, 2, 1,
6494 (SCM x, SCM y, SCM rest),
6495 "Return @code{#t} if the list of parameters is monotonically\n"
6496 "decreasing.")
6497#define FUNC_NAME s_scm_i_num_gr_p
6498{
6499 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6500 return SCM_BOOL_T;
6501 while (!scm_is_null (rest))
6502 {
6503 if (scm_is_false (scm_gr_p (x, y)))
6504 return SCM_BOOL_F;
6505 x = y;
6506 y = scm_car (rest);
6507 rest = scm_cdr (rest);
6508 }
6509 return scm_gr_p (x, y);
6510}
6511#undef FUNC_NAME
6512#define FUNC_NAME s_scm_i_num_gr_p
c76b1eaf
MD
6513SCM
6514scm_gr_p (SCM x, SCM y)
0f2d19dd 6515{
c76b1eaf 6516 if (!SCM_NUMBERP (x))
8a1f4f98 6517 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6518 else if (!SCM_NUMBERP (y))
8a1f4f98 6519 SCM_WTA_DISPATCH_2 (g_scm_i_num_gr_p, x, y, SCM_ARG2, FUNC_NAME);
c76b1eaf
MD
6520 else
6521 return scm_less_p (y, x);
0f2d19dd 6522}
1bbd0b84 6523#undef FUNC_NAME
0f2d19dd
JB
6524
6525
8a1f4f98
AW
6526SCM scm_i_num_leq_p (SCM, SCM, SCM);
6527SCM_PRIMITIVE_GENERIC (scm_i_num_leq_p, "<=", 0, 2, 1,
6528 (SCM x, SCM y, SCM rest),
6529 "Return @code{#t} if the list of parameters is monotonically\n"
6530 "non-decreasing.")
6531#define FUNC_NAME s_scm_i_num_leq_p
6532{
6533 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6534 return SCM_BOOL_T;
6535 while (!scm_is_null (rest))
6536 {
6537 if (scm_is_false (scm_leq_p (x, y)))
6538 return SCM_BOOL_F;
6539 x = y;
6540 y = scm_car (rest);
6541 rest = scm_cdr (rest);
6542 }
6543 return scm_leq_p (x, y);
6544}
6545#undef FUNC_NAME
6546#define FUNC_NAME s_scm_i_num_leq_p
c76b1eaf
MD
6547SCM
6548scm_leq_p (SCM x, SCM y)
0f2d19dd 6549{
c76b1eaf 6550 if (!SCM_NUMBERP (x))
8a1f4f98 6551 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6552 else if (!SCM_NUMBERP (y))
8a1f4f98 6553 SCM_WTA_DISPATCH_2 (g_scm_i_num_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 6554 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 6555 return SCM_BOOL_F;
c76b1eaf 6556 else
73e4de09 6557 return scm_not (scm_less_p (y, x));
0f2d19dd 6558}
1bbd0b84 6559#undef FUNC_NAME
0f2d19dd
JB
6560
6561
8a1f4f98
AW
6562SCM scm_i_num_geq_p (SCM, SCM, SCM);
6563SCM_PRIMITIVE_GENERIC (scm_i_num_geq_p, ">=", 0, 2, 1,
6564 (SCM x, SCM y, SCM rest),
6565 "Return @code{#t} if the list of parameters is monotonically\n"
6566 "non-increasing.")
6567#define FUNC_NAME s_scm_i_num_geq_p
6568{
6569 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6570 return SCM_BOOL_T;
6571 while (!scm_is_null (rest))
6572 {
6573 if (scm_is_false (scm_geq_p (x, y)))
6574 return SCM_BOOL_F;
6575 x = y;
6576 y = scm_car (rest);
6577 rest = scm_cdr (rest);
6578 }
6579 return scm_geq_p (x, y);
6580}
6581#undef FUNC_NAME
6582#define FUNC_NAME s_scm_i_num_geq_p
c76b1eaf
MD
6583SCM
6584scm_geq_p (SCM x, SCM y)
0f2d19dd 6585{
c76b1eaf 6586 if (!SCM_NUMBERP (x))
8a1f4f98 6587 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6588 else if (!SCM_NUMBERP (y))
8a1f4f98 6589 SCM_WTA_DISPATCH_2 (g_scm_i_num_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 6590 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 6591 return SCM_BOOL_F;
c76b1eaf 6592 else
73e4de09 6593 return scm_not (scm_less_p (x, y));
0f2d19dd 6594}
1bbd0b84 6595#undef FUNC_NAME
0f2d19dd
JB
6596
6597
2519490c
MW
6598SCM_PRIMITIVE_GENERIC (scm_zero_p, "zero?", 1, 0, 0,
6599 (SCM z),
6600 "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
6601 "zero.")
6602#define FUNC_NAME s_scm_zero_p
0f2d19dd 6603{
e11e83f3 6604 if (SCM_I_INUMP (z))
bc36d050 6605 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 6606 else if (SCM_BIGP (z))
c2ff8ab0 6607 return SCM_BOOL_F;
0aacf84e 6608 else if (SCM_REALP (z))
73e4de09 6609 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 6610 else if (SCM_COMPLEXP (z))
73e4de09 6611 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 6612 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
6613 else if (SCM_FRACTIONP (z))
6614 return SCM_BOOL_F;
0aacf84e 6615 else
2519490c 6616 SCM_WTA_DISPATCH_1 (g_scm_zero_p, z, SCM_ARG1, s_scm_zero_p);
0f2d19dd 6617}
2519490c 6618#undef FUNC_NAME
0f2d19dd
JB
6619
6620
2519490c
MW
6621SCM_PRIMITIVE_GENERIC (scm_positive_p, "positive?", 1, 0, 0,
6622 (SCM x),
6623 "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
6624 "zero.")
6625#define FUNC_NAME s_scm_positive_p
0f2d19dd 6626{
e11e83f3
MV
6627 if (SCM_I_INUMP (x))
6628 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
6629 else if (SCM_BIGP (x))
6630 {
6631 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6632 scm_remember_upto_here_1 (x);
73e4de09 6633 return scm_from_bool (sgn > 0);
0aacf84e
MD
6634 }
6635 else if (SCM_REALP (x))
73e4de09 6636 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
6637 else if (SCM_FRACTIONP (x))
6638 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 6639 else
2519490c 6640 SCM_WTA_DISPATCH_1 (g_scm_positive_p, x, SCM_ARG1, s_scm_positive_p);
0f2d19dd 6641}
2519490c 6642#undef FUNC_NAME
0f2d19dd
JB
6643
6644
2519490c
MW
6645SCM_PRIMITIVE_GENERIC (scm_negative_p, "negative?", 1, 0, 0,
6646 (SCM x),
6647 "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
6648 "zero.")
6649#define FUNC_NAME s_scm_negative_p
0f2d19dd 6650{
e11e83f3
MV
6651 if (SCM_I_INUMP (x))
6652 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
6653 else if (SCM_BIGP (x))
6654 {
6655 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6656 scm_remember_upto_here_1 (x);
73e4de09 6657 return scm_from_bool (sgn < 0);
0aacf84e
MD
6658 }
6659 else if (SCM_REALP (x))
73e4de09 6660 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
6661 else if (SCM_FRACTIONP (x))
6662 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 6663 else
2519490c 6664 SCM_WTA_DISPATCH_1 (g_scm_negative_p, x, SCM_ARG1, s_scm_negative_p);
0f2d19dd 6665}
2519490c 6666#undef FUNC_NAME
0f2d19dd
JB
6667
6668
2a06f791
KR
6669/* scm_min and scm_max return an inexact when either argument is inexact, as
6670 required by r5rs. On that basis, for exact/inexact combinations the
6671 exact is converted to inexact to compare and possibly return. This is
6672 unlike scm_less_p above which takes some trouble to preserve all bits in
6673 its test, such trouble is not required for min and max. */
6674
78d3deb1
AW
6675SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
6676 (SCM x, SCM y, SCM rest),
6677 "Return the maximum of all parameter values.")
6678#define FUNC_NAME s_scm_i_max
6679{
6680 while (!scm_is_null (rest))
6681 { x = scm_max (x, y);
6682 y = scm_car (rest);
6683 rest = scm_cdr (rest);
6684 }
6685 return scm_max (x, y);
6686}
6687#undef FUNC_NAME
6688
6689#define s_max s_scm_i_max
6690#define g_max g_scm_i_max
6691
0f2d19dd 6692SCM
6e8d25a6 6693scm_max (SCM x, SCM y)
0f2d19dd 6694{
0aacf84e
MD
6695 if (SCM_UNBNDP (y))
6696 {
6697 if (SCM_UNBNDP (x))
6698 SCM_WTA_DISPATCH_0 (g_max, s_max);
e11e83f3 6699 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
6700 return x;
6701 else
6702 SCM_WTA_DISPATCH_1 (g_max, x, SCM_ARG1, s_max);
f872b822 6703 }
f4c627b3 6704
e11e83f3 6705 if (SCM_I_INUMP (x))
0aacf84e 6706 {
e25f3727 6707 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6708 if (SCM_I_INUMP (y))
0aacf84e 6709 {
e25f3727 6710 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6711 return (xx < yy) ? y : x;
6712 }
6713 else if (SCM_BIGP (y))
6714 {
6715 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6716 scm_remember_upto_here_1 (y);
6717 return (sgn < 0) ? x : y;
6718 }
6719 else if (SCM_REALP (y))
6720 {
2e274311
MW
6721 double xxd = xx;
6722 double yyd = SCM_REAL_VALUE (y);
6723
6724 if (xxd > yyd)
6725 return scm_from_double (xxd);
6726 /* If y is a NaN, then "==" is false and we return the NaN */
6727 else if (SCM_LIKELY (!(xxd == yyd)))
6728 return y;
6729 /* Handle signed zeroes properly */
6730 else if (xx == 0)
6731 return flo0;
6732 else
6733 return y;
0aacf84e 6734 }
f92e85f7
MV
6735 else if (SCM_FRACTIONP (y))
6736 {
e4bc5d6c 6737 use_less:
73e4de09 6738 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 6739 }
0aacf84e
MD
6740 else
6741 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 6742 }
0aacf84e
MD
6743 else if (SCM_BIGP (x))
6744 {
e11e83f3 6745 if (SCM_I_INUMP (y))
0aacf84e
MD
6746 {
6747 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6748 scm_remember_upto_here_1 (x);
6749 return (sgn < 0) ? y : x;
6750 }
6751 else if (SCM_BIGP (y))
6752 {
6753 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6754 scm_remember_upto_here_2 (x, y);
6755 return (cmp > 0) ? x : y;
6756 }
6757 else if (SCM_REALP (y))
6758 {
2a06f791
KR
6759 /* if y==NaN then xx>yy is false, so we return the NaN y */
6760 double xx, yy;
6761 big_real:
6762 xx = scm_i_big2dbl (x);
6763 yy = SCM_REAL_VALUE (y);
55f26379 6764 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 6765 }
f92e85f7
MV
6766 else if (SCM_FRACTIONP (y))
6767 {
e4bc5d6c 6768 goto use_less;
f92e85f7 6769 }
0aacf84e
MD
6770 else
6771 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 6772 }
0aacf84e
MD
6773 else if (SCM_REALP (x))
6774 {
e11e83f3 6775 if (SCM_I_INUMP (y))
0aacf84e 6776 {
2e274311
MW
6777 scm_t_inum yy = SCM_I_INUM (y);
6778 double xxd = SCM_REAL_VALUE (x);
6779 double yyd = yy;
6780
6781 if (yyd > xxd)
6782 return scm_from_double (yyd);
6783 /* If x is a NaN, then "==" is false and we return the NaN */
6784 else if (SCM_LIKELY (!(xxd == yyd)))
6785 return x;
6786 /* Handle signed zeroes properly */
6787 else if (yy == 0)
6788 return flo0;
6789 else
6790 return x;
0aacf84e
MD
6791 }
6792 else if (SCM_BIGP (y))
6793 {
b6f8f763 6794 SCM_SWAP (x, y);
2a06f791 6795 goto big_real;
0aacf84e
MD
6796 }
6797 else if (SCM_REALP (y))
6798 {
0aacf84e 6799 double xx = SCM_REAL_VALUE (x);
2e274311
MW
6800 double yy = SCM_REAL_VALUE (y);
6801
6802 /* For purposes of max: +inf.0 > nan > everything else, per R6RS */
6803 if (xx > yy)
6804 return x;
6805 else if (SCM_LIKELY (xx < yy))
6806 return y;
6807 /* If neither (xx > yy) nor (xx < yy), then
6808 either they're equal or one is a NaN */
6809 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 6810 return DOUBLE_IS_POSITIVE_INFINITY (yy) ? y : x;
2e274311 6811 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 6812 return DOUBLE_IS_POSITIVE_INFINITY (xx) ? x : y;
2e274311
MW
6813 /* xx == yy, but handle signed zeroes properly */
6814 else if (double_is_non_negative_zero (yy))
6815 return y;
6816 else
6817 return x;
0aacf84e 6818 }
f92e85f7
MV
6819 else if (SCM_FRACTIONP (y))
6820 {
6821 double yy = scm_i_fraction2double (y);
6822 double xx = SCM_REAL_VALUE (x);
55f26379 6823 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
6824 }
6825 else
6826 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
6827 }
6828 else if (SCM_FRACTIONP (x))
6829 {
e11e83f3 6830 if (SCM_I_INUMP (y))
f92e85f7 6831 {
e4bc5d6c 6832 goto use_less;
f92e85f7
MV
6833 }
6834 else if (SCM_BIGP (y))
6835 {
e4bc5d6c 6836 goto use_less;
f92e85f7
MV
6837 }
6838 else if (SCM_REALP (y))
6839 {
6840 double xx = scm_i_fraction2double (x);
2e274311
MW
6841 /* if y==NaN then ">" is false, so we return the NaN y */
6842 return (xx > SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
6843 }
6844 else if (SCM_FRACTIONP (y))
6845 {
e4bc5d6c 6846 goto use_less;
f92e85f7 6847 }
0aacf84e
MD
6848 else
6849 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 6850 }
0aacf84e 6851 else
f4c627b3 6852 SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
6853}
6854
6855
78d3deb1
AW
6856SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
6857 (SCM x, SCM y, SCM rest),
6858 "Return the minimum of all parameter values.")
6859#define FUNC_NAME s_scm_i_min
6860{
6861 while (!scm_is_null (rest))
6862 { x = scm_min (x, y);
6863 y = scm_car (rest);
6864 rest = scm_cdr (rest);
6865 }
6866 return scm_min (x, y);
6867}
6868#undef FUNC_NAME
6869
6870#define s_min s_scm_i_min
6871#define g_min g_scm_i_min
6872
0f2d19dd 6873SCM
6e8d25a6 6874scm_min (SCM x, SCM y)
0f2d19dd 6875{
0aacf84e
MD
6876 if (SCM_UNBNDP (y))
6877 {
6878 if (SCM_UNBNDP (x))
6879 SCM_WTA_DISPATCH_0 (g_min, s_min);
e11e83f3 6880 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
6881 return x;
6882 else
6883 SCM_WTA_DISPATCH_1 (g_min, x, SCM_ARG1, s_min);
f872b822 6884 }
f4c627b3 6885
e11e83f3 6886 if (SCM_I_INUMP (x))
0aacf84e 6887 {
e25f3727 6888 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6889 if (SCM_I_INUMP (y))
0aacf84e 6890 {
e25f3727 6891 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6892 return (xx < yy) ? x : y;
6893 }
6894 else if (SCM_BIGP (y))
6895 {
6896 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6897 scm_remember_upto_here_1 (y);
6898 return (sgn < 0) ? y : x;
6899 }
6900 else if (SCM_REALP (y))
6901 {
6902 double z = xx;
6903 /* if y==NaN then "<" is false and we return NaN */
55f26379 6904 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 6905 }
f92e85f7
MV
6906 else if (SCM_FRACTIONP (y))
6907 {
e4bc5d6c 6908 use_less:
73e4de09 6909 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 6910 }
0aacf84e
MD
6911 else
6912 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 6913 }
0aacf84e
MD
6914 else if (SCM_BIGP (x))
6915 {
e11e83f3 6916 if (SCM_I_INUMP (y))
0aacf84e
MD
6917 {
6918 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6919 scm_remember_upto_here_1 (x);
6920 return (sgn < 0) ? x : y;
6921 }
6922 else if (SCM_BIGP (y))
6923 {
6924 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6925 scm_remember_upto_here_2 (x, y);
6926 return (cmp > 0) ? y : x;
6927 }
6928 else if (SCM_REALP (y))
6929 {
2a06f791
KR
6930 /* if y==NaN then xx<yy is false, so we return the NaN y */
6931 double xx, yy;
6932 big_real:
6933 xx = scm_i_big2dbl (x);
6934 yy = SCM_REAL_VALUE (y);
55f26379 6935 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 6936 }
f92e85f7
MV
6937 else if (SCM_FRACTIONP (y))
6938 {
e4bc5d6c 6939 goto use_less;
f92e85f7 6940 }
0aacf84e
MD
6941 else
6942 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 6943 }
0aacf84e
MD
6944 else if (SCM_REALP (x))
6945 {
e11e83f3 6946 if (SCM_I_INUMP (y))
0aacf84e 6947 {
e11e83f3 6948 double z = SCM_I_INUM (y);
0aacf84e 6949 /* if x==NaN then "<" is false and we return NaN */
55f26379 6950 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
6951 }
6952 else if (SCM_BIGP (y))
6953 {
b6f8f763 6954 SCM_SWAP (x, y);
2a06f791 6955 goto big_real;
0aacf84e
MD
6956 }
6957 else if (SCM_REALP (y))
6958 {
0aacf84e 6959 double xx = SCM_REAL_VALUE (x);
2e274311
MW
6960 double yy = SCM_REAL_VALUE (y);
6961
6962 /* For purposes of min: -inf.0 < nan < everything else, per R6RS */
6963 if (xx < yy)
6964 return x;
6965 else if (SCM_LIKELY (xx > yy))
6966 return y;
6967 /* If neither (xx < yy) nor (xx > yy), then
6968 either they're equal or one is a NaN */
6969 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 6970 return DOUBLE_IS_NEGATIVE_INFINITY (yy) ? y : x;
2e274311 6971 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 6972 return DOUBLE_IS_NEGATIVE_INFINITY (xx) ? x : y;
2e274311
MW
6973 /* xx == yy, but handle signed zeroes properly */
6974 else if (double_is_non_negative_zero (xx))
6975 return y;
6976 else
6977 return x;
0aacf84e 6978 }
f92e85f7
MV
6979 else if (SCM_FRACTIONP (y))
6980 {
6981 double yy = scm_i_fraction2double (y);
6982 double xx = SCM_REAL_VALUE (x);
55f26379 6983 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 6984 }
0aacf84e
MD
6985 else
6986 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 6987 }
f92e85f7
MV
6988 else if (SCM_FRACTIONP (x))
6989 {
e11e83f3 6990 if (SCM_I_INUMP (y))
f92e85f7 6991 {
e4bc5d6c 6992 goto use_less;
f92e85f7
MV
6993 }
6994 else if (SCM_BIGP (y))
6995 {
e4bc5d6c 6996 goto use_less;
f92e85f7
MV
6997 }
6998 else if (SCM_REALP (y))
6999 {
7000 double xx = scm_i_fraction2double (x);
2e274311
MW
7001 /* if y==NaN then "<" is false, so we return the NaN y */
7002 return (xx < SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
7003 }
7004 else if (SCM_FRACTIONP (y))
7005 {
e4bc5d6c 7006 goto use_less;
f92e85f7
MV
7007 }
7008 else
78d3deb1 7009 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
f92e85f7 7010 }
0aacf84e 7011 else
f4c627b3 7012 SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
7013}
7014
7015
8ccd24f7
AW
7016SCM_PRIMITIVE_GENERIC (scm_i_sum, "+", 0, 2, 1,
7017 (SCM x, SCM y, SCM rest),
7018 "Return the sum of all parameter values. Return 0 if called without\n"
7019 "any parameters." )
7020#define FUNC_NAME s_scm_i_sum
7021{
7022 while (!scm_is_null (rest))
7023 { x = scm_sum (x, y);
7024 y = scm_car (rest);
7025 rest = scm_cdr (rest);
7026 }
7027 return scm_sum (x, y);
7028}
7029#undef FUNC_NAME
7030
7031#define s_sum s_scm_i_sum
7032#define g_sum g_scm_i_sum
7033
0f2d19dd 7034SCM
6e8d25a6 7035scm_sum (SCM x, SCM y)
0f2d19dd 7036{
9cc37597 7037 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
7038 {
7039 if (SCM_NUMBERP (x)) return x;
7040 if (SCM_UNBNDP (x)) return SCM_INUM0;
98cb6e75 7041 SCM_WTA_DISPATCH_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 7042 }
c209c88e 7043
9cc37597 7044 if (SCM_LIKELY (SCM_I_INUMP (x)))
ca46fb90 7045 {
9cc37597 7046 if (SCM_LIKELY (SCM_I_INUMP (y)))
ca46fb90 7047 {
e25f3727
AW
7048 scm_t_inum xx = SCM_I_INUM (x);
7049 scm_t_inum yy = SCM_I_INUM (y);
7050 scm_t_inum z = xx + yy;
7051 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_inum2big (z);
ca46fb90
RB
7052 }
7053 else if (SCM_BIGP (y))
7054 {
7055 SCM_SWAP (x, y);
7056 goto add_big_inum;
7057 }
7058 else if (SCM_REALP (y))
7059 {
e25f3727 7060 scm_t_inum xx = SCM_I_INUM (x);
55f26379 7061 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
7062 }
7063 else if (SCM_COMPLEXP (y))
7064 {
e25f3727 7065 scm_t_inum xx = SCM_I_INUM (x);
8507ec80 7066 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
7067 SCM_COMPLEX_IMAG (y));
7068 }
f92e85f7 7069 else if (SCM_FRACTIONP (y))
cba42c93 7070 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
7071 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
7072 SCM_FRACTION_DENOMINATOR (y));
ca46fb90
RB
7073 else
7074 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
7075 } else if (SCM_BIGP (x))
7076 {
e11e83f3 7077 if (SCM_I_INUMP (y))
0aacf84e 7078 {
e25f3727 7079 scm_t_inum inum;
0aacf84e
MD
7080 int bigsgn;
7081 add_big_inum:
e11e83f3 7082 inum = SCM_I_INUM (y);
0aacf84e
MD
7083 if (inum == 0)
7084 return x;
7085 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
7086 if (inum < 0)
7087 {
7088 SCM result = scm_i_mkbig ();
7089 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
7090 scm_remember_upto_here_1 (x);
7091 /* we know the result will have to be a bignum */
7092 if (bigsgn == -1)
7093 return result;
7094 return scm_i_normbig (result);
7095 }
7096 else
7097 {
7098 SCM result = scm_i_mkbig ();
7099 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
7100 scm_remember_upto_here_1 (x);
7101 /* we know the result will have to be a bignum */
7102 if (bigsgn == 1)
7103 return result;
7104 return scm_i_normbig (result);
7105 }
7106 }
7107 else if (SCM_BIGP (y))
7108 {
7109 SCM result = scm_i_mkbig ();
7110 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
7111 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7112 mpz_add (SCM_I_BIG_MPZ (result),
7113 SCM_I_BIG_MPZ (x),
7114 SCM_I_BIG_MPZ (y));
7115 scm_remember_upto_here_2 (x, y);
7116 /* we know the result will have to be a bignum */
7117 if (sgn_x == sgn_y)
7118 return result;
7119 return scm_i_normbig (result);
7120 }
7121 else if (SCM_REALP (y))
7122 {
7123 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
7124 scm_remember_upto_here_1 (x);
55f26379 7125 return scm_from_double (result);
0aacf84e
MD
7126 }
7127 else if (SCM_COMPLEXP (y))
7128 {
7129 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
7130 + SCM_COMPLEX_REAL (y));
7131 scm_remember_upto_here_1 (x);
8507ec80 7132 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 7133 }
f92e85f7 7134 else if (SCM_FRACTIONP (y))
cba42c93 7135 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
7136 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
7137 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7138 else
7139 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 7140 }
0aacf84e
MD
7141 else if (SCM_REALP (x))
7142 {
e11e83f3 7143 if (SCM_I_INUMP (y))
55f26379 7144 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
7145 else if (SCM_BIGP (y))
7146 {
7147 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
7148 scm_remember_upto_here_1 (y);
55f26379 7149 return scm_from_double (result);
0aacf84e
MD
7150 }
7151 else if (SCM_REALP (y))
55f26379 7152 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 7153 else if (SCM_COMPLEXP (y))
8507ec80 7154 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 7155 SCM_COMPLEX_IMAG (y));
f92e85f7 7156 else if (SCM_FRACTIONP (y))
55f26379 7157 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e
MD
7158 else
7159 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 7160 }
0aacf84e
MD
7161 else if (SCM_COMPLEXP (x))
7162 {
e11e83f3 7163 if (SCM_I_INUMP (y))
8507ec80 7164 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
7165 SCM_COMPLEX_IMAG (x));
7166 else if (SCM_BIGP (y))
7167 {
7168 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
7169 + SCM_COMPLEX_REAL (x));
7170 scm_remember_upto_here_1 (y);
8507ec80 7171 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
7172 }
7173 else if (SCM_REALP (y))
8507ec80 7174 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
7175 SCM_COMPLEX_IMAG (x));
7176 else if (SCM_COMPLEXP (y))
8507ec80 7177 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 7178 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 7179 else if (SCM_FRACTIONP (y))
8507ec80 7180 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
7181 SCM_COMPLEX_IMAG (x));
7182 else
7183 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
7184 }
7185 else if (SCM_FRACTIONP (x))
7186 {
e11e83f3 7187 if (SCM_I_INUMP (y))
cba42c93 7188 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7189 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
7190 SCM_FRACTION_DENOMINATOR (x));
7191 else if (SCM_BIGP (y))
cba42c93 7192 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7193 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
7194 SCM_FRACTION_DENOMINATOR (x));
7195 else if (SCM_REALP (y))
55f26379 7196 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 7197 else if (SCM_COMPLEXP (y))
8507ec80 7198 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
7199 SCM_COMPLEX_IMAG (y));
7200 else if (SCM_FRACTIONP (y))
7201 /* a/b + c/d = (ad + bc) / bd */
cba42c93 7202 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7203 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
7204 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
7205 else
7206 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 7207 }
0aacf84e 7208 else
98cb6e75 7209 SCM_WTA_DISPATCH_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
7210}
7211
7212
40882e3d
KR
7213SCM_DEFINE (scm_oneplus, "1+", 1, 0, 0,
7214 (SCM x),
7215 "Return @math{@var{x}+1}.")
7216#define FUNC_NAME s_scm_oneplus
7217{
cff5fa33 7218 return scm_sum (x, SCM_INUM1);
40882e3d
KR
7219}
7220#undef FUNC_NAME
7221
7222
78d3deb1
AW
7223SCM_PRIMITIVE_GENERIC (scm_i_difference, "-", 0, 2, 1,
7224 (SCM x, SCM y, SCM rest),
7225 "If called with one argument @var{z1}, -@var{z1} returned. Otherwise\n"
7226 "the sum of all but the first argument are subtracted from the first\n"
7227 "argument.")
7228#define FUNC_NAME s_scm_i_difference
7229{
7230 while (!scm_is_null (rest))
7231 { x = scm_difference (x, y);
7232 y = scm_car (rest);
7233 rest = scm_cdr (rest);
7234 }
7235 return scm_difference (x, y);
7236}
7237#undef FUNC_NAME
7238
7239#define s_difference s_scm_i_difference
7240#define g_difference g_scm_i_difference
7241
0f2d19dd 7242SCM
6e8d25a6 7243scm_difference (SCM x, SCM y)
78d3deb1 7244#define FUNC_NAME s_difference
0f2d19dd 7245{
9cc37597 7246 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
7247 {
7248 if (SCM_UNBNDP (x))
7249 SCM_WTA_DISPATCH_0 (g_difference, s_difference);
7250 else
e11e83f3 7251 if (SCM_I_INUMP (x))
ca46fb90 7252 {
e25f3727 7253 scm_t_inum xx = -SCM_I_INUM (x);
ca46fb90 7254 if (SCM_FIXABLE (xx))
d956fa6f 7255 return SCM_I_MAKINUM (xx);
ca46fb90 7256 else
e25f3727 7257 return scm_i_inum2big (xx);
ca46fb90
RB
7258 }
7259 else if (SCM_BIGP (x))
a9ad4847
KR
7260 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
7261 bignum, but negating that gives a fixnum. */
ca46fb90
RB
7262 return scm_i_normbig (scm_i_clonebig (x, 0));
7263 else if (SCM_REALP (x))
55f26379 7264 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 7265 else if (SCM_COMPLEXP (x))
8507ec80 7266 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 7267 -SCM_COMPLEX_IMAG (x));
f92e85f7 7268 else if (SCM_FRACTIONP (x))
cba42c93 7269 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 7270 SCM_FRACTION_DENOMINATOR (x));
ca46fb90
RB
7271 else
7272 SCM_WTA_DISPATCH_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 7273 }
ca46fb90 7274
9cc37597 7275 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7276 {
9cc37597 7277 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7278 {
e25f3727
AW
7279 scm_t_inum xx = SCM_I_INUM (x);
7280 scm_t_inum yy = SCM_I_INUM (y);
7281 scm_t_inum z = xx - yy;
0aacf84e 7282 if (SCM_FIXABLE (z))
d956fa6f 7283 return SCM_I_MAKINUM (z);
0aacf84e 7284 else
e25f3727 7285 return scm_i_inum2big (z);
0aacf84e
MD
7286 }
7287 else if (SCM_BIGP (y))
7288 {
7289 /* inum-x - big-y */
e25f3727 7290 scm_t_inum xx = SCM_I_INUM (x);
ca46fb90 7291
0aacf84e 7292 if (xx == 0)
b5c40589
MW
7293 {
7294 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
7295 bignum, but negating that gives a fixnum. */
7296 return scm_i_normbig (scm_i_clonebig (y, 0));
7297 }
0aacf84e
MD
7298 else
7299 {
7300 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7301 SCM result = scm_i_mkbig ();
ca46fb90 7302
0aacf84e
MD
7303 if (xx >= 0)
7304 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
7305 else
7306 {
7307 /* x - y == -(y + -x) */
7308 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
7309 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
7310 }
7311 scm_remember_upto_here_1 (y);
ca46fb90 7312
0aacf84e
MD
7313 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
7314 /* we know the result will have to be a bignum */
7315 return result;
7316 else
7317 return scm_i_normbig (result);
7318 }
7319 }
7320 else if (SCM_REALP (y))
7321 {
e25f3727 7322 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
7323
7324 /*
7325 * We need to handle x == exact 0
7326 * specially because R6RS states that:
7327 * (- 0.0) ==> -0.0 and
7328 * (- 0.0 0.0) ==> 0.0
7329 * and the scheme compiler changes
7330 * (- 0.0) into (- 0 0.0)
7331 * So we need to treat (- 0 0.0) like (- 0.0).
7332 * At the C level, (-x) is different than (0.0 - x).
7333 * (0.0 - 0.0) ==> 0.0, but (- 0.0) ==> -0.0.
7334 */
7335 if (xx == 0)
7336 return scm_from_double (- SCM_REAL_VALUE (y));
7337 else
7338 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
7339 }
7340 else if (SCM_COMPLEXP (y))
7341 {
e25f3727 7342 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
7343
7344 /* We need to handle x == exact 0 specially.
7345 See the comment above (for SCM_REALP (y)) */
7346 if (xx == 0)
7347 return scm_c_make_rectangular (- SCM_COMPLEX_REAL (y),
7348 - SCM_COMPLEX_IMAG (y));
7349 else
7350 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
7351 - SCM_COMPLEX_IMAG (y));
0aacf84e 7352 }
f92e85f7
MV
7353 else if (SCM_FRACTIONP (y))
7354 /* a - b/c = (ac - b) / c */
cba42c93 7355 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7356 SCM_FRACTION_NUMERATOR (y)),
7357 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7358 else
7359 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 7360 }
0aacf84e
MD
7361 else if (SCM_BIGP (x))
7362 {
e11e83f3 7363 if (SCM_I_INUMP (y))
0aacf84e
MD
7364 {
7365 /* big-x - inum-y */
e25f3727 7366 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e 7367 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 7368
0aacf84e
MD
7369 scm_remember_upto_here_1 (x);
7370 if (sgn_x == 0)
c71b0706 7371 return (SCM_FIXABLE (-yy) ?
e25f3727 7372 SCM_I_MAKINUM (-yy) : scm_from_inum (-yy));
0aacf84e
MD
7373 else
7374 {
7375 SCM result = scm_i_mkbig ();
ca46fb90 7376
708f22c6
KR
7377 if (yy >= 0)
7378 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
7379 else
7380 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 7381 scm_remember_upto_here_1 (x);
ca46fb90 7382
0aacf84e
MD
7383 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
7384 /* we know the result will have to be a bignum */
7385 return result;
7386 else
7387 return scm_i_normbig (result);
7388 }
7389 }
7390 else if (SCM_BIGP (y))
7391 {
7392 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
7393 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7394 SCM result = scm_i_mkbig ();
7395 mpz_sub (SCM_I_BIG_MPZ (result),
7396 SCM_I_BIG_MPZ (x),
7397 SCM_I_BIG_MPZ (y));
7398 scm_remember_upto_here_2 (x, y);
7399 /* we know the result will have to be a bignum */
7400 if ((sgn_x == 1) && (sgn_y == -1))
7401 return result;
7402 if ((sgn_x == -1) && (sgn_y == 1))
7403 return result;
7404 return scm_i_normbig (result);
7405 }
7406 else if (SCM_REALP (y))
7407 {
7408 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
7409 scm_remember_upto_here_1 (x);
55f26379 7410 return scm_from_double (result);
0aacf84e
MD
7411 }
7412 else if (SCM_COMPLEXP (y))
7413 {
7414 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
7415 - SCM_COMPLEX_REAL (y));
7416 scm_remember_upto_here_1 (x);
8507ec80 7417 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 7418 }
f92e85f7 7419 else if (SCM_FRACTIONP (y))
cba42c93 7420 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7421 SCM_FRACTION_NUMERATOR (y)),
7422 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 7423 else SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 7424 }
0aacf84e
MD
7425 else if (SCM_REALP (x))
7426 {
e11e83f3 7427 if (SCM_I_INUMP (y))
55f26379 7428 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
7429 else if (SCM_BIGP (y))
7430 {
7431 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
7432 scm_remember_upto_here_1 (x);
55f26379 7433 return scm_from_double (result);
0aacf84e
MD
7434 }
7435 else if (SCM_REALP (y))
55f26379 7436 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 7437 else if (SCM_COMPLEXP (y))
8507ec80 7438 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 7439 -SCM_COMPLEX_IMAG (y));
f92e85f7 7440 else if (SCM_FRACTIONP (y))
55f26379 7441 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e
MD
7442 else
7443 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 7444 }
0aacf84e
MD
7445 else if (SCM_COMPLEXP (x))
7446 {
e11e83f3 7447 if (SCM_I_INUMP (y))
8507ec80 7448 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
7449 SCM_COMPLEX_IMAG (x));
7450 else if (SCM_BIGP (y))
7451 {
7452 double real_part = (SCM_COMPLEX_REAL (x)
7453 - mpz_get_d (SCM_I_BIG_MPZ (y)));
7454 scm_remember_upto_here_1 (x);
8507ec80 7455 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
7456 }
7457 else if (SCM_REALP (y))
8507ec80 7458 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
7459 SCM_COMPLEX_IMAG (x));
7460 else if (SCM_COMPLEXP (y))
8507ec80 7461 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 7462 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 7463 else if (SCM_FRACTIONP (y))
8507ec80 7464 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
7465 SCM_COMPLEX_IMAG (x));
7466 else
7467 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
7468 }
7469 else if (SCM_FRACTIONP (x))
7470 {
e11e83f3 7471 if (SCM_I_INUMP (y))
f92e85f7 7472 /* a/b - c = (a - cb) / b */
cba42c93 7473 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7474 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
7475 SCM_FRACTION_DENOMINATOR (x));
7476 else if (SCM_BIGP (y))
cba42c93 7477 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7478 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
7479 SCM_FRACTION_DENOMINATOR (x));
7480 else if (SCM_REALP (y))
55f26379 7481 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 7482 else if (SCM_COMPLEXP (y))
8507ec80 7483 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
7484 -SCM_COMPLEX_IMAG (y));
7485 else if (SCM_FRACTIONP (y))
7486 /* a/b - c/d = (ad - bc) / bd */
cba42c93 7487 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7488 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
7489 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
7490 else
7491 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 7492 }
0aacf84e 7493 else
98cb6e75 7494 SCM_WTA_DISPATCH_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 7495}
c05e97b7 7496#undef FUNC_NAME
0f2d19dd 7497
ca46fb90 7498
40882e3d
KR
7499SCM_DEFINE (scm_oneminus, "1-", 1, 0, 0,
7500 (SCM x),
7501 "Return @math{@var{x}-1}.")
7502#define FUNC_NAME s_scm_oneminus
7503{
cff5fa33 7504 return scm_difference (x, SCM_INUM1);
40882e3d
KR
7505}
7506#undef FUNC_NAME
7507
7508
78d3deb1
AW
7509SCM_PRIMITIVE_GENERIC (scm_i_product, "*", 0, 2, 1,
7510 (SCM x, SCM y, SCM rest),
7511 "Return the product of all arguments. If called without arguments,\n"
7512 "1 is returned.")
7513#define FUNC_NAME s_scm_i_product
7514{
7515 while (!scm_is_null (rest))
7516 { x = scm_product (x, y);
7517 y = scm_car (rest);
7518 rest = scm_cdr (rest);
7519 }
7520 return scm_product (x, y);
7521}
7522#undef FUNC_NAME
7523
7524#define s_product s_scm_i_product
7525#define g_product g_scm_i_product
7526
0f2d19dd 7527SCM
6e8d25a6 7528scm_product (SCM x, SCM y)
0f2d19dd 7529{
9cc37597 7530 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
7531 {
7532 if (SCM_UNBNDP (x))
d956fa6f 7533 return SCM_I_MAKINUM (1L);
0aacf84e
MD
7534 else if (SCM_NUMBERP (x))
7535 return x;
7536 else
7537 SCM_WTA_DISPATCH_1 (g_product, x, SCM_ARG1, s_product);
f872b822 7538 }
ca46fb90 7539
9cc37597 7540 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7541 {
e25f3727 7542 scm_t_inum xx;
f4c627b3 7543
5e791807 7544 xinum:
e11e83f3 7545 xx = SCM_I_INUM (x);
f4c627b3 7546
0aacf84e
MD
7547 switch (xx)
7548 {
5e791807
MW
7549 case 1:
7550 /* exact1 is the universal multiplicative identity */
7551 return y;
7552 break;
7553 case 0:
7554 /* exact0 times a fixnum is exact0: optimize this case */
7555 if (SCM_LIKELY (SCM_I_INUMP (y)))
7556 return SCM_INUM0;
7557 /* if the other argument is inexact, the result is inexact,
7558 and we must do the multiplication in order to handle
7559 infinities and NaNs properly. */
7560 else if (SCM_REALP (y))
7561 return scm_from_double (0.0 * SCM_REAL_VALUE (y));
7562 else if (SCM_COMPLEXP (y))
7563 return scm_c_make_rectangular (0.0 * SCM_COMPLEX_REAL (y),
7564 0.0 * SCM_COMPLEX_IMAG (y));
7565 /* we've already handled inexact numbers,
7566 so y must be exact, and we return exact0 */
7567 else if (SCM_NUMP (y))
7568 return SCM_INUM0;
7569 else
7570 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
7571 break;
7572 case -1:
b5c40589 7573 /*
5e791807
MW
7574 * This case is important for more than just optimization.
7575 * It handles the case of negating
b5c40589
MW
7576 * (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
7577 * which is a bignum that must be changed back into a fixnum.
7578 * Failure to do so will cause the following to return #f:
7579 * (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
7580 */
b5c40589
MW
7581 return scm_difference(y, SCM_UNDEFINED);
7582 break;
0aacf84e 7583 }
f4c627b3 7584
9cc37597 7585 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7586 {
e25f3727
AW
7587 scm_t_inum yy = SCM_I_INUM (y);
7588 scm_t_inum kk = xx * yy;
d956fa6f 7589 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 7590 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
7591 return k;
7592 else
7593 {
e25f3727 7594 SCM result = scm_i_inum2big (xx);
0aacf84e
MD
7595 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
7596 return scm_i_normbig (result);
7597 }
7598 }
7599 else if (SCM_BIGP (y))
7600 {
7601 SCM result = scm_i_mkbig ();
7602 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
7603 scm_remember_upto_here_1 (y);
7604 return result;
7605 }
7606 else if (SCM_REALP (y))
55f26379 7607 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 7608 else if (SCM_COMPLEXP (y))
8507ec80 7609 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 7610 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 7611 else if (SCM_FRACTIONP (y))
cba42c93 7612 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 7613 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7614 else
7615 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7616 }
0aacf84e
MD
7617 else if (SCM_BIGP (x))
7618 {
e11e83f3 7619 if (SCM_I_INUMP (y))
0aacf84e
MD
7620 {
7621 SCM_SWAP (x, y);
5e791807 7622 goto xinum;
0aacf84e
MD
7623 }
7624 else if (SCM_BIGP (y))
7625 {
7626 SCM result = scm_i_mkbig ();
7627 mpz_mul (SCM_I_BIG_MPZ (result),
7628 SCM_I_BIG_MPZ (x),
7629 SCM_I_BIG_MPZ (y));
7630 scm_remember_upto_here_2 (x, y);
7631 return result;
7632 }
7633 else if (SCM_REALP (y))
7634 {
7635 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
7636 scm_remember_upto_here_1 (x);
55f26379 7637 return scm_from_double (result);
0aacf84e
MD
7638 }
7639 else if (SCM_COMPLEXP (y))
7640 {
7641 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
7642 scm_remember_upto_here_1 (x);
8507ec80 7643 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
7644 z * SCM_COMPLEX_IMAG (y));
7645 }
f92e85f7 7646 else if (SCM_FRACTIONP (y))
cba42c93 7647 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 7648 SCM_FRACTION_DENOMINATOR (y));
0aacf84e
MD
7649 else
7650 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7651 }
0aacf84e
MD
7652 else if (SCM_REALP (x))
7653 {
e11e83f3 7654 if (SCM_I_INUMP (y))
5e791807
MW
7655 {
7656 SCM_SWAP (x, y);
7657 goto xinum;
7658 }
0aacf84e
MD
7659 else if (SCM_BIGP (y))
7660 {
7661 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
7662 scm_remember_upto_here_1 (y);
55f26379 7663 return scm_from_double (result);
0aacf84e
MD
7664 }
7665 else if (SCM_REALP (y))
55f26379 7666 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 7667 else if (SCM_COMPLEXP (y))
8507ec80 7668 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 7669 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 7670 else if (SCM_FRACTIONP (y))
55f26379 7671 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e
MD
7672 else
7673 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7674 }
0aacf84e
MD
7675 else if (SCM_COMPLEXP (x))
7676 {
e11e83f3 7677 if (SCM_I_INUMP (y))
5e791807
MW
7678 {
7679 SCM_SWAP (x, y);
7680 goto xinum;
7681 }
0aacf84e
MD
7682 else if (SCM_BIGP (y))
7683 {
7684 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
7685 scm_remember_upto_here_1 (y);
8507ec80 7686 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 7687 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
7688 }
7689 else if (SCM_REALP (y))
8507ec80 7690 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
7691 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
7692 else if (SCM_COMPLEXP (y))
7693 {
8507ec80 7694 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
7695 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
7696 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
7697 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
7698 }
f92e85f7
MV
7699 else if (SCM_FRACTIONP (y))
7700 {
7701 double yy = scm_i_fraction2double (y);
8507ec80 7702 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
7703 yy * SCM_COMPLEX_IMAG (x));
7704 }
7705 else
7706 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
7707 }
7708 else if (SCM_FRACTIONP (x))
7709 {
e11e83f3 7710 if (SCM_I_INUMP (y))
cba42c93 7711 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
7712 SCM_FRACTION_DENOMINATOR (x));
7713 else if (SCM_BIGP (y))
cba42c93 7714 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
7715 SCM_FRACTION_DENOMINATOR (x));
7716 else if (SCM_REALP (y))
55f26379 7717 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
7718 else if (SCM_COMPLEXP (y))
7719 {
7720 double xx = scm_i_fraction2double (x);
8507ec80 7721 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
7722 xx * SCM_COMPLEX_IMAG (y));
7723 }
7724 else if (SCM_FRACTIONP (y))
7725 /* a/b * c/d = ac / bd */
cba42c93 7726 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7727 SCM_FRACTION_NUMERATOR (y)),
7728 scm_product (SCM_FRACTION_DENOMINATOR (x),
7729 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e
MD
7730 else
7731 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7732 }
0aacf84e 7733 else
f4c627b3 7734 SCM_WTA_DISPATCH_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
7735}
7736
7351e207
MV
7737#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
7738 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
7739#define ALLOW_DIVIDE_BY_ZERO
7740/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
7741#endif
0f2d19dd 7742
ba74ef4e
MV
7743/* The code below for complex division is adapted from the GNU
7744 libstdc++, which adapted it from f2c's libF77, and is subject to
7745 this copyright: */
7746
7747/****************************************************************
7748Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
7749
7750Permission to use, copy, modify, and distribute this software
7751and its documentation for any purpose and without fee is hereby
7752granted, provided that the above copyright notice appear in all
7753copies and that both that the copyright notice and this
7754permission notice and warranty disclaimer appear in supporting
7755documentation, and that the names of AT&T Bell Laboratories or
7756Bellcore or any of their entities not be used in advertising or
7757publicity pertaining to distribution of the software without
7758specific, written prior permission.
7759
7760AT&T and Bellcore disclaim all warranties with regard to this
7761software, including all implied warranties of merchantability
7762and fitness. In no event shall AT&T or Bellcore be liable for
7763any special, indirect or consequential damages or any damages
7764whatsoever resulting from loss of use, data or profits, whether
7765in an action of contract, negligence or other tortious action,
7766arising out of or in connection with the use or performance of
7767this software.
7768****************************************************************/
7769
78d3deb1
AW
7770SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
7771 (SCM x, SCM y, SCM rest),
7772 "Divide the first argument by the product of the remaining\n"
7773 "arguments. If called with one argument @var{z1}, 1/@var{z1} is\n"
7774 "returned.")
7775#define FUNC_NAME s_scm_i_divide
7776{
7777 while (!scm_is_null (rest))
7778 { x = scm_divide (x, y);
7779 y = scm_car (rest);
7780 rest = scm_cdr (rest);
7781 }
7782 return scm_divide (x, y);
7783}
7784#undef FUNC_NAME
7785
7786#define s_divide s_scm_i_divide
7787#define g_divide g_scm_i_divide
7788
f92e85f7 7789static SCM
78d3deb1
AW
7790do_divide (SCM x, SCM y, int inexact)
7791#define FUNC_NAME s_divide
0f2d19dd 7792{
f8de44c1
DH
7793 double a;
7794
9cc37597 7795 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
7796 {
7797 if (SCM_UNBNDP (x))
7798 SCM_WTA_DISPATCH_0 (g_divide, s_divide);
e11e83f3 7799 else if (SCM_I_INUMP (x))
0aacf84e 7800 {
e25f3727 7801 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
7802 if (xx == 1 || xx == -1)
7803 return x;
7351e207 7804#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
7805 else if (xx == 0)
7806 scm_num_overflow (s_divide);
7351e207 7807#endif
0aacf84e 7808 else
f92e85f7
MV
7809 {
7810 if (inexact)
55f26379 7811 return scm_from_double (1.0 / (double) xx);
cff5fa33 7812 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 7813 }
0aacf84e
MD
7814 }
7815 else if (SCM_BIGP (x))
f92e85f7
MV
7816 {
7817 if (inexact)
55f26379 7818 return scm_from_double (1.0 / scm_i_big2dbl (x));
cff5fa33 7819 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 7820 }
0aacf84e
MD
7821 else if (SCM_REALP (x))
7822 {
7823 double xx = SCM_REAL_VALUE (x);
7351e207 7824#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
7825 if (xx == 0.0)
7826 scm_num_overflow (s_divide);
7827 else
7351e207 7828#endif
55f26379 7829 return scm_from_double (1.0 / xx);
0aacf84e
MD
7830 }
7831 else if (SCM_COMPLEXP (x))
7832 {
7833 double r = SCM_COMPLEX_REAL (x);
7834 double i = SCM_COMPLEX_IMAG (x);
4c6e36a6 7835 if (fabs(r) <= fabs(i))
0aacf84e
MD
7836 {
7837 double t = r / i;
7838 double d = i * (1.0 + t * t);
8507ec80 7839 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
7840 }
7841 else
7842 {
7843 double t = i / r;
7844 double d = r * (1.0 + t * t);
8507ec80 7845 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
7846 }
7847 }
f92e85f7 7848 else if (SCM_FRACTIONP (x))
cba42c93 7849 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 7850 SCM_FRACTION_NUMERATOR (x));
0aacf84e
MD
7851 else
7852 SCM_WTA_DISPATCH_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 7853 }
f8de44c1 7854
9cc37597 7855 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7856 {
e25f3727 7857 scm_t_inum xx = SCM_I_INUM (x);
9cc37597 7858 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7859 {
e25f3727 7860 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
7861 if (yy == 0)
7862 {
7351e207 7863#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 7864 scm_num_overflow (s_divide);
7351e207 7865#else
55f26379 7866 return scm_from_double ((double) xx / (double) yy);
7351e207 7867#endif
0aacf84e
MD
7868 }
7869 else if (xx % yy != 0)
f92e85f7
MV
7870 {
7871 if (inexact)
55f26379 7872 return scm_from_double ((double) xx / (double) yy);
cba42c93 7873 else return scm_i_make_ratio (x, y);
f92e85f7 7874 }
0aacf84e
MD
7875 else
7876 {
e25f3727 7877 scm_t_inum z = xx / yy;
0aacf84e 7878 if (SCM_FIXABLE (z))
d956fa6f 7879 return SCM_I_MAKINUM (z);
0aacf84e 7880 else
e25f3727 7881 return scm_i_inum2big (z);
0aacf84e 7882 }
f872b822 7883 }
0aacf84e 7884 else if (SCM_BIGP (y))
f92e85f7
MV
7885 {
7886 if (inexact)
55f26379 7887 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 7888 else return scm_i_make_ratio (x, y);
f92e85f7 7889 }
0aacf84e
MD
7890 else if (SCM_REALP (y))
7891 {
7892 double yy = SCM_REAL_VALUE (y);
7351e207 7893#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
7894 if (yy == 0.0)
7895 scm_num_overflow (s_divide);
7896 else
7351e207 7897#endif
55f26379 7898 return scm_from_double ((double) xx / yy);
ba74ef4e 7899 }
0aacf84e
MD
7900 else if (SCM_COMPLEXP (y))
7901 {
7902 a = xx;
7903 complex_div: /* y _must_ be a complex number */
7904 {
7905 double r = SCM_COMPLEX_REAL (y);
7906 double i = SCM_COMPLEX_IMAG (y);
4c6e36a6 7907 if (fabs(r) <= fabs(i))
0aacf84e
MD
7908 {
7909 double t = r / i;
7910 double d = i * (1.0 + t * t);
8507ec80 7911 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
7912 }
7913 else
7914 {
7915 double t = i / r;
7916 double d = r * (1.0 + t * t);
8507ec80 7917 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
7918 }
7919 }
7920 }
f92e85f7
MV
7921 else if (SCM_FRACTIONP (y))
7922 /* a / b/c = ac / b */
cba42c93 7923 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 7924 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
7925 else
7926 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 7927 }
0aacf84e
MD
7928 else if (SCM_BIGP (x))
7929 {
e11e83f3 7930 if (SCM_I_INUMP (y))
0aacf84e 7931 {
e25f3727 7932 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
7933 if (yy == 0)
7934 {
7351e207 7935#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 7936 scm_num_overflow (s_divide);
7351e207 7937#else
0aacf84e
MD
7938 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
7939 scm_remember_upto_here_1 (x);
7940 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 7941#endif
0aacf84e
MD
7942 }
7943 else if (yy == 1)
7944 return x;
7945 else
7946 {
7947 /* FIXME: HMM, what are the relative performance issues here?
7948 We need to test. Is it faster on average to test
7949 divisible_p, then perform whichever operation, or is it
7950 faster to perform the integer div opportunistically and
7951 switch to real if there's a remainder? For now we take the
7952 middle ground: test, then if divisible, use the faster div
7953 func. */
7954
e25f3727 7955 scm_t_inum abs_yy = yy < 0 ? -yy : yy;
0aacf84e
MD
7956 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
7957
7958 if (divisible_p)
7959 {
7960 SCM result = scm_i_mkbig ();
7961 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
7962 scm_remember_upto_here_1 (x);
7963 if (yy < 0)
7964 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
7965 return scm_i_normbig (result);
7966 }
7967 else
f92e85f7
MV
7968 {
7969 if (inexact)
55f26379 7970 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 7971 else return scm_i_make_ratio (x, y);
f92e85f7 7972 }
0aacf84e
MD
7973 }
7974 }
7975 else if (SCM_BIGP (y))
7976 {
a4955a04
MW
7977 /* big_x / big_y */
7978 if (inexact)
0aacf84e 7979 {
a4955a04
MW
7980 /* It's easily possible for the ratio x/y to fit a double
7981 but one or both x and y be too big to fit a double,
7982 hence the use of mpq_get_d rather than converting and
7983 dividing. */
7984 mpq_t q;
7985 *mpq_numref(q) = *SCM_I_BIG_MPZ (x);
7986 *mpq_denref(q) = *SCM_I_BIG_MPZ (y);
7987 return scm_from_double (mpq_get_d (q));
0aacf84e
MD
7988 }
7989 else
7990 {
a4955a04
MW
7991 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
7992 SCM_I_BIG_MPZ (y));
7993 if (divisible_p)
7994 {
7995 SCM result = scm_i_mkbig ();
7996 mpz_divexact (SCM_I_BIG_MPZ (result),
7997 SCM_I_BIG_MPZ (x),
7998 SCM_I_BIG_MPZ (y));
7999 scm_remember_upto_here_2 (x, y);
8000 return scm_i_normbig (result);
8001 }
8002 else
8003 return scm_i_make_ratio (x, y);
0aacf84e
MD
8004 }
8005 }
8006 else if (SCM_REALP (y))
8007 {
8008 double yy = SCM_REAL_VALUE (y);
7351e207 8009#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8010 if (yy == 0.0)
8011 scm_num_overflow (s_divide);
8012 else
7351e207 8013#endif
55f26379 8014 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
8015 }
8016 else if (SCM_COMPLEXP (y))
8017 {
8018 a = scm_i_big2dbl (x);
8019 goto complex_div;
8020 }
f92e85f7 8021 else if (SCM_FRACTIONP (y))
cba42c93 8022 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 8023 SCM_FRACTION_NUMERATOR (y));
0aacf84e
MD
8024 else
8025 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 8026 }
0aacf84e
MD
8027 else if (SCM_REALP (x))
8028 {
8029 double rx = SCM_REAL_VALUE (x);
e11e83f3 8030 if (SCM_I_INUMP (y))
0aacf84e 8031 {
e25f3727 8032 scm_t_inum yy = SCM_I_INUM (y);
7351e207 8033#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
8034 if (yy == 0)
8035 scm_num_overflow (s_divide);
8036 else
7351e207 8037#endif
55f26379 8038 return scm_from_double (rx / (double) yy);
0aacf84e
MD
8039 }
8040 else if (SCM_BIGP (y))
8041 {
8042 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
8043 scm_remember_upto_here_1 (y);
55f26379 8044 return scm_from_double (rx / dby);
0aacf84e
MD
8045 }
8046 else if (SCM_REALP (y))
8047 {
8048 double yy = SCM_REAL_VALUE (y);
7351e207 8049#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8050 if (yy == 0.0)
8051 scm_num_overflow (s_divide);
8052 else
7351e207 8053#endif
55f26379 8054 return scm_from_double (rx / yy);
0aacf84e
MD
8055 }
8056 else if (SCM_COMPLEXP (y))
8057 {
8058 a = rx;
8059 goto complex_div;
8060 }
f92e85f7 8061 else if (SCM_FRACTIONP (y))
55f26379 8062 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e
MD
8063 else
8064 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 8065 }
0aacf84e
MD
8066 else if (SCM_COMPLEXP (x))
8067 {
8068 double rx = SCM_COMPLEX_REAL (x);
8069 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 8070 if (SCM_I_INUMP (y))
0aacf84e 8071 {
e25f3727 8072 scm_t_inum yy = SCM_I_INUM (y);
7351e207 8073#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
8074 if (yy == 0)
8075 scm_num_overflow (s_divide);
8076 else
7351e207 8077#endif
0aacf84e
MD
8078 {
8079 double d = yy;
8507ec80 8080 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
8081 }
8082 }
8083 else if (SCM_BIGP (y))
8084 {
8085 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
8086 scm_remember_upto_here_1 (y);
8507ec80 8087 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
8088 }
8089 else if (SCM_REALP (y))
8090 {
8091 double yy = SCM_REAL_VALUE (y);
7351e207 8092#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8093 if (yy == 0.0)
8094 scm_num_overflow (s_divide);
8095 else
7351e207 8096#endif
8507ec80 8097 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
8098 }
8099 else if (SCM_COMPLEXP (y))
8100 {
8101 double ry = SCM_COMPLEX_REAL (y);
8102 double iy = SCM_COMPLEX_IMAG (y);
4c6e36a6 8103 if (fabs(ry) <= fabs(iy))
0aacf84e
MD
8104 {
8105 double t = ry / iy;
8106 double d = iy * (1.0 + t * t);
8507ec80 8107 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
8108 }
8109 else
8110 {
8111 double t = iy / ry;
8112 double d = ry * (1.0 + t * t);
8507ec80 8113 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
8114 }
8115 }
f92e85f7
MV
8116 else if (SCM_FRACTIONP (y))
8117 {
8118 double yy = scm_i_fraction2double (y);
8507ec80 8119 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 8120 }
0aacf84e
MD
8121 else
8122 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 8123 }
f92e85f7
MV
8124 else if (SCM_FRACTIONP (x))
8125 {
e11e83f3 8126 if (SCM_I_INUMP (y))
f92e85f7 8127 {
e25f3727 8128 scm_t_inum yy = SCM_I_INUM (y);
f92e85f7
MV
8129#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
8130 if (yy == 0)
8131 scm_num_overflow (s_divide);
8132 else
8133#endif
cba42c93 8134 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
8135 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
8136 }
8137 else if (SCM_BIGP (y))
8138 {
cba42c93 8139 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
8140 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
8141 }
8142 else if (SCM_REALP (y))
8143 {
8144 double yy = SCM_REAL_VALUE (y);
8145#ifndef ALLOW_DIVIDE_BY_ZERO
8146 if (yy == 0.0)
8147 scm_num_overflow (s_divide);
8148 else
8149#endif
55f26379 8150 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
8151 }
8152 else if (SCM_COMPLEXP (y))
8153 {
8154 a = scm_i_fraction2double (x);
8155 goto complex_div;
8156 }
8157 else if (SCM_FRACTIONP (y))
cba42c93 8158 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
8159 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
8160 else
8161 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARGn, s_divide);
8162 }
0aacf84e 8163 else
f8de44c1 8164 SCM_WTA_DISPATCH_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 8165}
f92e85f7
MV
8166
8167SCM
8168scm_divide (SCM x, SCM y)
8169{
78d3deb1 8170 return do_divide (x, y, 0);
f92e85f7
MV
8171}
8172
8173static SCM scm_divide2real (SCM x, SCM y)
8174{
78d3deb1 8175 return do_divide (x, y, 1);
f92e85f7 8176}
c05e97b7 8177#undef FUNC_NAME
0f2d19dd 8178
fa605590 8179
0f2d19dd 8180double
3101f40f 8181scm_c_truncate (double x)
0f2d19dd 8182{
fa605590 8183 return trunc (x);
0f2d19dd 8184}
0f2d19dd 8185
3101f40f
MV
8186/* scm_c_round is done using floor(x+0.5) to round to nearest and with
8187 half-way case (ie. when x is an integer plus 0.5) going upwards.
8188 Then half-way cases are identified and adjusted down if the
8189 round-upwards didn't give the desired even integer.
6187f48b
KR
8190
8191 "plus_half == result" identifies a half-way case. If plus_half, which is
8192 x + 0.5, is an integer then x must be an integer plus 0.5.
8193
8194 An odd "result" value is identified with result/2 != floor(result/2).
8195 This is done with plus_half, since that value is ready for use sooner in
8196 a pipelined cpu, and we're already requiring plus_half == result.
8197
8198 Note however that we need to be careful when x is big and already an
8199 integer. In that case "x+0.5" may round to an adjacent integer, causing
8200 us to return such a value, incorrectly. For instance if the hardware is
8201 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
8202 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
8203 returned. Or if the hardware is in round-upwards mode, then other bigger
8204 values like say x == 2^128 will see x+0.5 rounding up to the next higher
8205 representable value, 2^128+2^76 (or whatever), again incorrect.
8206
8207 These bad roundings of x+0.5 are avoided by testing at the start whether
8208 x is already an integer. If it is then clearly that's the desired result
8209 already. And if it's not then the exponent must be small enough to allow
8210 an 0.5 to be represented, and hence added without a bad rounding. */
8211
0f2d19dd 8212double
3101f40f 8213scm_c_round (double x)
0f2d19dd 8214{
6187f48b
KR
8215 double plus_half, result;
8216
8217 if (x == floor (x))
8218 return x;
8219
8220 plus_half = x + 0.5;
8221 result = floor (plus_half);
3101f40f 8222 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
8223 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
8224 ? result - 1
8225 : result);
0f2d19dd
JB
8226}
8227
8b56bcec
MW
8228SCM_PRIMITIVE_GENERIC (scm_truncate_number, "truncate", 1, 0, 0,
8229 (SCM x),
8230 "Round the number @var{x} towards zero.")
f92e85f7
MV
8231#define FUNC_NAME s_scm_truncate_number
8232{
8b56bcec
MW
8233 if (SCM_I_INUMP (x) || SCM_BIGP (x))
8234 return x;
8235 else if (SCM_REALP (x))
c251ab63 8236 return scm_from_double (trunc (SCM_REAL_VALUE (x)));
8b56bcec
MW
8237 else if (SCM_FRACTIONP (x))
8238 return scm_truncate_quotient (SCM_FRACTION_NUMERATOR (x),
8239 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8240 else
8b56bcec
MW
8241 SCM_WTA_DISPATCH_1 (g_scm_truncate_number, x, SCM_ARG1,
8242 s_scm_truncate_number);
f92e85f7
MV
8243}
8244#undef FUNC_NAME
8245
8b56bcec
MW
8246SCM_PRIMITIVE_GENERIC (scm_round_number, "round", 1, 0, 0,
8247 (SCM x),
8248 "Round the number @var{x} towards the nearest integer. "
8249 "When it is exactly halfway between two integers, "
8250 "round towards the even one.")
f92e85f7
MV
8251#define FUNC_NAME s_scm_round_number
8252{
e11e83f3 8253 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
8254 return x;
8255 else if (SCM_REALP (x))
3101f40f 8256 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
8b56bcec
MW
8257 else if (SCM_FRACTIONP (x))
8258 return scm_round_quotient (SCM_FRACTION_NUMERATOR (x),
8259 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8260 else
8b56bcec
MW
8261 SCM_WTA_DISPATCH_1 (g_scm_round_number, x, SCM_ARG1,
8262 s_scm_round_number);
f92e85f7
MV
8263}
8264#undef FUNC_NAME
8265
8266SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
8267 (SCM x),
8268 "Round the number @var{x} towards minus infinity.")
8269#define FUNC_NAME s_scm_floor
8270{
e11e83f3 8271 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
8272 return x;
8273 else if (SCM_REALP (x))
55f26379 8274 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7 8275 else if (SCM_FRACTIONP (x))
8b56bcec
MW
8276 return scm_floor_quotient (SCM_FRACTION_NUMERATOR (x),
8277 SCM_FRACTION_DENOMINATOR (x));
f92e85f7
MV
8278 else
8279 SCM_WTA_DISPATCH_1 (g_scm_floor, x, 1, s_scm_floor);
8280}
8281#undef FUNC_NAME
8282
8283SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
8284 (SCM x),
8285 "Round the number @var{x} towards infinity.")
8286#define FUNC_NAME s_scm_ceiling
8287{
e11e83f3 8288 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
8289 return x;
8290 else if (SCM_REALP (x))
55f26379 8291 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7 8292 else if (SCM_FRACTIONP (x))
8b56bcec
MW
8293 return scm_ceiling_quotient (SCM_FRACTION_NUMERATOR (x),
8294 SCM_FRACTION_DENOMINATOR (x));
f92e85f7
MV
8295 else
8296 SCM_WTA_DISPATCH_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
8297}
8298#undef FUNC_NAME
0f2d19dd 8299
2519490c
MW
8300SCM_PRIMITIVE_GENERIC (scm_expt, "expt", 2, 0, 0,
8301 (SCM x, SCM y),
8302 "Return @var{x} raised to the power of @var{y}.")
6fc4d012 8303#define FUNC_NAME s_scm_expt
0f2d19dd 8304{
01c7284a
MW
8305 if (scm_is_integer (y))
8306 {
8307 if (scm_is_true (scm_exact_p (y)))
8308 return scm_integer_expt (x, y);
8309 else
8310 {
8311 /* Here we handle the case where the exponent is an inexact
8312 integer. We make the exponent exact in order to use
8313 scm_integer_expt, and thus avoid the spurious imaginary
8314 parts that may result from round-off errors in the general
8315 e^(y log x) method below (for example when squaring a large
8316 negative number). In this case, we must return an inexact
8317 result for correctness. We also make the base inexact so
8318 that scm_integer_expt will use fast inexact arithmetic
8319 internally. Note that making the base inexact is not
8320 sufficient to guarantee an inexact result, because
8321 scm_integer_expt will return an exact 1 when the exponent
8322 is 0, even if the base is inexact. */
8323 return scm_exact_to_inexact
8324 (scm_integer_expt (scm_exact_to_inexact (x),
8325 scm_inexact_to_exact (y)));
8326 }
8327 }
6fc4d012
AW
8328 else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
8329 {
8330 return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
8331 }
2519490c 8332 else if (scm_is_complex (x) && scm_is_complex (y))
6fc4d012 8333 return scm_exp (scm_product (scm_log (x), y));
2519490c
MW
8334 else if (scm_is_complex (x))
8335 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG2, s_scm_expt);
8336 else
8337 SCM_WTA_DISPATCH_2 (g_scm_expt, x, y, SCM_ARG1, s_scm_expt);
0f2d19dd 8338}
1bbd0b84 8339#undef FUNC_NAME
0f2d19dd 8340
7f41099e
MW
8341/* sin/cos/tan/asin/acos/atan
8342 sinh/cosh/tanh/asinh/acosh/atanh
8343 Derived from "Transcen.scm", Complex trancendental functions for SCM.
8344 Written by Jerry D. Hedden, (C) FSF.
8345 See the file `COPYING' for terms applying to this program. */
8346
ad79736c
AW
8347SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
8348 (SCM z),
8349 "Compute the sine of @var{z}.")
8350#define FUNC_NAME s_scm_sin
8351{
8deddc94
MW
8352 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8353 return z; /* sin(exact0) = exact0 */
8354 else if (scm_is_real (z))
ad79736c
AW
8355 return scm_from_double (sin (scm_to_double (z)));
8356 else if (SCM_COMPLEXP (z))
8357 { double x, y;
8358 x = SCM_COMPLEX_REAL (z);
8359 y = SCM_COMPLEX_IMAG (z);
8360 return scm_c_make_rectangular (sin (x) * cosh (y),
8361 cos (x) * sinh (y));
8362 }
8363 else
8364 SCM_WTA_DISPATCH_1 (g_scm_sin, z, 1, s_scm_sin);
8365}
8366#undef FUNC_NAME
0f2d19dd 8367
ad79736c
AW
8368SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
8369 (SCM z),
8370 "Compute the cosine of @var{z}.")
8371#define FUNC_NAME s_scm_cos
8372{
8deddc94
MW
8373 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8374 return SCM_INUM1; /* cos(exact0) = exact1 */
8375 else if (scm_is_real (z))
ad79736c
AW
8376 return scm_from_double (cos (scm_to_double (z)));
8377 else if (SCM_COMPLEXP (z))
8378 { double x, y;
8379 x = SCM_COMPLEX_REAL (z);
8380 y = SCM_COMPLEX_IMAG (z);
8381 return scm_c_make_rectangular (cos (x) * cosh (y),
8382 -sin (x) * sinh (y));
8383 }
8384 else
8385 SCM_WTA_DISPATCH_1 (g_scm_cos, z, 1, s_scm_cos);
8386}
8387#undef FUNC_NAME
8388
8389SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
8390 (SCM z),
8391 "Compute the tangent of @var{z}.")
8392#define FUNC_NAME s_scm_tan
0f2d19dd 8393{
8deddc94
MW
8394 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8395 return z; /* tan(exact0) = exact0 */
8396 else if (scm_is_real (z))
ad79736c
AW
8397 return scm_from_double (tan (scm_to_double (z)));
8398 else if (SCM_COMPLEXP (z))
8399 { double x, y, w;
8400 x = 2.0 * SCM_COMPLEX_REAL (z);
8401 y = 2.0 * SCM_COMPLEX_IMAG (z);
8402 w = cos (x) + cosh (y);
8403#ifndef ALLOW_DIVIDE_BY_ZERO
8404 if (w == 0.0)
8405 scm_num_overflow (s_scm_tan);
8406#endif
8407 return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
8408 }
8409 else
8410 SCM_WTA_DISPATCH_1 (g_scm_tan, z, 1, s_scm_tan);
8411}
8412#undef FUNC_NAME
8413
8414SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
8415 (SCM z),
8416 "Compute the hyperbolic sine of @var{z}.")
8417#define FUNC_NAME s_scm_sinh
8418{
8deddc94
MW
8419 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8420 return z; /* sinh(exact0) = exact0 */
8421 else if (scm_is_real (z))
ad79736c
AW
8422 return scm_from_double (sinh (scm_to_double (z)));
8423 else if (SCM_COMPLEXP (z))
8424 { double x, y;
8425 x = SCM_COMPLEX_REAL (z);
8426 y = SCM_COMPLEX_IMAG (z);
8427 return scm_c_make_rectangular (sinh (x) * cos (y),
8428 cosh (x) * sin (y));
8429 }
8430 else
8431 SCM_WTA_DISPATCH_1 (g_scm_sinh, z, 1, s_scm_sinh);
8432}
8433#undef FUNC_NAME
8434
8435SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
8436 (SCM z),
8437 "Compute the hyperbolic cosine of @var{z}.")
8438#define FUNC_NAME s_scm_cosh
8439{
8deddc94
MW
8440 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8441 return SCM_INUM1; /* cosh(exact0) = exact1 */
8442 else if (scm_is_real (z))
ad79736c
AW
8443 return scm_from_double (cosh (scm_to_double (z)));
8444 else if (SCM_COMPLEXP (z))
8445 { double x, y;
8446 x = SCM_COMPLEX_REAL (z);
8447 y = SCM_COMPLEX_IMAG (z);
8448 return scm_c_make_rectangular (cosh (x) * cos (y),
8449 sinh (x) * sin (y));
8450 }
8451 else
8452 SCM_WTA_DISPATCH_1 (g_scm_cosh, z, 1, s_scm_cosh);
8453}
8454#undef FUNC_NAME
8455
8456SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
8457 (SCM z),
8458 "Compute the hyperbolic tangent of @var{z}.")
8459#define FUNC_NAME s_scm_tanh
8460{
8deddc94
MW
8461 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8462 return z; /* tanh(exact0) = exact0 */
8463 else if (scm_is_real (z))
ad79736c
AW
8464 return scm_from_double (tanh (scm_to_double (z)));
8465 else if (SCM_COMPLEXP (z))
8466 { double x, y, w;
8467 x = 2.0 * SCM_COMPLEX_REAL (z);
8468 y = 2.0 * SCM_COMPLEX_IMAG (z);
8469 w = cosh (x) + cos (y);
8470#ifndef ALLOW_DIVIDE_BY_ZERO
8471 if (w == 0.0)
8472 scm_num_overflow (s_scm_tanh);
8473#endif
8474 return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
8475 }
8476 else
8477 SCM_WTA_DISPATCH_1 (g_scm_tanh, z, 1, s_scm_tanh);
8478}
8479#undef FUNC_NAME
8480
8481SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
8482 (SCM z),
8483 "Compute the arc sine of @var{z}.")
8484#define FUNC_NAME s_scm_asin
8485{
8deddc94
MW
8486 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8487 return z; /* asin(exact0) = exact0 */
8488 else if (scm_is_real (z))
ad79736c
AW
8489 {
8490 double w = scm_to_double (z);
8491 if (w >= -1.0 && w <= 1.0)
8492 return scm_from_double (asin (w));
8493 else
8494 return scm_product (scm_c_make_rectangular (0, -1),
8495 scm_sys_asinh (scm_c_make_rectangular (0, w)));
8496 }
8497 else if (SCM_COMPLEXP (z))
8498 { double x, y;
8499 x = SCM_COMPLEX_REAL (z);
8500 y = SCM_COMPLEX_IMAG (z);
8501 return scm_product (scm_c_make_rectangular (0, -1),
8502 scm_sys_asinh (scm_c_make_rectangular (-y, x)));
8503 }
8504 else
8505 SCM_WTA_DISPATCH_1 (g_scm_asin, z, 1, s_scm_asin);
8506}
8507#undef FUNC_NAME
8508
8509SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
8510 (SCM z),
8511 "Compute the arc cosine of @var{z}.")
8512#define FUNC_NAME s_scm_acos
8513{
8deddc94
MW
8514 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
8515 return SCM_INUM0; /* acos(exact1) = exact0 */
8516 else if (scm_is_real (z))
ad79736c
AW
8517 {
8518 double w = scm_to_double (z);
8519 if (w >= -1.0 && w <= 1.0)
8520 return scm_from_double (acos (w));
8521 else
8522 return scm_sum (scm_from_double (acos (0.0)),
8523 scm_product (scm_c_make_rectangular (0, 1),
8524 scm_sys_asinh (scm_c_make_rectangular (0, w))));
8525 }
8526 else if (SCM_COMPLEXP (z))
8527 { double x, y;
8528 x = SCM_COMPLEX_REAL (z);
8529 y = SCM_COMPLEX_IMAG (z);
8530 return scm_sum (scm_from_double (acos (0.0)),
8531 scm_product (scm_c_make_rectangular (0, 1),
8532 scm_sys_asinh (scm_c_make_rectangular (-y, x))));
8533 }
8534 else
8535 SCM_WTA_DISPATCH_1 (g_scm_acos, z, 1, s_scm_acos);
8536}
8537#undef FUNC_NAME
8538
8539SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
8540 (SCM z, SCM y),
8541 "With one argument, compute the arc tangent of @var{z}.\n"
8542 "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
8543 "using the sign of @var{z} and @var{y} to determine the quadrant.")
8544#define FUNC_NAME s_scm_atan
8545{
8546 if (SCM_UNBNDP (y))
8547 {
8deddc94
MW
8548 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8549 return z; /* atan(exact0) = exact0 */
8550 else if (scm_is_real (z))
ad79736c
AW
8551 return scm_from_double (atan (scm_to_double (z)));
8552 else if (SCM_COMPLEXP (z))
8553 {
8554 double v, w;
8555 v = SCM_COMPLEX_REAL (z);
8556 w = SCM_COMPLEX_IMAG (z);
8557 return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
8558 scm_c_make_rectangular (v, w + 1.0))),
8559 scm_c_make_rectangular (0, 2));
8560 }
8561 else
18104cac 8562 SCM_WTA_DISPATCH_1 (g_scm_atan, z, SCM_ARG1, s_scm_atan);
ad79736c
AW
8563 }
8564 else if (scm_is_real (z))
8565 {
8566 if (scm_is_real (y))
8567 return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
8568 else
8569 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
8570 }
8571 else
8572 SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
8573}
8574#undef FUNC_NAME
8575
8576SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
8577 (SCM z),
8578 "Compute the inverse hyperbolic sine of @var{z}.")
8579#define FUNC_NAME s_scm_sys_asinh
8580{
8deddc94
MW
8581 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8582 return z; /* asinh(exact0) = exact0 */
8583 else if (scm_is_real (z))
ad79736c
AW
8584 return scm_from_double (asinh (scm_to_double (z)));
8585 else if (scm_is_number (z))
8586 return scm_log (scm_sum (z,
8587 scm_sqrt (scm_sum (scm_product (z, z),
cff5fa33 8588 SCM_INUM1))));
ad79736c
AW
8589 else
8590 SCM_WTA_DISPATCH_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
8591}
8592#undef FUNC_NAME
8593
8594SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
8595 (SCM z),
8596 "Compute the inverse hyperbolic cosine of @var{z}.")
8597#define FUNC_NAME s_scm_sys_acosh
8598{
8deddc94
MW
8599 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
8600 return SCM_INUM0; /* acosh(exact1) = exact0 */
8601 else if (scm_is_real (z) && scm_to_double (z) >= 1.0)
ad79736c
AW
8602 return scm_from_double (acosh (scm_to_double (z)));
8603 else if (scm_is_number (z))
8604 return scm_log (scm_sum (z,
8605 scm_sqrt (scm_difference (scm_product (z, z),
cff5fa33 8606 SCM_INUM1))));
ad79736c
AW
8607 else
8608 SCM_WTA_DISPATCH_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
8609}
8610#undef FUNC_NAME
8611
8612SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
8613 (SCM z),
8614 "Compute the inverse hyperbolic tangent of @var{z}.")
8615#define FUNC_NAME s_scm_sys_atanh
8616{
8deddc94
MW
8617 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8618 return z; /* atanh(exact0) = exact0 */
8619 else if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
ad79736c
AW
8620 return scm_from_double (atanh (scm_to_double (z)));
8621 else if (scm_is_number (z))
cff5fa33
MW
8622 return scm_divide (scm_log (scm_divide (scm_sum (SCM_INUM1, z),
8623 scm_difference (SCM_INUM1, z))),
ad79736c
AW
8624 SCM_I_MAKINUM (2));
8625 else
8626 SCM_WTA_DISPATCH_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
0f2d19dd 8627}
1bbd0b84 8628#undef FUNC_NAME
0f2d19dd 8629
8507ec80
MV
8630SCM
8631scm_c_make_rectangular (double re, double im)
8632{
c7218482 8633 SCM z;
03604fcf 8634
c7218482
MW
8635 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
8636 "complex"));
8637 SCM_SET_CELL_TYPE (z, scm_tc16_complex);
8638 SCM_COMPLEX_REAL (z) = re;
8639 SCM_COMPLEX_IMAG (z) = im;
8640 return z;
8507ec80 8641}
0f2d19dd 8642
a1ec6916 8643SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
a2c25234
LC
8644 (SCM real_part, SCM imaginary_part),
8645 "Return a complex number constructed of the given @var{real-part} "
8646 "and @var{imaginary-part} parts.")
1bbd0b84 8647#define FUNC_NAME s_scm_make_rectangular
0f2d19dd 8648{
ad79736c
AW
8649 SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
8650 SCM_ARG1, FUNC_NAME, "real");
8651 SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
8652 SCM_ARG2, FUNC_NAME, "real");
c7218482
MW
8653
8654 /* Return a real if and only if the imaginary_part is an _exact_ 0 */
8655 if (scm_is_eq (imaginary_part, SCM_INUM0))
8656 return real_part;
8657 else
8658 return scm_c_make_rectangular (scm_to_double (real_part),
8659 scm_to_double (imaginary_part));
0f2d19dd 8660}
1bbd0b84 8661#undef FUNC_NAME
0f2d19dd 8662
8507ec80
MV
8663SCM
8664scm_c_make_polar (double mag, double ang)
8665{
8666 double s, c;
5e647d08
LC
8667
8668 /* The sincos(3) function is undocumented an broken on Tru64. Thus we only
8669 use it on Glibc-based systems that have it (it's a GNU extension). See
8670 http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
8671 details. */
8672#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
8507ec80
MV
8673 sincos (ang, &s, &c);
8674#else
8675 s = sin (ang);
8676 c = cos (ang);
8677#endif
9d427b2c
MW
8678
8679 /* If s and c are NaNs, this indicates that the angle is a NaN,
8680 infinite, or perhaps simply too large to determine its value
8681 mod 2*pi. However, we know something that the floating-point
8682 implementation doesn't know: We know that s and c are finite.
8683 Therefore, if the magnitude is zero, return a complex zero.
8684
8685 The reason we check for the NaNs instead of using this case
8686 whenever mag == 0.0 is because when the angle is known, we'd
8687 like to return the correct kind of non-real complex zero:
8688 +0.0+0.0i, -0.0+0.0i, -0.0-0.0i, or +0.0-0.0i, depending
8689 on which quadrant the angle is in.
8690 */
8691 if (SCM_UNLIKELY (isnan(s)) && isnan(c) && (mag == 0.0))
8692 return scm_c_make_rectangular (0.0, 0.0);
8693 else
8694 return scm_c_make_rectangular (mag * c, mag * s);
8507ec80 8695}
0f2d19dd 8696
a1ec6916 8697SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
c7218482
MW
8698 (SCM mag, SCM ang),
8699 "Return the complex number @var{mag} * e^(i * @var{ang}).")
1bbd0b84 8700#define FUNC_NAME s_scm_make_polar
0f2d19dd 8701{
c7218482
MW
8702 SCM_ASSERT_TYPE (scm_is_real (mag), mag, SCM_ARG1, FUNC_NAME, "real");
8703 SCM_ASSERT_TYPE (scm_is_real (ang), ang, SCM_ARG2, FUNC_NAME, "real");
8704
8705 /* If mag is exact0, return exact0 */
8706 if (scm_is_eq (mag, SCM_INUM0))
8707 return SCM_INUM0;
8708 /* Return a real if ang is exact0 */
8709 else if (scm_is_eq (ang, SCM_INUM0))
8710 return mag;
8711 else
8712 return scm_c_make_polar (scm_to_double (mag), scm_to_double (ang));
0f2d19dd 8713}
1bbd0b84 8714#undef FUNC_NAME
0f2d19dd
JB
8715
8716
2519490c
MW
8717SCM_PRIMITIVE_GENERIC (scm_real_part, "real-part", 1, 0, 0,
8718 (SCM z),
8719 "Return the real part of the number @var{z}.")
8720#define FUNC_NAME s_scm_real_part
0f2d19dd 8721{
2519490c 8722 if (SCM_COMPLEXP (z))
55f26379 8723 return scm_from_double (SCM_COMPLEX_REAL (z));
2519490c 8724 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_REALP (z) || SCM_FRACTIONP (z))
2fa2d879 8725 return z;
0aacf84e 8726 else
2519490c 8727 SCM_WTA_DISPATCH_1 (g_scm_real_part, z, SCM_ARG1, s_scm_real_part);
0f2d19dd 8728}
2519490c 8729#undef FUNC_NAME
0f2d19dd
JB
8730
8731
2519490c
MW
8732SCM_PRIMITIVE_GENERIC (scm_imag_part, "imag-part", 1, 0, 0,
8733 (SCM z),
8734 "Return the imaginary part of the number @var{z}.")
8735#define FUNC_NAME s_scm_imag_part
0f2d19dd 8736{
2519490c
MW
8737 if (SCM_COMPLEXP (z))
8738 return scm_from_double (SCM_COMPLEX_IMAG (z));
c7218482 8739 else if (SCM_I_INUMP (z) || SCM_REALP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f92e85f7 8740 return SCM_INUM0;
0aacf84e 8741 else
2519490c 8742 SCM_WTA_DISPATCH_1 (g_scm_imag_part, z, SCM_ARG1, s_scm_imag_part);
0f2d19dd 8743}
2519490c 8744#undef FUNC_NAME
0f2d19dd 8745
2519490c
MW
8746SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
8747 (SCM z),
8748 "Return the numerator of the number @var{z}.")
8749#define FUNC_NAME s_scm_numerator
f92e85f7 8750{
2519490c 8751 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f92e85f7
MV
8752 return z;
8753 else if (SCM_FRACTIONP (z))
e2bf3b19 8754 return SCM_FRACTION_NUMERATOR (z);
f92e85f7
MV
8755 else if (SCM_REALP (z))
8756 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
8757 else
2519490c 8758 SCM_WTA_DISPATCH_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
f92e85f7 8759}
2519490c 8760#undef FUNC_NAME
f92e85f7
MV
8761
8762
2519490c
MW
8763SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
8764 (SCM z),
8765 "Return the denominator of the number @var{z}.")
8766#define FUNC_NAME s_scm_denominator
f92e85f7 8767{
2519490c 8768 if (SCM_I_INUMP (z) || SCM_BIGP (z))
cff5fa33 8769 return SCM_INUM1;
f92e85f7 8770 else if (SCM_FRACTIONP (z))
e2bf3b19 8771 return SCM_FRACTION_DENOMINATOR (z);
f92e85f7
MV
8772 else if (SCM_REALP (z))
8773 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
8774 else
2519490c 8775 SCM_WTA_DISPATCH_1 (g_scm_denominator, z, SCM_ARG1, s_scm_denominator);
f92e85f7 8776}
2519490c 8777#undef FUNC_NAME
0f2d19dd 8778
2519490c
MW
8779
8780SCM_PRIMITIVE_GENERIC (scm_magnitude, "magnitude", 1, 0, 0,
8781 (SCM z),
8782 "Return the magnitude of the number @var{z}. This is the same as\n"
8783 "@code{abs} for real arguments, but also allows complex numbers.")
8784#define FUNC_NAME s_scm_magnitude
0f2d19dd 8785{
e11e83f3 8786 if (SCM_I_INUMP (z))
0aacf84e 8787 {
e25f3727 8788 scm_t_inum zz = SCM_I_INUM (z);
0aacf84e
MD
8789 if (zz >= 0)
8790 return z;
8791 else if (SCM_POSFIXABLE (-zz))
d956fa6f 8792 return SCM_I_MAKINUM (-zz);
0aacf84e 8793 else
e25f3727 8794 return scm_i_inum2big (-zz);
5986c47d 8795 }
0aacf84e
MD
8796 else if (SCM_BIGP (z))
8797 {
8798 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
8799 scm_remember_upto_here_1 (z);
8800 if (sgn < 0)
8801 return scm_i_clonebig (z, 0);
8802 else
8803 return z;
5986c47d 8804 }
0aacf84e 8805 else if (SCM_REALP (z))
55f26379 8806 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 8807 else if (SCM_COMPLEXP (z))
55f26379 8808 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
8809 else if (SCM_FRACTIONP (z))
8810 {
73e4de09 8811 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 8812 return z;
cba42c93 8813 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
8814 SCM_FRACTION_DENOMINATOR (z));
8815 }
0aacf84e 8816 else
2519490c 8817 SCM_WTA_DISPATCH_1 (g_scm_magnitude, z, SCM_ARG1, s_scm_magnitude);
0f2d19dd 8818}
2519490c 8819#undef FUNC_NAME
0f2d19dd
JB
8820
8821
2519490c
MW
8822SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
8823 (SCM z),
8824 "Return the angle of the complex number @var{z}.")
8825#define FUNC_NAME s_scm_angle
0f2d19dd 8826{
c8ae173e 8827 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
e7efe8e7 8828 flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
8829 But if atan2 follows the floating point rounding mode, then the value
8830 is not a constant. Maybe it'd be close enough though. */
e11e83f3 8831 if (SCM_I_INUMP (z))
0aacf84e 8832 {
e11e83f3 8833 if (SCM_I_INUM (z) >= 0)
e7efe8e7 8834 return flo0;
0aacf84e 8835 else
55f26379 8836 return scm_from_double (atan2 (0.0, -1.0));
f872b822 8837 }
0aacf84e
MD
8838 else if (SCM_BIGP (z))
8839 {
8840 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
8841 scm_remember_upto_here_1 (z);
8842 if (sgn < 0)
55f26379 8843 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 8844 else
e7efe8e7 8845 return flo0;
0f2d19dd 8846 }
0aacf84e 8847 else if (SCM_REALP (z))
c8ae173e
KR
8848 {
8849 if (SCM_REAL_VALUE (z) >= 0)
e7efe8e7 8850 return flo0;
c8ae173e 8851 else
55f26379 8852 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 8853 }
0aacf84e 8854 else if (SCM_COMPLEXP (z))
55f26379 8855 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
8856 else if (SCM_FRACTIONP (z))
8857 {
73e4de09 8858 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
e7efe8e7 8859 return flo0;
55f26379 8860 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 8861 }
0aacf84e 8862 else
2519490c 8863 SCM_WTA_DISPATCH_1 (g_scm_angle, z, SCM_ARG1, s_scm_angle);
0f2d19dd 8864}
2519490c 8865#undef FUNC_NAME
0f2d19dd
JB
8866
8867
2519490c
MW
8868SCM_PRIMITIVE_GENERIC (scm_exact_to_inexact, "exact->inexact", 1, 0, 0,
8869 (SCM z),
8870 "Convert the number @var{z} to its inexact representation.\n")
8871#define FUNC_NAME s_scm_exact_to_inexact
3c9a524f 8872{
e11e83f3 8873 if (SCM_I_INUMP (z))
55f26379 8874 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 8875 else if (SCM_BIGP (z))
55f26379 8876 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 8877 else if (SCM_FRACTIONP (z))
55f26379 8878 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
8879 else if (SCM_INEXACTP (z))
8880 return z;
8881 else
2519490c 8882 SCM_WTA_DISPATCH_1 (g_scm_exact_to_inexact, z, 1, s_scm_exact_to_inexact);
3c9a524f 8883}
2519490c 8884#undef FUNC_NAME
3c9a524f
DH
8885
8886
2519490c
MW
8887SCM_PRIMITIVE_GENERIC (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
8888 (SCM z),
8889 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 8890#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 8891{
c7218482 8892 if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f872b822 8893 return z;
c7218482 8894 else
0aacf84e 8895 {
c7218482
MW
8896 double val;
8897
8898 if (SCM_REALP (z))
8899 val = SCM_REAL_VALUE (z);
8900 else if (SCM_COMPLEXP (z) && SCM_COMPLEX_IMAG (z) == 0.0)
8901 val = SCM_COMPLEX_REAL (z);
8902 else
8903 SCM_WTA_DISPATCH_1 (g_scm_inexact_to_exact, z, 1, s_scm_inexact_to_exact);
8904
8905 if (!SCM_LIKELY (DOUBLE_IS_FINITE (val)))
f92e85f7 8906 SCM_OUT_OF_RANGE (1, z);
2be24db4 8907 else
f92e85f7
MV
8908 {
8909 mpq_t frac;
8910 SCM q;
8911
8912 mpq_init (frac);
c7218482 8913 mpq_set_d (frac, val);
cba42c93 8914 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
c7218482 8915 scm_i_mpz2num (mpq_denref (frac)));
f92e85f7 8916
cba42c93 8917 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
8918 for frac...
8919 */
8920 mpq_clear (frac);
8921 return q;
8922 }
c2ff8ab0 8923 }
0f2d19dd 8924}
1bbd0b84 8925#undef FUNC_NAME
0f2d19dd 8926
f92e85f7 8927SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
76dae881
NJ
8928 (SCM x, SCM eps),
8929 "Returns the @emph{simplest} rational number differing\n"
8930 "from @var{x} by no more than @var{eps}.\n"
8931 "\n"
8932 "As required by @acronym{R5RS}, @code{rationalize} only returns an\n"
8933 "exact result when both its arguments are exact. Thus, you might need\n"
8934 "to use @code{inexact->exact} on the arguments.\n"
8935 "\n"
8936 "@lisp\n"
8937 "(rationalize (inexact->exact 1.2) 1/100)\n"
8938 "@result{} 6/5\n"
8939 "@end lisp")
f92e85f7
MV
8940#define FUNC_NAME s_scm_rationalize
8941{
605f6980
MW
8942 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
8943 SCM_ASSERT_TYPE (scm_is_real (eps), eps, SCM_ARG2, FUNC_NAME, "real");
8944 eps = scm_abs (eps);
8945 if (scm_is_false (scm_positive_p (eps)))
8946 {
8947 /* eps is either zero or a NaN */
8948 if (scm_is_true (scm_nan_p (eps)))
8949 return scm_nan ();
8950 else if (SCM_INEXACTP (eps))
8951 return scm_exact_to_inexact (x);
8952 else
8953 return x;
8954 }
8955 else if (scm_is_false (scm_finite_p (eps)))
8956 {
8957 if (scm_is_true (scm_finite_p (x)))
8958 return flo0;
8959 else
8960 return scm_nan ();
8961 }
8962 else if (scm_is_false (scm_finite_p (x))) /* checks for both inf and nan */
f92e85f7 8963 return x;
605f6980
MW
8964 else if (scm_is_false (scm_less_p (scm_floor (scm_sum (x, eps)),
8965 scm_ceiling (scm_difference (x, eps)))))
8966 {
8967 /* There's an integer within range; we want the one closest to zero */
8968 if (scm_is_false (scm_less_p (eps, scm_abs (x))))
8969 {
8970 /* zero is within range */
8971 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
8972 return flo0;
8973 else
8974 return SCM_INUM0;
8975 }
8976 else if (scm_is_true (scm_positive_p (x)))
8977 return scm_ceiling (scm_difference (x, eps));
8978 else
8979 return scm_floor (scm_sum (x, eps));
8980 }
8981 else
f92e85f7
MV
8982 {
8983 /* Use continued fractions to find closest ratio. All
8984 arithmetic is done with exact numbers.
8985 */
8986
8987 SCM ex = scm_inexact_to_exact (x);
8988 SCM int_part = scm_floor (ex);
cff5fa33
MW
8989 SCM tt = SCM_INUM1;
8990 SCM a1 = SCM_INUM0, a2 = SCM_INUM1, a = SCM_INUM0;
8991 SCM b1 = SCM_INUM1, b2 = SCM_INUM0, b = SCM_INUM0;
f92e85f7
MV
8992 SCM rx;
8993 int i = 0;
8994
f92e85f7
MV
8995 ex = scm_difference (ex, int_part); /* x = x-int_part */
8996 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
8997
8998 /* We stop after a million iterations just to be absolutely sure
8999 that we don't go into an infinite loop. The process normally
9000 converges after less than a dozen iterations.
9001 */
9002
f92e85f7
MV
9003 while (++i < 1000000)
9004 {
9005 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
9006 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
9007 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
9008 scm_is_false
f92e85f7 9009 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
76dae881 9010 eps))) /* abs(x-a/b) <= eps */
02164269
MV
9011 {
9012 SCM res = scm_sum (int_part, scm_divide (a, b));
605f6980 9013 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
02164269
MV
9014 return scm_exact_to_inexact (res);
9015 else
9016 return res;
9017 }
f92e85f7
MV
9018 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
9019 SCM_UNDEFINED);
9020 tt = scm_floor (rx); /* tt = floor (rx) */
9021 a2 = a1;
9022 b2 = b1;
9023 a1 = a;
9024 b1 = b;
9025 }
9026 scm_num_overflow (s_scm_rationalize);
9027 }
f92e85f7
MV
9028}
9029#undef FUNC_NAME
9030
73e4de09
MV
9031/* conversion functions */
9032
9033int
9034scm_is_integer (SCM val)
9035{
9036 return scm_is_true (scm_integer_p (val));
9037}
9038
9039int
9040scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
9041{
e11e83f3 9042 if (SCM_I_INUMP (val))
73e4de09 9043 {
e11e83f3 9044 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
9045 return n >= min && n <= max;
9046 }
9047 else if (SCM_BIGP (val))
9048 {
9049 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
9050 return 0;
9051 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
9052 {
9053 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
9054 {
9055 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
9056 return n >= min && n <= max;
9057 }
9058 else
9059 return 0;
9060 }
73e4de09
MV
9061 else
9062 {
d956fa6f
MV
9063 scm_t_intmax n;
9064 size_t count;
73e4de09 9065
d956fa6f
MV
9066 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
9067 > CHAR_BIT*sizeof (scm_t_uintmax))
9068 return 0;
9069
9070 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
9071 SCM_I_BIG_MPZ (val));
73e4de09 9072
d956fa6f 9073 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 9074 {
d956fa6f
MV
9075 if (n < 0)
9076 return 0;
73e4de09 9077 }
73e4de09
MV
9078 else
9079 {
d956fa6f
MV
9080 n = -n;
9081 if (n >= 0)
9082 return 0;
73e4de09 9083 }
d956fa6f
MV
9084
9085 return n >= min && n <= max;
73e4de09
MV
9086 }
9087 }
73e4de09
MV
9088 else
9089 return 0;
9090}
9091
9092int
9093scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
9094{
e11e83f3 9095 if (SCM_I_INUMP (val))
73e4de09 9096 {
e11e83f3 9097 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
9098 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
9099 }
9100 else if (SCM_BIGP (val))
9101 {
9102 if (max <= SCM_MOST_POSITIVE_FIXNUM)
9103 return 0;
9104 else if (max <= ULONG_MAX)
d956fa6f
MV
9105 {
9106 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
9107 {
9108 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
9109 return n >= min && n <= max;
9110 }
9111 else
9112 return 0;
9113 }
73e4de09
MV
9114 else
9115 {
d956fa6f
MV
9116 scm_t_uintmax n;
9117 size_t count;
73e4de09 9118
d956fa6f
MV
9119 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
9120 return 0;
73e4de09 9121
d956fa6f
MV
9122 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
9123 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 9124 return 0;
d956fa6f
MV
9125
9126 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
9127 SCM_I_BIG_MPZ (val));
73e4de09 9128
d956fa6f 9129 return n >= min && n <= max;
73e4de09
MV
9130 }
9131 }
73e4de09
MV
9132 else
9133 return 0;
9134}
9135
1713d319
MV
9136static void
9137scm_i_range_error (SCM bad_val, SCM min, SCM max)
9138{
9139 scm_error (scm_out_of_range_key,
9140 NULL,
9141 "Value out of range ~S to ~S: ~S",
9142 scm_list_3 (min, max, bad_val),
9143 scm_list_1 (bad_val));
9144}
9145
bfd7932e
MV
9146#define TYPE scm_t_intmax
9147#define TYPE_MIN min
9148#define TYPE_MAX max
9149#define SIZEOF_TYPE 0
9150#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
9151#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
9152#include "libguile/conv-integer.i.c"
9153
9154#define TYPE scm_t_uintmax
9155#define TYPE_MIN min
9156#define TYPE_MAX max
9157#define SIZEOF_TYPE 0
9158#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
9159#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
9160#include "libguile/conv-uinteger.i.c"
9161
9162#define TYPE scm_t_int8
9163#define TYPE_MIN SCM_T_INT8_MIN
9164#define TYPE_MAX SCM_T_INT8_MAX
9165#define SIZEOF_TYPE 1
9166#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
9167#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
9168#include "libguile/conv-integer.i.c"
9169
9170#define TYPE scm_t_uint8
9171#define TYPE_MIN 0
9172#define TYPE_MAX SCM_T_UINT8_MAX
9173#define SIZEOF_TYPE 1
9174#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
9175#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
9176#include "libguile/conv-uinteger.i.c"
9177
9178#define TYPE scm_t_int16
9179#define TYPE_MIN SCM_T_INT16_MIN
9180#define TYPE_MAX SCM_T_INT16_MAX
9181#define SIZEOF_TYPE 2
9182#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
9183#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
9184#include "libguile/conv-integer.i.c"
9185
9186#define TYPE scm_t_uint16
9187#define TYPE_MIN 0
9188#define TYPE_MAX SCM_T_UINT16_MAX
9189#define SIZEOF_TYPE 2
9190#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
9191#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
9192#include "libguile/conv-uinteger.i.c"
9193
9194#define TYPE scm_t_int32
9195#define TYPE_MIN SCM_T_INT32_MIN
9196#define TYPE_MAX SCM_T_INT32_MAX
9197#define SIZEOF_TYPE 4
9198#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
9199#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
9200#include "libguile/conv-integer.i.c"
9201
9202#define TYPE scm_t_uint32
9203#define TYPE_MIN 0
9204#define TYPE_MAX SCM_T_UINT32_MAX
9205#define SIZEOF_TYPE 4
9206#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
9207#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
9208#include "libguile/conv-uinteger.i.c"
9209
904a78f1
MG
9210#define TYPE scm_t_wchar
9211#define TYPE_MIN (scm_t_int32)-1
9212#define TYPE_MAX (scm_t_int32)0x10ffff
9213#define SIZEOF_TYPE 4
9214#define SCM_TO_TYPE_PROTO(arg) scm_to_wchar (arg)
9215#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
9216#include "libguile/conv-integer.i.c"
9217
bfd7932e
MV
9218#define TYPE scm_t_int64
9219#define TYPE_MIN SCM_T_INT64_MIN
9220#define TYPE_MAX SCM_T_INT64_MAX
9221#define SIZEOF_TYPE 8
9222#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
9223#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
9224#include "libguile/conv-integer.i.c"
9225
9226#define TYPE scm_t_uint64
9227#define TYPE_MIN 0
9228#define TYPE_MAX SCM_T_UINT64_MAX
9229#define SIZEOF_TYPE 8
9230#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
9231#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
9232#include "libguile/conv-uinteger.i.c"
73e4de09 9233
cd036260
MV
9234void
9235scm_to_mpz (SCM val, mpz_t rop)
9236{
9237 if (SCM_I_INUMP (val))
9238 mpz_set_si (rop, SCM_I_INUM (val));
9239 else if (SCM_BIGP (val))
9240 mpz_set (rop, SCM_I_BIG_MPZ (val));
9241 else
9242 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
9243}
9244
9245SCM
9246scm_from_mpz (mpz_t val)
9247{
9248 return scm_i_mpz2num (val);
9249}
9250
73e4de09
MV
9251int
9252scm_is_real (SCM val)
9253{
9254 return scm_is_true (scm_real_p (val));
9255}
9256
55f26379
MV
9257int
9258scm_is_rational (SCM val)
9259{
9260 return scm_is_true (scm_rational_p (val));
9261}
9262
73e4de09
MV
9263double
9264scm_to_double (SCM val)
9265{
55f26379
MV
9266 if (SCM_I_INUMP (val))
9267 return SCM_I_INUM (val);
9268 else if (SCM_BIGP (val))
9269 return scm_i_big2dbl (val);
9270 else if (SCM_FRACTIONP (val))
9271 return scm_i_fraction2double (val);
9272 else if (SCM_REALP (val))
9273 return SCM_REAL_VALUE (val);
9274 else
7a1aba42 9275 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
9276}
9277
9278SCM
9279scm_from_double (double val)
9280{
978c52d1
LC
9281 SCM z;
9282
9283 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
9284
9285 SCM_SET_CELL_TYPE (z, scm_tc16_real);
55f26379 9286 SCM_REAL_VALUE (z) = val;
978c52d1 9287
55f26379 9288 return z;
73e4de09
MV
9289}
9290
220058a8 9291#if SCM_ENABLE_DEPRECATED == 1
55f26379
MV
9292
9293float
e25f3727 9294scm_num2float (SCM num, unsigned long pos, const char *s_caller)
55f26379 9295{
220058a8
AW
9296 scm_c_issue_deprecation_warning
9297 ("`scm_num2float' is deprecated. Use scm_to_double instead.");
9298
55f26379
MV
9299 if (SCM_BIGP (num))
9300 {
9301 float res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 9302 if (!isinf (res))
55f26379
MV
9303 return res;
9304 else
9305 scm_out_of_range (NULL, num);
9306 }
9307 else
9308 return scm_to_double (num);
9309}
9310
9311double
e25f3727 9312scm_num2double (SCM num, unsigned long pos, const char *s_caller)
55f26379 9313{
220058a8
AW
9314 scm_c_issue_deprecation_warning
9315 ("`scm_num2double' is deprecated. Use scm_to_double instead.");
9316
55f26379
MV
9317 if (SCM_BIGP (num))
9318 {
9319 double res = mpz_get_d (SCM_I_BIG_MPZ (num));
2e65b52f 9320 if (!isinf (res))
55f26379
MV
9321 return res;
9322 else
9323 scm_out_of_range (NULL, num);
9324 }
9325 else
9326 return scm_to_double (num);
9327}
9328
9329#endif
9330
8507ec80
MV
9331int
9332scm_is_complex (SCM val)
9333{
9334 return scm_is_true (scm_complex_p (val));
9335}
9336
9337double
9338scm_c_real_part (SCM z)
9339{
9340 if (SCM_COMPLEXP (z))
9341 return SCM_COMPLEX_REAL (z);
9342 else
9343 {
9344 /* Use the scm_real_part to get proper error checking and
9345 dispatching.
9346 */
9347 return scm_to_double (scm_real_part (z));
9348 }
9349}
9350
9351double
9352scm_c_imag_part (SCM z)
9353{
9354 if (SCM_COMPLEXP (z))
9355 return SCM_COMPLEX_IMAG (z);
9356 else
9357 {
9358 /* Use the scm_imag_part to get proper error checking and
9359 dispatching. The result will almost always be 0.0, but not
9360 always.
9361 */
9362 return scm_to_double (scm_imag_part (z));
9363 }
9364}
9365
9366double
9367scm_c_magnitude (SCM z)
9368{
9369 return scm_to_double (scm_magnitude (z));
9370}
9371
9372double
9373scm_c_angle (SCM z)
9374{
9375 return scm_to_double (scm_angle (z));
9376}
9377
9378int
9379scm_is_number (SCM z)
9380{
9381 return scm_is_true (scm_number_p (z));
9382}
9383
8ab3d8a0 9384
a5f6b751
MW
9385/* Returns log(x * 2^shift) */
9386static SCM
9387log_of_shifted_double (double x, long shift)
9388{
9389 double ans = log (fabs (x)) + shift * M_LN2;
9390
9391 if (x > 0.0 || double_is_non_negative_zero (x))
9392 return scm_from_double (ans);
9393 else
9394 return scm_c_make_rectangular (ans, M_PI);
9395}
9396
9397/* Returns log(n), for exact integer n of integer-length size */
9398static SCM
9399log_of_exact_integer_with_size (SCM n, long size)
9400{
9401 long shift = size - 2 * scm_dblprec[0];
9402
9403 if (shift > 0)
9404 return log_of_shifted_double
9405 (scm_to_double (scm_ash (n, scm_from_long(-shift))),
9406 shift);
9407 else
9408 return log_of_shifted_double (scm_to_double (n), 0);
9409}
9410
85bdb6ac 9411/* Returns log(n), for exact integer n */
a5f6b751
MW
9412static SCM
9413log_of_exact_integer (SCM n)
9414{
9415 return log_of_exact_integer_with_size
9416 (n, scm_to_long (scm_integer_length (n)));
9417}
9418
9419/* Returns log(n/d), for exact non-zero integers n and d */
9420static SCM
9421log_of_fraction (SCM n, SCM d)
9422{
9423 long n_size = scm_to_long (scm_integer_length (n));
9424 long d_size = scm_to_long (scm_integer_length (d));
9425
9426 if (abs (n_size - d_size) > 1)
9427 return (scm_difference (log_of_exact_integer_with_size (n, n_size),
9428 log_of_exact_integer_with_size (d, d_size)));
9429 else if (scm_is_false (scm_negative_p (n)))
9430 return scm_from_double
9431 (log1p (scm_to_double (scm_divide2real (scm_difference (n, d), d))));
9432 else
9433 return scm_c_make_rectangular
9434 (log1p (scm_to_double (scm_divide2real
9435 (scm_difference (scm_abs (n), d),
9436 d))),
9437 M_PI);
9438}
9439
9440
8ab3d8a0
KR
9441/* In the following functions we dispatch to the real-arg funcs like log()
9442 when we know the arg is real, instead of just handing everything to
9443 clog() for instance. This is in case clog() doesn't optimize for a
9444 real-only case, and because we have to test SCM_COMPLEXP anyway so may as
9445 well use it to go straight to the applicable C func. */
9446
2519490c
MW
9447SCM_PRIMITIVE_GENERIC (scm_log, "log", 1, 0, 0,
9448 (SCM z),
9449 "Return the natural logarithm of @var{z}.")
8ab3d8a0
KR
9450#define FUNC_NAME s_scm_log
9451{
9452 if (SCM_COMPLEXP (z))
9453 {
03976fee
AW
9454#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG \
9455 && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
9456 return scm_from_complex_double (clog (SCM_COMPLEX_VALUE (z)));
9457#else
9458 double re = SCM_COMPLEX_REAL (z);
9459 double im = SCM_COMPLEX_IMAG (z);
9460 return scm_c_make_rectangular (log (hypot (re, im)),
9461 atan2 (im, re));
9462#endif
9463 }
a5f6b751
MW
9464 else if (SCM_REALP (z))
9465 return log_of_shifted_double (SCM_REAL_VALUE (z), 0);
9466 else if (SCM_I_INUMP (z))
8ab3d8a0 9467 {
a5f6b751
MW
9468#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
9469 if (scm_is_eq (z, SCM_INUM0))
9470 scm_num_overflow (s_scm_log);
9471#endif
9472 return log_of_shifted_double (SCM_I_INUM (z), 0);
8ab3d8a0 9473 }
a5f6b751
MW
9474 else if (SCM_BIGP (z))
9475 return log_of_exact_integer (z);
9476 else if (SCM_FRACTIONP (z))
9477 return log_of_fraction (SCM_FRACTION_NUMERATOR (z),
9478 SCM_FRACTION_DENOMINATOR (z));
2519490c
MW
9479 else
9480 SCM_WTA_DISPATCH_1 (g_scm_log, z, 1, s_scm_log);
8ab3d8a0
KR
9481}
9482#undef FUNC_NAME
9483
9484
2519490c
MW
9485SCM_PRIMITIVE_GENERIC (scm_log10, "log10", 1, 0, 0,
9486 (SCM z),
9487 "Return the base 10 logarithm of @var{z}.")
8ab3d8a0
KR
9488#define FUNC_NAME s_scm_log10
9489{
9490 if (SCM_COMPLEXP (z))
9491 {
9492 /* Mingw has clog() but not clog10(). (Maybe it'd be worth using
9493 clog() and a multiply by M_LOG10E, rather than the fallback
9494 log10+hypot+atan2.) */
f328f862
LC
9495#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
9496 && defined SCM_COMPLEX_VALUE
8ab3d8a0
KR
9497 return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
9498#else
9499 double re = SCM_COMPLEX_REAL (z);
9500 double im = SCM_COMPLEX_IMAG (z);
9501 return scm_c_make_rectangular (log10 (hypot (re, im)),
9502 M_LOG10E * atan2 (im, re));
9503#endif
9504 }
a5f6b751 9505 else if (SCM_REALP (z) || SCM_I_INUMP (z))
8ab3d8a0 9506 {
a5f6b751
MW
9507#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
9508 if (scm_is_eq (z, SCM_INUM0))
9509 scm_num_overflow (s_scm_log10);
9510#endif
9511 {
9512 double re = scm_to_double (z);
9513 double l = log10 (fabs (re));
9514 if (re > 0.0 || double_is_non_negative_zero (re))
9515 return scm_from_double (l);
9516 else
9517 return scm_c_make_rectangular (l, M_LOG10E * M_PI);
9518 }
8ab3d8a0 9519 }
a5f6b751
MW
9520 else if (SCM_BIGP (z))
9521 return scm_product (flo_log10e, log_of_exact_integer (z));
9522 else if (SCM_FRACTIONP (z))
9523 return scm_product (flo_log10e,
9524 log_of_fraction (SCM_FRACTION_NUMERATOR (z),
9525 SCM_FRACTION_DENOMINATOR (z)));
2519490c
MW
9526 else
9527 SCM_WTA_DISPATCH_1 (g_scm_log10, z, 1, s_scm_log10);
8ab3d8a0
KR
9528}
9529#undef FUNC_NAME
9530
9531
2519490c
MW
9532SCM_PRIMITIVE_GENERIC (scm_exp, "exp", 1, 0, 0,
9533 (SCM z),
9534 "Return @math{e} to the power of @var{z}, where @math{e} is the\n"
9535 "base of natural logarithms (2.71828@dots{}).")
8ab3d8a0
KR
9536#define FUNC_NAME s_scm_exp
9537{
9538 if (SCM_COMPLEXP (z))
9539 {
03976fee
AW
9540#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CEXP \
9541 && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
9542 return scm_from_complex_double (cexp (SCM_COMPLEX_VALUE (z)));
9543#else
9544 return scm_c_make_polar (exp (SCM_COMPLEX_REAL (z)),
9545 SCM_COMPLEX_IMAG (z));
9546#endif
9547 }
2519490c 9548 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
9549 {
9550 /* When z is a negative bignum the conversion to double overflows,
9551 giving -infinity, but that's ok, the exp is still 0.0. */
9552 return scm_from_double (exp (scm_to_double (z)));
9553 }
2519490c
MW
9554 else
9555 SCM_WTA_DISPATCH_1 (g_scm_exp, z, 1, s_scm_exp);
8ab3d8a0
KR
9556}
9557#undef FUNC_NAME
9558
9559
882c8963
MW
9560SCM_DEFINE (scm_i_exact_integer_sqrt, "exact-integer-sqrt", 1, 0, 0,
9561 (SCM k),
9562 "Return two exact non-negative integers @var{s} and @var{r}\n"
9563 "such that @math{@var{k} = @var{s}^2 + @var{r}} and\n"
9564 "@math{@var{s}^2 <= @var{k} < (@var{s} + 1)^2}.\n"
9565 "An error is raised if @var{k} is not an exact non-negative integer.\n"
9566 "\n"
9567 "@lisp\n"
9568 "(exact-integer-sqrt 10) @result{} 3 and 1\n"
9569 "@end lisp")
9570#define FUNC_NAME s_scm_i_exact_integer_sqrt
9571{
9572 SCM s, r;
9573
9574 scm_exact_integer_sqrt (k, &s, &r);
9575 return scm_values (scm_list_2 (s, r));
9576}
9577#undef FUNC_NAME
9578
9579void
9580scm_exact_integer_sqrt (SCM k, SCM *sp, SCM *rp)
9581{
9582 if (SCM_LIKELY (SCM_I_INUMP (k)))
9583 {
9584 scm_t_inum kk = SCM_I_INUM (k);
9585 scm_t_inum uu = kk;
9586 scm_t_inum ss;
9587
9588 if (SCM_LIKELY (kk > 0))
9589 {
9590 do
9591 {
9592 ss = uu;
9593 uu = (ss + kk/ss) / 2;
9594 } while (uu < ss);
9595 *sp = SCM_I_MAKINUM (ss);
9596 *rp = SCM_I_MAKINUM (kk - ss*ss);
9597 }
9598 else if (SCM_LIKELY (kk == 0))
9599 *sp = *rp = SCM_INUM0;
9600 else
9601 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9602 "exact non-negative integer");
9603 }
9604 else if (SCM_LIKELY (SCM_BIGP (k)))
9605 {
9606 SCM s, r;
9607
9608 if (mpz_sgn (SCM_I_BIG_MPZ (k)) < 0)
9609 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9610 "exact non-negative integer");
9611 s = scm_i_mkbig ();
9612 r = scm_i_mkbig ();
9613 mpz_sqrtrem (SCM_I_BIG_MPZ (s), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (k));
9614 scm_remember_upto_here_1 (k);
9615 *sp = scm_i_normbig (s);
9616 *rp = scm_i_normbig (r);
9617 }
9618 else
9619 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9620 "exact non-negative integer");
9621}
9622
9623
2519490c
MW
9624SCM_PRIMITIVE_GENERIC (scm_sqrt, "sqrt", 1, 0, 0,
9625 (SCM z),
9626 "Return the square root of @var{z}. Of the two possible roots\n"
ffb62a43 9627 "(positive and negative), the one with positive real part\n"
2519490c
MW
9628 "is returned, or if that's zero then a positive imaginary part.\n"
9629 "Thus,\n"
9630 "\n"
9631 "@example\n"
9632 "(sqrt 9.0) @result{} 3.0\n"
9633 "(sqrt -9.0) @result{} 0.0+3.0i\n"
9634 "(sqrt 1.0+1.0i) @result{} 1.09868411346781+0.455089860562227i\n"
9635 "(sqrt -1.0-1.0i) @result{} 0.455089860562227-1.09868411346781i\n"
9636 "@end example")
8ab3d8a0
KR
9637#define FUNC_NAME s_scm_sqrt
9638{
2519490c 9639 if (SCM_COMPLEXP (z))
8ab3d8a0 9640 {
f328f862
LC
9641#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT \
9642 && defined SCM_COMPLEX_VALUE
2519490c 9643 return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (z)));
8ab3d8a0 9644#else
2519490c
MW
9645 double re = SCM_COMPLEX_REAL (z);
9646 double im = SCM_COMPLEX_IMAG (z);
8ab3d8a0
KR
9647 return scm_c_make_polar (sqrt (hypot (re, im)),
9648 0.5 * atan2 (im, re));
9649#endif
9650 }
2519490c 9651 else if (SCM_NUMBERP (z))
8ab3d8a0 9652 {
2519490c 9653 double xx = scm_to_double (z);
8ab3d8a0
KR
9654 if (xx < 0)
9655 return scm_c_make_rectangular (0.0, sqrt (-xx));
9656 else
9657 return scm_from_double (sqrt (xx));
9658 }
2519490c
MW
9659 else
9660 SCM_WTA_DISPATCH_1 (g_scm_sqrt, z, 1, s_scm_sqrt);
8ab3d8a0
KR
9661}
9662#undef FUNC_NAME
9663
9664
9665
0f2d19dd
JB
9666void
9667scm_init_numbers ()
0f2d19dd 9668{
0b799eea
MV
9669 int i;
9670
713a4259
KR
9671 mpz_init_set_si (z_negative_one, -1);
9672
a261c0e9
DH
9673 /* It may be possible to tune the performance of some algorithms by using
9674 * the following constants to avoid the creation of bignums. Please, before
9675 * using these values, remember the two rules of program optimization:
9676 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 9677 scm_c_define ("most-positive-fixnum",
d956fa6f 9678 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 9679 scm_c_define ("most-negative-fixnum",
d956fa6f 9680 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 9681
f3ae5d60
MD
9682 scm_add_feature ("complex");
9683 scm_add_feature ("inexact");
e7efe8e7 9684 flo0 = scm_from_double (0.0);
a5f6b751 9685 flo_log10e = scm_from_double (M_LOG10E);
0b799eea
MV
9686
9687 /* determine floating point precision */
55f26379 9688 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
9689 {
9690 init_dblprec(&scm_dblprec[i-2],i);
9691 init_fx_radix(fx_per_radix[i-2],i);
9692 }
f872b822 9693#ifdef DBL_DIG
0b799eea 9694 /* hard code precision for base 10 if the preprocessor tells us to... */
f39448c5 9695 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
0b799eea 9696#endif
1be6b49c 9697
cff5fa33 9698 exactly_one_half = scm_divide (SCM_INUM1, SCM_I_MAKINUM (2));
a0599745 9699#include "libguile/numbers.x"
0f2d19dd 9700}
89e00824
ML
9701
9702/*
9703 Local Variables:
9704 c-file-style: "gnu"
9705 End:
9706*/