scm_wta_* procedures replace SCM_WTA_* macros
[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
fa075d40 535 return 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
fa075d40 551 return 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 }
fa075d40 585 return 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 }
fa075d40 619 return 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
fa075d40 634 return 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
fa075d40 649 return 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
fa075d40 664 return 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
fa075d40 791 return 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
fa075d40 806 return scm_wta_dispatch_2 (g_scm_quotient, x, y, SCM_ARG2, s_scm_quotient);
f872b822 807 }
0aacf84e 808 else
fa075d40 809 return 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
fa075d40 827 return scm_wta_dispatch_2 (g_scm_remainder, x, y, SCM_ARG2, s_scm_remainder);
f872b822 828 }
0aacf84e 829 else
fa075d40 830 return 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
fa075d40 849 return scm_wta_dispatch_2 (g_scm_modulo, x, y, SCM_ARG2, s_scm_modulo);
828865c3 850 }
0aacf84e 851 else
fa075d40 852 return 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{
fa075d40
AW
873 SCM vals = scm_wta_dispatch_2 (gf, a1, a2, pos, subr);
874
875 scm_i_extract_values_2 (vals, rp1, rp2);
5fbf680b
MW
876}
877
a8da6d93
MW
878SCM_DEFINE (scm_euclidean_quotient, "euclidean-quotient", 2, 0, 0,
879 (SCM x, SCM y),
880 "Return the integer @var{q} such that\n"
881 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
882 "where @math{0 <= @var{r} < abs(@var{y})}.\n"
883 "@lisp\n"
884 "(euclidean-quotient 123 10) @result{} 12\n"
885 "(euclidean-quotient 123 -10) @result{} -12\n"
886 "(euclidean-quotient -123 10) @result{} -13\n"
887 "(euclidean-quotient -123 -10) @result{} 13\n"
888 "(euclidean-quotient -123.2 -63.5) @result{} 2.0\n"
889 "(euclidean-quotient 16/3 -10/7) @result{} -3\n"
890 "@end lisp")
ff62c168
MW
891#define FUNC_NAME s_scm_euclidean_quotient
892{
a8da6d93
MW
893 if (scm_is_false (scm_negative_p (y)))
894 return scm_floor_quotient (x, y);
ff62c168 895 else
a8da6d93 896 return scm_ceiling_quotient (x, y);
ff62c168
MW
897}
898#undef FUNC_NAME
899
a8da6d93
MW
900SCM_DEFINE (scm_euclidean_remainder, "euclidean-remainder", 2, 0, 0,
901 (SCM x, SCM y),
902 "Return the real number @var{r} such that\n"
903 "@math{0 <= @var{r} < abs(@var{y})} and\n"
904 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
905 "for some integer @var{q}.\n"
906 "@lisp\n"
907 "(euclidean-remainder 123 10) @result{} 3\n"
908 "(euclidean-remainder 123 -10) @result{} 3\n"
909 "(euclidean-remainder -123 10) @result{} 7\n"
910 "(euclidean-remainder -123 -10) @result{} 7\n"
911 "(euclidean-remainder -123.2 -63.5) @result{} 3.8\n"
912 "(euclidean-remainder 16/3 -10/7) @result{} 22/21\n"
913 "@end lisp")
ff62c168
MW
914#define FUNC_NAME s_scm_euclidean_remainder
915{
a8da6d93
MW
916 if (scm_is_false (scm_negative_p (y)))
917 return scm_floor_remainder (x, y);
ff62c168 918 else
a8da6d93 919 return scm_ceiling_remainder (x, y);
ff62c168
MW
920}
921#undef FUNC_NAME
922
a8da6d93
MW
923SCM_DEFINE (scm_i_euclidean_divide, "euclidean/", 2, 0, 0,
924 (SCM x, SCM y),
925 "Return the integer @var{q} and the real number @var{r}\n"
926 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
927 "and @math{0 <= @var{r} < abs(@var{y})}.\n"
928 "@lisp\n"
929 "(euclidean/ 123 10) @result{} 12 and 3\n"
930 "(euclidean/ 123 -10) @result{} -12 and 3\n"
931 "(euclidean/ -123 10) @result{} -13 and 7\n"
932 "(euclidean/ -123 -10) @result{} 13 and 7\n"
933 "(euclidean/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
934 "(euclidean/ 16/3 -10/7) @result{} -3 and 22/21\n"
935 "@end lisp")
5fbf680b
MW
936#define FUNC_NAME s_scm_i_euclidean_divide
937{
a8da6d93
MW
938 if (scm_is_false (scm_negative_p (y)))
939 return scm_i_floor_divide (x, y);
940 else
941 return scm_i_ceiling_divide (x, y);
5fbf680b
MW
942}
943#undef FUNC_NAME
944
5fbf680b
MW
945void
946scm_euclidean_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 947{
a8da6d93
MW
948 if (scm_is_false (scm_negative_p (y)))
949 return scm_floor_divide (x, y, qp, rp);
ff62c168 950 else
a8da6d93 951 return scm_ceiling_divide (x, y, qp, rp);
ff62c168
MW
952}
953
8f9da340
MW
954static SCM scm_i_inexact_floor_quotient (double x, double y);
955static SCM scm_i_exact_rational_floor_quotient (SCM x, SCM y);
956
957SCM_PRIMITIVE_GENERIC (scm_floor_quotient, "floor-quotient", 2, 0, 0,
958 (SCM x, SCM y),
959 "Return the floor of @math{@var{x} / @var{y}}.\n"
960 "@lisp\n"
961 "(floor-quotient 123 10) @result{} 12\n"
962 "(floor-quotient 123 -10) @result{} -13\n"
963 "(floor-quotient -123 10) @result{} -13\n"
964 "(floor-quotient -123 -10) @result{} 12\n"
965 "(floor-quotient -123.2 -63.5) @result{} 1.0\n"
966 "(floor-quotient 16/3 -10/7) @result{} -4\n"
967 "@end lisp")
968#define FUNC_NAME s_scm_floor_quotient
969{
970 if (SCM_LIKELY (SCM_I_INUMP (x)))
971 {
972 scm_t_inum xx = SCM_I_INUM (x);
973 if (SCM_LIKELY (SCM_I_INUMP (y)))
974 {
975 scm_t_inum yy = SCM_I_INUM (y);
976 scm_t_inum xx1 = xx;
977 scm_t_inum qq;
978 if (SCM_LIKELY (yy > 0))
979 {
980 if (SCM_UNLIKELY (xx < 0))
981 xx1 = xx - yy + 1;
982 }
983 else if (SCM_UNLIKELY (yy == 0))
984 scm_num_overflow (s_scm_floor_quotient);
985 else if (xx > 0)
986 xx1 = xx - yy - 1;
987 qq = xx1 / yy;
988 if (SCM_LIKELY (SCM_FIXABLE (qq)))
989 return SCM_I_MAKINUM (qq);
990 else
991 return scm_i_inum2big (qq);
992 }
993 else if (SCM_BIGP (y))
994 {
995 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
996 scm_remember_upto_here_1 (y);
997 if (sign > 0)
998 return SCM_I_MAKINUM ((xx < 0) ? -1 : 0);
999 else
1000 return SCM_I_MAKINUM ((xx > 0) ? -1 : 0);
1001 }
1002 else if (SCM_REALP (y))
1003 return scm_i_inexact_floor_quotient (xx, SCM_REAL_VALUE (y));
1004 else if (SCM_FRACTIONP (y))
1005 return scm_i_exact_rational_floor_quotient (x, y);
1006 else
fa075d40
AW
1007 return scm_wta_dispatch_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1008 s_scm_floor_quotient);
8f9da340
MW
1009 }
1010 else if (SCM_BIGP (x))
1011 {
1012 if (SCM_LIKELY (SCM_I_INUMP (y)))
1013 {
1014 scm_t_inum yy = SCM_I_INUM (y);
1015 if (SCM_UNLIKELY (yy == 0))
1016 scm_num_overflow (s_scm_floor_quotient);
1017 else if (SCM_UNLIKELY (yy == 1))
1018 return x;
1019 else
1020 {
1021 SCM q = scm_i_mkbig ();
1022 if (yy > 0)
1023 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1024 else
1025 {
1026 mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1027 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1028 }
1029 scm_remember_upto_here_1 (x);
1030 return scm_i_normbig (q);
1031 }
1032 }
1033 else if (SCM_BIGP (y))
1034 {
1035 SCM q = scm_i_mkbig ();
1036 mpz_fdiv_q (SCM_I_BIG_MPZ (q),
1037 SCM_I_BIG_MPZ (x),
1038 SCM_I_BIG_MPZ (y));
1039 scm_remember_upto_here_2 (x, y);
1040 return scm_i_normbig (q);
1041 }
1042 else if (SCM_REALP (y))
1043 return scm_i_inexact_floor_quotient
1044 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1045 else if (SCM_FRACTIONP (y))
1046 return scm_i_exact_rational_floor_quotient (x, y);
1047 else
fa075d40
AW
1048 return scm_wta_dispatch_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1049 s_scm_floor_quotient);
8f9da340
MW
1050 }
1051 else if (SCM_REALP (x))
1052 {
1053 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1054 SCM_BIGP (y) || SCM_FRACTIONP (y))
1055 return scm_i_inexact_floor_quotient
1056 (SCM_REAL_VALUE (x), scm_to_double (y));
1057 else
fa075d40
AW
1058 return scm_wta_dispatch_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1059 s_scm_floor_quotient);
8f9da340
MW
1060 }
1061 else if (SCM_FRACTIONP (x))
1062 {
1063 if (SCM_REALP (y))
1064 return scm_i_inexact_floor_quotient
1065 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1066 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1067 return scm_i_exact_rational_floor_quotient (x, y);
1068 else
fa075d40
AW
1069 return scm_wta_dispatch_2 (g_scm_floor_quotient, x, y, SCM_ARG2,
1070 s_scm_floor_quotient);
8f9da340
MW
1071 }
1072 else
fa075d40
AW
1073 return scm_wta_dispatch_2 (g_scm_floor_quotient, x, y, SCM_ARG1,
1074 s_scm_floor_quotient);
8f9da340
MW
1075}
1076#undef FUNC_NAME
1077
1078static SCM
1079scm_i_inexact_floor_quotient (double x, double y)
1080{
1081 if (SCM_UNLIKELY (y == 0))
1082 scm_num_overflow (s_scm_floor_quotient); /* or return a NaN? */
1083 else
1084 return scm_from_double (floor (x / y));
1085}
1086
1087static SCM
1088scm_i_exact_rational_floor_quotient (SCM x, SCM y)
1089{
1090 return scm_floor_quotient
1091 (scm_product (scm_numerator (x), scm_denominator (y)),
1092 scm_product (scm_numerator (y), scm_denominator (x)));
1093}
1094
1095static SCM scm_i_inexact_floor_remainder (double x, double y);
1096static SCM scm_i_exact_rational_floor_remainder (SCM x, SCM y);
1097
1098SCM_PRIMITIVE_GENERIC (scm_floor_remainder, "floor-remainder", 2, 0, 0,
1099 (SCM x, SCM y),
1100 "Return the real number @var{r} such that\n"
1101 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1102 "where @math{@var{q} = floor(@var{x} / @var{y})}.\n"
1103 "@lisp\n"
1104 "(floor-remainder 123 10) @result{} 3\n"
1105 "(floor-remainder 123 -10) @result{} -7\n"
1106 "(floor-remainder -123 10) @result{} 7\n"
1107 "(floor-remainder -123 -10) @result{} -3\n"
1108 "(floor-remainder -123.2 -63.5) @result{} -59.7\n"
1109 "(floor-remainder 16/3 -10/7) @result{} -8/21\n"
1110 "@end lisp")
1111#define FUNC_NAME s_scm_floor_remainder
1112{
1113 if (SCM_LIKELY (SCM_I_INUMP (x)))
1114 {
1115 scm_t_inum xx = SCM_I_INUM (x);
1116 if (SCM_LIKELY (SCM_I_INUMP (y)))
1117 {
1118 scm_t_inum yy = SCM_I_INUM (y);
1119 if (SCM_UNLIKELY (yy == 0))
1120 scm_num_overflow (s_scm_floor_remainder);
1121 else
1122 {
1123 scm_t_inum rr = xx % yy;
1124 int needs_adjustment;
1125
1126 if (SCM_LIKELY (yy > 0))
1127 needs_adjustment = (rr < 0);
1128 else
1129 needs_adjustment = (rr > 0);
1130
1131 if (needs_adjustment)
1132 rr += yy;
1133 return SCM_I_MAKINUM (rr);
1134 }
1135 }
1136 else if (SCM_BIGP (y))
1137 {
1138 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1139 scm_remember_upto_here_1 (y);
1140 if (sign > 0)
1141 {
1142 if (xx < 0)
1143 {
1144 SCM r = scm_i_mkbig ();
1145 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1146 scm_remember_upto_here_1 (y);
1147 return scm_i_normbig (r);
1148 }
1149 else
1150 return x;
1151 }
1152 else if (xx <= 0)
1153 return x;
1154 else
1155 {
1156 SCM r = scm_i_mkbig ();
1157 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1158 scm_remember_upto_here_1 (y);
1159 return scm_i_normbig (r);
1160 }
1161 }
1162 else if (SCM_REALP (y))
1163 return scm_i_inexact_floor_remainder (xx, SCM_REAL_VALUE (y));
1164 else if (SCM_FRACTIONP (y))
1165 return scm_i_exact_rational_floor_remainder (x, y);
1166 else
fa075d40
AW
1167 return scm_wta_dispatch_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1168 s_scm_floor_remainder);
8f9da340
MW
1169 }
1170 else if (SCM_BIGP (x))
1171 {
1172 if (SCM_LIKELY (SCM_I_INUMP (y)))
1173 {
1174 scm_t_inum yy = SCM_I_INUM (y);
1175 if (SCM_UNLIKELY (yy == 0))
1176 scm_num_overflow (s_scm_floor_remainder);
1177 else
1178 {
1179 scm_t_inum rr;
1180 if (yy > 0)
1181 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), yy);
1182 else
1183 rr = -mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1184 scm_remember_upto_here_1 (x);
1185 return SCM_I_MAKINUM (rr);
1186 }
1187 }
1188 else if (SCM_BIGP (y))
1189 {
1190 SCM r = scm_i_mkbig ();
1191 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
1192 SCM_I_BIG_MPZ (x),
1193 SCM_I_BIG_MPZ (y));
1194 scm_remember_upto_here_2 (x, y);
1195 return scm_i_normbig (r);
1196 }
1197 else if (SCM_REALP (y))
1198 return scm_i_inexact_floor_remainder
1199 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1200 else if (SCM_FRACTIONP (y))
1201 return scm_i_exact_rational_floor_remainder (x, y);
1202 else
fa075d40
AW
1203 return scm_wta_dispatch_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1204 s_scm_floor_remainder);
8f9da340
MW
1205 }
1206 else if (SCM_REALP (x))
1207 {
1208 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1209 SCM_BIGP (y) || SCM_FRACTIONP (y))
1210 return scm_i_inexact_floor_remainder
1211 (SCM_REAL_VALUE (x), scm_to_double (y));
1212 else
fa075d40
AW
1213 return scm_wta_dispatch_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1214 s_scm_floor_remainder);
8f9da340
MW
1215 }
1216 else if (SCM_FRACTIONP (x))
1217 {
1218 if (SCM_REALP (y))
1219 return scm_i_inexact_floor_remainder
1220 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1221 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1222 return scm_i_exact_rational_floor_remainder (x, y);
1223 else
fa075d40
AW
1224 return scm_wta_dispatch_2 (g_scm_floor_remainder, x, y, SCM_ARG2,
1225 s_scm_floor_remainder);
8f9da340
MW
1226 }
1227 else
fa075d40
AW
1228 return scm_wta_dispatch_2 (g_scm_floor_remainder, x, y, SCM_ARG1,
1229 s_scm_floor_remainder);
8f9da340
MW
1230}
1231#undef FUNC_NAME
1232
1233static SCM
1234scm_i_inexact_floor_remainder (double x, double y)
1235{
1236 /* Although it would be more efficient to use fmod here, we can't
1237 because it would in some cases produce results inconsistent with
1238 scm_i_inexact_floor_quotient, such that x != q * y + r (not even
1239 close). In particular, when x is very close to a multiple of y,
1240 then r might be either 0.0 or y, but those two cases must
1241 correspond to different choices of q. If r = 0.0 then q must be
1242 x/y, and if r = y then q must be x/y-1. If quotient chooses one
1243 and remainder chooses the other, it would be bad. */
1244 if (SCM_UNLIKELY (y == 0))
1245 scm_num_overflow (s_scm_floor_remainder); /* or return a NaN? */
1246 else
1247 return scm_from_double (x - y * floor (x / y));
1248}
1249
1250static SCM
1251scm_i_exact_rational_floor_remainder (SCM x, SCM y)
1252{
1253 SCM xd = scm_denominator (x);
1254 SCM yd = scm_denominator (y);
1255 SCM r1 = scm_floor_remainder (scm_product (scm_numerator (x), yd),
1256 scm_product (scm_numerator (y), xd));
1257 return scm_divide (r1, scm_product (xd, yd));
1258}
1259
1260
1261static void scm_i_inexact_floor_divide (double x, double y,
1262 SCM *qp, SCM *rp);
1263static void scm_i_exact_rational_floor_divide (SCM x, SCM y,
1264 SCM *qp, SCM *rp);
1265
1266SCM_PRIMITIVE_GENERIC (scm_i_floor_divide, "floor/", 2, 0, 0,
1267 (SCM x, SCM y),
1268 "Return the integer @var{q} and the real number @var{r}\n"
1269 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1270 "and @math{@var{q} = floor(@var{x} / @var{y})}.\n"
1271 "@lisp\n"
1272 "(floor/ 123 10) @result{} 12 and 3\n"
1273 "(floor/ 123 -10) @result{} -13 and -7\n"
1274 "(floor/ -123 10) @result{} -13 and 7\n"
1275 "(floor/ -123 -10) @result{} 12 and -3\n"
1276 "(floor/ -123.2 -63.5) @result{} 1.0 and -59.7\n"
1277 "(floor/ 16/3 -10/7) @result{} -4 and -8/21\n"
1278 "@end lisp")
1279#define FUNC_NAME s_scm_i_floor_divide
1280{
1281 SCM q, r;
1282
1283 scm_floor_divide(x, y, &q, &r);
1284 return scm_values (scm_list_2 (q, r));
1285}
1286#undef FUNC_NAME
1287
1288#define s_scm_floor_divide s_scm_i_floor_divide
1289#define g_scm_floor_divide g_scm_i_floor_divide
1290
1291void
1292scm_floor_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1293{
1294 if (SCM_LIKELY (SCM_I_INUMP (x)))
1295 {
1296 scm_t_inum xx = SCM_I_INUM (x);
1297 if (SCM_LIKELY (SCM_I_INUMP (y)))
1298 {
1299 scm_t_inum yy = SCM_I_INUM (y);
1300 if (SCM_UNLIKELY (yy == 0))
1301 scm_num_overflow (s_scm_floor_divide);
1302 else
1303 {
1304 scm_t_inum qq = xx / yy;
1305 scm_t_inum rr = xx % yy;
1306 int needs_adjustment;
1307
1308 if (SCM_LIKELY (yy > 0))
1309 needs_adjustment = (rr < 0);
1310 else
1311 needs_adjustment = (rr > 0);
1312
1313 if (needs_adjustment)
1314 {
1315 rr += yy;
1316 qq--;
1317 }
1318
1319 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1320 *qp = SCM_I_MAKINUM (qq);
1321 else
1322 *qp = scm_i_inum2big (qq);
1323 *rp = SCM_I_MAKINUM (rr);
1324 }
1325 return;
1326 }
1327 else if (SCM_BIGP (y))
1328 {
1329 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1330 scm_remember_upto_here_1 (y);
1331 if (sign > 0)
1332 {
1333 if (xx < 0)
1334 {
1335 SCM r = scm_i_mkbig ();
1336 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1337 scm_remember_upto_here_1 (y);
1338 *qp = SCM_I_MAKINUM (-1);
1339 *rp = scm_i_normbig (r);
1340 }
1341 else
1342 {
1343 *qp = SCM_INUM0;
1344 *rp = x;
1345 }
1346 }
1347 else if (xx <= 0)
1348 {
1349 *qp = SCM_INUM0;
1350 *rp = x;
1351 }
1352 else
1353 {
1354 SCM r = scm_i_mkbig ();
1355 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1356 scm_remember_upto_here_1 (y);
1357 *qp = SCM_I_MAKINUM (-1);
1358 *rp = scm_i_normbig (r);
1359 }
1360 return;
1361 }
1362 else if (SCM_REALP (y))
1363 return scm_i_inexact_floor_divide (xx, SCM_REAL_VALUE (y), qp, rp);
1364 else if (SCM_FRACTIONP (y))
1365 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1366 else
1367 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1368 s_scm_floor_divide, qp, rp);
1369 }
1370 else if (SCM_BIGP (x))
1371 {
1372 if (SCM_LIKELY (SCM_I_INUMP (y)))
1373 {
1374 scm_t_inum yy = SCM_I_INUM (y);
1375 if (SCM_UNLIKELY (yy == 0))
1376 scm_num_overflow (s_scm_floor_divide);
1377 else
1378 {
1379 SCM q = scm_i_mkbig ();
1380 SCM r = scm_i_mkbig ();
1381 if (yy > 0)
1382 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1383 SCM_I_BIG_MPZ (x), yy);
1384 else
1385 {
1386 mpz_cdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1387 SCM_I_BIG_MPZ (x), -yy);
1388 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1389 }
1390 scm_remember_upto_here_1 (x);
1391 *qp = scm_i_normbig (q);
1392 *rp = scm_i_normbig (r);
1393 }
1394 return;
1395 }
1396 else if (SCM_BIGP (y))
1397 {
1398 SCM q = scm_i_mkbig ();
1399 SCM r = scm_i_mkbig ();
1400 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1401 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1402 scm_remember_upto_here_2 (x, y);
1403 *qp = scm_i_normbig (q);
1404 *rp = scm_i_normbig (r);
1405 return;
1406 }
1407 else if (SCM_REALP (y))
1408 return scm_i_inexact_floor_divide
1409 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
1410 else if (SCM_FRACTIONP (y))
1411 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1412 else
1413 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1414 s_scm_floor_divide, qp, rp);
1415 }
1416 else if (SCM_REALP (x))
1417 {
1418 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1419 SCM_BIGP (y) || SCM_FRACTIONP (y))
1420 return scm_i_inexact_floor_divide
1421 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
1422 else
1423 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1424 s_scm_floor_divide, qp, rp);
1425 }
1426 else if (SCM_FRACTIONP (x))
1427 {
1428 if (SCM_REALP (y))
1429 return scm_i_inexact_floor_divide
1430 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
1431 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1432 return scm_i_exact_rational_floor_divide (x, y, qp, rp);
1433 else
1434 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG2,
1435 s_scm_floor_divide, qp, rp);
1436 }
1437 else
1438 return two_valued_wta_dispatch_2 (g_scm_floor_divide, x, y, SCM_ARG1,
1439 s_scm_floor_divide, qp, rp);
1440}
1441
1442static void
1443scm_i_inexact_floor_divide (double x, double y, SCM *qp, SCM *rp)
1444{
1445 if (SCM_UNLIKELY (y == 0))
1446 scm_num_overflow (s_scm_floor_divide); /* or return a NaN? */
1447 else
1448 {
1449 double q = floor (x / y);
1450 double r = x - q * y;
1451 *qp = scm_from_double (q);
1452 *rp = scm_from_double (r);
1453 }
1454}
1455
1456static void
1457scm_i_exact_rational_floor_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1458{
1459 SCM r1;
1460 SCM xd = scm_denominator (x);
1461 SCM yd = scm_denominator (y);
1462
1463 scm_floor_divide (scm_product (scm_numerator (x), yd),
1464 scm_product (scm_numerator (y), xd),
1465 qp, &r1);
1466 *rp = scm_divide (r1, scm_product (xd, yd));
1467}
1468
1469static SCM scm_i_inexact_ceiling_quotient (double x, double y);
1470static SCM scm_i_exact_rational_ceiling_quotient (SCM x, SCM y);
1471
1472SCM_PRIMITIVE_GENERIC (scm_ceiling_quotient, "ceiling-quotient", 2, 0, 0,
1473 (SCM x, SCM y),
1474 "Return the ceiling of @math{@var{x} / @var{y}}.\n"
1475 "@lisp\n"
1476 "(ceiling-quotient 123 10) @result{} 13\n"
1477 "(ceiling-quotient 123 -10) @result{} -12\n"
1478 "(ceiling-quotient -123 10) @result{} -12\n"
1479 "(ceiling-quotient -123 -10) @result{} 13\n"
1480 "(ceiling-quotient -123.2 -63.5) @result{} 2.0\n"
1481 "(ceiling-quotient 16/3 -10/7) @result{} -3\n"
1482 "@end lisp")
1483#define FUNC_NAME s_scm_ceiling_quotient
1484{
1485 if (SCM_LIKELY (SCM_I_INUMP (x)))
1486 {
1487 scm_t_inum xx = SCM_I_INUM (x);
1488 if (SCM_LIKELY (SCM_I_INUMP (y)))
1489 {
1490 scm_t_inum yy = SCM_I_INUM (y);
1491 if (SCM_UNLIKELY (yy == 0))
1492 scm_num_overflow (s_scm_ceiling_quotient);
1493 else
1494 {
1495 scm_t_inum xx1 = xx;
1496 scm_t_inum qq;
1497 if (SCM_LIKELY (yy > 0))
1498 {
1499 if (SCM_LIKELY (xx >= 0))
1500 xx1 = xx + yy - 1;
1501 }
1502 else if (SCM_UNLIKELY (yy == 0))
1503 scm_num_overflow (s_scm_ceiling_quotient);
1504 else if (xx < 0)
1505 xx1 = xx + yy + 1;
1506 qq = xx1 / yy;
1507 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1508 return SCM_I_MAKINUM (qq);
1509 else
1510 return scm_i_inum2big (qq);
1511 }
1512 }
1513 else if (SCM_BIGP (y))
1514 {
1515 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1516 scm_remember_upto_here_1 (y);
1517 if (SCM_LIKELY (sign > 0))
1518 {
1519 if (SCM_LIKELY (xx > 0))
1520 return SCM_INUM1;
1521 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1522 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1523 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1524 {
1525 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1526 scm_remember_upto_here_1 (y);
1527 return SCM_I_MAKINUM (-1);
1528 }
1529 else
1530 return SCM_INUM0;
1531 }
1532 else if (xx >= 0)
1533 return SCM_INUM0;
1534 else
1535 return SCM_INUM1;
1536 }
1537 else if (SCM_REALP (y))
1538 return scm_i_inexact_ceiling_quotient (xx, SCM_REAL_VALUE (y));
1539 else if (SCM_FRACTIONP (y))
1540 return scm_i_exact_rational_ceiling_quotient (x, y);
1541 else
fa075d40
AW
1542 return scm_wta_dispatch_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1543 s_scm_ceiling_quotient);
8f9da340
MW
1544 }
1545 else if (SCM_BIGP (x))
1546 {
1547 if (SCM_LIKELY (SCM_I_INUMP (y)))
1548 {
1549 scm_t_inum yy = SCM_I_INUM (y);
1550 if (SCM_UNLIKELY (yy == 0))
1551 scm_num_overflow (s_scm_ceiling_quotient);
1552 else if (SCM_UNLIKELY (yy == 1))
1553 return x;
1554 else
1555 {
1556 SCM q = scm_i_mkbig ();
1557 if (yy > 0)
1558 mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
1559 else
1560 {
1561 mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
1562 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1563 }
1564 scm_remember_upto_here_1 (x);
1565 return scm_i_normbig (q);
1566 }
1567 }
1568 else if (SCM_BIGP (y))
1569 {
1570 SCM q = scm_i_mkbig ();
1571 mpz_cdiv_q (SCM_I_BIG_MPZ (q),
1572 SCM_I_BIG_MPZ (x),
1573 SCM_I_BIG_MPZ (y));
1574 scm_remember_upto_here_2 (x, y);
1575 return scm_i_normbig (q);
1576 }
1577 else if (SCM_REALP (y))
1578 return scm_i_inexact_ceiling_quotient
1579 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1580 else if (SCM_FRACTIONP (y))
1581 return scm_i_exact_rational_ceiling_quotient (x, y);
1582 else
fa075d40
AW
1583 return scm_wta_dispatch_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1584 s_scm_ceiling_quotient);
8f9da340
MW
1585 }
1586 else if (SCM_REALP (x))
1587 {
1588 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1589 SCM_BIGP (y) || SCM_FRACTIONP (y))
1590 return scm_i_inexact_ceiling_quotient
1591 (SCM_REAL_VALUE (x), scm_to_double (y));
1592 else
fa075d40
AW
1593 return scm_wta_dispatch_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1594 s_scm_ceiling_quotient);
8f9da340
MW
1595 }
1596 else if (SCM_FRACTIONP (x))
1597 {
1598 if (SCM_REALP (y))
1599 return scm_i_inexact_ceiling_quotient
1600 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1601 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1602 return scm_i_exact_rational_ceiling_quotient (x, y);
1603 else
fa075d40
AW
1604 return scm_wta_dispatch_2 (g_scm_ceiling_quotient, x, y, SCM_ARG2,
1605 s_scm_ceiling_quotient);
8f9da340
MW
1606 }
1607 else
fa075d40
AW
1608 return scm_wta_dispatch_2 (g_scm_ceiling_quotient, x, y, SCM_ARG1,
1609 s_scm_ceiling_quotient);
8f9da340
MW
1610}
1611#undef FUNC_NAME
1612
1613static SCM
1614scm_i_inexact_ceiling_quotient (double x, double y)
1615{
1616 if (SCM_UNLIKELY (y == 0))
1617 scm_num_overflow (s_scm_ceiling_quotient); /* or return a NaN? */
1618 else
1619 return scm_from_double (ceil (x / y));
1620}
1621
1622static SCM
1623scm_i_exact_rational_ceiling_quotient (SCM x, SCM y)
1624{
1625 return scm_ceiling_quotient
1626 (scm_product (scm_numerator (x), scm_denominator (y)),
1627 scm_product (scm_numerator (y), scm_denominator (x)));
1628}
1629
1630static SCM scm_i_inexact_ceiling_remainder (double x, double y);
1631static SCM scm_i_exact_rational_ceiling_remainder (SCM x, SCM y);
1632
1633SCM_PRIMITIVE_GENERIC (scm_ceiling_remainder, "ceiling-remainder", 2, 0, 0,
1634 (SCM x, SCM y),
1635 "Return the real number @var{r} such that\n"
1636 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1637 "where @math{@var{q} = ceiling(@var{x} / @var{y})}.\n"
1638 "@lisp\n"
1639 "(ceiling-remainder 123 10) @result{} -7\n"
1640 "(ceiling-remainder 123 -10) @result{} 3\n"
1641 "(ceiling-remainder -123 10) @result{} -3\n"
1642 "(ceiling-remainder -123 -10) @result{} 7\n"
1643 "(ceiling-remainder -123.2 -63.5) @result{} 3.8\n"
1644 "(ceiling-remainder 16/3 -10/7) @result{} 22/21\n"
1645 "@end lisp")
1646#define FUNC_NAME s_scm_ceiling_remainder
1647{
1648 if (SCM_LIKELY (SCM_I_INUMP (x)))
1649 {
1650 scm_t_inum xx = SCM_I_INUM (x);
1651 if (SCM_LIKELY (SCM_I_INUMP (y)))
1652 {
1653 scm_t_inum yy = SCM_I_INUM (y);
1654 if (SCM_UNLIKELY (yy == 0))
1655 scm_num_overflow (s_scm_ceiling_remainder);
1656 else
1657 {
1658 scm_t_inum rr = xx % yy;
1659 int needs_adjustment;
1660
1661 if (SCM_LIKELY (yy > 0))
1662 needs_adjustment = (rr > 0);
1663 else
1664 needs_adjustment = (rr < 0);
1665
1666 if (needs_adjustment)
1667 rr -= yy;
1668 return SCM_I_MAKINUM (rr);
1669 }
1670 }
1671 else if (SCM_BIGP (y))
1672 {
1673 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1674 scm_remember_upto_here_1 (y);
1675 if (SCM_LIKELY (sign > 0))
1676 {
1677 if (SCM_LIKELY (xx > 0))
1678 {
1679 SCM r = scm_i_mkbig ();
1680 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1681 scm_remember_upto_here_1 (y);
1682 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1683 return scm_i_normbig (r);
1684 }
1685 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1686 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1687 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1688 {
1689 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1690 scm_remember_upto_here_1 (y);
1691 return SCM_INUM0;
1692 }
1693 else
1694 return x;
1695 }
1696 else if (xx >= 0)
1697 return x;
1698 else
1699 {
1700 SCM r = scm_i_mkbig ();
1701 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1702 scm_remember_upto_here_1 (y);
1703 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1704 return scm_i_normbig (r);
1705 }
1706 }
1707 else if (SCM_REALP (y))
1708 return scm_i_inexact_ceiling_remainder (xx, SCM_REAL_VALUE (y));
1709 else if (SCM_FRACTIONP (y))
1710 return scm_i_exact_rational_ceiling_remainder (x, y);
1711 else
fa075d40
AW
1712 return scm_wta_dispatch_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1713 s_scm_ceiling_remainder);
8f9da340
MW
1714 }
1715 else if (SCM_BIGP (x))
1716 {
1717 if (SCM_LIKELY (SCM_I_INUMP (y)))
1718 {
1719 scm_t_inum yy = SCM_I_INUM (y);
1720 if (SCM_UNLIKELY (yy == 0))
1721 scm_num_overflow (s_scm_ceiling_remainder);
1722 else
1723 {
1724 scm_t_inum rr;
1725 if (yy > 0)
1726 rr = -mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
1727 else
1728 rr = mpz_fdiv_ui (SCM_I_BIG_MPZ (x), -yy);
1729 scm_remember_upto_here_1 (x);
1730 return SCM_I_MAKINUM (rr);
1731 }
1732 }
1733 else if (SCM_BIGP (y))
1734 {
1735 SCM r = scm_i_mkbig ();
1736 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
1737 SCM_I_BIG_MPZ (x),
1738 SCM_I_BIG_MPZ (y));
1739 scm_remember_upto_here_2 (x, y);
1740 return scm_i_normbig (r);
1741 }
1742 else if (SCM_REALP (y))
1743 return scm_i_inexact_ceiling_remainder
1744 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
1745 else if (SCM_FRACTIONP (y))
1746 return scm_i_exact_rational_ceiling_remainder (x, y);
1747 else
fa075d40
AW
1748 return scm_wta_dispatch_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1749 s_scm_ceiling_remainder);
8f9da340
MW
1750 }
1751 else if (SCM_REALP (x))
1752 {
1753 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1754 SCM_BIGP (y) || SCM_FRACTIONP (y))
1755 return scm_i_inexact_ceiling_remainder
1756 (SCM_REAL_VALUE (x), scm_to_double (y));
1757 else
fa075d40
AW
1758 return scm_wta_dispatch_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1759 s_scm_ceiling_remainder);
8f9da340
MW
1760 }
1761 else if (SCM_FRACTIONP (x))
1762 {
1763 if (SCM_REALP (y))
1764 return scm_i_inexact_ceiling_remainder
1765 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
1766 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1767 return scm_i_exact_rational_ceiling_remainder (x, y);
1768 else
fa075d40
AW
1769 return scm_wta_dispatch_2 (g_scm_ceiling_remainder, x, y, SCM_ARG2,
1770 s_scm_ceiling_remainder);
8f9da340
MW
1771 }
1772 else
fa075d40
AW
1773 return scm_wta_dispatch_2 (g_scm_ceiling_remainder, x, y, SCM_ARG1,
1774 s_scm_ceiling_remainder);
8f9da340
MW
1775}
1776#undef FUNC_NAME
1777
1778static SCM
1779scm_i_inexact_ceiling_remainder (double x, double y)
1780{
1781 /* Although it would be more efficient to use fmod here, we can't
1782 because it would in some cases produce results inconsistent with
1783 scm_i_inexact_ceiling_quotient, such that x != q * y + r (not even
1784 close). In particular, when x is very close to a multiple of y,
1785 then r might be either 0.0 or -y, but those two cases must
1786 correspond to different choices of q. If r = 0.0 then q must be
1787 x/y, and if r = -y then q must be x/y+1. If quotient chooses one
1788 and remainder chooses the other, it would be bad. */
1789 if (SCM_UNLIKELY (y == 0))
1790 scm_num_overflow (s_scm_ceiling_remainder); /* or return a NaN? */
1791 else
1792 return scm_from_double (x - y * ceil (x / y));
1793}
1794
1795static SCM
1796scm_i_exact_rational_ceiling_remainder (SCM x, SCM y)
1797{
1798 SCM xd = scm_denominator (x);
1799 SCM yd = scm_denominator (y);
1800 SCM r1 = scm_ceiling_remainder (scm_product (scm_numerator (x), yd),
1801 scm_product (scm_numerator (y), xd));
1802 return scm_divide (r1, scm_product (xd, yd));
1803}
1804
1805static void scm_i_inexact_ceiling_divide (double x, double y,
1806 SCM *qp, SCM *rp);
1807static void scm_i_exact_rational_ceiling_divide (SCM x, SCM y,
1808 SCM *qp, SCM *rp);
1809
1810SCM_PRIMITIVE_GENERIC (scm_i_ceiling_divide, "ceiling/", 2, 0, 0,
1811 (SCM x, SCM y),
1812 "Return the integer @var{q} and the real number @var{r}\n"
1813 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
1814 "and @math{@var{q} = ceiling(@var{x} / @var{y})}.\n"
1815 "@lisp\n"
1816 "(ceiling/ 123 10) @result{} 13 and -7\n"
1817 "(ceiling/ 123 -10) @result{} -12 and 3\n"
1818 "(ceiling/ -123 10) @result{} -12 and -3\n"
1819 "(ceiling/ -123 -10) @result{} 13 and 7\n"
1820 "(ceiling/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
1821 "(ceiling/ 16/3 -10/7) @result{} -3 and 22/21\n"
1822 "@end lisp")
1823#define FUNC_NAME s_scm_i_ceiling_divide
1824{
1825 SCM q, r;
1826
1827 scm_ceiling_divide(x, y, &q, &r);
1828 return scm_values (scm_list_2 (q, r));
1829}
1830#undef FUNC_NAME
1831
1832#define s_scm_ceiling_divide s_scm_i_ceiling_divide
1833#define g_scm_ceiling_divide g_scm_i_ceiling_divide
1834
1835void
1836scm_ceiling_divide (SCM x, SCM y, SCM *qp, SCM *rp)
1837{
1838 if (SCM_LIKELY (SCM_I_INUMP (x)))
1839 {
1840 scm_t_inum xx = SCM_I_INUM (x);
1841 if (SCM_LIKELY (SCM_I_INUMP (y)))
1842 {
1843 scm_t_inum yy = SCM_I_INUM (y);
1844 if (SCM_UNLIKELY (yy == 0))
1845 scm_num_overflow (s_scm_ceiling_divide);
1846 else
1847 {
1848 scm_t_inum qq = xx / yy;
1849 scm_t_inum rr = xx % yy;
1850 int needs_adjustment;
1851
1852 if (SCM_LIKELY (yy > 0))
1853 needs_adjustment = (rr > 0);
1854 else
1855 needs_adjustment = (rr < 0);
1856
1857 if (needs_adjustment)
1858 {
1859 rr -= yy;
1860 qq++;
1861 }
1862 if (SCM_LIKELY (SCM_FIXABLE (qq)))
1863 *qp = SCM_I_MAKINUM (qq);
1864 else
1865 *qp = scm_i_inum2big (qq);
1866 *rp = SCM_I_MAKINUM (rr);
1867 }
1868 return;
1869 }
1870 else if (SCM_BIGP (y))
1871 {
1872 int sign = mpz_sgn (SCM_I_BIG_MPZ (y));
1873 scm_remember_upto_here_1 (y);
1874 if (SCM_LIKELY (sign > 0))
1875 {
1876 if (SCM_LIKELY (xx > 0))
1877 {
1878 SCM r = scm_i_mkbig ();
1879 mpz_sub_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), xx);
1880 scm_remember_upto_here_1 (y);
1881 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1882 *qp = SCM_INUM1;
1883 *rp = scm_i_normbig (r);
1884 }
1885 else if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
1886 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
1887 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
1888 {
1889 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
1890 scm_remember_upto_here_1 (y);
1891 *qp = SCM_I_MAKINUM (-1);
1892 *rp = SCM_INUM0;
1893 }
1894 else
1895 {
1896 *qp = SCM_INUM0;
1897 *rp = x;
1898 }
1899 }
1900 else if (xx >= 0)
1901 {
1902 *qp = SCM_INUM0;
1903 *rp = x;
1904 }
1905 else
1906 {
1907 SCM r = scm_i_mkbig ();
1908 mpz_add_ui (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y), -xx);
1909 scm_remember_upto_here_1 (y);
1910 mpz_neg (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r));
1911 *qp = SCM_INUM1;
1912 *rp = scm_i_normbig (r);
1913 }
1914 return;
1915 }
1916 else if (SCM_REALP (y))
1917 return scm_i_inexact_ceiling_divide (xx, SCM_REAL_VALUE (y), qp, rp);
1918 else if (SCM_FRACTIONP (y))
1919 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1920 else
1921 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1922 s_scm_ceiling_divide, qp, rp);
1923 }
1924 else if (SCM_BIGP (x))
1925 {
1926 if (SCM_LIKELY (SCM_I_INUMP (y)))
1927 {
1928 scm_t_inum yy = SCM_I_INUM (y);
1929 if (SCM_UNLIKELY (yy == 0))
1930 scm_num_overflow (s_scm_ceiling_divide);
1931 else
1932 {
1933 SCM q = scm_i_mkbig ();
1934 SCM r = scm_i_mkbig ();
1935 if (yy > 0)
1936 mpz_cdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1937 SCM_I_BIG_MPZ (x), yy);
1938 else
1939 {
1940 mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1941 SCM_I_BIG_MPZ (x), -yy);
1942 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
1943 }
1944 scm_remember_upto_here_1 (x);
1945 *qp = scm_i_normbig (q);
1946 *rp = scm_i_normbig (r);
1947 }
1948 return;
1949 }
1950 else if (SCM_BIGP (y))
1951 {
1952 SCM q = scm_i_mkbig ();
1953 SCM r = scm_i_mkbig ();
1954 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
1955 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
1956 scm_remember_upto_here_2 (x, y);
1957 *qp = scm_i_normbig (q);
1958 *rp = scm_i_normbig (r);
1959 return;
1960 }
1961 else if (SCM_REALP (y))
1962 return scm_i_inexact_ceiling_divide
1963 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
1964 else if (SCM_FRACTIONP (y))
1965 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1966 else
1967 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1968 s_scm_ceiling_divide, qp, rp);
1969 }
1970 else if (SCM_REALP (x))
1971 {
1972 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
1973 SCM_BIGP (y) || SCM_FRACTIONP (y))
1974 return scm_i_inexact_ceiling_divide
1975 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
1976 else
1977 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1978 s_scm_ceiling_divide, qp, rp);
1979 }
1980 else if (SCM_FRACTIONP (x))
1981 {
1982 if (SCM_REALP (y))
1983 return scm_i_inexact_ceiling_divide
1984 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
1985 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
1986 return scm_i_exact_rational_ceiling_divide (x, y, qp, rp);
1987 else
1988 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG2,
1989 s_scm_ceiling_divide, qp, rp);
1990 }
1991 else
1992 return two_valued_wta_dispatch_2 (g_scm_ceiling_divide, x, y, SCM_ARG1,
1993 s_scm_ceiling_divide, qp, rp);
1994}
1995
1996static void
1997scm_i_inexact_ceiling_divide (double x, double y, SCM *qp, SCM *rp)
1998{
1999 if (SCM_UNLIKELY (y == 0))
2000 scm_num_overflow (s_scm_ceiling_divide); /* or return a NaN? */
2001 else
2002 {
2003 double q = ceil (x / y);
2004 double r = x - q * y;
2005 *qp = scm_from_double (q);
2006 *rp = scm_from_double (r);
2007 }
2008}
2009
2010static void
2011scm_i_exact_rational_ceiling_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2012{
2013 SCM r1;
2014 SCM xd = scm_denominator (x);
2015 SCM yd = scm_denominator (y);
2016
2017 scm_ceiling_divide (scm_product (scm_numerator (x), yd),
2018 scm_product (scm_numerator (y), xd),
2019 qp, &r1);
2020 *rp = scm_divide (r1, scm_product (xd, yd));
2021}
2022
2023static SCM scm_i_inexact_truncate_quotient (double x, double y);
2024static SCM scm_i_exact_rational_truncate_quotient (SCM x, SCM y);
2025
2026SCM_PRIMITIVE_GENERIC (scm_truncate_quotient, "truncate-quotient", 2, 0, 0,
2027 (SCM x, SCM y),
2028 "Return @math{@var{x} / @var{y}} rounded toward zero.\n"
2029 "@lisp\n"
2030 "(truncate-quotient 123 10) @result{} 12\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.2 -63.5) @result{} 1.0\n"
2035 "(truncate-quotient 16/3 -10/7) @result{} -3\n"
2036 "@end lisp")
2037#define FUNC_NAME s_scm_truncate_quotient
2038{
2039 if (SCM_LIKELY (SCM_I_INUMP (x)))
2040 {
2041 scm_t_inum xx = SCM_I_INUM (x);
2042 if (SCM_LIKELY (SCM_I_INUMP (y)))
2043 {
2044 scm_t_inum yy = SCM_I_INUM (y);
2045 if (SCM_UNLIKELY (yy == 0))
2046 scm_num_overflow (s_scm_truncate_quotient);
2047 else
2048 {
2049 scm_t_inum qq = xx / yy;
2050 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2051 return SCM_I_MAKINUM (qq);
2052 else
2053 return scm_i_inum2big (qq);
2054 }
2055 }
2056 else if (SCM_BIGP (y))
2057 {
2058 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2059 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2060 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2061 {
2062 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2063 scm_remember_upto_here_1 (y);
2064 return SCM_I_MAKINUM (-1);
2065 }
2066 else
2067 return SCM_INUM0;
2068 }
2069 else if (SCM_REALP (y))
2070 return scm_i_inexact_truncate_quotient (xx, SCM_REAL_VALUE (y));
2071 else if (SCM_FRACTIONP (y))
2072 return scm_i_exact_rational_truncate_quotient (x, y);
2073 else
fa075d40
AW
2074 return scm_wta_dispatch_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2075 s_scm_truncate_quotient);
8f9da340
MW
2076 }
2077 else if (SCM_BIGP (x))
2078 {
2079 if (SCM_LIKELY (SCM_I_INUMP (y)))
2080 {
2081 scm_t_inum yy = SCM_I_INUM (y);
2082 if (SCM_UNLIKELY (yy == 0))
2083 scm_num_overflow (s_scm_truncate_quotient);
2084 else if (SCM_UNLIKELY (yy == 1))
2085 return x;
2086 else
2087 {
2088 SCM q = scm_i_mkbig ();
2089 if (yy > 0)
2090 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), yy);
2091 else
2092 {
2093 mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (x), -yy);
2094 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2095 }
2096 scm_remember_upto_here_1 (x);
2097 return scm_i_normbig (q);
2098 }
2099 }
2100 else if (SCM_BIGP (y))
2101 {
2102 SCM q = scm_i_mkbig ();
2103 mpz_tdiv_q (SCM_I_BIG_MPZ (q),
2104 SCM_I_BIG_MPZ (x),
2105 SCM_I_BIG_MPZ (y));
2106 scm_remember_upto_here_2 (x, y);
2107 return scm_i_normbig (q);
2108 }
2109 else if (SCM_REALP (y))
2110 return scm_i_inexact_truncate_quotient
2111 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2112 else if (SCM_FRACTIONP (y))
2113 return scm_i_exact_rational_truncate_quotient (x, y);
2114 else
fa075d40
AW
2115 return scm_wta_dispatch_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2116 s_scm_truncate_quotient);
8f9da340
MW
2117 }
2118 else if (SCM_REALP (x))
2119 {
2120 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2121 SCM_BIGP (y) || SCM_FRACTIONP (y))
2122 return scm_i_inexact_truncate_quotient
2123 (SCM_REAL_VALUE (x), scm_to_double (y));
2124 else
fa075d40
AW
2125 return scm_wta_dispatch_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2126 s_scm_truncate_quotient);
8f9da340
MW
2127 }
2128 else if (SCM_FRACTIONP (x))
2129 {
2130 if (SCM_REALP (y))
2131 return scm_i_inexact_truncate_quotient
2132 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2133 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2134 return scm_i_exact_rational_truncate_quotient (x, y);
2135 else
fa075d40
AW
2136 return scm_wta_dispatch_2 (g_scm_truncate_quotient, x, y, SCM_ARG2,
2137 s_scm_truncate_quotient);
8f9da340
MW
2138 }
2139 else
fa075d40
AW
2140 return scm_wta_dispatch_2 (g_scm_truncate_quotient, x, y, SCM_ARG1,
2141 s_scm_truncate_quotient);
8f9da340
MW
2142}
2143#undef FUNC_NAME
2144
2145static SCM
2146scm_i_inexact_truncate_quotient (double x, double y)
2147{
2148 if (SCM_UNLIKELY (y == 0))
2149 scm_num_overflow (s_scm_truncate_quotient); /* or return a NaN? */
2150 else
c251ab63 2151 return scm_from_double (trunc (x / y));
8f9da340
MW
2152}
2153
2154static SCM
2155scm_i_exact_rational_truncate_quotient (SCM x, SCM y)
2156{
2157 return scm_truncate_quotient
2158 (scm_product (scm_numerator (x), scm_denominator (y)),
2159 scm_product (scm_numerator (y), scm_denominator (x)));
2160}
2161
2162static SCM scm_i_inexact_truncate_remainder (double x, double y);
2163static SCM scm_i_exact_rational_truncate_remainder (SCM x, SCM y);
2164
2165SCM_PRIMITIVE_GENERIC (scm_truncate_remainder, "truncate-remainder", 2, 0, 0,
2166 (SCM x, SCM y),
2167 "Return the real number @var{r} such that\n"
2168 "@math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2169 "where @math{@var{q} = truncate(@var{x} / @var{y})}.\n"
2170 "@lisp\n"
2171 "(truncate-remainder 123 10) @result{} 3\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.2 -63.5) @result{} -59.7\n"
2176 "(truncate-remainder 16/3 -10/7) @result{} 22/21\n"
2177 "@end lisp")
2178#define FUNC_NAME s_scm_truncate_remainder
2179{
2180 if (SCM_LIKELY (SCM_I_INUMP (x)))
2181 {
2182 scm_t_inum xx = SCM_I_INUM (x);
2183 if (SCM_LIKELY (SCM_I_INUMP (y)))
2184 {
2185 scm_t_inum yy = SCM_I_INUM (y);
2186 if (SCM_UNLIKELY (yy == 0))
2187 scm_num_overflow (s_scm_truncate_remainder);
2188 else
2189 return SCM_I_MAKINUM (xx % yy);
2190 }
2191 else if (SCM_BIGP (y))
2192 {
2193 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2194 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2195 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2196 {
2197 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2198 scm_remember_upto_here_1 (y);
2199 return SCM_INUM0;
2200 }
2201 else
2202 return x;
2203 }
2204 else if (SCM_REALP (y))
2205 return scm_i_inexact_truncate_remainder (xx, SCM_REAL_VALUE (y));
2206 else if (SCM_FRACTIONP (y))
2207 return scm_i_exact_rational_truncate_remainder (x, y);
2208 else
fa075d40
AW
2209 return scm_wta_dispatch_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2210 s_scm_truncate_remainder);
8f9da340
MW
2211 }
2212 else if (SCM_BIGP (x))
2213 {
2214 if (SCM_LIKELY (SCM_I_INUMP (y)))
2215 {
2216 scm_t_inum yy = SCM_I_INUM (y);
2217 if (SCM_UNLIKELY (yy == 0))
2218 scm_num_overflow (s_scm_truncate_remainder);
2219 else
2220 {
2221 scm_t_inum rr = (mpz_tdiv_ui (SCM_I_BIG_MPZ (x),
2222 (yy > 0) ? yy : -yy)
2223 * mpz_sgn (SCM_I_BIG_MPZ (x)));
2224 scm_remember_upto_here_1 (x);
2225 return SCM_I_MAKINUM (rr);
2226 }
2227 }
2228 else if (SCM_BIGP (y))
2229 {
2230 SCM r = scm_i_mkbig ();
2231 mpz_tdiv_r (SCM_I_BIG_MPZ (r),
2232 SCM_I_BIG_MPZ (x),
2233 SCM_I_BIG_MPZ (y));
2234 scm_remember_upto_here_2 (x, y);
2235 return scm_i_normbig (r);
2236 }
2237 else if (SCM_REALP (y))
2238 return scm_i_inexact_truncate_remainder
2239 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2240 else if (SCM_FRACTIONP (y))
2241 return scm_i_exact_rational_truncate_remainder (x, y);
2242 else
fa075d40
AW
2243 return scm_wta_dispatch_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2244 s_scm_truncate_remainder);
8f9da340
MW
2245 }
2246 else if (SCM_REALP (x))
2247 {
2248 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2249 SCM_BIGP (y) || SCM_FRACTIONP (y))
2250 return scm_i_inexact_truncate_remainder
2251 (SCM_REAL_VALUE (x), scm_to_double (y));
2252 else
fa075d40
AW
2253 return scm_wta_dispatch_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2254 s_scm_truncate_remainder);
8f9da340
MW
2255 }
2256 else if (SCM_FRACTIONP (x))
2257 {
2258 if (SCM_REALP (y))
2259 return scm_i_inexact_truncate_remainder
2260 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2261 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2262 return scm_i_exact_rational_truncate_remainder (x, y);
2263 else
fa075d40
AW
2264 return scm_wta_dispatch_2 (g_scm_truncate_remainder, x, y, SCM_ARG2,
2265 s_scm_truncate_remainder);
8f9da340
MW
2266 }
2267 else
fa075d40
AW
2268 return scm_wta_dispatch_2 (g_scm_truncate_remainder, x, y, SCM_ARG1,
2269 s_scm_truncate_remainder);
8f9da340
MW
2270}
2271#undef FUNC_NAME
2272
2273static SCM
2274scm_i_inexact_truncate_remainder (double x, double y)
2275{
2276 /* Although it would be more efficient to use fmod here, we can't
2277 because it would in some cases produce results inconsistent with
2278 scm_i_inexact_truncate_quotient, such that x != q * y + r (not even
2279 close). In particular, when x is very close to a multiple of y,
2280 then r might be either 0.0 or sgn(x)*|y|, but those two cases must
2281 correspond to different choices of q. If quotient chooses one and
2282 remainder chooses the other, it would be bad. */
2283 if (SCM_UNLIKELY (y == 0))
2284 scm_num_overflow (s_scm_truncate_remainder); /* or return a NaN? */
2285 else
c251ab63 2286 return scm_from_double (x - y * trunc (x / y));
8f9da340
MW
2287}
2288
2289static SCM
2290scm_i_exact_rational_truncate_remainder (SCM x, SCM y)
2291{
2292 SCM xd = scm_denominator (x);
2293 SCM yd = scm_denominator (y);
2294 SCM r1 = scm_truncate_remainder (scm_product (scm_numerator (x), yd),
2295 scm_product (scm_numerator (y), xd));
2296 return scm_divide (r1, scm_product (xd, yd));
2297}
2298
2299
2300static void scm_i_inexact_truncate_divide (double x, double y,
2301 SCM *qp, SCM *rp);
2302static void scm_i_exact_rational_truncate_divide (SCM x, SCM y,
2303 SCM *qp, SCM *rp);
2304
2305SCM_PRIMITIVE_GENERIC (scm_i_truncate_divide, "truncate/", 2, 0, 0,
2306 (SCM x, SCM y),
2307 "Return the integer @var{q} and the real number @var{r}\n"
2308 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2309 "and @math{@var{q} = truncate(@var{x} / @var{y})}.\n"
2310 "@lisp\n"
2311 "(truncate/ 123 10) @result{} 12 and 3\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.2 -63.5) @result{} 1.0 and -59.7\n"
2316 "(truncate/ 16/3 -10/7) @result{} -3 and 22/21\n"
2317 "@end lisp")
2318#define FUNC_NAME s_scm_i_truncate_divide
2319{
2320 SCM q, r;
2321
2322 scm_truncate_divide(x, y, &q, &r);
2323 return scm_values (scm_list_2 (q, r));
2324}
2325#undef FUNC_NAME
2326
2327#define s_scm_truncate_divide s_scm_i_truncate_divide
2328#define g_scm_truncate_divide g_scm_i_truncate_divide
2329
2330void
2331scm_truncate_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2332{
2333 if (SCM_LIKELY (SCM_I_INUMP (x)))
2334 {
2335 scm_t_inum xx = SCM_I_INUM (x);
2336 if (SCM_LIKELY (SCM_I_INUMP (y)))
2337 {
2338 scm_t_inum yy = SCM_I_INUM (y);
2339 if (SCM_UNLIKELY (yy == 0))
2340 scm_num_overflow (s_scm_truncate_divide);
2341 else
2342 {
2343 scm_t_inum qq = xx / yy;
2344 scm_t_inum rr = xx % yy;
2345 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2346 *qp = SCM_I_MAKINUM (qq);
2347 else
2348 *qp = scm_i_inum2big (qq);
2349 *rp = SCM_I_MAKINUM (rr);
2350 }
2351 return;
2352 }
2353 else if (SCM_BIGP (y))
2354 {
2355 if (SCM_UNLIKELY (xx == SCM_MOST_NEGATIVE_FIXNUM)
2356 && SCM_UNLIKELY (mpz_cmp_ui (SCM_I_BIG_MPZ (y),
2357 - SCM_MOST_NEGATIVE_FIXNUM) == 0))
2358 {
2359 /* Special case: x == fixnum-min && y == abs (fixnum-min) */
2360 scm_remember_upto_here_1 (y);
2361 *qp = SCM_I_MAKINUM (-1);
2362 *rp = SCM_INUM0;
2363 }
2364 else
2365 {
2366 *qp = SCM_INUM0;
2367 *rp = x;
2368 }
2369 return;
2370 }
2371 else if (SCM_REALP (y))
2372 return scm_i_inexact_truncate_divide (xx, SCM_REAL_VALUE (y), qp, rp);
2373 else if (SCM_FRACTIONP (y))
2374 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2375 else
2376 return two_valued_wta_dispatch_2
2377 (g_scm_truncate_divide, x, y, SCM_ARG2,
2378 s_scm_truncate_divide, qp, rp);
2379 }
2380 else if (SCM_BIGP (x))
2381 {
2382 if (SCM_LIKELY (SCM_I_INUMP (y)))
2383 {
2384 scm_t_inum yy = SCM_I_INUM (y);
2385 if (SCM_UNLIKELY (yy == 0))
2386 scm_num_overflow (s_scm_truncate_divide);
2387 else
2388 {
2389 SCM q = scm_i_mkbig ();
2390 scm_t_inum rr;
2391 if (yy > 0)
2392 rr = mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q),
2393 SCM_I_BIG_MPZ (x), yy);
2394 else
2395 {
2396 rr = mpz_tdiv_q_ui (SCM_I_BIG_MPZ (q),
2397 SCM_I_BIG_MPZ (x), -yy);
2398 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2399 }
2400 rr *= mpz_sgn (SCM_I_BIG_MPZ (x));
2401 scm_remember_upto_here_1 (x);
2402 *qp = scm_i_normbig (q);
2403 *rp = SCM_I_MAKINUM (rr);
2404 }
2405 return;
2406 }
2407 else if (SCM_BIGP (y))
2408 {
2409 SCM q = scm_i_mkbig ();
2410 SCM r = scm_i_mkbig ();
2411 mpz_tdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2412 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2413 scm_remember_upto_here_2 (x, y);
2414 *qp = scm_i_normbig (q);
2415 *rp = scm_i_normbig (r);
2416 }
2417 else if (SCM_REALP (y))
2418 return scm_i_inexact_truncate_divide
2419 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
2420 else if (SCM_FRACTIONP (y))
2421 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2422 else
2423 return two_valued_wta_dispatch_2
2424 (g_scm_truncate_divide, x, y, SCM_ARG2,
2425 s_scm_truncate_divide, qp, rp);
2426 }
2427 else if (SCM_REALP (x))
2428 {
2429 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2430 SCM_BIGP (y) || SCM_FRACTIONP (y))
2431 return scm_i_inexact_truncate_divide
2432 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
2433 else
2434 return two_valued_wta_dispatch_2
2435 (g_scm_truncate_divide, x, y, SCM_ARG2,
2436 s_scm_truncate_divide, qp, rp);
2437 }
2438 else if (SCM_FRACTIONP (x))
2439 {
2440 if (SCM_REALP (y))
2441 return scm_i_inexact_truncate_divide
2442 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
2443 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2444 return scm_i_exact_rational_truncate_divide (x, y, qp, rp);
2445 else
2446 return two_valued_wta_dispatch_2
2447 (g_scm_truncate_divide, x, y, SCM_ARG2,
2448 s_scm_truncate_divide, qp, rp);
2449 }
2450 else
2451 return two_valued_wta_dispatch_2 (g_scm_truncate_divide, x, y, SCM_ARG1,
2452 s_scm_truncate_divide, qp, rp);
2453}
2454
2455static void
2456scm_i_inexact_truncate_divide (double x, double y, SCM *qp, SCM *rp)
2457{
2458 if (SCM_UNLIKELY (y == 0))
2459 scm_num_overflow (s_scm_truncate_divide); /* or return a NaN? */
2460 else
2461 {
c15fe499
MW
2462 double q = trunc (x / y);
2463 double r = x - q * y;
8f9da340
MW
2464 *qp = scm_from_double (q);
2465 *rp = scm_from_double (r);
2466 }
2467}
2468
2469static void
2470scm_i_exact_rational_truncate_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2471{
2472 SCM r1;
2473 SCM xd = scm_denominator (x);
2474 SCM yd = scm_denominator (y);
2475
2476 scm_truncate_divide (scm_product (scm_numerator (x), yd),
2477 scm_product (scm_numerator (y), xd),
2478 qp, &r1);
2479 *rp = scm_divide (r1, scm_product (xd, yd));
2480}
2481
ff62c168
MW
2482static SCM scm_i_inexact_centered_quotient (double x, double y);
2483static SCM scm_i_bigint_centered_quotient (SCM x, SCM y);
03ddd15b 2484static SCM scm_i_exact_rational_centered_quotient (SCM x, SCM y);
ff62c168 2485
8f9da340
MW
2486SCM_PRIMITIVE_GENERIC (scm_centered_quotient, "centered-quotient", 2, 0, 0,
2487 (SCM x, SCM y),
2488 "Return the integer @var{q} such that\n"
2489 "@math{@var{x} = @var{q}*@var{y} + @var{r}} where\n"
2490 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2491 "@lisp\n"
2492 "(centered-quotient 123 10) @result{} 12\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.2 -63.5) @result{} 2.0\n"
2497 "(centered-quotient 16/3 -10/7) @result{} -4\n"
2498 "@end lisp")
2499#define FUNC_NAME s_scm_centered_quotient
2500{
2501 if (SCM_LIKELY (SCM_I_INUMP (x)))
2502 {
2503 scm_t_inum xx = SCM_I_INUM (x);
2504 if (SCM_LIKELY (SCM_I_INUMP (y)))
2505 {
2506 scm_t_inum yy = SCM_I_INUM (y);
2507 if (SCM_UNLIKELY (yy == 0))
2508 scm_num_overflow (s_scm_centered_quotient);
2509 else
2510 {
2511 scm_t_inum qq = xx / yy;
2512 scm_t_inum rr = xx % yy;
2513 if (SCM_LIKELY (xx > 0))
2514 {
2515 if (SCM_LIKELY (yy > 0))
2516 {
2517 if (rr >= (yy + 1) / 2)
2518 qq++;
2519 }
2520 else
2521 {
2522 if (rr >= (1 - yy) / 2)
2523 qq--;
2524 }
2525 }
2526 else
2527 {
2528 if (SCM_LIKELY (yy > 0))
2529 {
2530 if (rr < -yy / 2)
2531 qq--;
2532 }
2533 else
2534 {
2535 if (rr < yy / 2)
2536 qq++;
2537 }
2538 }
2539 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2540 return SCM_I_MAKINUM (qq);
2541 else
2542 return scm_i_inum2big (qq);
2543 }
2544 }
2545 else if (SCM_BIGP (y))
2546 {
2547 /* Pass a denormalized bignum version of x (even though it
2548 can fit in a fixnum) to scm_i_bigint_centered_quotient */
2549 return scm_i_bigint_centered_quotient (scm_i_long2big (xx), y);
2550 }
2551 else if (SCM_REALP (y))
2552 return scm_i_inexact_centered_quotient (xx, SCM_REAL_VALUE (y));
2553 else if (SCM_FRACTIONP (y))
2554 return scm_i_exact_rational_centered_quotient (x, y);
2555 else
fa075d40
AW
2556 return scm_wta_dispatch_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2557 s_scm_centered_quotient);
8f9da340
MW
2558 }
2559 else if (SCM_BIGP (x))
2560 {
2561 if (SCM_LIKELY (SCM_I_INUMP (y)))
2562 {
2563 scm_t_inum yy = SCM_I_INUM (y);
2564 if (SCM_UNLIKELY (yy == 0))
2565 scm_num_overflow (s_scm_centered_quotient);
2566 else if (SCM_UNLIKELY (yy == 1))
2567 return x;
2568 else
2569 {
2570 SCM q = scm_i_mkbig ();
2571 scm_t_inum rr;
2572 /* Arrange for rr to initially be non-positive,
2573 because that simplifies the test to see
2574 if it is within the needed bounds. */
2575 if (yy > 0)
2576 {
2577 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2578 SCM_I_BIG_MPZ (x), yy);
2579 scm_remember_upto_here_1 (x);
2580 if (rr < -yy / 2)
2581 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2582 SCM_I_BIG_MPZ (q), 1);
2583 }
2584 else
2585 {
2586 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
2587 SCM_I_BIG_MPZ (x), -yy);
2588 scm_remember_upto_here_1 (x);
2589 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
2590 if (rr < yy / 2)
2591 mpz_add_ui (SCM_I_BIG_MPZ (q),
2592 SCM_I_BIG_MPZ (q), 1);
2593 }
2594 return scm_i_normbig (q);
2595 }
2596 }
2597 else if (SCM_BIGP (y))
2598 return scm_i_bigint_centered_quotient (x, y);
2599 else if (SCM_REALP (y))
2600 return scm_i_inexact_centered_quotient
2601 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2602 else if (SCM_FRACTIONP (y))
2603 return scm_i_exact_rational_centered_quotient (x, y);
2604 else
fa075d40
AW
2605 return scm_wta_dispatch_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2606 s_scm_centered_quotient);
8f9da340
MW
2607 }
2608 else if (SCM_REALP (x))
2609 {
2610 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2611 SCM_BIGP (y) || SCM_FRACTIONP (y))
2612 return scm_i_inexact_centered_quotient
2613 (SCM_REAL_VALUE (x), scm_to_double (y));
2614 else
fa075d40
AW
2615 return scm_wta_dispatch_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2616 s_scm_centered_quotient);
8f9da340
MW
2617 }
2618 else if (SCM_FRACTIONP (x))
2619 {
2620 if (SCM_REALP (y))
2621 return scm_i_inexact_centered_quotient
2622 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2623 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2624 return scm_i_exact_rational_centered_quotient (x, y);
2625 else
fa075d40
AW
2626 return scm_wta_dispatch_2 (g_scm_centered_quotient, x, y, SCM_ARG2,
2627 s_scm_centered_quotient);
8f9da340
MW
2628 }
2629 else
fa075d40
AW
2630 return scm_wta_dispatch_2 (g_scm_centered_quotient, x, y, SCM_ARG1,
2631 s_scm_centered_quotient);
8f9da340
MW
2632}
2633#undef FUNC_NAME
2634
2635static SCM
2636scm_i_inexact_centered_quotient (double x, double y)
2637{
2638 if (SCM_LIKELY (y > 0))
2639 return scm_from_double (floor (x/y + 0.5));
2640 else if (SCM_LIKELY (y < 0))
2641 return scm_from_double (ceil (x/y - 0.5));
2642 else if (y == 0)
2643 scm_num_overflow (s_scm_centered_quotient); /* or return a NaN? */
2644 else
2645 return scm_nan ();
2646}
2647
2648/* Assumes that both x and y are bigints, though
2649 x might be able to fit into a fixnum. */
2650static SCM
2651scm_i_bigint_centered_quotient (SCM x, SCM y)
2652{
2653 SCM q, r, min_r;
2654
2655 /* Note that x might be small enough to fit into a
2656 fixnum, so we must not let it escape into the wild */
2657 q = scm_i_mkbig ();
2658 r = scm_i_mkbig ();
2659
2660 /* min_r will eventually become -abs(y)/2 */
2661 min_r = scm_i_mkbig ();
2662 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2663 SCM_I_BIG_MPZ (y), 1);
2664
2665 /* Arrange for rr to initially be non-positive,
2666 because that simplifies the test to see
2667 if it is within the needed bounds. */
2668 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2669 {
2670 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2671 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2672 scm_remember_upto_here_2 (x, y);
2673 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2674 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2675 mpz_sub_ui (SCM_I_BIG_MPZ (q),
2676 SCM_I_BIG_MPZ (q), 1);
2677 }
2678 else
2679 {
2680 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
2681 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2682 scm_remember_upto_here_2 (x, y);
2683 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2684 mpz_add_ui (SCM_I_BIG_MPZ (q),
2685 SCM_I_BIG_MPZ (q), 1);
2686 }
2687 scm_remember_upto_here_2 (r, min_r);
2688 return scm_i_normbig (q);
2689}
2690
2691static SCM
2692scm_i_exact_rational_centered_quotient (SCM x, SCM y)
2693{
2694 return scm_centered_quotient
2695 (scm_product (scm_numerator (x), scm_denominator (y)),
2696 scm_product (scm_numerator (y), scm_denominator (x)));
2697}
2698
2699static SCM scm_i_inexact_centered_remainder (double x, double y);
2700static SCM scm_i_bigint_centered_remainder (SCM x, SCM y);
2701static SCM scm_i_exact_rational_centered_remainder (SCM x, SCM y);
2702
2703SCM_PRIMITIVE_GENERIC (scm_centered_remainder, "centered-remainder", 2, 0, 0,
2704 (SCM x, SCM y),
2705 "Return the real number @var{r} such that\n"
2706 "@math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}\n"
2707 "and @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2708 "for some integer @var{q}.\n"
2709 "@lisp\n"
2710 "(centered-remainder 123 10) @result{} 3\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.2 -63.5) @result{} 3.8\n"
2715 "(centered-remainder 16/3 -10/7) @result{} -8/21\n"
2716 "@end lisp")
2717#define FUNC_NAME s_scm_centered_remainder
2718{
2719 if (SCM_LIKELY (SCM_I_INUMP (x)))
2720 {
2721 scm_t_inum xx = SCM_I_INUM (x);
2722 if (SCM_LIKELY (SCM_I_INUMP (y)))
2723 {
2724 scm_t_inum yy = SCM_I_INUM (y);
2725 if (SCM_UNLIKELY (yy == 0))
2726 scm_num_overflow (s_scm_centered_remainder);
2727 else
2728 {
2729 scm_t_inum rr = xx % yy;
2730 if (SCM_LIKELY (xx > 0))
2731 {
2732 if (SCM_LIKELY (yy > 0))
2733 {
2734 if (rr >= (yy + 1) / 2)
2735 rr -= yy;
2736 }
2737 else
2738 {
2739 if (rr >= (1 - yy) / 2)
2740 rr += yy;
2741 }
2742 }
2743 else
2744 {
2745 if (SCM_LIKELY (yy > 0))
2746 {
2747 if (rr < -yy / 2)
2748 rr += yy;
2749 }
2750 else
2751 {
2752 if (rr < yy / 2)
2753 rr -= yy;
2754 }
2755 }
2756 return SCM_I_MAKINUM (rr);
2757 }
2758 }
2759 else if (SCM_BIGP (y))
2760 {
2761 /* Pass a denormalized bignum version of x (even though it
2762 can fit in a fixnum) to scm_i_bigint_centered_remainder */
2763 return scm_i_bigint_centered_remainder (scm_i_long2big (xx), y);
2764 }
2765 else if (SCM_REALP (y))
2766 return scm_i_inexact_centered_remainder (xx, SCM_REAL_VALUE (y));
2767 else if (SCM_FRACTIONP (y))
2768 return scm_i_exact_rational_centered_remainder (x, y);
2769 else
fa075d40
AW
2770 return scm_wta_dispatch_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2771 s_scm_centered_remainder);
8f9da340
MW
2772 }
2773 else if (SCM_BIGP (x))
2774 {
2775 if (SCM_LIKELY (SCM_I_INUMP (y)))
2776 {
2777 scm_t_inum yy = SCM_I_INUM (y);
2778 if (SCM_UNLIKELY (yy == 0))
2779 scm_num_overflow (s_scm_centered_remainder);
2780 else
2781 {
2782 scm_t_inum rr;
2783 /* Arrange for rr to initially be non-positive,
2784 because that simplifies the test to see
2785 if it is within the needed bounds. */
2786 if (yy > 0)
2787 {
2788 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), yy);
2789 scm_remember_upto_here_1 (x);
2790 if (rr < -yy / 2)
2791 rr += yy;
2792 }
2793 else
2794 {
2795 rr = - mpz_cdiv_ui (SCM_I_BIG_MPZ (x), -yy);
2796 scm_remember_upto_here_1 (x);
2797 if (rr < yy / 2)
2798 rr -= yy;
2799 }
2800 return SCM_I_MAKINUM (rr);
2801 }
2802 }
2803 else if (SCM_BIGP (y))
2804 return scm_i_bigint_centered_remainder (x, y);
2805 else if (SCM_REALP (y))
2806 return scm_i_inexact_centered_remainder
2807 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
2808 else if (SCM_FRACTIONP (y))
2809 return scm_i_exact_rational_centered_remainder (x, y);
2810 else
fa075d40
AW
2811 return scm_wta_dispatch_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2812 s_scm_centered_remainder);
8f9da340
MW
2813 }
2814 else if (SCM_REALP (x))
2815 {
2816 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
2817 SCM_BIGP (y) || SCM_FRACTIONP (y))
2818 return scm_i_inexact_centered_remainder
2819 (SCM_REAL_VALUE (x), scm_to_double (y));
2820 else
fa075d40
AW
2821 return scm_wta_dispatch_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2822 s_scm_centered_remainder);
8f9da340
MW
2823 }
2824 else if (SCM_FRACTIONP (x))
2825 {
2826 if (SCM_REALP (y))
2827 return scm_i_inexact_centered_remainder
2828 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
2829 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
2830 return scm_i_exact_rational_centered_remainder (x, y);
2831 else
fa075d40
AW
2832 return scm_wta_dispatch_2 (g_scm_centered_remainder, x, y, SCM_ARG2,
2833 s_scm_centered_remainder);
8f9da340
MW
2834 }
2835 else
fa075d40
AW
2836 return scm_wta_dispatch_2 (g_scm_centered_remainder, x, y, SCM_ARG1,
2837 s_scm_centered_remainder);
8f9da340
MW
2838}
2839#undef FUNC_NAME
2840
2841static SCM
2842scm_i_inexact_centered_remainder (double x, double y)
2843{
2844 double q;
2845
2846 /* Although it would be more efficient to use fmod here, we can't
2847 because it would in some cases produce results inconsistent with
2848 scm_i_inexact_centered_quotient, such that x != r + q * y (not even
2849 close). In particular, when x-y/2 is very close to a multiple of
2850 y, then r might be either -abs(y/2) or abs(y/2)-epsilon, but those
2851 two cases must correspond to different choices of q. If quotient
2852 chooses one and remainder chooses the other, it would be bad. */
2853 if (SCM_LIKELY (y > 0))
2854 q = floor (x/y + 0.5);
2855 else if (SCM_LIKELY (y < 0))
2856 q = ceil (x/y - 0.5);
2857 else if (y == 0)
2858 scm_num_overflow (s_scm_centered_remainder); /* or return a NaN? */
2859 else
2860 return scm_nan ();
2861 return scm_from_double (x - q * y);
2862}
2863
2864/* Assumes that both x and y are bigints, though
2865 x might be able to fit into a fixnum. */
2866static SCM
2867scm_i_bigint_centered_remainder (SCM x, SCM y)
2868{
2869 SCM r, min_r;
2870
2871 /* Note that x might be small enough to fit into a
2872 fixnum, so we must not let it escape into the wild */
2873 r = scm_i_mkbig ();
2874
2875 /* min_r will eventually become -abs(y)/2 */
2876 min_r = scm_i_mkbig ();
2877 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
2878 SCM_I_BIG_MPZ (y), 1);
2879
2880 /* Arrange for rr to initially be non-positive,
2881 because that simplifies the test to see
2882 if it is within the needed bounds. */
2883 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
2884 {
2885 mpz_cdiv_r (SCM_I_BIG_MPZ (r),
2886 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2887 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
2888 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2889 mpz_add (SCM_I_BIG_MPZ (r),
2890 SCM_I_BIG_MPZ (r),
2891 SCM_I_BIG_MPZ (y));
2892 }
2893 else
2894 {
2895 mpz_fdiv_r (SCM_I_BIG_MPZ (r),
2896 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
2897 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
2898 mpz_sub (SCM_I_BIG_MPZ (r),
2899 SCM_I_BIG_MPZ (r),
2900 SCM_I_BIG_MPZ (y));
2901 }
2902 scm_remember_upto_here_2 (x, y);
2903 return scm_i_normbig (r);
2904}
2905
2906static SCM
2907scm_i_exact_rational_centered_remainder (SCM x, SCM y)
2908{
2909 SCM xd = scm_denominator (x);
2910 SCM yd = scm_denominator (y);
2911 SCM r1 = scm_centered_remainder (scm_product (scm_numerator (x), yd),
2912 scm_product (scm_numerator (y), xd));
2913 return scm_divide (r1, scm_product (xd, yd));
2914}
2915
2916
2917static void scm_i_inexact_centered_divide (double x, double y,
2918 SCM *qp, SCM *rp);
2919static void scm_i_bigint_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp);
2920static void scm_i_exact_rational_centered_divide (SCM x, SCM y,
2921 SCM *qp, SCM *rp);
2922
2923SCM_PRIMITIVE_GENERIC (scm_i_centered_divide, "centered/", 2, 0, 0,
2924 (SCM x, SCM y),
2925 "Return the integer @var{q} and the real number @var{r}\n"
2926 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
2927 "and @math{-abs(@var{y}/2) <= @var{r} < abs(@var{y}/2)}.\n"
2928 "@lisp\n"
2929 "(centered/ 123 10) @result{} 12 and 3\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.2 -63.5) @result{} 2.0 and 3.8\n"
2934 "(centered/ 16/3 -10/7) @result{} -4 and -8/21\n"
2935 "@end lisp")
2936#define FUNC_NAME s_scm_i_centered_divide
2937{
2938 SCM q, r;
2939
2940 scm_centered_divide(x, y, &q, &r);
2941 return scm_values (scm_list_2 (q, r));
2942}
2943#undef FUNC_NAME
2944
2945#define s_scm_centered_divide s_scm_i_centered_divide
2946#define g_scm_centered_divide g_scm_i_centered_divide
2947
2948void
2949scm_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
2950{
2951 if (SCM_LIKELY (SCM_I_INUMP (x)))
2952 {
2953 scm_t_inum xx = SCM_I_INUM (x);
2954 if (SCM_LIKELY (SCM_I_INUMP (y)))
2955 {
2956 scm_t_inum yy = SCM_I_INUM (y);
2957 if (SCM_UNLIKELY (yy == 0))
2958 scm_num_overflow (s_scm_centered_divide);
2959 else
2960 {
2961 scm_t_inum qq = xx / yy;
2962 scm_t_inum rr = xx % yy;
2963 if (SCM_LIKELY (xx > 0))
2964 {
2965 if (SCM_LIKELY (yy > 0))
2966 {
2967 if (rr >= (yy + 1) / 2)
2968 { qq++; rr -= yy; }
2969 }
2970 else
2971 {
2972 if (rr >= (1 - yy) / 2)
2973 { qq--; rr += yy; }
2974 }
2975 }
2976 else
2977 {
2978 if (SCM_LIKELY (yy > 0))
2979 {
2980 if (rr < -yy / 2)
2981 { qq--; rr += yy; }
2982 }
2983 else
2984 {
2985 if (rr < yy / 2)
2986 { qq++; rr -= yy; }
2987 }
2988 }
2989 if (SCM_LIKELY (SCM_FIXABLE (qq)))
2990 *qp = SCM_I_MAKINUM (qq);
2991 else
2992 *qp = scm_i_inum2big (qq);
2993 *rp = SCM_I_MAKINUM (rr);
2994 }
2995 return;
2996 }
2997 else if (SCM_BIGP (y))
2998 {
2999 /* Pass a denormalized bignum version of x (even though it
3000 can fit in a fixnum) to scm_i_bigint_centered_divide */
3001 return scm_i_bigint_centered_divide (scm_i_long2big (xx), y, qp, rp);
3002 }
3003 else if (SCM_REALP (y))
3004 return scm_i_inexact_centered_divide (xx, SCM_REAL_VALUE (y), qp, rp);
3005 else if (SCM_FRACTIONP (y))
3006 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3007 else
3008 return two_valued_wta_dispatch_2
3009 (g_scm_centered_divide, x, y, SCM_ARG2,
3010 s_scm_centered_divide, qp, rp);
3011 }
3012 else if (SCM_BIGP (x))
3013 {
3014 if (SCM_LIKELY (SCM_I_INUMP (y)))
3015 {
3016 scm_t_inum yy = SCM_I_INUM (y);
3017 if (SCM_UNLIKELY (yy == 0))
3018 scm_num_overflow (s_scm_centered_divide);
3019 else
3020 {
3021 SCM q = scm_i_mkbig ();
3022 scm_t_inum rr;
3023 /* Arrange for rr to initially be non-positive,
3024 because that simplifies the test to see
3025 if it is within the needed bounds. */
3026 if (yy > 0)
3027 {
3028 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3029 SCM_I_BIG_MPZ (x), yy);
3030 scm_remember_upto_here_1 (x);
3031 if (rr < -yy / 2)
3032 {
3033 mpz_sub_ui (SCM_I_BIG_MPZ (q),
3034 SCM_I_BIG_MPZ (q), 1);
3035 rr += yy;
3036 }
3037 }
3038 else
3039 {
3040 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3041 SCM_I_BIG_MPZ (x), -yy);
3042 scm_remember_upto_here_1 (x);
3043 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
3044 if (rr < yy / 2)
3045 {
3046 mpz_add_ui (SCM_I_BIG_MPZ (q),
3047 SCM_I_BIG_MPZ (q), 1);
3048 rr -= yy;
3049 }
3050 }
3051 *qp = scm_i_normbig (q);
3052 *rp = SCM_I_MAKINUM (rr);
3053 }
3054 return;
3055 }
3056 else if (SCM_BIGP (y))
3057 return scm_i_bigint_centered_divide (x, y, qp, rp);
3058 else if (SCM_REALP (y))
3059 return scm_i_inexact_centered_divide
3060 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
3061 else if (SCM_FRACTIONP (y))
3062 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3063 else
3064 return two_valued_wta_dispatch_2
3065 (g_scm_centered_divide, x, y, SCM_ARG2,
3066 s_scm_centered_divide, qp, rp);
3067 }
3068 else if (SCM_REALP (x))
3069 {
3070 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3071 SCM_BIGP (y) || SCM_FRACTIONP (y))
3072 return scm_i_inexact_centered_divide
3073 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
3074 else
3075 return two_valued_wta_dispatch_2
3076 (g_scm_centered_divide, x, y, SCM_ARG2,
3077 s_scm_centered_divide, qp, rp);
3078 }
3079 else if (SCM_FRACTIONP (x))
3080 {
3081 if (SCM_REALP (y))
3082 return scm_i_inexact_centered_divide
3083 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
3084 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
3085 return scm_i_exact_rational_centered_divide (x, y, qp, rp);
3086 else
3087 return two_valued_wta_dispatch_2
3088 (g_scm_centered_divide, x, y, SCM_ARG2,
3089 s_scm_centered_divide, qp, rp);
3090 }
3091 else
3092 return two_valued_wta_dispatch_2 (g_scm_centered_divide, x, y, SCM_ARG1,
3093 s_scm_centered_divide, qp, rp);
3094}
3095
3096static void
3097scm_i_inexact_centered_divide (double x, double y, SCM *qp, SCM *rp)
3098{
3099 double q, r;
3100
3101 if (SCM_LIKELY (y > 0))
3102 q = floor (x/y + 0.5);
3103 else if (SCM_LIKELY (y < 0))
3104 q = ceil (x/y - 0.5);
3105 else if (y == 0)
3106 scm_num_overflow (s_scm_centered_divide); /* or return a NaN? */
3107 else
3108 q = guile_NaN;
3109 r = x - q * y;
3110 *qp = scm_from_double (q);
3111 *rp = scm_from_double (r);
3112}
3113
3114/* Assumes that both x and y are bigints, though
3115 x might be able to fit into a fixnum. */
3116static void
3117scm_i_bigint_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
3118{
3119 SCM q, r, min_r;
3120
3121 /* Note that x might be small enough to fit into a
3122 fixnum, so we must not let it escape into the wild */
3123 q = scm_i_mkbig ();
3124 r = scm_i_mkbig ();
3125
3126 /* min_r will eventually become -abs(y/2) */
3127 min_r = scm_i_mkbig ();
3128 mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (min_r),
3129 SCM_I_BIG_MPZ (y), 1);
3130
3131 /* Arrange for rr to initially be non-positive,
3132 because that simplifies the test to see
3133 if it is within the needed bounds. */
3134 if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
3135 {
3136 mpz_cdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3137 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3138 mpz_neg (SCM_I_BIG_MPZ (min_r), SCM_I_BIG_MPZ (min_r));
3139 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
3140 {
3141 mpz_sub_ui (SCM_I_BIG_MPZ (q),
3142 SCM_I_BIG_MPZ (q), 1);
3143 mpz_add (SCM_I_BIG_MPZ (r),
3144 SCM_I_BIG_MPZ (r),
3145 SCM_I_BIG_MPZ (y));
3146 }
3147 }
3148 else
3149 {
3150 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3151 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3152 if (mpz_cmp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (min_r)) < 0)
3153 {
3154 mpz_add_ui (SCM_I_BIG_MPZ (q),
3155 SCM_I_BIG_MPZ (q), 1);
3156 mpz_sub (SCM_I_BIG_MPZ (r),
3157 SCM_I_BIG_MPZ (r),
3158 SCM_I_BIG_MPZ (y));
3159 }
3160 }
3161 scm_remember_upto_here_2 (x, y);
3162 *qp = scm_i_normbig (q);
3163 *rp = scm_i_normbig (r);
3164}
3165
3166static void
3167scm_i_exact_rational_centered_divide (SCM x, SCM y, SCM *qp, SCM *rp)
3168{
3169 SCM r1;
3170 SCM xd = scm_denominator (x);
3171 SCM yd = scm_denominator (y);
3172
3173 scm_centered_divide (scm_product (scm_numerator (x), yd),
3174 scm_product (scm_numerator (y), xd),
3175 qp, &r1);
3176 *rp = scm_divide (r1, scm_product (xd, yd));
3177}
3178
3179static SCM scm_i_inexact_round_quotient (double x, double y);
3180static SCM scm_i_bigint_round_quotient (SCM x, SCM y);
3181static SCM scm_i_exact_rational_round_quotient (SCM x, SCM y);
3182
3183SCM_PRIMITIVE_GENERIC (scm_round_quotient, "round-quotient", 2, 0, 0,
ff62c168 3184 (SCM x, SCM y),
8f9da340
MW
3185 "Return @math{@var{x} / @var{y}} to the nearest integer,\n"
3186 "with ties going to the nearest even integer.\n"
ff62c168 3187 "@lisp\n"
8f9da340
MW
3188 "(round-quotient 123 10) @result{} 12\n"
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 125 10) @result{} 12\n"
3193 "(round-quotient 127 10) @result{} 13\n"
3194 "(round-quotient 135 10) @result{} 14\n"
3195 "(round-quotient -123.2 -63.5) @result{} 2.0\n"
3196 "(round-quotient 16/3 -10/7) @result{} -4\n"
ff62c168 3197 "@end lisp")
8f9da340 3198#define FUNC_NAME s_scm_round_quotient
ff62c168
MW
3199{
3200 if (SCM_LIKELY (SCM_I_INUMP (x)))
3201 {
4a46bc2a 3202 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3203 if (SCM_LIKELY (SCM_I_INUMP (y)))
3204 {
3205 scm_t_inum yy = SCM_I_INUM (y);
3206 if (SCM_UNLIKELY (yy == 0))
8f9da340 3207 scm_num_overflow (s_scm_round_quotient);
ff62c168
MW
3208 else
3209 {
ff62c168 3210 scm_t_inum qq = xx / yy;
4a46bc2a 3211 scm_t_inum rr = xx % yy;
8f9da340
MW
3212 scm_t_inum ay = yy;
3213 scm_t_inum r2 = 2 * rr;
3214
3215 if (SCM_LIKELY (yy < 0))
ff62c168 3216 {
8f9da340
MW
3217 ay = -ay;
3218 r2 = -r2;
3219 }
3220
3221 if (qq & 1L)
3222 {
3223 if (r2 >= ay)
3224 qq++;
3225 else if (r2 <= -ay)
3226 qq--;
ff62c168
MW
3227 }
3228 else
3229 {
8f9da340
MW
3230 if (r2 > ay)
3231 qq++;
3232 else if (r2 < -ay)
3233 qq--;
ff62c168 3234 }
4a46bc2a
MW
3235 if (SCM_LIKELY (SCM_FIXABLE (qq)))
3236 return SCM_I_MAKINUM (qq);
3237 else
3238 return scm_i_inum2big (qq);
ff62c168
MW
3239 }
3240 }
3241 else if (SCM_BIGP (y))
3242 {
3243 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3244 can fit in a fixnum) to scm_i_bigint_round_quotient */
3245 return scm_i_bigint_round_quotient (scm_i_long2big (xx), y);
ff62c168
MW
3246 }
3247 else if (SCM_REALP (y))
8f9da340 3248 return scm_i_inexact_round_quotient (xx, SCM_REAL_VALUE (y));
ff62c168 3249 else if (SCM_FRACTIONP (y))
8f9da340 3250 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3251 else
fa075d40
AW
3252 return scm_wta_dispatch_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3253 s_scm_round_quotient);
ff62c168
MW
3254 }
3255 else if (SCM_BIGP (x))
3256 {
3257 if (SCM_LIKELY (SCM_I_INUMP (y)))
3258 {
3259 scm_t_inum yy = SCM_I_INUM (y);
3260 if (SCM_UNLIKELY (yy == 0))
8f9da340 3261 scm_num_overflow (s_scm_round_quotient);
4a46bc2a
MW
3262 else if (SCM_UNLIKELY (yy == 1))
3263 return x;
ff62c168
MW
3264 else
3265 {
3266 SCM q = scm_i_mkbig ();
3267 scm_t_inum rr;
8f9da340
MW
3268 int needs_adjustment;
3269
ff62c168
MW
3270 if (yy > 0)
3271 {
8f9da340
MW
3272 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3273 SCM_I_BIG_MPZ (x), yy);
3274 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3275 needs_adjustment = (2*rr >= yy);
3276 else
3277 needs_adjustment = (2*rr > yy);
ff62c168
MW
3278 }
3279 else
3280 {
3281 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3282 SCM_I_BIG_MPZ (x), -yy);
ff62c168 3283 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
8f9da340
MW
3284 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3285 needs_adjustment = (2*rr <= yy);
3286 else
3287 needs_adjustment = (2*rr < yy);
ff62c168 3288 }
8f9da340
MW
3289 scm_remember_upto_here_1 (x);
3290 if (needs_adjustment)
3291 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
ff62c168
MW
3292 return scm_i_normbig (q);
3293 }
3294 }
3295 else if (SCM_BIGP (y))
8f9da340 3296 return scm_i_bigint_round_quotient (x, y);
ff62c168 3297 else if (SCM_REALP (y))
8f9da340 3298 return scm_i_inexact_round_quotient
ff62c168
MW
3299 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
3300 else if (SCM_FRACTIONP (y))
8f9da340 3301 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3302 else
fa075d40
AW
3303 return scm_wta_dispatch_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3304 s_scm_round_quotient);
ff62c168
MW
3305 }
3306 else if (SCM_REALP (x))
3307 {
3308 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3309 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3310 return scm_i_inexact_round_quotient
ff62c168
MW
3311 (SCM_REAL_VALUE (x), scm_to_double (y));
3312 else
fa075d40
AW
3313 return scm_wta_dispatch_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3314 s_scm_round_quotient);
ff62c168
MW
3315 }
3316 else if (SCM_FRACTIONP (x))
3317 {
3318 if (SCM_REALP (y))
8f9da340 3319 return scm_i_inexact_round_quotient
ff62c168 3320 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
03ddd15b 3321 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3322 return scm_i_exact_rational_round_quotient (x, y);
ff62c168 3323 else
fa075d40
AW
3324 return scm_wta_dispatch_2 (g_scm_round_quotient, x, y, SCM_ARG2,
3325 s_scm_round_quotient);
ff62c168
MW
3326 }
3327 else
fa075d40
AW
3328 return scm_wta_dispatch_2 (g_scm_round_quotient, x, y, SCM_ARG1,
3329 s_scm_round_quotient);
ff62c168
MW
3330}
3331#undef FUNC_NAME
3332
3333static SCM
8f9da340 3334scm_i_inexact_round_quotient (double x, double y)
ff62c168 3335{
8f9da340
MW
3336 if (SCM_UNLIKELY (y == 0))
3337 scm_num_overflow (s_scm_round_quotient); /* or return a NaN? */
ff62c168 3338 else
8f9da340 3339 return scm_from_double (scm_c_round (x / y));
ff62c168
MW
3340}
3341
3342/* Assumes that both x and y are bigints, though
3343 x might be able to fit into a fixnum. */
3344static SCM
8f9da340 3345scm_i_bigint_round_quotient (SCM x, SCM y)
ff62c168 3346{
8f9da340
MW
3347 SCM q, r, r2;
3348 int cmp, needs_adjustment;
ff62c168
MW
3349
3350 /* Note that x might be small enough to fit into a
3351 fixnum, so we must not let it escape into the wild */
3352 q = scm_i_mkbig ();
3353 r = scm_i_mkbig ();
8f9da340 3354 r2 = scm_i_mkbig ();
ff62c168 3355
8f9da340
MW
3356 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3357 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3358 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
3359 scm_remember_upto_here_2 (x, r);
ff62c168 3360
8f9da340
MW
3361 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3362 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3363 needs_adjustment = (cmp >= 0);
ff62c168 3364 else
8f9da340
MW
3365 needs_adjustment = (cmp > 0);
3366 scm_remember_upto_here_2 (r2, y);
3367
3368 if (needs_adjustment)
3369 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3370
ff62c168
MW
3371 return scm_i_normbig (q);
3372}
3373
ff62c168 3374static SCM
8f9da340 3375scm_i_exact_rational_round_quotient (SCM x, SCM y)
ff62c168 3376{
8f9da340 3377 return scm_round_quotient
03ddd15b
MW
3378 (scm_product (scm_numerator (x), scm_denominator (y)),
3379 scm_product (scm_numerator (y), scm_denominator (x)));
ff62c168
MW
3380}
3381
8f9da340
MW
3382static SCM scm_i_inexact_round_remainder (double x, double y);
3383static SCM scm_i_bigint_round_remainder (SCM x, SCM y);
3384static SCM scm_i_exact_rational_round_remainder (SCM x, SCM y);
ff62c168 3385
8f9da340 3386SCM_PRIMITIVE_GENERIC (scm_round_remainder, "round-remainder", 2, 0, 0,
ff62c168
MW
3387 (SCM x, SCM y),
3388 "Return the real number @var{r} such that\n"
8f9da340
MW
3389 "@math{@var{x} = @var{q}*@var{y} + @var{r}}, where\n"
3390 "@var{q} is @math{@var{x} / @var{y}} rounded to the\n"
3391 "nearest integer, with ties going to the nearest\n"
3392 "even integer.\n"
ff62c168 3393 "@lisp\n"
8f9da340
MW
3394 "(round-remainder 123 10) @result{} 3\n"
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 125 10) @result{} 5\n"
3399 "(round-remainder 127 10) @result{} -3\n"
3400 "(round-remainder 135 10) @result{} -5\n"
3401 "(round-remainder -123.2 -63.5) @result{} 3.8\n"
3402 "(round-remainder 16/3 -10/7) @result{} -8/21\n"
ff62c168 3403 "@end lisp")
8f9da340 3404#define FUNC_NAME s_scm_round_remainder
ff62c168
MW
3405{
3406 if (SCM_LIKELY (SCM_I_INUMP (x)))
3407 {
4a46bc2a 3408 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3409 if (SCM_LIKELY (SCM_I_INUMP (y)))
3410 {
3411 scm_t_inum yy = SCM_I_INUM (y);
3412 if (SCM_UNLIKELY (yy == 0))
8f9da340 3413 scm_num_overflow (s_scm_round_remainder);
ff62c168
MW
3414 else
3415 {
8f9da340 3416 scm_t_inum qq = xx / yy;
ff62c168 3417 scm_t_inum rr = xx % yy;
8f9da340
MW
3418 scm_t_inum ay = yy;
3419 scm_t_inum r2 = 2 * rr;
3420
3421 if (SCM_LIKELY (yy < 0))
ff62c168 3422 {
8f9da340
MW
3423 ay = -ay;
3424 r2 = -r2;
3425 }
3426
3427 if (qq & 1L)
3428 {
3429 if (r2 >= ay)
3430 rr -= yy;
3431 else if (r2 <= -ay)
3432 rr += yy;
ff62c168
MW
3433 }
3434 else
3435 {
8f9da340
MW
3436 if (r2 > ay)
3437 rr -= yy;
3438 else if (r2 < -ay)
3439 rr += yy;
ff62c168
MW
3440 }
3441 return SCM_I_MAKINUM (rr);
3442 }
3443 }
3444 else if (SCM_BIGP (y))
3445 {
3446 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3447 can fit in a fixnum) to scm_i_bigint_round_remainder */
3448 return scm_i_bigint_round_remainder
3449 (scm_i_long2big (xx), y);
ff62c168
MW
3450 }
3451 else if (SCM_REALP (y))
8f9da340 3452 return scm_i_inexact_round_remainder (xx, SCM_REAL_VALUE (y));
ff62c168 3453 else if (SCM_FRACTIONP (y))
8f9da340 3454 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3455 else
fa075d40
AW
3456 return scm_wta_dispatch_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3457 s_scm_round_remainder);
ff62c168
MW
3458 }
3459 else if (SCM_BIGP (x))
3460 {
3461 if (SCM_LIKELY (SCM_I_INUMP (y)))
3462 {
3463 scm_t_inum yy = SCM_I_INUM (y);
3464 if (SCM_UNLIKELY (yy == 0))
8f9da340 3465 scm_num_overflow (s_scm_round_remainder);
ff62c168
MW
3466 else
3467 {
8f9da340 3468 SCM q = scm_i_mkbig ();
ff62c168 3469 scm_t_inum rr;
8f9da340
MW
3470 int needs_adjustment;
3471
ff62c168
MW
3472 if (yy > 0)
3473 {
8f9da340
MW
3474 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3475 SCM_I_BIG_MPZ (x), yy);
3476 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3477 needs_adjustment = (2*rr >= yy);
3478 else
3479 needs_adjustment = (2*rr > yy);
ff62c168
MW
3480 }
3481 else
3482 {
8f9da340
MW
3483 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3484 SCM_I_BIG_MPZ (x), -yy);
3485 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3486 needs_adjustment = (2*rr <= yy);
3487 else
3488 needs_adjustment = (2*rr < yy);
ff62c168 3489 }
8f9da340
MW
3490 scm_remember_upto_here_2 (x, q);
3491 if (needs_adjustment)
3492 rr -= yy;
ff62c168
MW
3493 return SCM_I_MAKINUM (rr);
3494 }
3495 }
3496 else if (SCM_BIGP (y))
8f9da340 3497 return scm_i_bigint_round_remainder (x, y);
ff62c168 3498 else if (SCM_REALP (y))
8f9da340 3499 return scm_i_inexact_round_remainder
ff62c168
MW
3500 (scm_i_big2dbl (x), SCM_REAL_VALUE (y));
3501 else if (SCM_FRACTIONP (y))
8f9da340 3502 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3503 else
fa075d40
AW
3504 return scm_wta_dispatch_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3505 s_scm_round_remainder);
ff62c168
MW
3506 }
3507 else if (SCM_REALP (x))
3508 {
3509 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3510 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3511 return scm_i_inexact_round_remainder
ff62c168
MW
3512 (SCM_REAL_VALUE (x), scm_to_double (y));
3513 else
fa075d40
AW
3514 return scm_wta_dispatch_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3515 s_scm_round_remainder);
ff62c168
MW
3516 }
3517 else if (SCM_FRACTIONP (x))
3518 {
3519 if (SCM_REALP (y))
8f9da340 3520 return scm_i_inexact_round_remainder
ff62c168 3521 (scm_i_fraction2double (x), SCM_REAL_VALUE (y));
03ddd15b 3522 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3523 return scm_i_exact_rational_round_remainder (x, y);
ff62c168 3524 else
fa075d40
AW
3525 return scm_wta_dispatch_2 (g_scm_round_remainder, x, y, SCM_ARG2,
3526 s_scm_round_remainder);
ff62c168
MW
3527 }
3528 else
fa075d40
AW
3529 return scm_wta_dispatch_2 (g_scm_round_remainder, x, y, SCM_ARG1,
3530 s_scm_round_remainder);
ff62c168
MW
3531}
3532#undef FUNC_NAME
3533
3534static SCM
8f9da340 3535scm_i_inexact_round_remainder (double x, double y)
ff62c168 3536{
ff62c168
MW
3537 /* Although it would be more efficient to use fmod here, we can't
3538 because it would in some cases produce results inconsistent with
8f9da340 3539 scm_i_inexact_round_quotient, such that x != r + q * y (not even
ff62c168 3540 close). In particular, when x-y/2 is very close to a multiple of
8f9da340
MW
3541 y, then r might be either -abs(y/2) or abs(y/2), but those two
3542 cases must correspond to different choices of q. If quotient
ff62c168 3543 chooses one and remainder chooses the other, it would be bad. */
8f9da340
MW
3544
3545 if (SCM_UNLIKELY (y == 0))
3546 scm_num_overflow (s_scm_round_remainder); /* or return a NaN? */
ff62c168 3547 else
8f9da340
MW
3548 {
3549 double q = scm_c_round (x / y);
3550 return scm_from_double (x - q * y);
3551 }
ff62c168
MW
3552}
3553
3554/* Assumes that both x and y are bigints, though
3555 x might be able to fit into a fixnum. */
3556static SCM
8f9da340 3557scm_i_bigint_round_remainder (SCM x, SCM y)
ff62c168 3558{
8f9da340
MW
3559 SCM q, r, r2;
3560 int cmp, needs_adjustment;
ff62c168
MW
3561
3562 /* Note that x might be small enough to fit into a
3563 fixnum, so we must not let it escape into the wild */
8f9da340 3564 q = scm_i_mkbig ();
ff62c168 3565 r = scm_i_mkbig ();
8f9da340 3566 r2 = scm_i_mkbig ();
ff62c168 3567
8f9da340
MW
3568 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3569 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3570 scm_remember_upto_here_1 (x);
3571 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
ff62c168 3572
8f9da340
MW
3573 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3574 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3575 needs_adjustment = (cmp >= 0);
ff62c168 3576 else
8f9da340
MW
3577 needs_adjustment = (cmp > 0);
3578 scm_remember_upto_here_2 (q, r2);
3579
3580 if (needs_adjustment)
3581 mpz_sub (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y));
3582
3583 scm_remember_upto_here_1 (y);
ff62c168
MW
3584 return scm_i_normbig (r);
3585}
3586
ff62c168 3587static SCM
8f9da340 3588scm_i_exact_rational_round_remainder (SCM x, SCM y)
ff62c168 3589{
03ddd15b
MW
3590 SCM xd = scm_denominator (x);
3591 SCM yd = scm_denominator (y);
8f9da340
MW
3592 SCM r1 = scm_round_remainder (scm_product (scm_numerator (x), yd),
3593 scm_product (scm_numerator (y), xd));
03ddd15b 3594 return scm_divide (r1, scm_product (xd, yd));
ff62c168
MW
3595}
3596
3597
8f9da340
MW
3598static void scm_i_inexact_round_divide (double x, double y, SCM *qp, SCM *rp);
3599static void scm_i_bigint_round_divide (SCM x, SCM y, SCM *qp, SCM *rp);
3600static void scm_i_exact_rational_round_divide (SCM x, SCM y, SCM *qp, SCM *rp);
ff62c168 3601
8f9da340 3602SCM_PRIMITIVE_GENERIC (scm_i_round_divide, "round/", 2, 0, 0,
ff62c168
MW
3603 (SCM x, SCM y),
3604 "Return the integer @var{q} and the real number @var{r}\n"
3605 "such that @math{@var{x} = @var{q}*@var{y} + @var{r}}\n"
8f9da340
MW
3606 "and @var{q} is @math{@var{x} / @var{y}} rounded to the\n"
3607 "nearest integer, with ties going to the nearest even integer.\n"
ff62c168 3608 "@lisp\n"
8f9da340
MW
3609 "(round/ 123 10) @result{} 12 and 3\n"
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/ 125 10) @result{} 12 and 5\n"
3614 "(round/ 127 10) @result{} 13 and -3\n"
3615 "(round/ 135 10) @result{} 14 and -5\n"
3616 "(round/ -123.2 -63.5) @result{} 2.0 and 3.8\n"
3617 "(round/ 16/3 -10/7) @result{} -4 and -8/21\n"
ff62c168 3618 "@end lisp")
8f9da340 3619#define FUNC_NAME s_scm_i_round_divide
5fbf680b
MW
3620{
3621 SCM q, r;
3622
8f9da340 3623 scm_round_divide(x, y, &q, &r);
5fbf680b
MW
3624 return scm_values (scm_list_2 (q, r));
3625}
3626#undef FUNC_NAME
3627
8f9da340
MW
3628#define s_scm_round_divide s_scm_i_round_divide
3629#define g_scm_round_divide g_scm_i_round_divide
5fbf680b
MW
3630
3631void
8f9da340 3632scm_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168
MW
3633{
3634 if (SCM_LIKELY (SCM_I_INUMP (x)))
3635 {
4a46bc2a 3636 scm_t_inum xx = SCM_I_INUM (x);
ff62c168
MW
3637 if (SCM_LIKELY (SCM_I_INUMP (y)))
3638 {
3639 scm_t_inum yy = SCM_I_INUM (y);
3640 if (SCM_UNLIKELY (yy == 0))
8f9da340 3641 scm_num_overflow (s_scm_round_divide);
ff62c168
MW
3642 else
3643 {
ff62c168 3644 scm_t_inum qq = xx / yy;
4a46bc2a 3645 scm_t_inum rr = xx % yy;
8f9da340
MW
3646 scm_t_inum ay = yy;
3647 scm_t_inum r2 = 2 * rr;
3648
3649 if (SCM_LIKELY (yy < 0))
ff62c168 3650 {
8f9da340
MW
3651 ay = -ay;
3652 r2 = -r2;
3653 }
3654
3655 if (qq & 1L)
3656 {
3657 if (r2 >= ay)
3658 { qq++; rr -= yy; }
3659 else if (r2 <= -ay)
3660 { qq--; rr += yy; }
ff62c168
MW
3661 }
3662 else
3663 {
8f9da340
MW
3664 if (r2 > ay)
3665 { qq++; rr -= yy; }
3666 else if (r2 < -ay)
3667 { qq--; rr += yy; }
ff62c168 3668 }
4a46bc2a 3669 if (SCM_LIKELY (SCM_FIXABLE (qq)))
5fbf680b 3670 *qp = SCM_I_MAKINUM (qq);
4a46bc2a 3671 else
5fbf680b
MW
3672 *qp = scm_i_inum2big (qq);
3673 *rp = SCM_I_MAKINUM (rr);
ff62c168 3674 }
5fbf680b 3675 return;
ff62c168
MW
3676 }
3677 else if (SCM_BIGP (y))
3678 {
3679 /* Pass a denormalized bignum version of x (even though it
8f9da340
MW
3680 can fit in a fixnum) to scm_i_bigint_round_divide */
3681 return scm_i_bigint_round_divide
3682 (scm_i_long2big (SCM_I_INUM (x)), y, qp, rp);
ff62c168
MW
3683 }
3684 else if (SCM_REALP (y))
8f9da340 3685 return scm_i_inexact_round_divide (xx, SCM_REAL_VALUE (y), qp, rp);
ff62c168 3686 else if (SCM_FRACTIONP (y))
8f9da340 3687 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3688 else
8f9da340
MW
3689 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3690 s_scm_round_divide, qp, rp);
ff62c168
MW
3691 }
3692 else if (SCM_BIGP (x))
3693 {
3694 if (SCM_LIKELY (SCM_I_INUMP (y)))
3695 {
3696 scm_t_inum yy = SCM_I_INUM (y);
3697 if (SCM_UNLIKELY (yy == 0))
8f9da340 3698 scm_num_overflow (s_scm_round_divide);
ff62c168
MW
3699 else
3700 {
3701 SCM q = scm_i_mkbig ();
3702 scm_t_inum rr;
8f9da340
MW
3703 int needs_adjustment;
3704
ff62c168
MW
3705 if (yy > 0)
3706 {
8f9da340
MW
3707 rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
3708 SCM_I_BIG_MPZ (x), yy);
3709 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3710 needs_adjustment = (2*rr >= yy);
3711 else
3712 needs_adjustment = (2*rr > yy);
ff62c168
MW
3713 }
3714 else
3715 {
3716 rr = - mpz_cdiv_q_ui (SCM_I_BIG_MPZ (q),
3717 SCM_I_BIG_MPZ (x), -yy);
ff62c168 3718 mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
8f9da340
MW
3719 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3720 needs_adjustment = (2*rr <= yy);
3721 else
3722 needs_adjustment = (2*rr < yy);
3723 }
3724 scm_remember_upto_here_1 (x);
3725 if (needs_adjustment)
3726 {
3727 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3728 rr -= yy;
ff62c168 3729 }
5fbf680b
MW
3730 *qp = scm_i_normbig (q);
3731 *rp = SCM_I_MAKINUM (rr);
ff62c168 3732 }
5fbf680b 3733 return;
ff62c168
MW
3734 }
3735 else if (SCM_BIGP (y))
8f9da340 3736 return scm_i_bigint_round_divide (x, y, qp, rp);
ff62c168 3737 else if (SCM_REALP (y))
8f9da340 3738 return scm_i_inexact_round_divide
5fbf680b 3739 (scm_i_big2dbl (x), SCM_REAL_VALUE (y), qp, rp);
ff62c168 3740 else if (SCM_FRACTIONP (y))
8f9da340 3741 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3742 else
8f9da340
MW
3743 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3744 s_scm_round_divide, qp, rp);
ff62c168
MW
3745 }
3746 else if (SCM_REALP (x))
3747 {
3748 if (SCM_REALP (y) || SCM_I_INUMP (y) ||
3749 SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3750 return scm_i_inexact_round_divide
5fbf680b 3751 (SCM_REAL_VALUE (x), scm_to_double (y), qp, rp);
03ddd15b 3752 else
8f9da340
MW
3753 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3754 s_scm_round_divide, qp, rp);
ff62c168
MW
3755 }
3756 else if (SCM_FRACTIONP (x))
3757 {
3758 if (SCM_REALP (y))
8f9da340 3759 return scm_i_inexact_round_divide
5fbf680b 3760 (scm_i_fraction2double (x), SCM_REAL_VALUE (y), qp, rp);
03ddd15b 3761 else if (SCM_I_INUMP (y) || SCM_BIGP (y) || SCM_FRACTIONP (y))
8f9da340 3762 return scm_i_exact_rational_round_divide (x, y, qp, rp);
ff62c168 3763 else
8f9da340
MW
3764 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG2,
3765 s_scm_round_divide, qp, rp);
ff62c168
MW
3766 }
3767 else
8f9da340
MW
3768 return two_valued_wta_dispatch_2 (g_scm_round_divide, x, y, SCM_ARG1,
3769 s_scm_round_divide, qp, rp);
ff62c168 3770}
ff62c168 3771
5fbf680b 3772static void
8f9da340 3773scm_i_inexact_round_divide (double x, double y, SCM *qp, SCM *rp)
ff62c168 3774{
8f9da340
MW
3775 if (SCM_UNLIKELY (y == 0))
3776 scm_num_overflow (s_scm_round_divide); /* or return a NaN? */
ff62c168 3777 else
8f9da340
MW
3778 {
3779 double q = scm_c_round (x / y);
3780 double r = x - q * y;
3781 *qp = scm_from_double (q);
3782 *rp = scm_from_double (r);
3783 }
ff62c168
MW
3784}
3785
3786/* Assumes that both x and y are bigints, though
3787 x might be able to fit into a fixnum. */
5fbf680b 3788static void
8f9da340 3789scm_i_bigint_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 3790{
8f9da340
MW
3791 SCM q, r, r2;
3792 int cmp, needs_adjustment;
ff62c168
MW
3793
3794 /* Note that x might be small enough to fit into a
3795 fixnum, so we must not let it escape into the wild */
3796 q = scm_i_mkbig ();
3797 r = scm_i_mkbig ();
8f9da340 3798 r2 = scm_i_mkbig ();
ff62c168 3799
8f9da340
MW
3800 mpz_fdiv_qr (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
3801 SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
3802 scm_remember_upto_here_1 (x);
3803 mpz_mul_2exp (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (r), 1); /* r2 = 2*r */
ff62c168 3804
8f9da340
MW
3805 cmp = mpz_cmpabs (SCM_I_BIG_MPZ (r2), SCM_I_BIG_MPZ (y));
3806 if (mpz_odd_p (SCM_I_BIG_MPZ (q)))
3807 needs_adjustment = (cmp >= 0);
ff62c168 3808 else
8f9da340
MW
3809 needs_adjustment = (cmp > 0);
3810
3811 if (needs_adjustment)
ff62c168 3812 {
8f9da340
MW
3813 mpz_add_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q), 1);
3814 mpz_sub (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (y));
ff62c168 3815 }
8f9da340
MW
3816
3817 scm_remember_upto_here_2 (r2, y);
5fbf680b
MW
3818 *qp = scm_i_normbig (q);
3819 *rp = scm_i_normbig (r);
ff62c168
MW
3820}
3821
5fbf680b 3822static void
8f9da340 3823scm_i_exact_rational_round_divide (SCM x, SCM y, SCM *qp, SCM *rp)
ff62c168 3824{
03ddd15b
MW
3825 SCM r1;
3826 SCM xd = scm_denominator (x);
3827 SCM yd = scm_denominator (y);
3828
8f9da340
MW
3829 scm_round_divide (scm_product (scm_numerator (x), yd),
3830 scm_product (scm_numerator (y), xd),
3831 qp, &r1);
03ddd15b 3832 *rp = scm_divide (r1, scm_product (xd, yd));
ff62c168
MW
3833}
3834
3835
78d3deb1
AW
3836SCM_PRIMITIVE_GENERIC (scm_i_gcd, "gcd", 0, 2, 1,
3837 (SCM x, SCM y, SCM rest),
3838 "Return the greatest common divisor of all parameter values.\n"
3839 "If called without arguments, 0 is returned.")
3840#define FUNC_NAME s_scm_i_gcd
3841{
3842 while (!scm_is_null (rest))
3843 { x = scm_gcd (x, y);
3844 y = scm_car (rest);
3845 rest = scm_cdr (rest);
3846 }
3847 return scm_gcd (x, y);
3848}
3849#undef FUNC_NAME
3850
3851#define s_gcd s_scm_i_gcd
3852#define g_gcd g_scm_i_gcd
3853
0f2d19dd 3854SCM
6e8d25a6 3855scm_gcd (SCM x, SCM y)
0f2d19dd 3856{
ca46fb90 3857 if (SCM_UNBNDP (y))
1dd79792 3858 return SCM_UNBNDP (x) ? SCM_INUM0 : scm_abs (x);
ca46fb90 3859
e11e83f3 3860 if (SCM_I_INUMP (x))
ca46fb90 3861 {
e11e83f3 3862 if (SCM_I_INUMP (y))
ca46fb90 3863 {
e25f3727
AW
3864 scm_t_inum xx = SCM_I_INUM (x);
3865 scm_t_inum yy = SCM_I_INUM (y);
3866 scm_t_inum u = xx < 0 ? -xx : xx;
3867 scm_t_inum v = yy < 0 ? -yy : yy;
3868 scm_t_inum result;
0aacf84e
MD
3869 if (xx == 0)
3870 result = v;
3871 else if (yy == 0)
3872 result = u;
3873 else
3874 {
e25f3727
AW
3875 scm_t_inum k = 1;
3876 scm_t_inum t;
0aacf84e
MD
3877 /* Determine a common factor 2^k */
3878 while (!(1 & (u | v)))
3879 {
3880 k <<= 1;
3881 u >>= 1;
3882 v >>= 1;
3883 }
3884 /* Now, any factor 2^n can be eliminated */
3885 if (u & 1)
3886 t = -v;
3887 else
3888 {
3889 t = u;
3890 b3:
3891 t = SCM_SRS (t, 1);
3892 }
3893 if (!(1 & t))
3894 goto b3;
3895 if (t > 0)
3896 u = t;
3897 else
3898 v = -t;
3899 t = u - v;
3900 if (t != 0)
3901 goto b3;
3902 result = u * k;
3903 }
3904 return (SCM_POSFIXABLE (result)
d956fa6f 3905 ? SCM_I_MAKINUM (result)
e25f3727 3906 : scm_i_inum2big (result));
ca46fb90
RB
3907 }
3908 else if (SCM_BIGP (y))
3909 {
0bff4dce
KR
3910 SCM_SWAP (x, y);
3911 goto big_inum;
ca46fb90
RB
3912 }
3913 else
fa075d40 3914 return scm_wta_dispatch_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
f872b822 3915 }
ca46fb90
RB
3916 else if (SCM_BIGP (x))
3917 {
e11e83f3 3918 if (SCM_I_INUMP (y))
ca46fb90 3919 {
e25f3727
AW
3920 scm_t_bits result;
3921 scm_t_inum yy;
0bff4dce 3922 big_inum:
e11e83f3 3923 yy = SCM_I_INUM (y);
8c5b0afc
KR
3924 if (yy == 0)
3925 return scm_abs (x);
0aacf84e
MD
3926 if (yy < 0)
3927 yy = -yy;
ca46fb90
RB
3928 result = mpz_gcd_ui (NULL, SCM_I_BIG_MPZ (x), yy);
3929 scm_remember_upto_here_1 (x);
0aacf84e 3930 return (SCM_POSFIXABLE (result)
d956fa6f 3931 ? SCM_I_MAKINUM (result)
e25f3727 3932 : scm_from_unsigned_integer (result));
ca46fb90
RB
3933 }
3934 else if (SCM_BIGP (y))
3935 {
3936 SCM result = scm_i_mkbig ();
0aacf84e
MD
3937 mpz_gcd (SCM_I_BIG_MPZ (result),
3938 SCM_I_BIG_MPZ (x),
3939 SCM_I_BIG_MPZ (y));
3940 scm_remember_upto_here_2 (x, y);
ca46fb90
RB
3941 return scm_i_normbig (result);
3942 }
3943 else
fa075d40 3944 return scm_wta_dispatch_2 (g_gcd, x, y, SCM_ARG2, s_gcd);
09fb7599 3945 }
ca46fb90 3946 else
fa075d40 3947 return scm_wta_dispatch_2 (g_gcd, x, y, SCM_ARG1, s_gcd);
0f2d19dd
JB
3948}
3949
78d3deb1
AW
3950SCM_PRIMITIVE_GENERIC (scm_i_lcm, "lcm", 0, 2, 1,
3951 (SCM x, SCM y, SCM rest),
3952 "Return the least common multiple of the arguments.\n"
3953 "If called without arguments, 1 is returned.")
3954#define FUNC_NAME s_scm_i_lcm
3955{
3956 while (!scm_is_null (rest))
3957 { x = scm_lcm (x, y);
3958 y = scm_car (rest);
3959 rest = scm_cdr (rest);
3960 }
3961 return scm_lcm (x, y);
3962}
3963#undef FUNC_NAME
3964
3965#define s_lcm s_scm_i_lcm
3966#define g_lcm g_scm_i_lcm
3967
0f2d19dd 3968SCM
6e8d25a6 3969scm_lcm (SCM n1, SCM n2)
0f2d19dd 3970{
ca46fb90
RB
3971 if (SCM_UNBNDP (n2))
3972 {
3973 if (SCM_UNBNDP (n1))
d956fa6f
MV
3974 return SCM_I_MAKINUM (1L);
3975 n2 = SCM_I_MAKINUM (1L);
09fb7599 3976 }
09fb7599 3977
fa075d40
AW
3978 if (SCM_UNLIKELY (!(SCM_I_INUMP (n1) || SCM_BIGP (n1))))
3979 return scm_wta_dispatch_2 (g_lcm, n1, n2, SCM_ARG1, s_lcm);
3980
3981 if (SCM_UNLIKELY (!(SCM_I_INUMP (n2) || SCM_BIGP (n2))))
3982 return scm_wta_dispatch_2 (g_lcm, n1, n2, SCM_ARG2, 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:
2e16a342 4115 if (nn1 == 0)
0aacf84e
MD
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:
f872b822 5112 efmt = (exp < -3) || (exp > wp + 2);
0f2d19dd 5113 if (!efmt)
cda139a7
MD
5114 {
5115 if (exp < 0)
5116 {
5117 a[ch++] = '0';
5118 a[ch++] = '.';
5119 dpt = exp;
f872b822
MD
5120 while (++dpt)
5121 a[ch++] = '0';
cda139a7
MD
5122 }
5123 else
f872b822 5124 dpt = exp + 1;
cda139a7 5125 }
0f2d19dd
JB
5126 else
5127 dpt = 1;
f872b822
MD
5128
5129 do
5130 {
5131 d = f;
5132 f -= d;
0b799eea 5133 a[ch++] = number_chars[d];
f872b822
MD
5134 if (f < fx[wp])
5135 break;
5136 if (f + fx[wp] >= 1.0)
5137 {
0b799eea 5138 a[ch - 1] = number_chars[d+1];
f872b822
MD
5139 break;
5140 }
0b799eea 5141 f *= radix;
f872b822
MD
5142 if (!(--dpt))
5143 a[ch++] = '.';
0f2d19dd 5144 }
f872b822 5145 while (wp--);
0f2d19dd
JB
5146
5147 if (dpt > 0)
cda139a7 5148 {
cda139a7
MD
5149 if ((dpt > 4) && (exp > 6))
5150 {
f872b822 5151 d = (a[0] == '-' ? 2 : 1);
cda139a7 5152 for (i = ch++; i > d; i--)
f872b822 5153 a[i] = a[i - 1];
cda139a7
MD
5154 a[d] = '.';
5155 efmt = 1;
5156 }
5157 else
cda139a7 5158 {
f872b822
MD
5159 while (--dpt)
5160 a[ch++] = '0';
cda139a7
MD
5161 a[ch++] = '.';
5162 }
5163 }
f872b822
MD
5164 if (a[ch - 1] == '.')
5165 a[ch++] = '0'; /* trailing zero */
5166 if (efmt && exp)
5167 {
5168 a[ch++] = 'e';
5169 if (exp < 0)
5170 {
5171 exp = -exp;
5172 a[ch++] = '-';
5173 }
0b799eea
MV
5174 for (i = radix; i <= exp; i *= radix);
5175 for (i /= radix; i; i /= radix)
f872b822 5176 {
0b799eea 5177 a[ch++] = number_chars[exp / i];
f872b822
MD
5178 exp %= i;
5179 }
0f2d19dd 5180 }
0f2d19dd
JB
5181 return ch;
5182}
5183
7a1aba42
MV
5184
5185static size_t
5186icmplx2str (double real, double imag, char *str, int radix)
5187{
5188 size_t i;
c7218482 5189 double sgn;
7a1aba42
MV
5190
5191 i = idbl2str (real, str, radix);
c7218482
MW
5192#ifdef HAVE_COPYSIGN
5193 sgn = copysign (1.0, imag);
5194#else
5195 sgn = imag;
5196#endif
5197 /* Don't output a '+' for negative numbers or for Inf and
5198 NaN. They will provide their own sign. */
5199 if (sgn >= 0 && DOUBLE_IS_FINITE (imag))
5200 str[i++] = '+';
5201 i += idbl2str (imag, &str[i], radix);
5202 str[i++] = 'i';
7a1aba42
MV
5203 return i;
5204}
5205
1be6b49c 5206static size_t
0b799eea 5207iflo2str (SCM flt, char *str, int radix)
0f2d19dd 5208{
1be6b49c 5209 size_t i;
3c9a524f 5210 if (SCM_REALP (flt))
0b799eea 5211 i = idbl2str (SCM_REAL_VALUE (flt), str, radix);
0f2d19dd 5212 else
7a1aba42
MV
5213 i = icmplx2str (SCM_COMPLEX_REAL (flt), SCM_COMPLEX_IMAG (flt),
5214 str, radix);
0f2d19dd
JB
5215 return i;
5216}
0f2d19dd 5217
2881e77b 5218/* convert a scm_t_intmax to a string (unterminated). returns the number of
1bbd0b84
GB
5219 characters in the result.
5220 rad is output base
5221 p is destination: worst case (base 2) is SCM_INTBUFLEN */
1be6b49c 5222size_t
2881e77b
MV
5223scm_iint2str (scm_t_intmax num, int rad, char *p)
5224{
5225 if (num < 0)
5226 {
5227 *p++ = '-';
5228 return scm_iuint2str (-num, rad, p) + 1;
5229 }
5230 else
5231 return scm_iuint2str (num, rad, p);
5232}
5233
5234/* convert a scm_t_intmax to a string (unterminated). returns the number of
5235 characters in the result.
5236 rad is output base
5237 p is destination: worst case (base 2) is SCM_INTBUFLEN */
5238size_t
5239scm_iuint2str (scm_t_uintmax num, int rad, char *p)
0f2d19dd 5240{
1be6b49c
ML
5241 size_t j = 1;
5242 size_t i;
2881e77b 5243 scm_t_uintmax n = num;
5c11cc9d 5244
a6f3af16
AW
5245 if (rad < 2 || rad > 36)
5246 scm_out_of_range ("scm_iuint2str", scm_from_int (rad));
5247
f872b822 5248 for (n /= rad; n > 0; n /= rad)
5c11cc9d
GH
5249 j++;
5250
5251 i = j;
2881e77b 5252 n = num;
f872b822
MD
5253 while (i--)
5254 {
5c11cc9d
GH
5255 int d = n % rad;
5256
f872b822 5257 n /= rad;
a6f3af16 5258 p[i] = number_chars[d];
f872b822 5259 }
0f2d19dd
JB
5260 return j;
5261}
5262
a1ec6916 5263SCM_DEFINE (scm_number_to_string, "number->string", 1, 1, 0,
bb628794
DH
5264 (SCM n, SCM radix),
5265 "Return a string holding the external representation of the\n"
942e5b91
MG
5266 "number @var{n} in the given @var{radix}. If @var{n} is\n"
5267 "inexact, a radix of 10 will be used.")
1bbd0b84 5268#define FUNC_NAME s_scm_number_to_string
0f2d19dd 5269{
1bbd0b84 5270 int base;
98cb6e75 5271
0aacf84e 5272 if (SCM_UNBNDP (radix))
98cb6e75 5273 base = 10;
0aacf84e 5274 else
5efd3c7d 5275 base = scm_to_signed_integer (radix, 2, 36);
98cb6e75 5276
e11e83f3 5277 if (SCM_I_INUMP (n))
0aacf84e
MD
5278 {
5279 char num_buf [SCM_INTBUFLEN];
e11e83f3 5280 size_t length = scm_iint2str (SCM_I_INUM (n), base, num_buf);
cc95e00a 5281 return scm_from_locale_stringn (num_buf, length);
0aacf84e
MD
5282 }
5283 else if (SCM_BIGP (n))
5284 {
5285 char *str = mpz_get_str (NULL, base, SCM_I_BIG_MPZ (n));
5286 scm_remember_upto_here_1 (n);
cc95e00a 5287 return scm_take_locale_string (str);
0aacf84e 5288 }
f92e85f7
MV
5289 else if (SCM_FRACTIONP (n))
5290 {
f92e85f7 5291 return scm_string_append (scm_list_3 (scm_number_to_string (SCM_FRACTION_NUMERATOR (n), radix),
cc95e00a 5292 scm_from_locale_string ("/"),
f92e85f7
MV
5293 scm_number_to_string (SCM_FRACTION_DENOMINATOR (n), radix)));
5294 }
0aacf84e
MD
5295 else if (SCM_INEXACTP (n))
5296 {
5297 char num_buf [FLOBUFLEN];
cc95e00a 5298 return scm_from_locale_stringn (num_buf, iflo2str (n, num_buf, base));
0aacf84e
MD
5299 }
5300 else
bb628794 5301 SCM_WRONG_TYPE_ARG (1, n);
0f2d19dd 5302}
1bbd0b84 5303#undef FUNC_NAME
0f2d19dd
JB
5304
5305
ca46fb90
RB
5306/* These print routines used to be stubbed here so that scm_repl.c
5307 wouldn't need SCM_BIGDIG conditionals (pre GMP) */
1cc91f1b 5308
0f2d19dd 5309int
e81d98ec 5310scm_print_real (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 5311{
56e55ac7 5312 char num_buf[FLOBUFLEN];
0b799eea 5313 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
0f2d19dd
JB
5314 return !0;
5315}
5316
b479fe9a
MV
5317void
5318scm_i_print_double (double val, SCM port)
5319{
5320 char num_buf[FLOBUFLEN];
5321 scm_lfwrite (num_buf, idbl2str (val, num_buf, 10), port);
5322}
5323
f3ae5d60 5324int
e81d98ec 5325scm_print_complex (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
f92e85f7 5326
f3ae5d60 5327{
56e55ac7 5328 char num_buf[FLOBUFLEN];
0b799eea 5329 scm_lfwrite (num_buf, iflo2str (sexp, num_buf, 10), port);
f3ae5d60
MD
5330 return !0;
5331}
1cc91f1b 5332
7a1aba42
MV
5333void
5334scm_i_print_complex (double real, double imag, SCM port)
5335{
5336 char num_buf[FLOBUFLEN];
5337 scm_lfwrite (num_buf, icmplx2str (real, imag, num_buf, 10), port);
5338}
5339
f92e85f7
MV
5340int
5341scm_i_print_fraction (SCM sexp, SCM port, scm_print_state *pstate SCM_UNUSED)
5342{
5343 SCM str;
f92e85f7 5344 str = scm_number_to_string (sexp, SCM_UNDEFINED);
a9178715 5345 scm_display (str, port);
f92e85f7
MV
5346 scm_remember_upto_here_1 (str);
5347 return !0;
5348}
5349
0f2d19dd 5350int
e81d98ec 5351scm_bigprint (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
0f2d19dd 5352{
ca46fb90
RB
5353 char *str = mpz_get_str (NULL, 10, SCM_I_BIG_MPZ (exp));
5354 scm_remember_upto_here_1 (exp);
5355 scm_lfwrite (str, (size_t) strlen (str), port);
5356 free (str);
0f2d19dd
JB
5357 return !0;
5358}
5359/*** END nums->strs ***/
5360
3c9a524f 5361
0f2d19dd 5362/*** STRINGS -> NUMBERS ***/
2a8fecee 5363
3c9a524f
DH
5364/* The following functions implement the conversion from strings to numbers.
5365 * The implementation somehow follows the grammar for numbers as it is given
5366 * in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
5367 * <uinteger R>, ...) that are used to build up numbers in the grammar. Some
5368 * points should be noted about the implementation:
bc3d34f5 5369 *
3c9a524f
DH
5370 * * Each function keeps a local index variable 'idx' that points at the
5371 * current position within the parsed string. The global index is only
5372 * updated if the function could parse the corresponding syntactic unit
5373 * successfully.
bc3d34f5 5374 *
3c9a524f 5375 * * Similarly, the functions keep track of indicators of inexactness ('#',
bc3d34f5
MW
5376 * '.' or exponents) using local variables ('hash_seen', 'x').
5377 *
3c9a524f
DH
5378 * * Sequences of digits are parsed into temporary variables holding fixnums.
5379 * Only if these fixnums would overflow, the result variables are updated
5380 * using the standard functions scm_add, scm_product, scm_divide etc. Then,
5381 * the temporary variables holding the fixnums are cleared, and the process
5382 * starts over again. If for example fixnums were able to store five decimal
5383 * digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
5384 * and the result was computed as 12345 * 100000 + 67890. In other words,
5385 * only every five digits two bignum operations were performed.
bc3d34f5
MW
5386 *
5387 * Notes on the handling of exactness specifiers:
5388 *
5389 * When parsing non-real complex numbers, we apply exactness specifiers on
5390 * per-component basis, as is done in PLT Scheme. For complex numbers
5391 * written in rectangular form, exactness specifiers are applied to the
5392 * real and imaginary parts before calling scm_make_rectangular. For
5393 * complex numbers written in polar form, exactness specifiers are applied
5394 * to the magnitude and angle before calling scm_make_polar.
5395 *
5396 * There are two kinds of exactness specifiers: forced and implicit. A
5397 * forced exactness specifier is a "#e" or "#i" prefix at the beginning of
5398 * the entire number, and applies to both components of a complex number.
5399 * "#e" causes each component to be made exact, and "#i" causes each
5400 * component to be made inexact. If no forced exactness specifier is
5401 * present, then the exactness of each component is determined
5402 * independently by the presence or absence of a decimal point or hash mark
5403 * within that component. If a decimal point or hash mark is present, the
5404 * component is made inexact, otherwise it is made exact.
5405 *
5406 * After the exactness specifiers have been applied to each component, they
5407 * are passed to either scm_make_rectangular or scm_make_polar to produce
5408 * the final result. Note that this will result in a real number if the
5409 * imaginary part, magnitude, or angle is an exact 0.
5410 *
5411 * For example, (string->number "#i5.0+0i") does the equivalent of:
5412 *
5413 * (make-rectangular (exact->inexact 5) (exact->inexact 0))
3c9a524f
DH
5414 */
5415
5416enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
5417
5418/* R5RS, section 7.1.1, lexical structure of numbers: <uinteger R>. */
5419
a6f3af16
AW
5420/* Caller is responsible for checking that the return value is in range
5421 for the given radix, which should be <= 36. */
5422static unsigned int
5423char_decimal_value (scm_t_uint32 c)
5424{
5425 /* uc_decimal_value returns -1 on error. When cast to an unsigned int,
5426 that's certainly above any valid decimal, so we take advantage of
5427 that to elide some tests. */
5428 unsigned int d = (unsigned int) uc_decimal_value (c);
5429
5430 /* If that failed, try extended hexadecimals, then. Only accept ascii
5431 hexadecimals. */
5432 if (d >= 10U)
5433 {
5434 c = uc_tolower (c);
5435 if (c >= (scm_t_uint32) 'a')
5436 d = c - (scm_t_uint32)'a' + 10U;
5437 }
5438 return d;
5439}
3c9a524f 5440
2a8fecee 5441static SCM
3f47e526 5442mem2uinteger (SCM mem, unsigned int *p_idx,
3c9a524f 5443 unsigned int radix, enum t_exactness *p_exactness)
2a8fecee 5444{
3c9a524f
DH
5445 unsigned int idx = *p_idx;
5446 unsigned int hash_seen = 0;
5447 scm_t_bits shift = 1;
5448 scm_t_bits add = 0;
5449 unsigned int digit_value;
5450 SCM result;
5451 char c;
3f47e526 5452 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5453
5454 if (idx == len)
5455 return SCM_BOOL_F;
2a8fecee 5456
3f47e526 5457 c = scm_i_string_ref (mem, idx);
a6f3af16 5458 digit_value = char_decimal_value (c);
3c9a524f
DH
5459 if (digit_value >= radix)
5460 return SCM_BOOL_F;
5461
5462 idx++;
d956fa6f 5463 result = SCM_I_MAKINUM (digit_value);
3c9a524f 5464 while (idx != len)
f872b822 5465 {
3f47e526 5466 scm_t_wchar c = scm_i_string_ref (mem, idx);
a6f3af16 5467 if (c == '#')
3c9a524f
DH
5468 {
5469 hash_seen = 1;
5470 digit_value = 0;
5471 }
a6f3af16
AW
5472 else if (hash_seen)
5473 break;
3c9a524f 5474 else
a6f3af16
AW
5475 {
5476 digit_value = char_decimal_value (c);
5477 /* This check catches non-decimals in addition to out-of-range
5478 decimals. */
5479 if (digit_value >= radix)
5480 break;
5481 }
3c9a524f
DH
5482
5483 idx++;
5484 if (SCM_MOST_POSITIVE_FIXNUM / radix < shift)
5485 {
d956fa6f 5486 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5487 if (add > 0)
d956fa6f 5488 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5489
5490 shift = radix;
5491 add = digit_value;
5492 }
5493 else
5494 {
5495 shift = shift * radix;
5496 add = add * radix + digit_value;
5497 }
5498 };
5499
5500 if (shift > 1)
d956fa6f 5501 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5502 if (add > 0)
d956fa6f 5503 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5504
5505 *p_idx = idx;
5506 if (hash_seen)
5507 *p_exactness = INEXACT;
5508
5509 return result;
2a8fecee
JB
5510}
5511
5512
3c9a524f
DH
5513/* R5RS, section 7.1.1, lexical structure of numbers: <decimal 10>. Only
5514 * covers the parts of the rules that start at a potential point. The value
5515 * of the digits up to the point have been parsed by the caller and are given
79d34f68
DH
5516 * in variable result. The content of *p_exactness indicates, whether a hash
5517 * has already been seen in the digits before the point.
3c9a524f 5518 */
1cc91f1b 5519
3f47e526 5520#define DIGIT2UINT(d) (uc_numeric_value(d).numerator)
3c9a524f
DH
5521
5522static SCM
3f47e526 5523mem2decimal_from_point (SCM result, SCM mem,
3c9a524f 5524 unsigned int *p_idx, enum t_exactness *p_exactness)
0f2d19dd 5525{
3c9a524f
DH
5526 unsigned int idx = *p_idx;
5527 enum t_exactness x = *p_exactness;
3f47e526 5528 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5529
5530 if (idx == len)
79d34f68 5531 return result;
3c9a524f 5532
3f47e526 5533 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
5534 {
5535 scm_t_bits shift = 1;
5536 scm_t_bits add = 0;
5537 unsigned int digit_value;
cff5fa33 5538 SCM big_shift = SCM_INUM1;
3c9a524f
DH
5539
5540 idx++;
5541 while (idx != len)
5542 {
3f47e526
MG
5543 scm_t_wchar c = scm_i_string_ref (mem, idx);
5544 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5545 {
5546 if (x == INEXACT)
5547 return SCM_BOOL_F;
5548 else
5549 digit_value = DIGIT2UINT (c);
5550 }
5551 else if (c == '#')
5552 {
5553 x = INEXACT;
5554 digit_value = 0;
5555 }
5556 else
5557 break;
5558
5559 idx++;
5560 if (SCM_MOST_POSITIVE_FIXNUM / 10 < shift)
5561 {
d956fa6f
MV
5562 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
5563 result = scm_product (result, SCM_I_MAKINUM (shift));
3c9a524f 5564 if (add > 0)
d956fa6f 5565 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5566
5567 shift = 10;
5568 add = digit_value;
5569 }
5570 else
5571 {
5572 shift = shift * 10;
5573 add = add * 10 + digit_value;
5574 }
5575 };
5576
5577 if (add > 0)
5578 {
d956fa6f
MV
5579 big_shift = scm_product (big_shift, SCM_I_MAKINUM (shift));
5580 result = scm_product (result, SCM_I_MAKINUM (shift));
5581 result = scm_sum (result, SCM_I_MAKINUM (add));
3c9a524f
DH
5582 }
5583
d8592269 5584 result = scm_divide (result, big_shift);
79d34f68 5585
3c9a524f
DH
5586 /* We've seen a decimal point, thus the value is implicitly inexact. */
5587 x = INEXACT;
f872b822 5588 }
3c9a524f 5589
3c9a524f 5590 if (idx != len)
f872b822 5591 {
3c9a524f
DH
5592 int sign = 1;
5593 unsigned int start;
3f47e526 5594 scm_t_wchar c;
3c9a524f
DH
5595 int exponent;
5596 SCM e;
5597
5598 /* R5RS, section 7.1.1, lexical structure of numbers: <suffix> */
5599
3f47e526 5600 switch (scm_i_string_ref (mem, idx))
f872b822 5601 {
3c9a524f
DH
5602 case 'd': case 'D':
5603 case 'e': case 'E':
5604 case 'f': case 'F':
5605 case 'l': case 'L':
5606 case 's': case 'S':
5607 idx++;
ee0ddd21
AW
5608 if (idx == len)
5609 return SCM_BOOL_F;
5610
3c9a524f 5611 start = idx;
3f47e526 5612 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5613 if (c == '-')
5614 {
5615 idx++;
ee0ddd21
AW
5616 if (idx == len)
5617 return SCM_BOOL_F;
5618
3c9a524f 5619 sign = -1;
3f47e526 5620 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5621 }
5622 else 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
5632 sign = 1;
5633
3f47e526 5634 if (!uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5635 return SCM_BOOL_F;
5636
5637 idx++;
5638 exponent = DIGIT2UINT (c);
5639 while (idx != len)
f872b822 5640 {
3f47e526
MG
5641 scm_t_wchar c = scm_i_string_ref (mem, idx);
5642 if (uc_is_property_decimal_digit ((scm_t_uint32) c))
3c9a524f
DH
5643 {
5644 idx++;
5645 if (exponent <= SCM_MAXEXP)
5646 exponent = exponent * 10 + DIGIT2UINT (c);
5647 }
5648 else
5649 break;
f872b822 5650 }
3c9a524f
DH
5651
5652 if (exponent > SCM_MAXEXP)
f872b822 5653 {
3c9a524f 5654 size_t exp_len = idx - start;
3f47e526 5655 SCM exp_string = scm_i_substring_copy (mem, start, start + exp_len);
3c9a524f
DH
5656 SCM exp_num = scm_string_to_number (exp_string, SCM_UNDEFINED);
5657 scm_out_of_range ("string->number", exp_num);
f872b822 5658 }
3c9a524f 5659
d956fa6f 5660 e = scm_integer_expt (SCM_I_MAKINUM (10), SCM_I_MAKINUM (exponent));
3c9a524f
DH
5661 if (sign == 1)
5662 result = scm_product (result, e);
5663 else
6ebecdeb 5664 result = scm_divide (result, e);
3c9a524f
DH
5665
5666 /* We've seen an exponent, thus the value is implicitly inexact. */
5667 x = INEXACT;
5668
f872b822 5669 break;
3c9a524f 5670
f872b822 5671 default:
3c9a524f 5672 break;
f872b822 5673 }
0f2d19dd 5674 }
3c9a524f
DH
5675
5676 *p_idx = idx;
5677 if (x == INEXACT)
5678 *p_exactness = x;
5679
5680 return result;
0f2d19dd 5681}
0f2d19dd 5682
3c9a524f
DH
5683
5684/* R5RS, section 7.1.1, lexical structure of numbers: <ureal R> */
5685
5686static SCM
3f47e526 5687mem2ureal (SCM mem, unsigned int *p_idx,
9d427b2c 5688 unsigned int radix, enum t_exactness forced_x)
0f2d19dd 5689{
3c9a524f 5690 unsigned int idx = *p_idx;
164d2481 5691 SCM result;
3f47e526 5692 size_t len = scm_i_string_length (mem);
3c9a524f 5693
40f89215
NJ
5694 /* Start off believing that the number will be exact. This changes
5695 to INEXACT if we see a decimal point or a hash. */
9d427b2c 5696 enum t_exactness implicit_x = EXACT;
40f89215 5697
3c9a524f
DH
5698 if (idx == len)
5699 return SCM_BOOL_F;
5700
3f47e526 5701 if (idx+5 <= len && !scm_i_string_strcmp (mem, idx, "inf.0"))
7351e207
MV
5702 {
5703 *p_idx = idx+5;
5704 return scm_inf ();
5705 }
5706
3f47e526 5707 if (idx+4 < len && !scm_i_string_strcmp (mem, idx, "nan."))
7351e207 5708 {
d8592269
MV
5709 /* Cobble up the fractional part. We might want to set the
5710 NaN's mantissa from it. */
7351e207 5711 idx += 4;
9d427b2c 5712 mem2uinteger (mem, &idx, 10, &implicit_x);
7351e207
MV
5713 *p_idx = idx;
5714 return scm_nan ();
5715 }
5716
3f47e526 5717 if (scm_i_string_ref (mem, idx) == '.')
3c9a524f
DH
5718 {
5719 if (radix != 10)
5720 return SCM_BOOL_F;
5721 else if (idx + 1 == len)
5722 return SCM_BOOL_F;
3f47e526 5723 else if (!uc_is_property_decimal_digit ((scm_t_uint32) scm_i_string_ref (mem, idx+1)))
3c9a524f
DH
5724 return SCM_BOOL_F;
5725 else
cff5fa33 5726 result = mem2decimal_from_point (SCM_INUM0, mem,
9d427b2c 5727 p_idx, &implicit_x);
f872b822 5728 }
3c9a524f
DH
5729 else
5730 {
3c9a524f 5731 SCM uinteger;
3c9a524f 5732
9d427b2c 5733 uinteger = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 5734 if (scm_is_false (uinteger))
3c9a524f
DH
5735 return SCM_BOOL_F;
5736
5737 if (idx == len)
5738 result = uinteger;
3f47e526 5739 else if (scm_i_string_ref (mem, idx) == '/')
f872b822 5740 {
3c9a524f
DH
5741 SCM divisor;
5742
5743 idx++;
ee0ddd21
AW
5744 if (idx == len)
5745 return SCM_BOOL_F;
3c9a524f 5746
9d427b2c 5747 divisor = mem2uinteger (mem, &idx, radix, &implicit_x);
73e4de09 5748 if (scm_is_false (divisor))
3c9a524f
DH
5749 return SCM_BOOL_F;
5750
f92e85f7 5751 /* both are int/big here, I assume */
cba42c93 5752 result = scm_i_make_ratio (uinteger, divisor);
f872b822 5753 }
3c9a524f
DH
5754 else if (radix == 10)
5755 {
9d427b2c 5756 result = mem2decimal_from_point (uinteger, mem, &idx, &implicit_x);
73e4de09 5757 if (scm_is_false (result))
3c9a524f
DH
5758 return SCM_BOOL_F;
5759 }
5760 else
5761 result = uinteger;
5762
5763 *p_idx = idx;
f872b822 5764 }
164d2481 5765
9d427b2c
MW
5766 switch (forced_x)
5767 {
5768 case EXACT:
5769 if (SCM_INEXACTP (result))
5770 return scm_inexact_to_exact (result);
5771 else
5772 return result;
5773 case INEXACT:
5774 if (SCM_INEXACTP (result))
5775 return result;
5776 else
5777 return scm_exact_to_inexact (result);
5778 case NO_EXACTNESS:
5779 if (implicit_x == INEXACT)
5780 {
5781 if (SCM_INEXACTP (result))
5782 return result;
5783 else
5784 return scm_exact_to_inexact (result);
5785 }
5786 else
5787 return result;
5788 }
164d2481 5789
9d427b2c
MW
5790 /* We should never get here */
5791 scm_syserror ("mem2ureal");
3c9a524f 5792}
0f2d19dd 5793
0f2d19dd 5794
3c9a524f 5795/* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
0f2d19dd 5796
3c9a524f 5797static SCM
3f47e526 5798mem2complex (SCM mem, unsigned int idx,
9d427b2c 5799 unsigned int radix, enum t_exactness forced_x)
3c9a524f 5800{
3f47e526 5801 scm_t_wchar c;
3c9a524f
DH
5802 int sign = 0;
5803 SCM ureal;
3f47e526 5804 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5805
5806 if (idx == len)
5807 return SCM_BOOL_F;
5808
3f47e526 5809 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5810 if (c == '+')
5811 {
5812 idx++;
5813 sign = 1;
5814 }
5815 else if (c == '-')
5816 {
5817 idx++;
5818 sign = -1;
0f2d19dd 5819 }
0f2d19dd 5820
3c9a524f
DH
5821 if (idx == len)
5822 return SCM_BOOL_F;
5823
9d427b2c 5824 ureal = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 5825 if (scm_is_false (ureal))
f872b822 5826 {
3c9a524f
DH
5827 /* input must be either +i or -i */
5828
5829 if (sign == 0)
5830 return SCM_BOOL_F;
5831
3f47e526
MG
5832 if (scm_i_string_ref (mem, idx) == 'i'
5833 || scm_i_string_ref (mem, idx) == 'I')
f872b822 5834 {
3c9a524f
DH
5835 idx++;
5836 if (idx != len)
5837 return SCM_BOOL_F;
5838
cff5fa33 5839 return scm_make_rectangular (SCM_INUM0, SCM_I_MAKINUM (sign));
f872b822 5840 }
3c9a524f
DH
5841 else
5842 return SCM_BOOL_F;
0f2d19dd 5843 }
3c9a524f
DH
5844 else
5845 {
73e4de09 5846 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f 5847 ureal = scm_difference (ureal, SCM_UNDEFINED);
f872b822 5848
3c9a524f
DH
5849 if (idx == len)
5850 return ureal;
5851
3f47e526 5852 c = scm_i_string_ref (mem, idx);
3c9a524f 5853 switch (c)
f872b822 5854 {
3c9a524f
DH
5855 case 'i': case 'I':
5856 /* either +<ureal>i or -<ureal>i */
5857
5858 idx++;
5859 if (sign == 0)
5860 return SCM_BOOL_F;
5861 if (idx != len)
5862 return SCM_BOOL_F;
cff5fa33 5863 return scm_make_rectangular (SCM_INUM0, ureal);
3c9a524f
DH
5864
5865 case '@':
5866 /* polar input: <real>@<real>. */
5867
5868 idx++;
5869 if (idx == len)
5870 return SCM_BOOL_F;
5871 else
f872b822 5872 {
3c9a524f
DH
5873 int sign;
5874 SCM angle;
5875 SCM result;
5876
3f47e526 5877 c = scm_i_string_ref (mem, idx);
3c9a524f
DH
5878 if (c == '+')
5879 {
5880 idx++;
ee0ddd21
AW
5881 if (idx == len)
5882 return SCM_BOOL_F;
3c9a524f
DH
5883 sign = 1;
5884 }
5885 else if (c == '-')
5886 {
5887 idx++;
ee0ddd21
AW
5888 if (idx == len)
5889 return SCM_BOOL_F;
3c9a524f
DH
5890 sign = -1;
5891 }
5892 else
5893 sign = 1;
5894
9d427b2c 5895 angle = mem2ureal (mem, &idx, radix, forced_x);
73e4de09 5896 if (scm_is_false (angle))
3c9a524f
DH
5897 return SCM_BOOL_F;
5898 if (idx != len)
5899 return SCM_BOOL_F;
5900
73e4de09 5901 if (sign == -1 && scm_is_false (scm_nan_p (ureal)))
3c9a524f
DH
5902 angle = scm_difference (angle, SCM_UNDEFINED);
5903
5904 result = scm_make_polar (ureal, angle);
5905 return result;
f872b822 5906 }
3c9a524f
DH
5907 case '+':
5908 case '-':
5909 /* expecting input matching <real>[+-]<ureal>?i */
0f2d19dd 5910
3c9a524f
DH
5911 idx++;
5912 if (idx == len)
5913 return SCM_BOOL_F;
5914 else
5915 {
5916 int sign = (c == '+') ? 1 : -1;
9d427b2c 5917 SCM imag = mem2ureal (mem, &idx, radix, forced_x);
0f2d19dd 5918
73e4de09 5919 if (scm_is_false (imag))
d956fa6f 5920 imag = SCM_I_MAKINUM (sign);
23295dc3 5921 else if (sign == -1 && scm_is_false (scm_nan_p (imag)))
1fe5e088 5922 imag = scm_difference (imag, SCM_UNDEFINED);
0f2d19dd 5923
3c9a524f
DH
5924 if (idx == len)
5925 return SCM_BOOL_F;
3f47e526
MG
5926 if (scm_i_string_ref (mem, idx) != 'i'
5927 && scm_i_string_ref (mem, idx) != 'I')
3c9a524f 5928 return SCM_BOOL_F;
0f2d19dd 5929
3c9a524f
DH
5930 idx++;
5931 if (idx != len)
5932 return SCM_BOOL_F;
0f2d19dd 5933
1fe5e088 5934 return scm_make_rectangular (ureal, imag);
3c9a524f
DH
5935 }
5936 default:
5937 return SCM_BOOL_F;
5938 }
5939 }
0f2d19dd 5940}
0f2d19dd
JB
5941
5942
3c9a524f
DH
5943/* R5RS, section 7.1.1, lexical structure of numbers: <number> */
5944
5945enum t_radix {NO_RADIX=0, DUAL=2, OCT=8, DEC=10, HEX=16};
1cc91f1b 5946
0f2d19dd 5947SCM
3f47e526 5948scm_i_string_to_number (SCM mem, unsigned int default_radix)
0f2d19dd 5949{
3c9a524f
DH
5950 unsigned int idx = 0;
5951 unsigned int radix = NO_RADIX;
5952 enum t_exactness forced_x = NO_EXACTNESS;
3f47e526 5953 size_t len = scm_i_string_length (mem);
3c9a524f
DH
5954
5955 /* R5RS, section 7.1.1, lexical structure of numbers: <prefix R> */
3f47e526 5956 while (idx + 2 < len && scm_i_string_ref (mem, idx) == '#')
3c9a524f 5957 {
3f47e526 5958 switch (scm_i_string_ref (mem, idx + 1))
3c9a524f
DH
5959 {
5960 case 'b': case 'B':
5961 if (radix != NO_RADIX)
5962 return SCM_BOOL_F;
5963 radix = DUAL;
5964 break;
5965 case 'd': case 'D':
5966 if (radix != NO_RADIX)
5967 return SCM_BOOL_F;
5968 radix = DEC;
5969 break;
5970 case 'i': case 'I':
5971 if (forced_x != NO_EXACTNESS)
5972 return SCM_BOOL_F;
5973 forced_x = INEXACT;
5974 break;
5975 case 'e': case 'E':
5976 if (forced_x != NO_EXACTNESS)
5977 return SCM_BOOL_F;
5978 forced_x = EXACT;
5979 break;
5980 case 'o': case 'O':
5981 if (radix != NO_RADIX)
5982 return SCM_BOOL_F;
5983 radix = OCT;
5984 break;
5985 case 'x': case 'X':
5986 if (radix != NO_RADIX)
5987 return SCM_BOOL_F;
5988 radix = HEX;
5989 break;
5990 default:
f872b822 5991 return SCM_BOOL_F;
3c9a524f
DH
5992 }
5993 idx += 2;
5994 }
5995
5996 /* R5RS, section 7.1.1, lexical structure of numbers: <complex R> */
5997 if (radix == NO_RADIX)
9d427b2c 5998 radix = default_radix;
f872b822 5999
9d427b2c 6000 return mem2complex (mem, idx, radix, forced_x);
0f2d19dd
JB
6001}
6002
3f47e526
MG
6003SCM
6004scm_c_locale_stringn_to_number (const char* mem, size_t len,
6005 unsigned int default_radix)
6006{
6007 SCM str = scm_from_locale_stringn (mem, len);
6008
6009 return scm_i_string_to_number (str, default_radix);
6010}
6011
0f2d19dd 6012
a1ec6916 6013SCM_DEFINE (scm_string_to_number, "string->number", 1, 1, 0,
bb628794 6014 (SCM string, SCM radix),
1e6808ea 6015 "Return a number of the maximally precise representation\n"
942e5b91 6016 "expressed by the given @var{string}. @var{radix} must be an\n"
5352393c
MG
6017 "exact integer, either 2, 8, 10, or 16. If supplied, @var{radix}\n"
6018 "is a default radix that may be overridden by an explicit radix\n"
6019 "prefix in @var{string} (e.g. \"#o177\"). If @var{radix} is not\n"
6020 "supplied, then the default radix is 10. If string is not a\n"
6021 "syntactically valid notation for a number, then\n"
6022 "@code{string->number} returns @code{#f}.")
1bbd0b84 6023#define FUNC_NAME s_scm_string_to_number
0f2d19dd
JB
6024{
6025 SCM answer;
5efd3c7d 6026 unsigned int base;
a6d9e5ab 6027 SCM_VALIDATE_STRING (1, string);
5efd3c7d
MV
6028
6029 if (SCM_UNBNDP (radix))
6030 base = 10;
6031 else
6032 base = scm_to_unsigned_integer (radix, 2, INT_MAX);
6033
3f47e526 6034 answer = scm_i_string_to_number (string, base);
8824ac88
MV
6035 scm_remember_upto_here_1 (string);
6036 return answer;
0f2d19dd 6037}
1bbd0b84 6038#undef FUNC_NAME
3c9a524f
DH
6039
6040
0f2d19dd
JB
6041/*** END strs->nums ***/
6042
5986c47d 6043
8507ec80
MV
6044SCM_DEFINE (scm_number_p, "number?", 1, 0, 0,
6045 (SCM x),
6046 "Return @code{#t} if @var{x} is a number, @code{#f}\n"
6047 "otherwise.")
6048#define FUNC_NAME s_scm_number_p
6049{
6050 return scm_from_bool (SCM_NUMBERP (x));
6051}
6052#undef FUNC_NAME
6053
6054SCM_DEFINE (scm_complex_p, "complex?", 1, 0, 0,
1bbd0b84 6055 (SCM x),
942e5b91 6056 "Return @code{#t} if @var{x} is a complex number, @code{#f}\n"
bb2c02f2 6057 "otherwise. Note that the sets of real, rational and integer\n"
942e5b91
MG
6058 "values form subsets of the set of complex numbers, i. e. the\n"
6059 "predicate will also be fulfilled if @var{x} is a real,\n"
6060 "rational or integer number.")
8507ec80 6061#define FUNC_NAME s_scm_complex_p
0f2d19dd 6062{
8507ec80
MV
6063 /* all numbers are complex. */
6064 return scm_number_p (x);
0f2d19dd 6065}
1bbd0b84 6066#undef FUNC_NAME
0f2d19dd 6067
f92e85f7
MV
6068SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
6069 (SCM x),
6070 "Return @code{#t} if @var{x} is a real number, @code{#f}\n"
6071 "otherwise. Note that the set of integer values forms a subset of\n"
6072 "the set of real numbers, i. e. the predicate will also be\n"
6073 "fulfilled if @var{x} is an integer number.")
6074#define FUNC_NAME s_scm_real_p
6075{
c960e556
MW
6076 return scm_from_bool
6077 (SCM_I_INUMP (x) || SCM_REALP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x));
f92e85f7
MV
6078}
6079#undef FUNC_NAME
6080
6081SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
1bbd0b84 6082 (SCM x),
942e5b91 6083 "Return @code{#t} if @var{x} is a rational number, @code{#f}\n"
bb2c02f2 6084 "otherwise. Note that the set of integer values forms a subset of\n"
942e5b91 6085 "the set of rational numbers, i. e. the predicate will also be\n"
f92e85f7
MV
6086 "fulfilled if @var{x} is an integer number.")
6087#define FUNC_NAME s_scm_rational_p
0f2d19dd 6088{
c960e556 6089 if (SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x))
f92e85f7
MV
6090 return SCM_BOOL_T;
6091 else if (SCM_REALP (x))
c960e556
MW
6092 /* due to their limited precision, finite floating point numbers are
6093 rational as well. (finite means neither infinity nor a NaN) */
6094 return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
0aacf84e 6095 else
bb628794 6096 return SCM_BOOL_F;
0f2d19dd 6097}
1bbd0b84 6098#undef FUNC_NAME
0f2d19dd 6099
a1ec6916 6100SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
1bbd0b84 6101 (SCM x),
942e5b91
MG
6102 "Return @code{#t} if @var{x} is an integer number, @code{#f}\n"
6103 "else.")
1bbd0b84 6104#define FUNC_NAME s_scm_integer_p
0f2d19dd 6105{
c960e556 6106 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f872b822 6107 return SCM_BOOL_T;
c960e556
MW
6108 else if (SCM_REALP (x))
6109 {
6110 double val = SCM_REAL_VALUE (x);
6111 return scm_from_bool (!isinf (val) && (val == floor (val)));
6112 }
6113 else
8e43ed5d 6114 return SCM_BOOL_F;
0f2d19dd 6115}
1bbd0b84 6116#undef FUNC_NAME
0f2d19dd
JB
6117
6118
8a1f4f98
AW
6119SCM scm_i_num_eq_p (SCM, SCM, SCM);
6120SCM_PRIMITIVE_GENERIC (scm_i_num_eq_p, "=", 0, 2, 1,
6121 (SCM x, SCM y, SCM rest),
6122 "Return @code{#t} if all parameters are numerically equal.")
6123#define FUNC_NAME s_scm_i_num_eq_p
6124{
6125 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6126 return SCM_BOOL_T;
6127 while (!scm_is_null (rest))
6128 {
6129 if (scm_is_false (scm_num_eq_p (x, y)))
6130 return SCM_BOOL_F;
6131 x = y;
6132 y = scm_car (rest);
6133 rest = scm_cdr (rest);
6134 }
6135 return scm_num_eq_p (x, y);
6136}
6137#undef FUNC_NAME
0f2d19dd 6138SCM
6e8d25a6 6139scm_num_eq_p (SCM x, SCM y)
0f2d19dd 6140{
d8b95e27 6141 again:
e11e83f3 6142 if (SCM_I_INUMP (x))
0aacf84e 6143 {
e25f3727 6144 scm_t_signed_bits xx = SCM_I_INUM (x);
e11e83f3 6145 if (SCM_I_INUMP (y))
0aacf84e 6146 {
e25f3727 6147 scm_t_signed_bits yy = SCM_I_INUM (y);
73e4de09 6148 return scm_from_bool (xx == yy);
0aacf84e
MD
6149 }
6150 else if (SCM_BIGP (y))
6151 return SCM_BOOL_F;
6152 else if (SCM_REALP (y))
e8c5b1f2
KR
6153 {
6154 /* On a 32-bit system an inum fits a double, we can cast the inum
6155 to a double and compare.
6156
6157 But on a 64-bit system an inum is bigger than a double and
6158 casting it to a double (call that dxx) will round. dxx is at
6159 worst 1 bigger or smaller than xx, so if dxx==yy we know yy is
6160 an integer and fits a long. So we cast yy to a long and
6161 compare with plain xx.
6162
6163 An alternative (for any size system actually) would be to check
6164 yy is an integer (with floor) and is in range of an inum
6165 (compare against appropriate powers of 2) then test
e25f3727
AW
6166 xx==(scm_t_signed_bits)yy. It's just a matter of which
6167 casts/comparisons might be fastest or easiest for the cpu. */
e8c5b1f2
KR
6168
6169 double yy = SCM_REAL_VALUE (y);
3a1b45fd
MV
6170 return scm_from_bool ((double) xx == yy
6171 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 6172 || xx == (scm_t_signed_bits) yy));
e8c5b1f2 6173 }
0aacf84e 6174 else if (SCM_COMPLEXP (y))
73e4de09 6175 return scm_from_bool (((double) xx == SCM_COMPLEX_REAL (y))
0aacf84e 6176 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7
MV
6177 else if (SCM_FRACTIONP (y))
6178 return SCM_BOOL_F;
0aacf84e 6179 else
fa075d40
AW
6180 return scm_wta_dispatch_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn,
6181 s_scm_i_num_eq_p);
f872b822 6182 }
0aacf84e
MD
6183 else if (SCM_BIGP (x))
6184 {
e11e83f3 6185 if (SCM_I_INUMP (y))
0aacf84e
MD
6186 return SCM_BOOL_F;
6187 else if (SCM_BIGP (y))
6188 {
6189 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6190 scm_remember_upto_here_2 (x, y);
73e4de09 6191 return scm_from_bool (0 == cmp);
0aacf84e
MD
6192 }
6193 else if (SCM_REALP (y))
6194 {
6195 int cmp;
2e65b52f 6196 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
6197 return SCM_BOOL_F;
6198 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
6199 scm_remember_upto_here_1 (x);
73e4de09 6200 return scm_from_bool (0 == cmp);
0aacf84e
MD
6201 }
6202 else if (SCM_COMPLEXP (y))
6203 {
6204 int cmp;
6205 if (0.0 != SCM_COMPLEX_IMAG (y))
6206 return SCM_BOOL_F;
2e65b52f 6207 if (isnan (SCM_COMPLEX_REAL (y)))
0aacf84e
MD
6208 return SCM_BOOL_F;
6209 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_COMPLEX_REAL (y));
6210 scm_remember_upto_here_1 (x);
73e4de09 6211 return scm_from_bool (0 == cmp);
0aacf84e 6212 }
f92e85f7
MV
6213 else if (SCM_FRACTIONP (y))
6214 return SCM_BOOL_F;
0aacf84e 6215 else
fa075d40
AW
6216 return scm_wta_dispatch_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn,
6217 s_scm_i_num_eq_p);
f4c627b3 6218 }
0aacf84e
MD
6219 else if (SCM_REALP (x))
6220 {
e8c5b1f2 6221 double xx = SCM_REAL_VALUE (x);
e11e83f3 6222 if (SCM_I_INUMP (y))
e8c5b1f2
KR
6223 {
6224 /* see comments with inum/real above */
e25f3727 6225 scm_t_signed_bits yy = SCM_I_INUM (y);
3a1b45fd
MV
6226 return scm_from_bool (xx == (double) yy
6227 && (DBL_MANT_DIG >= SCM_I_FIXNUM_BIT-1
e25f3727 6228 || (scm_t_signed_bits) xx == yy));
e8c5b1f2 6229 }
0aacf84e
MD
6230 else if (SCM_BIGP (y))
6231 {
6232 int cmp;
2e65b52f 6233 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
6234 return SCM_BOOL_F;
6235 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
6236 scm_remember_upto_here_1 (y);
73e4de09 6237 return scm_from_bool (0 == cmp);
0aacf84e
MD
6238 }
6239 else if (SCM_REALP (y))
73e4de09 6240 return scm_from_bool (SCM_REAL_VALUE (x) == SCM_REAL_VALUE (y));
0aacf84e 6241 else if (SCM_COMPLEXP (y))
73e4de09 6242 return scm_from_bool ((SCM_REAL_VALUE (x) == SCM_COMPLEX_REAL (y))
0aacf84e 6243 && (0.0 == SCM_COMPLEX_IMAG (y)));
f92e85f7 6244 else if (SCM_FRACTIONP (y))
d8b95e27
KR
6245 {
6246 double xx = SCM_REAL_VALUE (x);
2e65b52f 6247 if (isnan (xx))
d8b95e27 6248 return SCM_BOOL_F;
2e65b52f 6249 if (isinf (xx))
73e4de09 6250 return scm_from_bool (xx < 0.0);
d8b95e27
KR
6251 x = scm_inexact_to_exact (x); /* with x as frac or int */
6252 goto again;
6253 }
0aacf84e 6254 else
fa075d40
AW
6255 return scm_wta_dispatch_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn,
6256 s_scm_i_num_eq_p);
f872b822 6257 }
0aacf84e
MD
6258 else if (SCM_COMPLEXP (x))
6259 {
e11e83f3
MV
6260 if (SCM_I_INUMP (y))
6261 return scm_from_bool ((SCM_COMPLEX_REAL (x) == (double) SCM_I_INUM (y))
0aacf84e
MD
6262 && (SCM_COMPLEX_IMAG (x) == 0.0));
6263 else if (SCM_BIGP (y))
6264 {
6265 int cmp;
6266 if (0.0 != SCM_COMPLEX_IMAG (x))
6267 return SCM_BOOL_F;
2e65b52f 6268 if (isnan (SCM_COMPLEX_REAL (x)))
0aacf84e
MD
6269 return SCM_BOOL_F;
6270 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_COMPLEX_REAL (x));
6271 scm_remember_upto_here_1 (y);
73e4de09 6272 return scm_from_bool (0 == cmp);
0aacf84e
MD
6273 }
6274 else if (SCM_REALP (y))
73e4de09 6275 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_REAL_VALUE (y))
0aacf84e
MD
6276 && (SCM_COMPLEX_IMAG (x) == 0.0));
6277 else if (SCM_COMPLEXP (y))
73e4de09 6278 return scm_from_bool ((SCM_COMPLEX_REAL (x) == SCM_COMPLEX_REAL (y))
0aacf84e 6279 && (SCM_COMPLEX_IMAG (x) == SCM_COMPLEX_IMAG (y)));
f92e85f7 6280 else if (SCM_FRACTIONP (y))
d8b95e27
KR
6281 {
6282 double xx;
6283 if (SCM_COMPLEX_IMAG (x) != 0.0)
6284 return SCM_BOOL_F;
6285 xx = SCM_COMPLEX_REAL (x);
2e65b52f 6286 if (isnan (xx))
d8b95e27 6287 return SCM_BOOL_F;
2e65b52f 6288 if (isinf (xx))
73e4de09 6289 return scm_from_bool (xx < 0.0);
d8b95e27
KR
6290 x = scm_inexact_to_exact (x); /* with x as frac or int */
6291 goto again;
6292 }
f92e85f7 6293 else
fa075d40
AW
6294 return scm_wta_dispatch_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn,
6295 s_scm_i_num_eq_p);
f92e85f7
MV
6296 }
6297 else if (SCM_FRACTIONP (x))
6298 {
e11e83f3 6299 if (SCM_I_INUMP (y))
f92e85f7
MV
6300 return SCM_BOOL_F;
6301 else if (SCM_BIGP (y))
6302 return SCM_BOOL_F;
6303 else if (SCM_REALP (y))
d8b95e27
KR
6304 {
6305 double yy = SCM_REAL_VALUE (y);
2e65b52f 6306 if (isnan (yy))
d8b95e27 6307 return SCM_BOOL_F;
2e65b52f 6308 if (isinf (yy))
73e4de09 6309 return scm_from_bool (0.0 < yy);
d8b95e27
KR
6310 y = scm_inexact_to_exact (y); /* with y as frac or int */
6311 goto again;
6312 }
f92e85f7 6313 else if (SCM_COMPLEXP (y))
d8b95e27
KR
6314 {
6315 double yy;
6316 if (SCM_COMPLEX_IMAG (y) != 0.0)
6317 return SCM_BOOL_F;
6318 yy = SCM_COMPLEX_REAL (y);
2e65b52f 6319 if (isnan (yy))
d8b95e27 6320 return SCM_BOOL_F;
2e65b52f 6321 if (isinf (yy))
73e4de09 6322 return scm_from_bool (0.0 < yy);
d8b95e27
KR
6323 y = scm_inexact_to_exact (y); /* with y as frac or int */
6324 goto again;
6325 }
f92e85f7
MV
6326 else if (SCM_FRACTIONP (y))
6327 return scm_i_fraction_equalp (x, y);
0aacf84e 6328 else
fa075d40
AW
6329 return scm_wta_dispatch_2 (g_scm_i_num_eq_p, x, y, SCM_ARGn,
6330 s_scm_i_num_eq_p);
f4c627b3 6331 }
0aacf84e 6332 else
fa075d40
AW
6333 return scm_wta_dispatch_2 (g_scm_i_num_eq_p, x, y, SCM_ARG1,
6334 s_scm_i_num_eq_p);
0f2d19dd
JB
6335}
6336
6337
a5f0b599
KR
6338/* OPTIMIZE-ME: For int/frac and frac/frac compares, the multiplications
6339 done are good for inums, but for bignums an answer can almost always be
6340 had by just examining a few high bits of the operands, as done by GMP in
6341 mpq_cmp. flonum/frac compares likewise, but with the slight complication
6342 of the float exponent to take into account. */
6343
8c93b597 6344SCM_INTERNAL SCM scm_i_num_less_p (SCM, SCM, SCM);
8a1f4f98
AW
6345SCM_PRIMITIVE_GENERIC (scm_i_num_less_p, "<", 0, 2, 1,
6346 (SCM x, SCM y, SCM rest),
6347 "Return @code{#t} if the list of parameters is monotonically\n"
6348 "increasing.")
6349#define FUNC_NAME s_scm_i_num_less_p
6350{
6351 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6352 return SCM_BOOL_T;
6353 while (!scm_is_null (rest))
6354 {
6355 if (scm_is_false (scm_less_p (x, y)))
6356 return SCM_BOOL_F;
6357 x = y;
6358 y = scm_car (rest);
6359 rest = scm_cdr (rest);
6360 }
6361 return scm_less_p (x, y);
6362}
6363#undef FUNC_NAME
0f2d19dd 6364SCM
6e8d25a6 6365scm_less_p (SCM x, SCM y)
0f2d19dd 6366{
a5f0b599 6367 again:
e11e83f3 6368 if (SCM_I_INUMP (x))
0aacf84e 6369 {
e25f3727 6370 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6371 if (SCM_I_INUMP (y))
0aacf84e 6372 {
e25f3727 6373 scm_t_inum yy = SCM_I_INUM (y);
73e4de09 6374 return scm_from_bool (xx < yy);
0aacf84e
MD
6375 }
6376 else if (SCM_BIGP (y))
6377 {
6378 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6379 scm_remember_upto_here_1 (y);
73e4de09 6380 return scm_from_bool (sgn > 0);
0aacf84e
MD
6381 }
6382 else if (SCM_REALP (y))
73e4de09 6383 return scm_from_bool ((double) xx < SCM_REAL_VALUE (y));
f92e85f7 6384 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6385 {
6386 /* "x < a/b" becomes "x*b < a" */
6387 int_frac:
6388 x = scm_product (x, SCM_FRACTION_DENOMINATOR (y));
6389 y = SCM_FRACTION_NUMERATOR (y);
6390 goto again;
6391 }
0aacf84e 6392 else
fa075d40
AW
6393 return scm_wta_dispatch_2 (g_scm_i_num_less_p, x, y, SCM_ARGn,
6394 s_scm_i_num_less_p);
f872b822 6395 }
0aacf84e
MD
6396 else if (SCM_BIGP (x))
6397 {
e11e83f3 6398 if (SCM_I_INUMP (y))
0aacf84e
MD
6399 {
6400 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6401 scm_remember_upto_here_1 (x);
73e4de09 6402 return scm_from_bool (sgn < 0);
0aacf84e
MD
6403 }
6404 else if (SCM_BIGP (y))
6405 {
6406 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6407 scm_remember_upto_here_2 (x, y);
73e4de09 6408 return scm_from_bool (cmp < 0);
0aacf84e
MD
6409 }
6410 else if (SCM_REALP (y))
6411 {
6412 int cmp;
2e65b52f 6413 if (isnan (SCM_REAL_VALUE (y)))
0aacf84e
MD
6414 return SCM_BOOL_F;
6415 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
6416 scm_remember_upto_here_1 (x);
73e4de09 6417 return scm_from_bool (cmp < 0);
0aacf84e 6418 }
f92e85f7 6419 else if (SCM_FRACTIONP (y))
a5f0b599 6420 goto int_frac;
0aacf84e 6421 else
fa075d40
AW
6422 return scm_wta_dispatch_2 (g_scm_i_num_less_p, x, y, SCM_ARGn,
6423 s_scm_i_num_less_p);
f4c627b3 6424 }
0aacf84e
MD
6425 else if (SCM_REALP (x))
6426 {
e11e83f3
MV
6427 if (SCM_I_INUMP (y))
6428 return scm_from_bool (SCM_REAL_VALUE (x) < (double) SCM_I_INUM (y));
0aacf84e
MD
6429 else if (SCM_BIGP (y))
6430 {
6431 int cmp;
2e65b52f 6432 if (isnan (SCM_REAL_VALUE (x)))
0aacf84e
MD
6433 return SCM_BOOL_F;
6434 cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
6435 scm_remember_upto_here_1 (y);
73e4de09 6436 return scm_from_bool (cmp > 0);
0aacf84e
MD
6437 }
6438 else if (SCM_REALP (y))
73e4de09 6439 return scm_from_bool (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y));
f92e85f7 6440 else if (SCM_FRACTIONP (y))
a5f0b599
KR
6441 {
6442 double xx = SCM_REAL_VALUE (x);
2e65b52f 6443 if (isnan (xx))
a5f0b599 6444 return SCM_BOOL_F;
2e65b52f 6445 if (isinf (xx))
73e4de09 6446 return scm_from_bool (xx < 0.0);
a5f0b599
KR
6447 x = scm_inexact_to_exact (x); /* with x as frac or int */
6448 goto again;
6449 }
f92e85f7 6450 else
fa075d40
AW
6451 return scm_wta_dispatch_2 (g_scm_i_num_less_p, x, y, SCM_ARGn,
6452 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
fa075d40
AW
6485 return scm_wta_dispatch_2 (g_scm_i_num_less_p, x, y, SCM_ARGn,
6486 s_scm_i_num_less_p);
f872b822 6487 }
0aacf84e 6488 else
fa075d40
AW
6489 return scm_wta_dispatch_2 (g_scm_i_num_less_p, x, y, SCM_ARG1,
6490 s_scm_i_num_less_p);
0f2d19dd
JB
6491}
6492
6493
8a1f4f98
AW
6494SCM scm_i_num_gr_p (SCM, SCM, SCM);
6495SCM_PRIMITIVE_GENERIC (scm_i_num_gr_p, ">", 0, 2, 1,
6496 (SCM x, SCM y, SCM rest),
6497 "Return @code{#t} if the list of parameters is monotonically\n"
6498 "decreasing.")
6499#define FUNC_NAME s_scm_i_num_gr_p
6500{
6501 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6502 return SCM_BOOL_T;
6503 while (!scm_is_null (rest))
6504 {
6505 if (scm_is_false (scm_gr_p (x, y)))
6506 return SCM_BOOL_F;
6507 x = y;
6508 y = scm_car (rest);
6509 rest = scm_cdr (rest);
6510 }
6511 return scm_gr_p (x, y);
6512}
6513#undef FUNC_NAME
6514#define FUNC_NAME s_scm_i_num_gr_p
c76b1eaf
MD
6515SCM
6516scm_gr_p (SCM x, SCM y)
0f2d19dd 6517{
c76b1eaf 6518 if (!SCM_NUMBERP (x))
fa075d40 6519 return scm_wta_dispatch_2 (g_scm_i_num_gr_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6520 else if (!SCM_NUMBERP (y))
fa075d40 6521 return scm_wta_dispatch_2 (g_scm_i_num_gr_p, x, y, SCM_ARG2, FUNC_NAME);
c76b1eaf
MD
6522 else
6523 return scm_less_p (y, x);
0f2d19dd 6524}
1bbd0b84 6525#undef FUNC_NAME
0f2d19dd
JB
6526
6527
8a1f4f98
AW
6528SCM scm_i_num_leq_p (SCM, SCM, SCM);
6529SCM_PRIMITIVE_GENERIC (scm_i_num_leq_p, "<=", 0, 2, 1,
6530 (SCM x, SCM y, SCM rest),
6531 "Return @code{#t} if the list of parameters is monotonically\n"
6532 "non-decreasing.")
6533#define FUNC_NAME s_scm_i_num_leq_p
6534{
6535 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6536 return SCM_BOOL_T;
6537 while (!scm_is_null (rest))
6538 {
6539 if (scm_is_false (scm_leq_p (x, y)))
6540 return SCM_BOOL_F;
6541 x = y;
6542 y = scm_car (rest);
6543 rest = scm_cdr (rest);
6544 }
6545 return scm_leq_p (x, y);
6546}
6547#undef FUNC_NAME
6548#define FUNC_NAME s_scm_i_num_leq_p
c76b1eaf
MD
6549SCM
6550scm_leq_p (SCM x, SCM y)
0f2d19dd 6551{
c76b1eaf 6552 if (!SCM_NUMBERP (x))
fa075d40 6553 return scm_wta_dispatch_2 (g_scm_i_num_leq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6554 else if (!SCM_NUMBERP (y))
fa075d40 6555 return scm_wta_dispatch_2 (g_scm_i_num_leq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 6556 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 6557 return SCM_BOOL_F;
c76b1eaf 6558 else
73e4de09 6559 return scm_not (scm_less_p (y, x));
0f2d19dd 6560}
1bbd0b84 6561#undef FUNC_NAME
0f2d19dd
JB
6562
6563
8a1f4f98
AW
6564SCM scm_i_num_geq_p (SCM, SCM, SCM);
6565SCM_PRIMITIVE_GENERIC (scm_i_num_geq_p, ">=", 0, 2, 1,
6566 (SCM x, SCM y, SCM rest),
6567 "Return @code{#t} if the list of parameters is monotonically\n"
6568 "non-increasing.")
6569#define FUNC_NAME s_scm_i_num_geq_p
6570{
6571 if (SCM_UNBNDP (x) || SCM_UNBNDP (y))
6572 return SCM_BOOL_T;
6573 while (!scm_is_null (rest))
6574 {
6575 if (scm_is_false (scm_geq_p (x, y)))
6576 return SCM_BOOL_F;
6577 x = y;
6578 y = scm_car (rest);
6579 rest = scm_cdr (rest);
6580 }
6581 return scm_geq_p (x, y);
6582}
6583#undef FUNC_NAME
6584#define FUNC_NAME s_scm_i_num_geq_p
c76b1eaf
MD
6585SCM
6586scm_geq_p (SCM x, SCM y)
0f2d19dd 6587{
c76b1eaf 6588 if (!SCM_NUMBERP (x))
fa075d40 6589 return scm_wta_dispatch_2 (g_scm_i_num_geq_p, x, y, SCM_ARG1, FUNC_NAME);
c76b1eaf 6590 else if (!SCM_NUMBERP (y))
fa075d40 6591 return scm_wta_dispatch_2 (g_scm_i_num_geq_p, x, y, SCM_ARG2, FUNC_NAME);
73e4de09 6592 else if (scm_is_true (scm_nan_p (x)) || scm_is_true (scm_nan_p (y)))
fc194577 6593 return SCM_BOOL_F;
c76b1eaf 6594 else
73e4de09 6595 return scm_not (scm_less_p (x, y));
0f2d19dd 6596}
1bbd0b84 6597#undef FUNC_NAME
0f2d19dd
JB
6598
6599
2519490c
MW
6600SCM_PRIMITIVE_GENERIC (scm_zero_p, "zero?", 1, 0, 0,
6601 (SCM z),
6602 "Return @code{#t} if @var{z} is an exact or inexact number equal to\n"
6603 "zero.")
6604#define FUNC_NAME s_scm_zero_p
0f2d19dd 6605{
e11e83f3 6606 if (SCM_I_INUMP (z))
bc36d050 6607 return scm_from_bool (scm_is_eq (z, SCM_INUM0));
0aacf84e 6608 else if (SCM_BIGP (z))
c2ff8ab0 6609 return SCM_BOOL_F;
0aacf84e 6610 else if (SCM_REALP (z))
73e4de09 6611 return scm_from_bool (SCM_REAL_VALUE (z) == 0.0);
0aacf84e 6612 else if (SCM_COMPLEXP (z))
73e4de09 6613 return scm_from_bool (SCM_COMPLEX_REAL (z) == 0.0
c2ff8ab0 6614 && SCM_COMPLEX_IMAG (z) == 0.0);
f92e85f7
MV
6615 else if (SCM_FRACTIONP (z))
6616 return SCM_BOOL_F;
0aacf84e 6617 else
fa075d40 6618 return scm_wta_dispatch_1 (g_scm_zero_p, z, SCM_ARG1, s_scm_zero_p);
0f2d19dd 6619}
2519490c 6620#undef FUNC_NAME
0f2d19dd
JB
6621
6622
2519490c
MW
6623SCM_PRIMITIVE_GENERIC (scm_positive_p, "positive?", 1, 0, 0,
6624 (SCM x),
6625 "Return @code{#t} if @var{x} is an exact or inexact number greater than\n"
6626 "zero.")
6627#define FUNC_NAME s_scm_positive_p
0f2d19dd 6628{
e11e83f3
MV
6629 if (SCM_I_INUMP (x))
6630 return scm_from_bool (SCM_I_INUM (x) > 0);
0aacf84e
MD
6631 else if (SCM_BIGP (x))
6632 {
6633 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6634 scm_remember_upto_here_1 (x);
73e4de09 6635 return scm_from_bool (sgn > 0);
0aacf84e
MD
6636 }
6637 else if (SCM_REALP (x))
73e4de09 6638 return scm_from_bool(SCM_REAL_VALUE (x) > 0.0);
f92e85f7
MV
6639 else if (SCM_FRACTIONP (x))
6640 return scm_positive_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 6641 else
fa075d40 6642 return scm_wta_dispatch_1 (g_scm_positive_p, x, SCM_ARG1, s_scm_positive_p);
0f2d19dd 6643}
2519490c 6644#undef FUNC_NAME
0f2d19dd
JB
6645
6646
2519490c
MW
6647SCM_PRIMITIVE_GENERIC (scm_negative_p, "negative?", 1, 0, 0,
6648 (SCM x),
6649 "Return @code{#t} if @var{x} is an exact or inexact number less than\n"
6650 "zero.")
6651#define FUNC_NAME s_scm_negative_p
0f2d19dd 6652{
e11e83f3
MV
6653 if (SCM_I_INUMP (x))
6654 return scm_from_bool (SCM_I_INUM (x) < 0);
0aacf84e
MD
6655 else if (SCM_BIGP (x))
6656 {
6657 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6658 scm_remember_upto_here_1 (x);
73e4de09 6659 return scm_from_bool (sgn < 0);
0aacf84e
MD
6660 }
6661 else if (SCM_REALP (x))
73e4de09 6662 return scm_from_bool(SCM_REAL_VALUE (x) < 0.0);
f92e85f7
MV
6663 else if (SCM_FRACTIONP (x))
6664 return scm_negative_p (SCM_FRACTION_NUMERATOR (x));
0aacf84e 6665 else
fa075d40 6666 return scm_wta_dispatch_1 (g_scm_negative_p, x, SCM_ARG1, s_scm_negative_p);
0f2d19dd 6667}
2519490c 6668#undef FUNC_NAME
0f2d19dd
JB
6669
6670
2a06f791
KR
6671/* scm_min and scm_max return an inexact when either argument is inexact, as
6672 required by r5rs. On that basis, for exact/inexact combinations the
6673 exact is converted to inexact to compare and possibly return. This is
6674 unlike scm_less_p above which takes some trouble to preserve all bits in
6675 its test, such trouble is not required for min and max. */
6676
78d3deb1
AW
6677SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
6678 (SCM x, SCM y, SCM rest),
6679 "Return the maximum of all parameter values.")
6680#define FUNC_NAME s_scm_i_max
6681{
6682 while (!scm_is_null (rest))
6683 { x = scm_max (x, y);
6684 y = scm_car (rest);
6685 rest = scm_cdr (rest);
6686 }
6687 return scm_max (x, y);
6688}
6689#undef FUNC_NAME
6690
6691#define s_max s_scm_i_max
6692#define g_max g_scm_i_max
6693
0f2d19dd 6694SCM
6e8d25a6 6695scm_max (SCM x, SCM y)
0f2d19dd 6696{
0aacf84e
MD
6697 if (SCM_UNBNDP (y))
6698 {
6699 if (SCM_UNBNDP (x))
fa075d40 6700 return scm_wta_dispatch_0 (g_max, s_max);
e11e83f3 6701 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
6702 return x;
6703 else
fa075d40 6704 return scm_wta_dispatch_1 (g_max, x, SCM_ARG1, s_max);
f872b822 6705 }
f4c627b3 6706
e11e83f3 6707 if (SCM_I_INUMP (x))
0aacf84e 6708 {
e25f3727 6709 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6710 if (SCM_I_INUMP (y))
0aacf84e 6711 {
e25f3727 6712 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6713 return (xx < yy) ? y : x;
6714 }
6715 else if (SCM_BIGP (y))
6716 {
6717 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6718 scm_remember_upto_here_1 (y);
6719 return (sgn < 0) ? x : y;
6720 }
6721 else if (SCM_REALP (y))
6722 {
2e274311
MW
6723 double xxd = xx;
6724 double yyd = SCM_REAL_VALUE (y);
6725
6726 if (xxd > yyd)
6727 return scm_from_double (xxd);
6728 /* If y is a NaN, then "==" is false and we return the NaN */
6729 else if (SCM_LIKELY (!(xxd == yyd)))
6730 return y;
6731 /* Handle signed zeroes properly */
6732 else if (xx == 0)
6733 return flo0;
6734 else
6735 return y;
0aacf84e 6736 }
f92e85f7
MV
6737 else if (SCM_FRACTIONP (y))
6738 {
e4bc5d6c 6739 use_less:
73e4de09 6740 return (scm_is_false (scm_less_p (x, y)) ? x : y);
f92e85f7 6741 }
0aacf84e 6742 else
fa075d40 6743 return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 6744 }
0aacf84e
MD
6745 else if (SCM_BIGP (x))
6746 {
e11e83f3 6747 if (SCM_I_INUMP (y))
0aacf84e
MD
6748 {
6749 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6750 scm_remember_upto_here_1 (x);
6751 return (sgn < 0) ? y : x;
6752 }
6753 else if (SCM_BIGP (y))
6754 {
6755 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6756 scm_remember_upto_here_2 (x, y);
6757 return (cmp > 0) ? x : y;
6758 }
6759 else if (SCM_REALP (y))
6760 {
2a06f791
KR
6761 /* if y==NaN then xx>yy is false, so we return the NaN y */
6762 double xx, yy;
6763 big_real:
6764 xx = scm_i_big2dbl (x);
6765 yy = SCM_REAL_VALUE (y);
55f26379 6766 return (xx > yy ? scm_from_double (xx) : y);
0aacf84e 6767 }
f92e85f7
MV
6768 else if (SCM_FRACTIONP (y))
6769 {
e4bc5d6c 6770 goto use_less;
f92e85f7 6771 }
0aacf84e 6772 else
fa075d40 6773 return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
f4c627b3 6774 }
0aacf84e
MD
6775 else if (SCM_REALP (x))
6776 {
e11e83f3 6777 if (SCM_I_INUMP (y))
0aacf84e 6778 {
2e274311
MW
6779 scm_t_inum yy = SCM_I_INUM (y);
6780 double xxd = SCM_REAL_VALUE (x);
6781 double yyd = yy;
6782
6783 if (yyd > xxd)
6784 return scm_from_double (yyd);
6785 /* If x is a NaN, then "==" is false and we return the NaN */
6786 else if (SCM_LIKELY (!(xxd == yyd)))
6787 return x;
6788 /* Handle signed zeroes properly */
6789 else if (yy == 0)
6790 return flo0;
6791 else
6792 return x;
0aacf84e
MD
6793 }
6794 else if (SCM_BIGP (y))
6795 {
b6f8f763 6796 SCM_SWAP (x, y);
2a06f791 6797 goto big_real;
0aacf84e
MD
6798 }
6799 else if (SCM_REALP (y))
6800 {
0aacf84e 6801 double xx = SCM_REAL_VALUE (x);
2e274311
MW
6802 double yy = SCM_REAL_VALUE (y);
6803
6804 /* For purposes of max: +inf.0 > nan > everything else, per R6RS */
6805 if (xx > yy)
6806 return x;
6807 else if (SCM_LIKELY (xx < yy))
6808 return y;
6809 /* If neither (xx > yy) nor (xx < yy), then
6810 either they're equal or one is a NaN */
6811 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 6812 return DOUBLE_IS_POSITIVE_INFINITY (yy) ? y : x;
2e274311 6813 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 6814 return DOUBLE_IS_POSITIVE_INFINITY (xx) ? x : y;
2e274311
MW
6815 /* xx == yy, but handle signed zeroes properly */
6816 else if (double_is_non_negative_zero (yy))
6817 return y;
6818 else
6819 return x;
0aacf84e 6820 }
f92e85f7
MV
6821 else if (SCM_FRACTIONP (y))
6822 {
6823 double yy = scm_i_fraction2double (y);
6824 double xx = SCM_REAL_VALUE (x);
55f26379 6825 return (xx < yy) ? scm_from_double (yy) : x;
f92e85f7
MV
6826 }
6827 else
fa075d40 6828 return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
f92e85f7
MV
6829 }
6830 else if (SCM_FRACTIONP (x))
6831 {
e11e83f3 6832 if (SCM_I_INUMP (y))
f92e85f7 6833 {
e4bc5d6c 6834 goto use_less;
f92e85f7
MV
6835 }
6836 else if (SCM_BIGP (y))
6837 {
e4bc5d6c 6838 goto use_less;
f92e85f7
MV
6839 }
6840 else if (SCM_REALP (y))
6841 {
6842 double xx = scm_i_fraction2double (x);
2e274311
MW
6843 /* if y==NaN then ">" is false, so we return the NaN y */
6844 return (xx > SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
6845 }
6846 else if (SCM_FRACTIONP (y))
6847 {
e4bc5d6c 6848 goto use_less;
f92e85f7 6849 }
0aacf84e 6850 else
fa075d40 6851 return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
f872b822 6852 }
0aacf84e 6853 else
fa075d40 6854 return scm_wta_dispatch_2 (g_max, x, y, SCM_ARG1, s_max);
0f2d19dd
JB
6855}
6856
6857
78d3deb1
AW
6858SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
6859 (SCM x, SCM y, SCM rest),
6860 "Return the minimum of all parameter values.")
6861#define FUNC_NAME s_scm_i_min
6862{
6863 while (!scm_is_null (rest))
6864 { x = scm_min (x, y);
6865 y = scm_car (rest);
6866 rest = scm_cdr (rest);
6867 }
6868 return scm_min (x, y);
6869}
6870#undef FUNC_NAME
6871
6872#define s_min s_scm_i_min
6873#define g_min g_scm_i_min
6874
0f2d19dd 6875SCM
6e8d25a6 6876scm_min (SCM x, SCM y)
0f2d19dd 6877{
0aacf84e
MD
6878 if (SCM_UNBNDP (y))
6879 {
6880 if (SCM_UNBNDP (x))
fa075d40 6881 return scm_wta_dispatch_0 (g_min, s_min);
e11e83f3 6882 else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) || SCM_FRACTIONP(x))
0aacf84e
MD
6883 return x;
6884 else
fa075d40 6885 return scm_wta_dispatch_1 (g_min, x, SCM_ARG1, s_min);
f872b822 6886 }
f4c627b3 6887
e11e83f3 6888 if (SCM_I_INUMP (x))
0aacf84e 6889 {
e25f3727 6890 scm_t_inum xx = SCM_I_INUM (x);
e11e83f3 6891 if (SCM_I_INUMP (y))
0aacf84e 6892 {
e25f3727 6893 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
6894 return (xx < yy) ? x : y;
6895 }
6896 else if (SCM_BIGP (y))
6897 {
6898 int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
6899 scm_remember_upto_here_1 (y);
6900 return (sgn < 0) ? y : x;
6901 }
6902 else if (SCM_REALP (y))
6903 {
6904 double z = xx;
6905 /* if y==NaN then "<" is false and we return NaN */
55f26379 6906 return (z < SCM_REAL_VALUE (y)) ? scm_from_double (z) : y;
0aacf84e 6907 }
f92e85f7
MV
6908 else if (SCM_FRACTIONP (y))
6909 {
e4bc5d6c 6910 use_less:
73e4de09 6911 return (scm_is_false (scm_less_p (x, y)) ? y : x);
f92e85f7 6912 }
0aacf84e 6913 else
fa075d40 6914 return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 6915 }
0aacf84e
MD
6916 else if (SCM_BIGP (x))
6917 {
e11e83f3 6918 if (SCM_I_INUMP (y))
0aacf84e
MD
6919 {
6920 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
6921 scm_remember_upto_here_1 (x);
6922 return (sgn < 0) ? x : y;
6923 }
6924 else if (SCM_BIGP (y))
6925 {
6926 int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
6927 scm_remember_upto_here_2 (x, y);
6928 return (cmp > 0) ? y : x;
6929 }
6930 else if (SCM_REALP (y))
6931 {
2a06f791
KR
6932 /* if y==NaN then xx<yy is false, so we return the NaN y */
6933 double xx, yy;
6934 big_real:
6935 xx = scm_i_big2dbl (x);
6936 yy = SCM_REAL_VALUE (y);
55f26379 6937 return (xx < yy ? scm_from_double (xx) : y);
0aacf84e 6938 }
f92e85f7
MV
6939 else if (SCM_FRACTIONP (y))
6940 {
e4bc5d6c 6941 goto use_less;
f92e85f7 6942 }
0aacf84e 6943 else
fa075d40 6944 return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
f4c627b3 6945 }
0aacf84e
MD
6946 else if (SCM_REALP (x))
6947 {
e11e83f3 6948 if (SCM_I_INUMP (y))
0aacf84e 6949 {
e11e83f3 6950 double z = SCM_I_INUM (y);
0aacf84e 6951 /* if x==NaN then "<" is false and we return NaN */
55f26379 6952 return (z < SCM_REAL_VALUE (x)) ? scm_from_double (z) : x;
0aacf84e
MD
6953 }
6954 else if (SCM_BIGP (y))
6955 {
b6f8f763 6956 SCM_SWAP (x, y);
2a06f791 6957 goto big_real;
0aacf84e
MD
6958 }
6959 else if (SCM_REALP (y))
6960 {
0aacf84e 6961 double xx = SCM_REAL_VALUE (x);
2e274311
MW
6962 double yy = SCM_REAL_VALUE (y);
6963
6964 /* For purposes of min: -inf.0 < nan < everything else, per R6RS */
6965 if (xx < yy)
6966 return x;
6967 else if (SCM_LIKELY (xx > yy))
6968 return y;
6969 /* If neither (xx < yy) nor (xx > yy), then
6970 either they're equal or one is a NaN */
6971 else if (SCM_UNLIKELY (isnan (xx)))
041fccf6 6972 return DOUBLE_IS_NEGATIVE_INFINITY (yy) ? y : x;
2e274311 6973 else if (SCM_UNLIKELY (isnan (yy)))
041fccf6 6974 return DOUBLE_IS_NEGATIVE_INFINITY (xx) ? x : y;
2e274311
MW
6975 /* xx == yy, but handle signed zeroes properly */
6976 else if (double_is_non_negative_zero (xx))
6977 return y;
6978 else
6979 return x;
0aacf84e 6980 }
f92e85f7
MV
6981 else if (SCM_FRACTIONP (y))
6982 {
6983 double yy = scm_i_fraction2double (y);
6984 double xx = SCM_REAL_VALUE (x);
55f26379 6985 return (yy < xx) ? scm_from_double (yy) : x;
f92e85f7 6986 }
0aacf84e 6987 else
fa075d40 6988 return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
f872b822 6989 }
f92e85f7
MV
6990 else if (SCM_FRACTIONP (x))
6991 {
e11e83f3 6992 if (SCM_I_INUMP (y))
f92e85f7 6993 {
e4bc5d6c 6994 goto use_less;
f92e85f7
MV
6995 }
6996 else if (SCM_BIGP (y))
6997 {
e4bc5d6c 6998 goto use_less;
f92e85f7
MV
6999 }
7000 else if (SCM_REALP (y))
7001 {
7002 double xx = scm_i_fraction2double (x);
2e274311
MW
7003 /* if y==NaN then "<" is false, so we return the NaN y */
7004 return (xx < SCM_REAL_VALUE (y)) ? scm_from_double (xx) : y;
f92e85f7
MV
7005 }
7006 else if (SCM_FRACTIONP (y))
7007 {
e4bc5d6c 7008 goto use_less;
f92e85f7
MV
7009 }
7010 else
fa075d40 7011 return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
f92e85f7 7012 }
0aacf84e 7013 else
fa075d40 7014 return scm_wta_dispatch_2 (g_min, x, y, SCM_ARG1, s_min);
0f2d19dd
JB
7015}
7016
7017
8ccd24f7
AW
7018SCM_PRIMITIVE_GENERIC (scm_i_sum, "+", 0, 2, 1,
7019 (SCM x, SCM y, SCM rest),
7020 "Return the sum of all parameter values. Return 0 if called without\n"
7021 "any parameters." )
7022#define FUNC_NAME s_scm_i_sum
7023{
7024 while (!scm_is_null (rest))
7025 { x = scm_sum (x, y);
7026 y = scm_car (rest);
7027 rest = scm_cdr (rest);
7028 }
7029 return scm_sum (x, y);
7030}
7031#undef FUNC_NAME
7032
7033#define s_sum s_scm_i_sum
7034#define g_sum g_scm_i_sum
7035
0f2d19dd 7036SCM
6e8d25a6 7037scm_sum (SCM x, SCM y)
0f2d19dd 7038{
9cc37597 7039 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
7040 {
7041 if (SCM_NUMBERP (x)) return x;
7042 if (SCM_UNBNDP (x)) return SCM_INUM0;
fa075d40 7043 return scm_wta_dispatch_1 (g_sum, x, SCM_ARG1, s_sum);
f872b822 7044 }
c209c88e 7045
9cc37597 7046 if (SCM_LIKELY (SCM_I_INUMP (x)))
ca46fb90 7047 {
9cc37597 7048 if (SCM_LIKELY (SCM_I_INUMP (y)))
ca46fb90 7049 {
e25f3727
AW
7050 scm_t_inum xx = SCM_I_INUM (x);
7051 scm_t_inum yy = SCM_I_INUM (y);
7052 scm_t_inum z = xx + yy;
7053 return SCM_FIXABLE (z) ? SCM_I_MAKINUM (z) : scm_i_inum2big (z);
ca46fb90
RB
7054 }
7055 else if (SCM_BIGP (y))
7056 {
7057 SCM_SWAP (x, y);
7058 goto add_big_inum;
7059 }
7060 else if (SCM_REALP (y))
7061 {
e25f3727 7062 scm_t_inum xx = SCM_I_INUM (x);
55f26379 7063 return scm_from_double (xx + SCM_REAL_VALUE (y));
ca46fb90
RB
7064 }
7065 else if (SCM_COMPLEXP (y))
7066 {
e25f3727 7067 scm_t_inum xx = SCM_I_INUM (x);
8507ec80 7068 return scm_c_make_rectangular (xx + SCM_COMPLEX_REAL (y),
ca46fb90
RB
7069 SCM_COMPLEX_IMAG (y));
7070 }
f92e85f7 7071 else if (SCM_FRACTIONP (y))
cba42c93 7072 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
7073 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
7074 SCM_FRACTION_DENOMINATOR (y));
ca46fb90 7075 else
fa075d40 7076 return scm_wta_dispatch_2 (g_sum, x, y, SCM_ARGn, s_sum);
0aacf84e
MD
7077 } else if (SCM_BIGP (x))
7078 {
e11e83f3 7079 if (SCM_I_INUMP (y))
0aacf84e 7080 {
e25f3727 7081 scm_t_inum inum;
0aacf84e
MD
7082 int bigsgn;
7083 add_big_inum:
e11e83f3 7084 inum = SCM_I_INUM (y);
0aacf84e
MD
7085 if (inum == 0)
7086 return x;
7087 bigsgn = mpz_sgn (SCM_I_BIG_MPZ (x));
7088 if (inum < 0)
7089 {
7090 SCM result = scm_i_mkbig ();
7091 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), - inum);
7092 scm_remember_upto_here_1 (x);
7093 /* we know the result will have to be a bignum */
7094 if (bigsgn == -1)
7095 return result;
7096 return scm_i_normbig (result);
7097 }
7098 else
7099 {
7100 SCM result = scm_i_mkbig ();
7101 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), inum);
7102 scm_remember_upto_here_1 (x);
7103 /* we know the result will have to be a bignum */
7104 if (bigsgn == 1)
7105 return result;
7106 return scm_i_normbig (result);
7107 }
7108 }
7109 else if (SCM_BIGP (y))
7110 {
7111 SCM result = scm_i_mkbig ();
7112 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
7113 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7114 mpz_add (SCM_I_BIG_MPZ (result),
7115 SCM_I_BIG_MPZ (x),
7116 SCM_I_BIG_MPZ (y));
7117 scm_remember_upto_here_2 (x, y);
7118 /* we know the result will have to be a bignum */
7119 if (sgn_x == sgn_y)
7120 return result;
7121 return scm_i_normbig (result);
7122 }
7123 else if (SCM_REALP (y))
7124 {
7125 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) + SCM_REAL_VALUE (y);
7126 scm_remember_upto_here_1 (x);
55f26379 7127 return scm_from_double (result);
0aacf84e
MD
7128 }
7129 else if (SCM_COMPLEXP (y))
7130 {
7131 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
7132 + SCM_COMPLEX_REAL (y));
7133 scm_remember_upto_here_1 (x);
8507ec80 7134 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e 7135 }
f92e85f7 7136 else if (SCM_FRACTIONP (y))
cba42c93 7137 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (y),
f92e85f7
MV
7138 scm_product (x, SCM_FRACTION_DENOMINATOR (y))),
7139 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 7140 else
fa075d40 7141 return scm_wta_dispatch_2 (g_sum, x, y, SCM_ARGn, s_sum);
0f2d19dd 7142 }
0aacf84e
MD
7143 else if (SCM_REALP (x))
7144 {
e11e83f3 7145 if (SCM_I_INUMP (y))
55f26379 7146 return scm_from_double (SCM_REAL_VALUE (x) + SCM_I_INUM (y));
0aacf84e
MD
7147 else if (SCM_BIGP (y))
7148 {
7149 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) + SCM_REAL_VALUE (x);
7150 scm_remember_upto_here_1 (y);
55f26379 7151 return scm_from_double (result);
0aacf84e
MD
7152 }
7153 else if (SCM_REALP (y))
55f26379 7154 return scm_from_double (SCM_REAL_VALUE (x) + SCM_REAL_VALUE (y));
0aacf84e 7155 else if (SCM_COMPLEXP (y))
8507ec80 7156 return scm_c_make_rectangular (SCM_REAL_VALUE (x) + SCM_COMPLEX_REAL (y),
0aacf84e 7157 SCM_COMPLEX_IMAG (y));
f92e85f7 7158 else if (SCM_FRACTIONP (y))
55f26379 7159 return scm_from_double (SCM_REAL_VALUE (x) + scm_i_fraction2double (y));
0aacf84e 7160 else
fa075d40 7161 return scm_wta_dispatch_2 (g_sum, x, y, SCM_ARGn, s_sum);
f872b822 7162 }
0aacf84e
MD
7163 else if (SCM_COMPLEXP (x))
7164 {
e11e83f3 7165 if (SCM_I_INUMP (y))
8507ec80 7166 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_I_INUM (y),
0aacf84e
MD
7167 SCM_COMPLEX_IMAG (x));
7168 else if (SCM_BIGP (y))
7169 {
7170 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (y))
7171 + SCM_COMPLEX_REAL (x));
7172 scm_remember_upto_here_1 (y);
8507ec80 7173 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (x));
0aacf84e
MD
7174 }
7175 else if (SCM_REALP (y))
8507ec80 7176 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_REAL_VALUE (y),
0aacf84e
MD
7177 SCM_COMPLEX_IMAG (x));
7178 else if (SCM_COMPLEXP (y))
8507ec80 7179 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + SCM_COMPLEX_REAL (y),
0aacf84e 7180 SCM_COMPLEX_IMAG (x) + SCM_COMPLEX_IMAG (y));
f92e85f7 7181 else if (SCM_FRACTIONP (y))
8507ec80 7182 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) + scm_i_fraction2double (y),
f92e85f7
MV
7183 SCM_COMPLEX_IMAG (x));
7184 else
fa075d40 7185 return scm_wta_dispatch_2 (g_sum, x, y, SCM_ARGn, s_sum);
f92e85f7
MV
7186 }
7187 else if (SCM_FRACTIONP (x))
7188 {
e11e83f3 7189 if (SCM_I_INUMP (y))
cba42c93 7190 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7191 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
7192 SCM_FRACTION_DENOMINATOR (x));
7193 else if (SCM_BIGP (y))
cba42c93 7194 return scm_i_make_ratio (scm_sum (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7195 scm_product (y, SCM_FRACTION_DENOMINATOR (x))),
7196 SCM_FRACTION_DENOMINATOR (x));
7197 else if (SCM_REALP (y))
55f26379 7198 return scm_from_double (SCM_REAL_VALUE (y) + scm_i_fraction2double (x));
f92e85f7 7199 else if (SCM_COMPLEXP (y))
8507ec80 7200 return scm_c_make_rectangular (SCM_COMPLEX_REAL (y) + scm_i_fraction2double (x),
f92e85f7
MV
7201 SCM_COMPLEX_IMAG (y));
7202 else if (SCM_FRACTIONP (y))
7203 /* a/b + c/d = (ad + bc) / bd */
cba42c93 7204 return scm_i_make_ratio (scm_sum (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7205 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
7206 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e 7207 else
fa075d40 7208 return scm_wta_dispatch_2 (g_sum, x, y, SCM_ARGn, s_sum);
98cb6e75 7209 }
0aacf84e 7210 else
fa075d40 7211 return scm_wta_dispatch_2 (g_sum, x, y, SCM_ARG1, s_sum);
0f2d19dd
JB
7212}
7213
7214
40882e3d
KR
7215SCM_DEFINE (scm_oneplus, "1+", 1, 0, 0,
7216 (SCM x),
7217 "Return @math{@var{x}+1}.")
7218#define FUNC_NAME s_scm_oneplus
7219{
cff5fa33 7220 return scm_sum (x, SCM_INUM1);
40882e3d
KR
7221}
7222#undef FUNC_NAME
7223
7224
78d3deb1
AW
7225SCM_PRIMITIVE_GENERIC (scm_i_difference, "-", 0, 2, 1,
7226 (SCM x, SCM y, SCM rest),
7227 "If called with one argument @var{z1}, -@var{z1} returned. Otherwise\n"
7228 "the sum of all but the first argument are subtracted from the first\n"
7229 "argument.")
7230#define FUNC_NAME s_scm_i_difference
7231{
7232 while (!scm_is_null (rest))
7233 { x = scm_difference (x, y);
7234 y = scm_car (rest);
7235 rest = scm_cdr (rest);
7236 }
7237 return scm_difference (x, y);
7238}
7239#undef FUNC_NAME
7240
7241#define s_difference s_scm_i_difference
7242#define g_difference g_scm_i_difference
7243
0f2d19dd 7244SCM
6e8d25a6 7245scm_difference (SCM x, SCM y)
78d3deb1 7246#define FUNC_NAME s_difference
0f2d19dd 7247{
9cc37597 7248 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
ca46fb90
RB
7249 {
7250 if (SCM_UNBNDP (x))
fa075d40 7251 return scm_wta_dispatch_0 (g_difference, s_difference);
ca46fb90 7252 else
e11e83f3 7253 if (SCM_I_INUMP (x))
ca46fb90 7254 {
e25f3727 7255 scm_t_inum xx = -SCM_I_INUM (x);
ca46fb90 7256 if (SCM_FIXABLE (xx))
d956fa6f 7257 return SCM_I_MAKINUM (xx);
ca46fb90 7258 else
e25f3727 7259 return scm_i_inum2big (xx);
ca46fb90
RB
7260 }
7261 else if (SCM_BIGP (x))
a9ad4847
KR
7262 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
7263 bignum, but negating that gives a fixnum. */
ca46fb90
RB
7264 return scm_i_normbig (scm_i_clonebig (x, 0));
7265 else if (SCM_REALP (x))
55f26379 7266 return scm_from_double (-SCM_REAL_VALUE (x));
ca46fb90 7267 else if (SCM_COMPLEXP (x))
8507ec80 7268 return scm_c_make_rectangular (-SCM_COMPLEX_REAL (x),
ca46fb90 7269 -SCM_COMPLEX_IMAG (x));
f92e85f7 7270 else if (SCM_FRACTIONP (x))
cba42c93 7271 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x), SCM_UNDEFINED),
f92e85f7 7272 SCM_FRACTION_DENOMINATOR (x));
ca46fb90 7273 else
fa075d40 7274 return scm_wta_dispatch_1 (g_difference, x, SCM_ARG1, s_difference);
f872b822 7275 }
ca46fb90 7276
9cc37597 7277 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7278 {
9cc37597 7279 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7280 {
e25f3727
AW
7281 scm_t_inum xx = SCM_I_INUM (x);
7282 scm_t_inum yy = SCM_I_INUM (y);
7283 scm_t_inum z = xx - yy;
0aacf84e 7284 if (SCM_FIXABLE (z))
d956fa6f 7285 return SCM_I_MAKINUM (z);
0aacf84e 7286 else
e25f3727 7287 return scm_i_inum2big (z);
0aacf84e
MD
7288 }
7289 else if (SCM_BIGP (y))
7290 {
7291 /* inum-x - big-y */
e25f3727 7292 scm_t_inum xx = SCM_I_INUM (x);
ca46fb90 7293
0aacf84e 7294 if (xx == 0)
b5c40589
MW
7295 {
7296 /* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
7297 bignum, but negating that gives a fixnum. */
7298 return scm_i_normbig (scm_i_clonebig (y, 0));
7299 }
0aacf84e
MD
7300 else
7301 {
7302 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7303 SCM result = scm_i_mkbig ();
ca46fb90 7304
0aacf84e
MD
7305 if (xx >= 0)
7306 mpz_ui_sub (SCM_I_BIG_MPZ (result), xx, SCM_I_BIG_MPZ (y));
7307 else
7308 {
7309 /* x - y == -(y + -x) */
7310 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), -xx);
7311 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
7312 }
7313 scm_remember_upto_here_1 (y);
ca46fb90 7314
0aacf84e
MD
7315 if ((xx < 0 && (sgn_y > 0)) || ((xx > 0) && sgn_y < 0))
7316 /* we know the result will have to be a bignum */
7317 return result;
7318 else
7319 return scm_i_normbig (result);
7320 }
7321 }
7322 else if (SCM_REALP (y))
7323 {
e25f3727 7324 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
7325
7326 /*
7327 * We need to handle x == exact 0
7328 * specially because R6RS states that:
7329 * (- 0.0) ==> -0.0 and
7330 * (- 0.0 0.0) ==> 0.0
7331 * and the scheme compiler changes
7332 * (- 0.0) into (- 0 0.0)
7333 * So we need to treat (- 0 0.0) like (- 0.0).
7334 * At the C level, (-x) is different than (0.0 - x).
7335 * (0.0 - 0.0) ==> 0.0, but (- 0.0) ==> -0.0.
7336 */
7337 if (xx == 0)
7338 return scm_from_double (- SCM_REAL_VALUE (y));
7339 else
7340 return scm_from_double (xx - SCM_REAL_VALUE (y));
0aacf84e
MD
7341 }
7342 else if (SCM_COMPLEXP (y))
7343 {
e25f3727 7344 scm_t_inum xx = SCM_I_INUM (x);
9b9ef10c
MW
7345
7346 /* We need to handle x == exact 0 specially.
7347 See the comment above (for SCM_REALP (y)) */
7348 if (xx == 0)
7349 return scm_c_make_rectangular (- SCM_COMPLEX_REAL (y),
7350 - SCM_COMPLEX_IMAG (y));
7351 else
7352 return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
7353 - SCM_COMPLEX_IMAG (y));
0aacf84e 7354 }
f92e85f7
MV
7355 else if (SCM_FRACTIONP (y))
7356 /* a - b/c = (ac - b) / c */
cba42c93 7357 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7358 SCM_FRACTION_NUMERATOR (y)),
7359 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 7360 else
fa075d40 7361 return scm_wta_dispatch_2 (g_difference, x, y, SCM_ARGn, s_difference);
f872b822 7362 }
0aacf84e
MD
7363 else if (SCM_BIGP (x))
7364 {
e11e83f3 7365 if (SCM_I_INUMP (y))
0aacf84e
MD
7366 {
7367 /* big-x - inum-y */
e25f3727 7368 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e 7369 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
ca46fb90 7370
0aacf84e
MD
7371 scm_remember_upto_here_1 (x);
7372 if (sgn_x == 0)
c71b0706 7373 return (SCM_FIXABLE (-yy) ?
e25f3727 7374 SCM_I_MAKINUM (-yy) : scm_from_inum (-yy));
0aacf84e
MD
7375 else
7376 {
7377 SCM result = scm_i_mkbig ();
ca46fb90 7378
708f22c6
KR
7379 if (yy >= 0)
7380 mpz_sub_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), yy);
7381 else
7382 mpz_add_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), -yy);
0aacf84e 7383 scm_remember_upto_here_1 (x);
ca46fb90 7384
0aacf84e
MD
7385 if ((sgn_x < 0 && (yy > 0)) || ((sgn_x > 0) && yy < 0))
7386 /* we know the result will have to be a bignum */
7387 return result;
7388 else
7389 return scm_i_normbig (result);
7390 }
7391 }
7392 else if (SCM_BIGP (y))
7393 {
7394 int sgn_x = mpz_sgn (SCM_I_BIG_MPZ (x));
7395 int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
7396 SCM result = scm_i_mkbig ();
7397 mpz_sub (SCM_I_BIG_MPZ (result),
7398 SCM_I_BIG_MPZ (x),
7399 SCM_I_BIG_MPZ (y));
7400 scm_remember_upto_here_2 (x, y);
7401 /* we know the result will have to be a bignum */
7402 if ((sgn_x == 1) && (sgn_y == -1))
7403 return result;
7404 if ((sgn_x == -1) && (sgn_y == 1))
7405 return result;
7406 return scm_i_normbig (result);
7407 }
7408 else if (SCM_REALP (y))
7409 {
7410 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) - SCM_REAL_VALUE (y);
7411 scm_remember_upto_here_1 (x);
55f26379 7412 return scm_from_double (result);
0aacf84e
MD
7413 }
7414 else if (SCM_COMPLEXP (y))
7415 {
7416 double real_part = (mpz_get_d (SCM_I_BIG_MPZ (x))
7417 - SCM_COMPLEX_REAL (y));
7418 scm_remember_upto_here_1 (x);
8507ec80 7419 return scm_c_make_rectangular (real_part, - SCM_COMPLEX_IMAG (y));
0aacf84e 7420 }
f92e85f7 7421 else if (SCM_FRACTIONP (y))
cba42c93 7422 return scm_i_make_ratio (scm_difference (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7423 SCM_FRACTION_NUMERATOR (y)),
7424 SCM_FRACTION_DENOMINATOR (y));
fa075d40
AW
7425 else
7426 return scm_wta_dispatch_2 (g_difference, x, y, SCM_ARGn, s_difference);
ca46fb90 7427 }
0aacf84e
MD
7428 else if (SCM_REALP (x))
7429 {
e11e83f3 7430 if (SCM_I_INUMP (y))
55f26379 7431 return scm_from_double (SCM_REAL_VALUE (x) - SCM_I_INUM (y));
0aacf84e
MD
7432 else if (SCM_BIGP (y))
7433 {
7434 double result = SCM_REAL_VALUE (x) - mpz_get_d (SCM_I_BIG_MPZ (y));
7435 scm_remember_upto_here_1 (x);
55f26379 7436 return scm_from_double (result);
0aacf84e
MD
7437 }
7438 else if (SCM_REALP (y))
55f26379 7439 return scm_from_double (SCM_REAL_VALUE (x) - SCM_REAL_VALUE (y));
0aacf84e 7440 else if (SCM_COMPLEXP (y))
8507ec80 7441 return scm_c_make_rectangular (SCM_REAL_VALUE (x) - SCM_COMPLEX_REAL (y),
0aacf84e 7442 -SCM_COMPLEX_IMAG (y));
f92e85f7 7443 else if (SCM_FRACTIONP (y))
55f26379 7444 return scm_from_double (SCM_REAL_VALUE (x) - scm_i_fraction2double (y));
0aacf84e 7445 else
fa075d40 7446 return scm_wta_dispatch_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 7447 }
0aacf84e
MD
7448 else if (SCM_COMPLEXP (x))
7449 {
e11e83f3 7450 if (SCM_I_INUMP (y))
8507ec80 7451 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_I_INUM (y),
0aacf84e
MD
7452 SCM_COMPLEX_IMAG (x));
7453 else if (SCM_BIGP (y))
7454 {
7455 double real_part = (SCM_COMPLEX_REAL (x)
7456 - mpz_get_d (SCM_I_BIG_MPZ (y)));
7457 scm_remember_upto_here_1 (x);
8507ec80 7458 return scm_c_make_rectangular (real_part, SCM_COMPLEX_IMAG (y));
0aacf84e
MD
7459 }
7460 else if (SCM_REALP (y))
8507ec80 7461 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_REAL_VALUE (y),
0aacf84e
MD
7462 SCM_COMPLEX_IMAG (x));
7463 else if (SCM_COMPLEXP (y))
8507ec80 7464 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - SCM_COMPLEX_REAL (y),
0aacf84e 7465 SCM_COMPLEX_IMAG (x) - SCM_COMPLEX_IMAG (y));
f92e85f7 7466 else if (SCM_FRACTIONP (y))
8507ec80 7467 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) - scm_i_fraction2double (y),
f92e85f7
MV
7468 SCM_COMPLEX_IMAG (x));
7469 else
fa075d40 7470 return scm_wta_dispatch_2 (g_difference, x, y, SCM_ARGn, s_difference);
f92e85f7
MV
7471 }
7472 else if (SCM_FRACTIONP (x))
7473 {
e11e83f3 7474 if (SCM_I_INUMP (y))
f92e85f7 7475 /* a/b - c = (a - cb) / b */
cba42c93 7476 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7477 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
7478 SCM_FRACTION_DENOMINATOR (x));
7479 else if (SCM_BIGP (y))
cba42c93 7480 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7481 scm_product(y, SCM_FRACTION_DENOMINATOR (x))),
7482 SCM_FRACTION_DENOMINATOR (x));
7483 else if (SCM_REALP (y))
55f26379 7484 return scm_from_double (scm_i_fraction2double (x) - SCM_REAL_VALUE (y));
f92e85f7 7485 else if (SCM_COMPLEXP (y))
8507ec80 7486 return scm_c_make_rectangular (scm_i_fraction2double (x) - SCM_COMPLEX_REAL (y),
f92e85f7
MV
7487 -SCM_COMPLEX_IMAG (y));
7488 else if (SCM_FRACTIONP (y))
7489 /* a/b - c/d = (ad - bc) / bd */
cba42c93 7490 return scm_i_make_ratio (scm_difference (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
7491 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x))),
7492 scm_product (SCM_FRACTION_DENOMINATOR (x), SCM_FRACTION_DENOMINATOR (y)));
0aacf84e 7493 else
fa075d40 7494 return scm_wta_dispatch_2 (g_difference, x, y, SCM_ARGn, s_difference);
98cb6e75 7495 }
0aacf84e 7496 else
fa075d40 7497 return scm_wta_dispatch_2 (g_difference, x, y, SCM_ARG1, s_difference);
0f2d19dd 7498}
c05e97b7 7499#undef FUNC_NAME
0f2d19dd 7500
ca46fb90 7501
40882e3d
KR
7502SCM_DEFINE (scm_oneminus, "1-", 1, 0, 0,
7503 (SCM x),
7504 "Return @math{@var{x}-1}.")
7505#define FUNC_NAME s_scm_oneminus
7506{
cff5fa33 7507 return scm_difference (x, SCM_INUM1);
40882e3d
KR
7508}
7509#undef FUNC_NAME
7510
7511
78d3deb1
AW
7512SCM_PRIMITIVE_GENERIC (scm_i_product, "*", 0, 2, 1,
7513 (SCM x, SCM y, SCM rest),
7514 "Return the product of all arguments. If called without arguments,\n"
7515 "1 is returned.")
7516#define FUNC_NAME s_scm_i_product
7517{
7518 while (!scm_is_null (rest))
7519 { x = scm_product (x, y);
7520 y = scm_car (rest);
7521 rest = scm_cdr (rest);
7522 }
7523 return scm_product (x, y);
7524}
7525#undef FUNC_NAME
7526
7527#define s_product s_scm_i_product
7528#define g_product g_scm_i_product
7529
0f2d19dd 7530SCM
6e8d25a6 7531scm_product (SCM x, SCM y)
0f2d19dd 7532{
9cc37597 7533 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
7534 {
7535 if (SCM_UNBNDP (x))
d956fa6f 7536 return SCM_I_MAKINUM (1L);
0aacf84e
MD
7537 else if (SCM_NUMBERP (x))
7538 return x;
7539 else
fa075d40 7540 return scm_wta_dispatch_1 (g_product, x, SCM_ARG1, s_product);
f872b822 7541 }
ca46fb90 7542
9cc37597 7543 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7544 {
e25f3727 7545 scm_t_inum xx;
f4c627b3 7546
5e791807 7547 xinum:
e11e83f3 7548 xx = SCM_I_INUM (x);
f4c627b3 7549
0aacf84e
MD
7550 switch (xx)
7551 {
5e791807
MW
7552 case 1:
7553 /* exact1 is the universal multiplicative identity */
7554 return y;
7555 break;
7556 case 0:
7557 /* exact0 times a fixnum is exact0: optimize this case */
7558 if (SCM_LIKELY (SCM_I_INUMP (y)))
7559 return SCM_INUM0;
7560 /* if the other argument is inexact, the result is inexact,
7561 and we must do the multiplication in order to handle
7562 infinities and NaNs properly. */
7563 else if (SCM_REALP (y))
7564 return scm_from_double (0.0 * SCM_REAL_VALUE (y));
7565 else if (SCM_COMPLEXP (y))
7566 return scm_c_make_rectangular (0.0 * SCM_COMPLEX_REAL (y),
7567 0.0 * SCM_COMPLEX_IMAG (y));
7568 /* we've already handled inexact numbers,
7569 so y must be exact, and we return exact0 */
7570 else if (SCM_NUMP (y))
7571 return SCM_INUM0;
7572 else
fa075d40 7573 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product);
5e791807
MW
7574 break;
7575 case -1:
b5c40589 7576 /*
5e791807
MW
7577 * This case is important for more than just optimization.
7578 * It handles the case of negating
b5c40589
MW
7579 * (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
7580 * which is a bignum that must be changed back into a fixnum.
7581 * Failure to do so will cause the following to return #f:
7582 * (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
7583 */
b5c40589
MW
7584 return scm_difference(y, SCM_UNDEFINED);
7585 break;
0aacf84e 7586 }
f4c627b3 7587
9cc37597 7588 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7589 {
e25f3727
AW
7590 scm_t_inum yy = SCM_I_INUM (y);
7591 scm_t_inum kk = xx * yy;
d956fa6f 7592 SCM k = SCM_I_MAKINUM (kk);
e11e83f3 7593 if ((kk == SCM_I_INUM (k)) && (kk / xx == yy))
0aacf84e
MD
7594 return k;
7595 else
7596 {
e25f3727 7597 SCM result = scm_i_inum2big (xx);
0aacf84e
MD
7598 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result), yy);
7599 return scm_i_normbig (result);
7600 }
7601 }
7602 else if (SCM_BIGP (y))
7603 {
7604 SCM result = scm_i_mkbig ();
7605 mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx);
7606 scm_remember_upto_here_1 (y);
7607 return result;
7608 }
7609 else if (SCM_REALP (y))
55f26379 7610 return scm_from_double (xx * SCM_REAL_VALUE (y));
0aacf84e 7611 else if (SCM_COMPLEXP (y))
8507ec80 7612 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
0aacf84e 7613 xx * SCM_COMPLEX_IMAG (y));
f92e85f7 7614 else if (SCM_FRACTIONP (y))
cba42c93 7615 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 7616 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 7617 else
fa075d40 7618 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7619 }
0aacf84e
MD
7620 else if (SCM_BIGP (x))
7621 {
e11e83f3 7622 if (SCM_I_INUMP (y))
0aacf84e
MD
7623 {
7624 SCM_SWAP (x, y);
5e791807 7625 goto xinum;
0aacf84e
MD
7626 }
7627 else if (SCM_BIGP (y))
7628 {
7629 SCM result = scm_i_mkbig ();
7630 mpz_mul (SCM_I_BIG_MPZ (result),
7631 SCM_I_BIG_MPZ (x),
7632 SCM_I_BIG_MPZ (y));
7633 scm_remember_upto_here_2 (x, y);
7634 return result;
7635 }
7636 else if (SCM_REALP (y))
7637 {
7638 double result = mpz_get_d (SCM_I_BIG_MPZ (x)) * SCM_REAL_VALUE (y);
7639 scm_remember_upto_here_1 (x);
55f26379 7640 return scm_from_double (result);
0aacf84e
MD
7641 }
7642 else if (SCM_COMPLEXP (y))
7643 {
7644 double z = mpz_get_d (SCM_I_BIG_MPZ (x));
7645 scm_remember_upto_here_1 (x);
8507ec80 7646 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (y),
0aacf84e
MD
7647 z * SCM_COMPLEX_IMAG (y));
7648 }
f92e85f7 7649 else if (SCM_FRACTIONP (y))
cba42c93 7650 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_NUMERATOR (y)),
f92e85f7 7651 SCM_FRACTION_DENOMINATOR (y));
0aacf84e 7652 else
fa075d40 7653 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7654 }
0aacf84e
MD
7655 else if (SCM_REALP (x))
7656 {
e11e83f3 7657 if (SCM_I_INUMP (y))
5e791807
MW
7658 {
7659 SCM_SWAP (x, y);
7660 goto xinum;
7661 }
0aacf84e
MD
7662 else if (SCM_BIGP (y))
7663 {
7664 double result = mpz_get_d (SCM_I_BIG_MPZ (y)) * SCM_REAL_VALUE (x);
7665 scm_remember_upto_here_1 (y);
55f26379 7666 return scm_from_double (result);
0aacf84e
MD
7667 }
7668 else if (SCM_REALP (y))
55f26379 7669 return scm_from_double (SCM_REAL_VALUE (x) * SCM_REAL_VALUE (y));
0aacf84e 7670 else if (SCM_COMPLEXP (y))
8507ec80 7671 return scm_c_make_rectangular (SCM_REAL_VALUE (x) * SCM_COMPLEX_REAL (y),
0aacf84e 7672 SCM_REAL_VALUE (x) * SCM_COMPLEX_IMAG (y));
f92e85f7 7673 else if (SCM_FRACTIONP (y))
55f26379 7674 return scm_from_double (SCM_REAL_VALUE (x) * scm_i_fraction2double (y));
0aacf84e 7675 else
fa075d40 7676 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7677 }
0aacf84e
MD
7678 else if (SCM_COMPLEXP (x))
7679 {
e11e83f3 7680 if (SCM_I_INUMP (y))
5e791807
MW
7681 {
7682 SCM_SWAP (x, y);
7683 goto xinum;
7684 }
0aacf84e
MD
7685 else if (SCM_BIGP (y))
7686 {
7687 double z = mpz_get_d (SCM_I_BIG_MPZ (y));
7688 scm_remember_upto_here_1 (y);
8507ec80 7689 return scm_c_make_rectangular (z * SCM_COMPLEX_REAL (x),
76506335 7690 z * SCM_COMPLEX_IMAG (x));
0aacf84e
MD
7691 }
7692 else if (SCM_REALP (y))
8507ec80 7693 return scm_c_make_rectangular (SCM_REAL_VALUE (y) * SCM_COMPLEX_REAL (x),
0aacf84e
MD
7694 SCM_REAL_VALUE (y) * SCM_COMPLEX_IMAG (x));
7695 else if (SCM_COMPLEXP (y))
7696 {
8507ec80 7697 return scm_c_make_rectangular (SCM_COMPLEX_REAL (x) * SCM_COMPLEX_REAL (y)
0aacf84e
MD
7698 - SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_IMAG (y),
7699 SCM_COMPLEX_REAL (x) * SCM_COMPLEX_IMAG (y)
7700 + SCM_COMPLEX_IMAG (x) * SCM_COMPLEX_REAL (y));
7701 }
f92e85f7
MV
7702 else if (SCM_FRACTIONP (y))
7703 {
7704 double yy = scm_i_fraction2double (y);
8507ec80 7705 return scm_c_make_rectangular (yy * SCM_COMPLEX_REAL (x),
f92e85f7
MV
7706 yy * SCM_COMPLEX_IMAG (x));
7707 }
7708 else
fa075d40 7709 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product);
f92e85f7
MV
7710 }
7711 else if (SCM_FRACTIONP (x))
7712 {
e11e83f3 7713 if (SCM_I_INUMP (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_BIGP (y))
cba42c93 7717 return scm_i_make_ratio (scm_product (y, SCM_FRACTION_NUMERATOR (x)),
f92e85f7
MV
7718 SCM_FRACTION_DENOMINATOR (x));
7719 else if (SCM_REALP (y))
55f26379 7720 return scm_from_double (scm_i_fraction2double (x) * SCM_REAL_VALUE (y));
f92e85f7
MV
7721 else if (SCM_COMPLEXP (y))
7722 {
7723 double xx = scm_i_fraction2double (x);
8507ec80 7724 return scm_c_make_rectangular (xx * SCM_COMPLEX_REAL (y),
f92e85f7
MV
7725 xx * SCM_COMPLEX_IMAG (y));
7726 }
7727 else if (SCM_FRACTIONP (y))
7728 /* a/b * c/d = ac / bd */
cba42c93 7729 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
7730 SCM_FRACTION_NUMERATOR (y)),
7731 scm_product (SCM_FRACTION_DENOMINATOR (x),
7732 SCM_FRACTION_DENOMINATOR (y)));
0aacf84e 7733 else
fa075d40 7734 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product);
f4c627b3 7735 }
0aacf84e 7736 else
fa075d40 7737 return scm_wta_dispatch_2 (g_product, x, y, SCM_ARG1, s_product);
0f2d19dd
JB
7738}
7739
7351e207
MV
7740#if ((defined (HAVE_ISINF) && defined (HAVE_ISNAN)) \
7741 || (defined (HAVE_FINITE) && defined (HAVE_ISNAN)))
7742#define ALLOW_DIVIDE_BY_ZERO
7743/* #define ALLOW_DIVIDE_BY_EXACT_ZERO */
7744#endif
0f2d19dd 7745
ba74ef4e
MV
7746/* The code below for complex division is adapted from the GNU
7747 libstdc++, which adapted it from f2c's libF77, and is subject to
7748 this copyright: */
7749
7750/****************************************************************
7751Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
7752
7753Permission to use, copy, modify, and distribute this software
7754and its documentation for any purpose and without fee is hereby
7755granted, provided that the above copyright notice appear in all
7756copies and that both that the copyright notice and this
7757permission notice and warranty disclaimer appear in supporting
7758documentation, and that the names of AT&T Bell Laboratories or
7759Bellcore or any of their entities not be used in advertising or
7760publicity pertaining to distribution of the software without
7761specific, written prior permission.
7762
7763AT&T and Bellcore disclaim all warranties with regard to this
7764software, including all implied warranties of merchantability
7765and fitness. In no event shall AT&T or Bellcore be liable for
7766any special, indirect or consequential damages or any damages
7767whatsoever resulting from loss of use, data or profits, whether
7768in an action of contract, negligence or other tortious action,
7769arising out of or in connection with the use or performance of
7770this software.
7771****************************************************************/
7772
78d3deb1
AW
7773SCM_PRIMITIVE_GENERIC (scm_i_divide, "/", 0, 2, 1,
7774 (SCM x, SCM y, SCM rest),
7775 "Divide the first argument by the product of the remaining\n"
7776 "arguments. If called with one argument @var{z1}, 1/@var{z1} is\n"
7777 "returned.")
7778#define FUNC_NAME s_scm_i_divide
7779{
7780 while (!scm_is_null (rest))
7781 { x = scm_divide (x, y);
7782 y = scm_car (rest);
7783 rest = scm_cdr (rest);
7784 }
7785 return scm_divide (x, y);
7786}
7787#undef FUNC_NAME
7788
7789#define s_divide s_scm_i_divide
7790#define g_divide g_scm_i_divide
7791
f92e85f7 7792static SCM
78d3deb1
AW
7793do_divide (SCM x, SCM y, int inexact)
7794#define FUNC_NAME s_divide
0f2d19dd 7795{
f8de44c1
DH
7796 double a;
7797
9cc37597 7798 if (SCM_UNLIKELY (SCM_UNBNDP (y)))
0aacf84e
MD
7799 {
7800 if (SCM_UNBNDP (x))
fa075d40 7801 return scm_wta_dispatch_0 (g_divide, s_divide);
e11e83f3 7802 else if (SCM_I_INUMP (x))
0aacf84e 7803 {
e25f3727 7804 scm_t_inum xx = SCM_I_INUM (x);
0aacf84e
MD
7805 if (xx == 1 || xx == -1)
7806 return x;
7351e207 7807#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
7808 else if (xx == 0)
7809 scm_num_overflow (s_divide);
7351e207 7810#endif
0aacf84e 7811 else
f92e85f7
MV
7812 {
7813 if (inexact)
55f26379 7814 return scm_from_double (1.0 / (double) xx);
cff5fa33 7815 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 7816 }
0aacf84e
MD
7817 }
7818 else if (SCM_BIGP (x))
f92e85f7
MV
7819 {
7820 if (inexact)
55f26379 7821 return scm_from_double (1.0 / scm_i_big2dbl (x));
cff5fa33 7822 else return scm_i_make_ratio (SCM_INUM1, x);
f92e85f7 7823 }
0aacf84e
MD
7824 else if (SCM_REALP (x))
7825 {
7826 double xx = SCM_REAL_VALUE (x);
7351e207 7827#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
7828 if (xx == 0.0)
7829 scm_num_overflow (s_divide);
7830 else
7351e207 7831#endif
55f26379 7832 return scm_from_double (1.0 / xx);
0aacf84e
MD
7833 }
7834 else if (SCM_COMPLEXP (x))
7835 {
7836 double r = SCM_COMPLEX_REAL (x);
7837 double i = SCM_COMPLEX_IMAG (x);
4c6e36a6 7838 if (fabs(r) <= fabs(i))
0aacf84e
MD
7839 {
7840 double t = r / i;
7841 double d = i * (1.0 + t * t);
8507ec80 7842 return scm_c_make_rectangular (t / d, -1.0 / d);
0aacf84e
MD
7843 }
7844 else
7845 {
7846 double t = i / r;
7847 double d = r * (1.0 + t * t);
8507ec80 7848 return scm_c_make_rectangular (1.0 / d, -t / d);
0aacf84e
MD
7849 }
7850 }
f92e85f7 7851 else if (SCM_FRACTIONP (x))
cba42c93 7852 return scm_i_make_ratio (SCM_FRACTION_DENOMINATOR (x),
f92e85f7 7853 SCM_FRACTION_NUMERATOR (x));
0aacf84e 7854 else
fa075d40 7855 return scm_wta_dispatch_1 (g_divide, x, SCM_ARG1, s_divide);
f8de44c1 7856 }
f8de44c1 7857
9cc37597 7858 if (SCM_LIKELY (SCM_I_INUMP (x)))
0aacf84e 7859 {
e25f3727 7860 scm_t_inum xx = SCM_I_INUM (x);
9cc37597 7861 if (SCM_LIKELY (SCM_I_INUMP (y)))
0aacf84e 7862 {
e25f3727 7863 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
7864 if (yy == 0)
7865 {
7351e207 7866#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 7867 scm_num_overflow (s_divide);
7351e207 7868#else
55f26379 7869 return scm_from_double ((double) xx / (double) yy);
7351e207 7870#endif
0aacf84e
MD
7871 }
7872 else if (xx % yy != 0)
f92e85f7
MV
7873 {
7874 if (inexact)
55f26379 7875 return scm_from_double ((double) xx / (double) yy);
cba42c93 7876 else return scm_i_make_ratio (x, y);
f92e85f7 7877 }
0aacf84e
MD
7878 else
7879 {
e25f3727 7880 scm_t_inum z = xx / yy;
0aacf84e 7881 if (SCM_FIXABLE (z))
d956fa6f 7882 return SCM_I_MAKINUM (z);
0aacf84e 7883 else
e25f3727 7884 return scm_i_inum2big (z);
0aacf84e 7885 }
f872b822 7886 }
0aacf84e 7887 else if (SCM_BIGP (y))
f92e85f7
MV
7888 {
7889 if (inexact)
55f26379 7890 return scm_from_double ((double) xx / scm_i_big2dbl (y));
cba42c93 7891 else return scm_i_make_ratio (x, y);
f92e85f7 7892 }
0aacf84e
MD
7893 else if (SCM_REALP (y))
7894 {
7895 double yy = SCM_REAL_VALUE (y);
7351e207 7896#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
7897 if (yy == 0.0)
7898 scm_num_overflow (s_divide);
7899 else
7351e207 7900#endif
55f26379 7901 return scm_from_double ((double) xx / yy);
ba74ef4e 7902 }
0aacf84e
MD
7903 else if (SCM_COMPLEXP (y))
7904 {
7905 a = xx;
7906 complex_div: /* y _must_ be a complex number */
7907 {
7908 double r = SCM_COMPLEX_REAL (y);
7909 double i = SCM_COMPLEX_IMAG (y);
4c6e36a6 7910 if (fabs(r) <= fabs(i))
0aacf84e
MD
7911 {
7912 double t = r / i;
7913 double d = i * (1.0 + t * t);
8507ec80 7914 return scm_c_make_rectangular ((a * t) / d, -a / d);
0aacf84e
MD
7915 }
7916 else
7917 {
7918 double t = i / r;
7919 double d = r * (1.0 + t * t);
8507ec80 7920 return scm_c_make_rectangular (a / d, -(a * t) / d);
0aacf84e
MD
7921 }
7922 }
7923 }
f92e85f7
MV
7924 else if (SCM_FRACTIONP (y))
7925 /* a / b/c = ac / b */
cba42c93 7926 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 7927 SCM_FRACTION_NUMERATOR (y));
0aacf84e 7928 else
fa075d40 7929 return scm_wta_dispatch_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 7930 }
0aacf84e
MD
7931 else if (SCM_BIGP (x))
7932 {
e11e83f3 7933 if (SCM_I_INUMP (y))
0aacf84e 7934 {
e25f3727 7935 scm_t_inum yy = SCM_I_INUM (y);
0aacf84e
MD
7936 if (yy == 0)
7937 {
7351e207 7938#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e 7939 scm_num_overflow (s_divide);
7351e207 7940#else
0aacf84e
MD
7941 int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
7942 scm_remember_upto_here_1 (x);
7943 return (sgn == 0) ? scm_nan () : scm_inf ();
7351e207 7944#endif
0aacf84e
MD
7945 }
7946 else if (yy == 1)
7947 return x;
7948 else
7949 {
7950 /* FIXME: HMM, what are the relative performance issues here?
7951 We need to test. Is it faster on average to test
7952 divisible_p, then perform whichever operation, or is it
7953 faster to perform the integer div opportunistically and
7954 switch to real if there's a remainder? For now we take the
7955 middle ground: test, then if divisible, use the faster div
7956 func. */
7957
e25f3727 7958 scm_t_inum abs_yy = yy < 0 ? -yy : yy;
0aacf84e
MD
7959 int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (x), abs_yy);
7960
7961 if (divisible_p)
7962 {
7963 SCM result = scm_i_mkbig ();
7964 mpz_divexact_ui (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (x), abs_yy);
7965 scm_remember_upto_here_1 (x);
7966 if (yy < 0)
7967 mpz_neg (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (result));
7968 return scm_i_normbig (result);
7969 }
7970 else
f92e85f7
MV
7971 {
7972 if (inexact)
55f26379 7973 return scm_from_double (scm_i_big2dbl (x) / (double) yy);
cba42c93 7974 else return scm_i_make_ratio (x, y);
f92e85f7 7975 }
0aacf84e
MD
7976 }
7977 }
7978 else if (SCM_BIGP (y))
7979 {
a4955a04
MW
7980 /* big_x / big_y */
7981 if (inexact)
0aacf84e 7982 {
a4955a04
MW
7983 /* It's easily possible for the ratio x/y to fit a double
7984 but one or both x and y be too big to fit a double,
7985 hence the use of mpq_get_d rather than converting and
7986 dividing. */
7987 mpq_t q;
7988 *mpq_numref(q) = *SCM_I_BIG_MPZ (x);
7989 *mpq_denref(q) = *SCM_I_BIG_MPZ (y);
7990 return scm_from_double (mpq_get_d (q));
0aacf84e
MD
7991 }
7992 else
7993 {
a4955a04
MW
7994 int divisible_p = mpz_divisible_p (SCM_I_BIG_MPZ (x),
7995 SCM_I_BIG_MPZ (y));
7996 if (divisible_p)
7997 {
7998 SCM result = scm_i_mkbig ();
7999 mpz_divexact (SCM_I_BIG_MPZ (result),
8000 SCM_I_BIG_MPZ (x),
8001 SCM_I_BIG_MPZ (y));
8002 scm_remember_upto_here_2 (x, y);
8003 return scm_i_normbig (result);
8004 }
8005 else
8006 return scm_i_make_ratio (x, y);
0aacf84e
MD
8007 }
8008 }
8009 else if (SCM_REALP (y))
8010 {
8011 double yy = SCM_REAL_VALUE (y);
7351e207 8012#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8013 if (yy == 0.0)
8014 scm_num_overflow (s_divide);
8015 else
7351e207 8016#endif
55f26379 8017 return scm_from_double (scm_i_big2dbl (x) / yy);
0aacf84e
MD
8018 }
8019 else if (SCM_COMPLEXP (y))
8020 {
8021 a = scm_i_big2dbl (x);
8022 goto complex_div;
8023 }
f92e85f7 8024 else if (SCM_FRACTIONP (y))
cba42c93 8025 return scm_i_make_ratio (scm_product (x, SCM_FRACTION_DENOMINATOR (y)),
f92e85f7 8026 SCM_FRACTION_NUMERATOR (y));
0aacf84e 8027 else
fa075d40 8028 return scm_wta_dispatch_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 8029 }
0aacf84e
MD
8030 else if (SCM_REALP (x))
8031 {
8032 double rx = SCM_REAL_VALUE (x);
e11e83f3 8033 if (SCM_I_INUMP (y))
0aacf84e 8034 {
e25f3727 8035 scm_t_inum yy = SCM_I_INUM (y);
7351e207 8036#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
8037 if (yy == 0)
8038 scm_num_overflow (s_divide);
8039 else
7351e207 8040#endif
55f26379 8041 return scm_from_double (rx / (double) yy);
0aacf84e
MD
8042 }
8043 else if (SCM_BIGP (y))
8044 {
8045 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
8046 scm_remember_upto_here_1 (y);
55f26379 8047 return scm_from_double (rx / dby);
0aacf84e
MD
8048 }
8049 else if (SCM_REALP (y))
8050 {
8051 double yy = SCM_REAL_VALUE (y);
7351e207 8052#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8053 if (yy == 0.0)
8054 scm_num_overflow (s_divide);
8055 else
7351e207 8056#endif
55f26379 8057 return scm_from_double (rx / yy);
0aacf84e
MD
8058 }
8059 else if (SCM_COMPLEXP (y))
8060 {
8061 a = rx;
8062 goto complex_div;
8063 }
f92e85f7 8064 else if (SCM_FRACTIONP (y))
55f26379 8065 return scm_from_double (rx / scm_i_fraction2double (y));
0aacf84e 8066 else
fa075d40 8067 return scm_wta_dispatch_2 (g_divide, x, y, SCM_ARGn, s_divide);
f872b822 8068 }
0aacf84e
MD
8069 else if (SCM_COMPLEXP (x))
8070 {
8071 double rx = SCM_COMPLEX_REAL (x);
8072 double ix = SCM_COMPLEX_IMAG (x);
e11e83f3 8073 if (SCM_I_INUMP (y))
0aacf84e 8074 {
e25f3727 8075 scm_t_inum yy = SCM_I_INUM (y);
7351e207 8076#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
0aacf84e
MD
8077 if (yy == 0)
8078 scm_num_overflow (s_divide);
8079 else
7351e207 8080#endif
0aacf84e
MD
8081 {
8082 double d = yy;
8507ec80 8083 return scm_c_make_rectangular (rx / d, ix / d);
0aacf84e
MD
8084 }
8085 }
8086 else if (SCM_BIGP (y))
8087 {
8088 double dby = mpz_get_d (SCM_I_BIG_MPZ (y));
8089 scm_remember_upto_here_1 (y);
8507ec80 8090 return scm_c_make_rectangular (rx / dby, ix / dby);
0aacf84e
MD
8091 }
8092 else if (SCM_REALP (y))
8093 {
8094 double yy = SCM_REAL_VALUE (y);
7351e207 8095#ifndef ALLOW_DIVIDE_BY_ZERO
0aacf84e
MD
8096 if (yy == 0.0)
8097 scm_num_overflow (s_divide);
8098 else
7351e207 8099#endif
8507ec80 8100 return scm_c_make_rectangular (rx / yy, ix / yy);
0aacf84e
MD
8101 }
8102 else if (SCM_COMPLEXP (y))
8103 {
8104 double ry = SCM_COMPLEX_REAL (y);
8105 double iy = SCM_COMPLEX_IMAG (y);
4c6e36a6 8106 if (fabs(ry) <= fabs(iy))
0aacf84e
MD
8107 {
8108 double t = ry / iy;
8109 double d = iy * (1.0 + t * t);
8507ec80 8110 return scm_c_make_rectangular ((rx * t + ix) / d, (ix * t - rx) / d);
0aacf84e
MD
8111 }
8112 else
8113 {
8114 double t = iy / ry;
8115 double d = ry * (1.0 + t * t);
8507ec80 8116 return scm_c_make_rectangular ((rx + ix * t) / d, (ix - rx * t) / d);
0aacf84e
MD
8117 }
8118 }
f92e85f7
MV
8119 else if (SCM_FRACTIONP (y))
8120 {
8121 double yy = scm_i_fraction2double (y);
8507ec80 8122 return scm_c_make_rectangular (rx / yy, ix / yy);
f92e85f7 8123 }
0aacf84e 8124 else
fa075d40 8125 return scm_wta_dispatch_2 (g_divide, x, y, SCM_ARGn, s_divide);
f8de44c1 8126 }
f92e85f7
MV
8127 else if (SCM_FRACTIONP (x))
8128 {
e11e83f3 8129 if (SCM_I_INUMP (y))
f92e85f7 8130 {
e25f3727 8131 scm_t_inum yy = SCM_I_INUM (y);
f92e85f7
MV
8132#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
8133 if (yy == 0)
8134 scm_num_overflow (s_divide);
8135 else
8136#endif
cba42c93 8137 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
8138 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
8139 }
8140 else if (SCM_BIGP (y))
8141 {
cba42c93 8142 return scm_i_make_ratio (SCM_FRACTION_NUMERATOR (x),
f92e85f7
MV
8143 scm_product (SCM_FRACTION_DENOMINATOR (x), y));
8144 }
8145 else if (SCM_REALP (y))
8146 {
8147 double yy = SCM_REAL_VALUE (y);
8148#ifndef ALLOW_DIVIDE_BY_ZERO
8149 if (yy == 0.0)
8150 scm_num_overflow (s_divide);
8151 else
8152#endif
55f26379 8153 return scm_from_double (scm_i_fraction2double (x) / yy);
f92e85f7
MV
8154 }
8155 else if (SCM_COMPLEXP (y))
8156 {
8157 a = scm_i_fraction2double (x);
8158 goto complex_div;
8159 }
8160 else if (SCM_FRACTIONP (y))
cba42c93 8161 return scm_i_make_ratio (scm_product (SCM_FRACTION_NUMERATOR (x), SCM_FRACTION_DENOMINATOR (y)),
f92e85f7
MV
8162 scm_product (SCM_FRACTION_NUMERATOR (y), SCM_FRACTION_DENOMINATOR (x)));
8163 else
fa075d40 8164 return scm_wta_dispatch_2 (g_divide, x, y, SCM_ARGn, s_divide);
f92e85f7 8165 }
0aacf84e 8166 else
fa075d40 8167 return scm_wta_dispatch_2 (g_divide, x, y, SCM_ARG1, s_divide);
0f2d19dd 8168}
f92e85f7
MV
8169
8170SCM
8171scm_divide (SCM x, SCM y)
8172{
78d3deb1 8173 return do_divide (x, y, 0);
f92e85f7
MV
8174}
8175
8176static SCM scm_divide2real (SCM x, SCM y)
8177{
78d3deb1 8178 return do_divide (x, y, 1);
f92e85f7 8179}
c05e97b7 8180#undef FUNC_NAME
0f2d19dd 8181
fa605590 8182
0f2d19dd 8183double
3101f40f 8184scm_c_truncate (double x)
0f2d19dd 8185{
fa605590 8186 return trunc (x);
0f2d19dd 8187}
0f2d19dd 8188
3101f40f
MV
8189/* scm_c_round is done using floor(x+0.5) to round to nearest and with
8190 half-way case (ie. when x is an integer plus 0.5) going upwards.
8191 Then half-way cases are identified and adjusted down if the
8192 round-upwards didn't give the desired even integer.
6187f48b
KR
8193
8194 "plus_half == result" identifies a half-way case. If plus_half, which is
8195 x + 0.5, is an integer then x must be an integer plus 0.5.
8196
8197 An odd "result" value is identified with result/2 != floor(result/2).
8198 This is done with plus_half, since that value is ready for use sooner in
8199 a pipelined cpu, and we're already requiring plus_half == result.
8200
8201 Note however that we need to be careful when x is big and already an
8202 integer. In that case "x+0.5" may round to an adjacent integer, causing
8203 us to return such a value, incorrectly. For instance if the hardware is
8204 in the usual default nearest-even rounding, then for x = 0x1FFFFFFFFFFFFF
8205 (ie. 53 one bits) we will have x+0.5 = 0x20000000000000 and that value
8206 returned. Or if the hardware is in round-upwards mode, then other bigger
8207 values like say x == 2^128 will see x+0.5 rounding up to the next higher
8208 representable value, 2^128+2^76 (or whatever), again incorrect.
8209
8210 These bad roundings of x+0.5 are avoided by testing at the start whether
8211 x is already an integer. If it is then clearly that's the desired result
8212 already. And if it's not then the exponent must be small enough to allow
8213 an 0.5 to be represented, and hence added without a bad rounding. */
8214
0f2d19dd 8215double
3101f40f 8216scm_c_round (double x)
0f2d19dd 8217{
6187f48b
KR
8218 double plus_half, result;
8219
8220 if (x == floor (x))
8221 return x;
8222
8223 plus_half = x + 0.5;
8224 result = floor (plus_half);
3101f40f 8225 /* Adjust so that the rounding is towards even. */
0aacf84e
MD
8226 return ((plus_half == result && plus_half / 2 != floor (plus_half / 2))
8227 ? result - 1
8228 : result);
0f2d19dd
JB
8229}
8230
8b56bcec
MW
8231SCM_PRIMITIVE_GENERIC (scm_truncate_number, "truncate", 1, 0, 0,
8232 (SCM x),
8233 "Round the number @var{x} towards zero.")
f92e85f7
MV
8234#define FUNC_NAME s_scm_truncate_number
8235{
8b56bcec
MW
8236 if (SCM_I_INUMP (x) || SCM_BIGP (x))
8237 return x;
8238 else if (SCM_REALP (x))
c251ab63 8239 return scm_from_double (trunc (SCM_REAL_VALUE (x)));
8b56bcec
MW
8240 else if (SCM_FRACTIONP (x))
8241 return scm_truncate_quotient (SCM_FRACTION_NUMERATOR (x),
8242 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8243 else
fa075d40 8244 return scm_wta_dispatch_1 (g_scm_truncate_number, x, SCM_ARG1,
8b56bcec 8245 s_scm_truncate_number);
f92e85f7
MV
8246}
8247#undef FUNC_NAME
8248
8b56bcec
MW
8249SCM_PRIMITIVE_GENERIC (scm_round_number, "round", 1, 0, 0,
8250 (SCM x),
8251 "Round the number @var{x} towards the nearest integer. "
8252 "When it is exactly halfway between two integers, "
8253 "round towards the even one.")
f92e85f7
MV
8254#define FUNC_NAME s_scm_round_number
8255{
e11e83f3 8256 if (SCM_I_INUMP (x) || SCM_BIGP (x))
bae30667
KR
8257 return x;
8258 else if (SCM_REALP (x))
3101f40f 8259 return scm_from_double (scm_c_round (SCM_REAL_VALUE (x)));
8b56bcec
MW
8260 else if (SCM_FRACTIONP (x))
8261 return scm_round_quotient (SCM_FRACTION_NUMERATOR (x),
8262 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8263 else
fa075d40
AW
8264 return scm_wta_dispatch_1 (g_scm_round_number, x, SCM_ARG1,
8265 s_scm_round_number);
f92e85f7
MV
8266}
8267#undef FUNC_NAME
8268
8269SCM_PRIMITIVE_GENERIC (scm_floor, "floor", 1, 0, 0,
8270 (SCM x),
8271 "Round the number @var{x} towards minus infinity.")
8272#define FUNC_NAME s_scm_floor
8273{
e11e83f3 8274 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
8275 return x;
8276 else if (SCM_REALP (x))
55f26379 8277 return scm_from_double (floor (SCM_REAL_VALUE (x)));
f92e85f7 8278 else if (SCM_FRACTIONP (x))
8b56bcec
MW
8279 return scm_floor_quotient (SCM_FRACTION_NUMERATOR (x),
8280 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8281 else
fa075d40 8282 return scm_wta_dispatch_1 (g_scm_floor, x, 1, s_scm_floor);
f92e85f7
MV
8283}
8284#undef FUNC_NAME
8285
8286SCM_PRIMITIVE_GENERIC (scm_ceiling, "ceiling", 1, 0, 0,
8287 (SCM x),
8288 "Round the number @var{x} towards infinity.")
8289#define FUNC_NAME s_scm_ceiling
8290{
e11e83f3 8291 if (SCM_I_INUMP (x) || SCM_BIGP (x))
f92e85f7
MV
8292 return x;
8293 else if (SCM_REALP (x))
55f26379 8294 return scm_from_double (ceil (SCM_REAL_VALUE (x)));
f92e85f7 8295 else if (SCM_FRACTIONP (x))
8b56bcec
MW
8296 return scm_ceiling_quotient (SCM_FRACTION_NUMERATOR (x),
8297 SCM_FRACTION_DENOMINATOR (x));
f92e85f7 8298 else
fa075d40 8299 return scm_wta_dispatch_1 (g_scm_ceiling, x, 1, s_scm_ceiling);
f92e85f7
MV
8300}
8301#undef FUNC_NAME
0f2d19dd 8302
2519490c
MW
8303SCM_PRIMITIVE_GENERIC (scm_expt, "expt", 2, 0, 0,
8304 (SCM x, SCM y),
8305 "Return @var{x} raised to the power of @var{y}.")
6fc4d012 8306#define FUNC_NAME s_scm_expt
0f2d19dd 8307{
01c7284a
MW
8308 if (scm_is_integer (y))
8309 {
8310 if (scm_is_true (scm_exact_p (y)))
8311 return scm_integer_expt (x, y);
8312 else
8313 {
8314 /* Here we handle the case where the exponent is an inexact
8315 integer. We make the exponent exact in order to use
8316 scm_integer_expt, and thus avoid the spurious imaginary
8317 parts that may result from round-off errors in the general
8318 e^(y log x) method below (for example when squaring a large
8319 negative number). In this case, we must return an inexact
8320 result for correctness. We also make the base inexact so
8321 that scm_integer_expt will use fast inexact arithmetic
8322 internally. Note that making the base inexact is not
8323 sufficient to guarantee an inexact result, because
8324 scm_integer_expt will return an exact 1 when the exponent
8325 is 0, even if the base is inexact. */
8326 return scm_exact_to_inexact
8327 (scm_integer_expt (scm_exact_to_inexact (x),
8328 scm_inexact_to_exact (y)));
8329 }
8330 }
6fc4d012
AW
8331 else if (scm_is_real (x) && scm_is_real (y) && scm_to_double (x) >= 0.0)
8332 {
8333 return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
8334 }
2519490c 8335 else if (scm_is_complex (x) && scm_is_complex (y))
6fc4d012 8336 return scm_exp (scm_product (scm_log (x), y));
2519490c 8337 else if (scm_is_complex (x))
fa075d40 8338 return scm_wta_dispatch_2 (g_scm_expt, x, y, SCM_ARG2, s_scm_expt);
2519490c 8339 else
fa075d40 8340 return scm_wta_dispatch_2 (g_scm_expt, x, y, SCM_ARG1, s_scm_expt);
0f2d19dd 8341}
1bbd0b84 8342#undef FUNC_NAME
0f2d19dd 8343
7f41099e
MW
8344/* sin/cos/tan/asin/acos/atan
8345 sinh/cosh/tanh/asinh/acosh/atanh
8346 Derived from "Transcen.scm", Complex trancendental functions for SCM.
8347 Written by Jerry D. Hedden, (C) FSF.
8348 See the file `COPYING' for terms applying to this program. */
8349
ad79736c
AW
8350SCM_PRIMITIVE_GENERIC (scm_sin, "sin", 1, 0, 0,
8351 (SCM z),
8352 "Compute the sine of @var{z}.")
8353#define FUNC_NAME s_scm_sin
8354{
8deddc94
MW
8355 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8356 return z; /* sin(exact0) = exact0 */
8357 else if (scm_is_real (z))
ad79736c
AW
8358 return scm_from_double (sin (scm_to_double (z)));
8359 else if (SCM_COMPLEXP (z))
8360 { double x, y;
8361 x = SCM_COMPLEX_REAL (z);
8362 y = SCM_COMPLEX_IMAG (z);
8363 return scm_c_make_rectangular (sin (x) * cosh (y),
8364 cos (x) * sinh (y));
8365 }
8366 else
fa075d40 8367 return scm_wta_dispatch_1 (g_scm_sin, z, 1, s_scm_sin);
ad79736c
AW
8368}
8369#undef FUNC_NAME
0f2d19dd 8370
ad79736c
AW
8371SCM_PRIMITIVE_GENERIC (scm_cos, "cos", 1, 0, 0,
8372 (SCM z),
8373 "Compute the cosine of @var{z}.")
8374#define FUNC_NAME s_scm_cos
8375{
8deddc94
MW
8376 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8377 return SCM_INUM1; /* cos(exact0) = exact1 */
8378 else if (scm_is_real (z))
ad79736c
AW
8379 return scm_from_double (cos (scm_to_double (z)));
8380 else if (SCM_COMPLEXP (z))
8381 { double x, y;
8382 x = SCM_COMPLEX_REAL (z);
8383 y = SCM_COMPLEX_IMAG (z);
8384 return scm_c_make_rectangular (cos (x) * cosh (y),
8385 -sin (x) * sinh (y));
8386 }
8387 else
fa075d40 8388 return scm_wta_dispatch_1 (g_scm_cos, z, 1, s_scm_cos);
ad79736c
AW
8389}
8390#undef FUNC_NAME
8391
8392SCM_PRIMITIVE_GENERIC (scm_tan, "tan", 1, 0, 0,
8393 (SCM z),
8394 "Compute the tangent of @var{z}.")
8395#define FUNC_NAME s_scm_tan
0f2d19dd 8396{
8deddc94
MW
8397 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8398 return z; /* tan(exact0) = exact0 */
8399 else if (scm_is_real (z))
ad79736c
AW
8400 return scm_from_double (tan (scm_to_double (z)));
8401 else if (SCM_COMPLEXP (z))
8402 { double x, y, w;
8403 x = 2.0 * SCM_COMPLEX_REAL (z);
8404 y = 2.0 * SCM_COMPLEX_IMAG (z);
8405 w = cos (x) + cosh (y);
8406#ifndef ALLOW_DIVIDE_BY_ZERO
8407 if (w == 0.0)
8408 scm_num_overflow (s_scm_tan);
8409#endif
8410 return scm_c_make_rectangular (sin (x) / w, sinh (y) / w);
8411 }
8412 else
fa075d40 8413 return scm_wta_dispatch_1 (g_scm_tan, z, 1, s_scm_tan);
ad79736c
AW
8414}
8415#undef FUNC_NAME
8416
8417SCM_PRIMITIVE_GENERIC (scm_sinh, "sinh", 1, 0, 0,
8418 (SCM z),
8419 "Compute the hyperbolic sine of @var{z}.")
8420#define FUNC_NAME s_scm_sinh
8421{
8deddc94
MW
8422 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8423 return z; /* sinh(exact0) = exact0 */
8424 else if (scm_is_real (z))
ad79736c
AW
8425 return scm_from_double (sinh (scm_to_double (z)));
8426 else if (SCM_COMPLEXP (z))
8427 { double x, y;
8428 x = SCM_COMPLEX_REAL (z);
8429 y = SCM_COMPLEX_IMAG (z);
8430 return scm_c_make_rectangular (sinh (x) * cos (y),
8431 cosh (x) * sin (y));
8432 }
8433 else
fa075d40 8434 return scm_wta_dispatch_1 (g_scm_sinh, z, 1, s_scm_sinh);
ad79736c
AW
8435}
8436#undef FUNC_NAME
8437
8438SCM_PRIMITIVE_GENERIC (scm_cosh, "cosh", 1, 0, 0,
8439 (SCM z),
8440 "Compute the hyperbolic cosine of @var{z}.")
8441#define FUNC_NAME s_scm_cosh
8442{
8deddc94
MW
8443 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8444 return SCM_INUM1; /* cosh(exact0) = exact1 */
8445 else if (scm_is_real (z))
ad79736c
AW
8446 return scm_from_double (cosh (scm_to_double (z)));
8447 else if (SCM_COMPLEXP (z))
8448 { double x, y;
8449 x = SCM_COMPLEX_REAL (z);
8450 y = SCM_COMPLEX_IMAG (z);
8451 return scm_c_make_rectangular (cosh (x) * cos (y),
8452 sinh (x) * sin (y));
8453 }
8454 else
fa075d40 8455 return scm_wta_dispatch_1 (g_scm_cosh, z, 1, s_scm_cosh);
ad79736c
AW
8456}
8457#undef FUNC_NAME
8458
8459SCM_PRIMITIVE_GENERIC (scm_tanh, "tanh", 1, 0, 0,
8460 (SCM z),
8461 "Compute the hyperbolic tangent of @var{z}.")
8462#define FUNC_NAME s_scm_tanh
8463{
8deddc94
MW
8464 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8465 return z; /* tanh(exact0) = exact0 */
8466 else if (scm_is_real (z))
ad79736c
AW
8467 return scm_from_double (tanh (scm_to_double (z)));
8468 else if (SCM_COMPLEXP (z))
8469 { double x, y, w;
8470 x = 2.0 * SCM_COMPLEX_REAL (z);
8471 y = 2.0 * SCM_COMPLEX_IMAG (z);
8472 w = cosh (x) + cos (y);
8473#ifndef ALLOW_DIVIDE_BY_ZERO
8474 if (w == 0.0)
8475 scm_num_overflow (s_scm_tanh);
8476#endif
8477 return scm_c_make_rectangular (sinh (x) / w, sin (y) / w);
8478 }
8479 else
fa075d40 8480 return scm_wta_dispatch_1 (g_scm_tanh, z, 1, s_scm_tanh);
ad79736c
AW
8481}
8482#undef FUNC_NAME
8483
8484SCM_PRIMITIVE_GENERIC (scm_asin, "asin", 1, 0, 0,
8485 (SCM z),
8486 "Compute the arc sine of @var{z}.")
8487#define FUNC_NAME s_scm_asin
8488{
8deddc94
MW
8489 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8490 return z; /* asin(exact0) = exact0 */
8491 else if (scm_is_real (z))
ad79736c
AW
8492 {
8493 double w = scm_to_double (z);
8494 if (w >= -1.0 && w <= 1.0)
8495 return scm_from_double (asin (w));
8496 else
8497 return scm_product (scm_c_make_rectangular (0, -1),
8498 scm_sys_asinh (scm_c_make_rectangular (0, w)));
8499 }
8500 else if (SCM_COMPLEXP (z))
8501 { double x, y;
8502 x = SCM_COMPLEX_REAL (z);
8503 y = SCM_COMPLEX_IMAG (z);
8504 return scm_product (scm_c_make_rectangular (0, -1),
8505 scm_sys_asinh (scm_c_make_rectangular (-y, x)));
8506 }
8507 else
fa075d40 8508 return scm_wta_dispatch_1 (g_scm_asin, z, 1, s_scm_asin);
ad79736c
AW
8509}
8510#undef FUNC_NAME
8511
8512SCM_PRIMITIVE_GENERIC (scm_acos, "acos", 1, 0, 0,
8513 (SCM z),
8514 "Compute the arc cosine of @var{z}.")
8515#define FUNC_NAME s_scm_acos
8516{
8deddc94
MW
8517 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
8518 return SCM_INUM0; /* acos(exact1) = exact0 */
8519 else if (scm_is_real (z))
ad79736c
AW
8520 {
8521 double w = scm_to_double (z);
8522 if (w >= -1.0 && w <= 1.0)
8523 return scm_from_double (acos (w));
8524 else
8525 return scm_sum (scm_from_double (acos (0.0)),
8526 scm_product (scm_c_make_rectangular (0, 1),
8527 scm_sys_asinh (scm_c_make_rectangular (0, w))));
8528 }
8529 else if (SCM_COMPLEXP (z))
8530 { double x, y;
8531 x = SCM_COMPLEX_REAL (z);
8532 y = SCM_COMPLEX_IMAG (z);
8533 return scm_sum (scm_from_double (acos (0.0)),
8534 scm_product (scm_c_make_rectangular (0, 1),
8535 scm_sys_asinh (scm_c_make_rectangular (-y, x))));
8536 }
8537 else
fa075d40 8538 return scm_wta_dispatch_1 (g_scm_acos, z, 1, s_scm_acos);
ad79736c
AW
8539}
8540#undef FUNC_NAME
8541
8542SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
8543 (SCM z, SCM y),
8544 "With one argument, compute the arc tangent of @var{z}.\n"
8545 "If @var{y} is present, compute the arc tangent of @var{z}/@var{y},\n"
8546 "using the sign of @var{z} and @var{y} to determine the quadrant.")
8547#define FUNC_NAME s_scm_atan
8548{
8549 if (SCM_UNBNDP (y))
8550 {
8deddc94
MW
8551 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8552 return z; /* atan(exact0) = exact0 */
8553 else if (scm_is_real (z))
ad79736c
AW
8554 return scm_from_double (atan (scm_to_double (z)));
8555 else if (SCM_COMPLEXP (z))
8556 {
8557 double v, w;
8558 v = SCM_COMPLEX_REAL (z);
8559 w = SCM_COMPLEX_IMAG (z);
8560 return scm_divide (scm_log (scm_divide (scm_c_make_rectangular (v, w - 1.0),
8561 scm_c_make_rectangular (v, w + 1.0))),
8562 scm_c_make_rectangular (0, 2));
8563 }
8564 else
fa075d40 8565 return scm_wta_dispatch_1 (g_scm_atan, z, SCM_ARG1, s_scm_atan);
ad79736c
AW
8566 }
8567 else if (scm_is_real (z))
8568 {
8569 if (scm_is_real (y))
8570 return scm_from_double (atan2 (scm_to_double (z), scm_to_double (y)));
8571 else
fa075d40 8572 return scm_wta_dispatch_2 (g_scm_atan, z, y, SCM_ARG2, s_scm_atan);
ad79736c
AW
8573 }
8574 else
fa075d40 8575 return scm_wta_dispatch_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
ad79736c
AW
8576}
8577#undef FUNC_NAME
8578
8579SCM_PRIMITIVE_GENERIC (scm_sys_asinh, "asinh", 1, 0, 0,
8580 (SCM z),
8581 "Compute the inverse hyperbolic sine of @var{z}.")
8582#define FUNC_NAME s_scm_sys_asinh
8583{
8deddc94
MW
8584 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8585 return z; /* asinh(exact0) = exact0 */
8586 else if (scm_is_real (z))
ad79736c
AW
8587 return scm_from_double (asinh (scm_to_double (z)));
8588 else if (scm_is_number (z))
8589 return scm_log (scm_sum (z,
8590 scm_sqrt (scm_sum (scm_product (z, z),
cff5fa33 8591 SCM_INUM1))));
ad79736c 8592 else
fa075d40 8593 return scm_wta_dispatch_1 (g_scm_sys_asinh, z, 1, s_scm_sys_asinh);
ad79736c
AW
8594}
8595#undef FUNC_NAME
8596
8597SCM_PRIMITIVE_GENERIC (scm_sys_acosh, "acosh", 1, 0, 0,
8598 (SCM z),
8599 "Compute the inverse hyperbolic cosine of @var{z}.")
8600#define FUNC_NAME s_scm_sys_acosh
8601{
8deddc94
MW
8602 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM1)))
8603 return SCM_INUM0; /* acosh(exact1) = exact0 */
8604 else if (scm_is_real (z) && scm_to_double (z) >= 1.0)
ad79736c
AW
8605 return scm_from_double (acosh (scm_to_double (z)));
8606 else if (scm_is_number (z))
8607 return scm_log (scm_sum (z,
8608 scm_sqrt (scm_difference (scm_product (z, z),
cff5fa33 8609 SCM_INUM1))));
ad79736c 8610 else
fa075d40 8611 return scm_wta_dispatch_1 (g_scm_sys_acosh, z, 1, s_scm_sys_acosh);
ad79736c
AW
8612}
8613#undef FUNC_NAME
8614
8615SCM_PRIMITIVE_GENERIC (scm_sys_atanh, "atanh", 1, 0, 0,
8616 (SCM z),
8617 "Compute the inverse hyperbolic tangent of @var{z}.")
8618#define FUNC_NAME s_scm_sys_atanh
8619{
8deddc94
MW
8620 if (SCM_UNLIKELY (scm_is_eq (z, SCM_INUM0)))
8621 return z; /* atanh(exact0) = exact0 */
8622 else if (scm_is_real (z) && scm_to_double (z) >= -1.0 && scm_to_double (z) <= 1.0)
ad79736c
AW
8623 return scm_from_double (atanh (scm_to_double (z)));
8624 else if (scm_is_number (z))
cff5fa33
MW
8625 return scm_divide (scm_log (scm_divide (scm_sum (SCM_INUM1, z),
8626 scm_difference (SCM_INUM1, z))),
ad79736c
AW
8627 SCM_I_MAKINUM (2));
8628 else
fa075d40 8629 return scm_wta_dispatch_1 (g_scm_sys_atanh, z, 1, s_scm_sys_atanh);
0f2d19dd 8630}
1bbd0b84 8631#undef FUNC_NAME
0f2d19dd 8632
8507ec80
MV
8633SCM
8634scm_c_make_rectangular (double re, double im)
8635{
c7218482 8636 SCM z;
03604fcf 8637
c7218482
MW
8638 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_complex),
8639 "complex"));
8640 SCM_SET_CELL_TYPE (z, scm_tc16_complex);
8641 SCM_COMPLEX_REAL (z) = re;
8642 SCM_COMPLEX_IMAG (z) = im;
8643 return z;
8507ec80 8644}
0f2d19dd 8645
a1ec6916 8646SCM_DEFINE (scm_make_rectangular, "make-rectangular", 2, 0, 0,
a2c25234
LC
8647 (SCM real_part, SCM imaginary_part),
8648 "Return a complex number constructed of the given @var{real-part} "
8649 "and @var{imaginary-part} parts.")
1bbd0b84 8650#define FUNC_NAME s_scm_make_rectangular
0f2d19dd 8651{
ad79736c
AW
8652 SCM_ASSERT_TYPE (scm_is_real (real_part), real_part,
8653 SCM_ARG1, FUNC_NAME, "real");
8654 SCM_ASSERT_TYPE (scm_is_real (imaginary_part), imaginary_part,
8655 SCM_ARG2, FUNC_NAME, "real");
c7218482
MW
8656
8657 /* Return a real if and only if the imaginary_part is an _exact_ 0 */
8658 if (scm_is_eq (imaginary_part, SCM_INUM0))
8659 return real_part;
8660 else
8661 return scm_c_make_rectangular (scm_to_double (real_part),
8662 scm_to_double (imaginary_part));
0f2d19dd 8663}
1bbd0b84 8664#undef FUNC_NAME
0f2d19dd 8665
8507ec80
MV
8666SCM
8667scm_c_make_polar (double mag, double ang)
8668{
8669 double s, c;
5e647d08
LC
8670
8671 /* The sincos(3) function is undocumented an broken on Tru64. Thus we only
8672 use it on Glibc-based systems that have it (it's a GNU extension). See
8673 http://lists.gnu.org/archive/html/guile-user/2009-04/msg00033.html for
8674 details. */
8675#if (defined HAVE_SINCOS) && (defined __GLIBC__) && (defined _GNU_SOURCE)
8507ec80
MV
8676 sincos (ang, &s, &c);
8677#else
8678 s = sin (ang);
8679 c = cos (ang);
8680#endif
9d427b2c
MW
8681
8682 /* If s and c are NaNs, this indicates that the angle is a NaN,
8683 infinite, or perhaps simply too large to determine its value
8684 mod 2*pi. However, we know something that the floating-point
8685 implementation doesn't know: We know that s and c are finite.
8686 Therefore, if the magnitude is zero, return a complex zero.
8687
8688 The reason we check for the NaNs instead of using this case
8689 whenever mag == 0.0 is because when the angle is known, we'd
8690 like to return the correct kind of non-real complex zero:
8691 +0.0+0.0i, -0.0+0.0i, -0.0-0.0i, or +0.0-0.0i, depending
8692 on which quadrant the angle is in.
8693 */
8694 if (SCM_UNLIKELY (isnan(s)) && isnan(c) && (mag == 0.0))
8695 return scm_c_make_rectangular (0.0, 0.0);
8696 else
8697 return scm_c_make_rectangular (mag * c, mag * s);
8507ec80 8698}
0f2d19dd 8699
a1ec6916 8700SCM_DEFINE (scm_make_polar, "make-polar", 2, 0, 0,
c7218482
MW
8701 (SCM mag, SCM ang),
8702 "Return the complex number @var{mag} * e^(i * @var{ang}).")
1bbd0b84 8703#define FUNC_NAME s_scm_make_polar
0f2d19dd 8704{
c7218482
MW
8705 SCM_ASSERT_TYPE (scm_is_real (mag), mag, SCM_ARG1, FUNC_NAME, "real");
8706 SCM_ASSERT_TYPE (scm_is_real (ang), ang, SCM_ARG2, FUNC_NAME, "real");
8707
8708 /* If mag is exact0, return exact0 */
8709 if (scm_is_eq (mag, SCM_INUM0))
8710 return SCM_INUM0;
8711 /* Return a real if ang is exact0 */
8712 else if (scm_is_eq (ang, SCM_INUM0))
8713 return mag;
8714 else
8715 return scm_c_make_polar (scm_to_double (mag), scm_to_double (ang));
0f2d19dd 8716}
1bbd0b84 8717#undef FUNC_NAME
0f2d19dd
JB
8718
8719
2519490c
MW
8720SCM_PRIMITIVE_GENERIC (scm_real_part, "real-part", 1, 0, 0,
8721 (SCM z),
8722 "Return the real part of the number @var{z}.")
8723#define FUNC_NAME s_scm_real_part
0f2d19dd 8724{
2519490c 8725 if (SCM_COMPLEXP (z))
55f26379 8726 return scm_from_double (SCM_COMPLEX_REAL (z));
2519490c 8727 else if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_REALP (z) || SCM_FRACTIONP (z))
2fa2d879 8728 return z;
0aacf84e 8729 else
fa075d40 8730 return scm_wta_dispatch_1 (g_scm_real_part, z, SCM_ARG1, s_scm_real_part);
0f2d19dd 8731}
2519490c 8732#undef FUNC_NAME
0f2d19dd
JB
8733
8734
2519490c
MW
8735SCM_PRIMITIVE_GENERIC (scm_imag_part, "imag-part", 1, 0, 0,
8736 (SCM z),
8737 "Return the imaginary part of the number @var{z}.")
8738#define FUNC_NAME s_scm_imag_part
0f2d19dd 8739{
2519490c
MW
8740 if (SCM_COMPLEXP (z))
8741 return scm_from_double (SCM_COMPLEX_IMAG (z));
c7218482 8742 else if (SCM_I_INUMP (z) || SCM_REALP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f92e85f7 8743 return SCM_INUM0;
0aacf84e 8744 else
fa075d40 8745 return scm_wta_dispatch_1 (g_scm_imag_part, z, SCM_ARG1, s_scm_imag_part);
0f2d19dd 8746}
2519490c 8747#undef FUNC_NAME
0f2d19dd 8748
2519490c
MW
8749SCM_PRIMITIVE_GENERIC (scm_numerator, "numerator", 1, 0, 0,
8750 (SCM z),
8751 "Return the numerator of the number @var{z}.")
8752#define FUNC_NAME s_scm_numerator
f92e85f7 8753{
2519490c 8754 if (SCM_I_INUMP (z) || SCM_BIGP (z))
f92e85f7
MV
8755 return z;
8756 else if (SCM_FRACTIONP (z))
e2bf3b19 8757 return SCM_FRACTION_NUMERATOR (z);
f92e85f7
MV
8758 else if (SCM_REALP (z))
8759 return scm_exact_to_inexact (scm_numerator (scm_inexact_to_exact (z)));
8760 else
fa075d40 8761 return scm_wta_dispatch_1 (g_scm_numerator, z, SCM_ARG1, s_scm_numerator);
f92e85f7 8762}
2519490c 8763#undef FUNC_NAME
f92e85f7
MV
8764
8765
2519490c
MW
8766SCM_PRIMITIVE_GENERIC (scm_denominator, "denominator", 1, 0, 0,
8767 (SCM z),
8768 "Return the denominator of the number @var{z}.")
8769#define FUNC_NAME s_scm_denominator
f92e85f7 8770{
2519490c 8771 if (SCM_I_INUMP (z) || SCM_BIGP (z))
cff5fa33 8772 return SCM_INUM1;
f92e85f7 8773 else if (SCM_FRACTIONP (z))
e2bf3b19 8774 return SCM_FRACTION_DENOMINATOR (z);
f92e85f7
MV
8775 else if (SCM_REALP (z))
8776 return scm_exact_to_inexact (scm_denominator (scm_inexact_to_exact (z)));
8777 else
fa075d40
AW
8778 return scm_wta_dispatch_1 (g_scm_denominator, z, SCM_ARG1,
8779 s_scm_denominator);
f92e85f7 8780}
2519490c 8781#undef FUNC_NAME
0f2d19dd 8782
2519490c
MW
8783
8784SCM_PRIMITIVE_GENERIC (scm_magnitude, "magnitude", 1, 0, 0,
8785 (SCM z),
8786 "Return the magnitude of the number @var{z}. This is the same as\n"
8787 "@code{abs} for real arguments, but also allows complex numbers.")
8788#define FUNC_NAME s_scm_magnitude
0f2d19dd 8789{
e11e83f3 8790 if (SCM_I_INUMP (z))
0aacf84e 8791 {
e25f3727 8792 scm_t_inum zz = SCM_I_INUM (z);
0aacf84e
MD
8793 if (zz >= 0)
8794 return z;
8795 else if (SCM_POSFIXABLE (-zz))
d956fa6f 8796 return SCM_I_MAKINUM (-zz);
0aacf84e 8797 else
e25f3727 8798 return scm_i_inum2big (-zz);
5986c47d 8799 }
0aacf84e
MD
8800 else if (SCM_BIGP (z))
8801 {
8802 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
8803 scm_remember_upto_here_1 (z);
8804 if (sgn < 0)
8805 return scm_i_clonebig (z, 0);
8806 else
8807 return z;
5986c47d 8808 }
0aacf84e 8809 else if (SCM_REALP (z))
55f26379 8810 return scm_from_double (fabs (SCM_REAL_VALUE (z)));
0aacf84e 8811 else if (SCM_COMPLEXP (z))
55f26379 8812 return scm_from_double (hypot (SCM_COMPLEX_REAL (z), SCM_COMPLEX_IMAG (z)));
f92e85f7
MV
8813 else if (SCM_FRACTIONP (z))
8814 {
73e4de09 8815 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
f92e85f7 8816 return z;
cba42c93 8817 return scm_i_make_ratio (scm_difference (SCM_FRACTION_NUMERATOR (z), SCM_UNDEFINED),
f92e85f7
MV
8818 SCM_FRACTION_DENOMINATOR (z));
8819 }
0aacf84e 8820 else
fa075d40
AW
8821 return scm_wta_dispatch_1 (g_scm_magnitude, z, SCM_ARG1,
8822 s_scm_magnitude);
0f2d19dd 8823}
2519490c 8824#undef FUNC_NAME
0f2d19dd
JB
8825
8826
2519490c
MW
8827SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
8828 (SCM z),
8829 "Return the angle of the complex number @var{z}.")
8830#define FUNC_NAME s_scm_angle
0f2d19dd 8831{
c8ae173e 8832 /* atan(0,-1) is pi and it'd be possible to have that as a constant like
e7efe8e7 8833 flo0 to save allocating a new flonum with scm_from_double each time.
c8ae173e
KR
8834 But if atan2 follows the floating point rounding mode, then the value
8835 is not a constant. Maybe it'd be close enough though. */
e11e83f3 8836 if (SCM_I_INUMP (z))
0aacf84e 8837 {
e11e83f3 8838 if (SCM_I_INUM (z) >= 0)
e7efe8e7 8839 return flo0;
0aacf84e 8840 else
55f26379 8841 return scm_from_double (atan2 (0.0, -1.0));
f872b822 8842 }
0aacf84e
MD
8843 else if (SCM_BIGP (z))
8844 {
8845 int sgn = mpz_sgn (SCM_I_BIG_MPZ (z));
8846 scm_remember_upto_here_1 (z);
8847 if (sgn < 0)
55f26379 8848 return scm_from_double (atan2 (0.0, -1.0));
0aacf84e 8849 else
e7efe8e7 8850 return flo0;
0f2d19dd 8851 }
0aacf84e 8852 else if (SCM_REALP (z))
c8ae173e
KR
8853 {
8854 if (SCM_REAL_VALUE (z) >= 0)
e7efe8e7 8855 return flo0;
c8ae173e 8856 else
55f26379 8857 return scm_from_double (atan2 (0.0, -1.0));
c8ae173e 8858 }
0aacf84e 8859 else if (SCM_COMPLEXP (z))
55f26379 8860 return scm_from_double (atan2 (SCM_COMPLEX_IMAG (z), SCM_COMPLEX_REAL (z)));
f92e85f7
MV
8861 else if (SCM_FRACTIONP (z))
8862 {
73e4de09 8863 if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (z))))
e7efe8e7 8864 return flo0;
55f26379 8865 else return scm_from_double (atan2 (0.0, -1.0));
f92e85f7 8866 }
0aacf84e 8867 else
fa075d40 8868 return scm_wta_dispatch_1 (g_scm_angle, z, SCM_ARG1, s_scm_angle);
0f2d19dd 8869}
2519490c 8870#undef FUNC_NAME
0f2d19dd
JB
8871
8872
2519490c
MW
8873SCM_PRIMITIVE_GENERIC (scm_exact_to_inexact, "exact->inexact", 1, 0, 0,
8874 (SCM z),
8875 "Convert the number @var{z} to its inexact representation.\n")
8876#define FUNC_NAME s_scm_exact_to_inexact
3c9a524f 8877{
e11e83f3 8878 if (SCM_I_INUMP (z))
55f26379 8879 return scm_from_double ((double) SCM_I_INUM (z));
3c9a524f 8880 else if (SCM_BIGP (z))
55f26379 8881 return scm_from_double (scm_i_big2dbl (z));
f92e85f7 8882 else if (SCM_FRACTIONP (z))
55f26379 8883 return scm_from_double (scm_i_fraction2double (z));
3c9a524f
DH
8884 else if (SCM_INEXACTP (z))
8885 return z;
8886 else
fa075d40
AW
8887 return scm_wta_dispatch_1 (g_scm_exact_to_inexact, z, 1,
8888 s_scm_exact_to_inexact);
3c9a524f 8889}
2519490c 8890#undef FUNC_NAME
3c9a524f
DH
8891
8892
2519490c
MW
8893SCM_PRIMITIVE_GENERIC (scm_inexact_to_exact, "inexact->exact", 1, 0, 0,
8894 (SCM z),
8895 "Return an exact number that is numerically closest to @var{z}.")
1bbd0b84 8896#define FUNC_NAME s_scm_inexact_to_exact
0f2d19dd 8897{
c7218482 8898 if (SCM_I_INUMP (z) || SCM_BIGP (z) || SCM_FRACTIONP (z))
f872b822 8899 return z;
c7218482 8900 else
0aacf84e 8901 {
c7218482
MW
8902 double val;
8903
8904 if (SCM_REALP (z))
8905 val = SCM_REAL_VALUE (z);
8906 else if (SCM_COMPLEXP (z) && SCM_COMPLEX_IMAG (z) == 0.0)
8907 val = SCM_COMPLEX_REAL (z);
8908 else
fa075d40
AW
8909 return scm_wta_dispatch_1 (g_scm_inexact_to_exact, z, 1,
8910 s_scm_inexact_to_exact);
c7218482
MW
8911
8912 if (!SCM_LIKELY (DOUBLE_IS_FINITE (val)))
f92e85f7 8913 SCM_OUT_OF_RANGE (1, z);
2be24db4 8914 else
f92e85f7
MV
8915 {
8916 mpq_t frac;
8917 SCM q;
8918
8919 mpq_init (frac);
c7218482 8920 mpq_set_d (frac, val);
cba42c93 8921 q = scm_i_make_ratio (scm_i_mpz2num (mpq_numref (frac)),
c7218482 8922 scm_i_mpz2num (mpq_denref (frac)));
f92e85f7 8923
cba42c93 8924 /* When scm_i_make_ratio throws, we leak the memory allocated
f92e85f7
MV
8925 for frac...
8926 */
8927 mpq_clear (frac);
8928 return q;
8929 }
c2ff8ab0 8930 }
0f2d19dd 8931}
1bbd0b84 8932#undef FUNC_NAME
0f2d19dd 8933
f92e85f7 8934SCM_DEFINE (scm_rationalize, "rationalize", 2, 0, 0,
76dae881
NJ
8935 (SCM x, SCM eps),
8936 "Returns the @emph{simplest} rational number differing\n"
8937 "from @var{x} by no more than @var{eps}.\n"
8938 "\n"
8939 "As required by @acronym{R5RS}, @code{rationalize} only returns an\n"
8940 "exact result when both its arguments are exact. Thus, you might need\n"
8941 "to use @code{inexact->exact} on the arguments.\n"
8942 "\n"
8943 "@lisp\n"
8944 "(rationalize (inexact->exact 1.2) 1/100)\n"
8945 "@result{} 6/5\n"
8946 "@end lisp")
f92e85f7
MV
8947#define FUNC_NAME s_scm_rationalize
8948{
605f6980
MW
8949 SCM_ASSERT_TYPE (scm_is_real (x), x, SCM_ARG1, FUNC_NAME, "real");
8950 SCM_ASSERT_TYPE (scm_is_real (eps), eps, SCM_ARG2, FUNC_NAME, "real");
8951 eps = scm_abs (eps);
8952 if (scm_is_false (scm_positive_p (eps)))
8953 {
8954 /* eps is either zero or a NaN */
8955 if (scm_is_true (scm_nan_p (eps)))
8956 return scm_nan ();
8957 else if (SCM_INEXACTP (eps))
8958 return scm_exact_to_inexact (x);
8959 else
8960 return x;
8961 }
8962 else if (scm_is_false (scm_finite_p (eps)))
8963 {
8964 if (scm_is_true (scm_finite_p (x)))
8965 return flo0;
8966 else
8967 return scm_nan ();
8968 }
8969 else if (scm_is_false (scm_finite_p (x))) /* checks for both inf and nan */
f92e85f7 8970 return x;
605f6980
MW
8971 else if (scm_is_false (scm_less_p (scm_floor (scm_sum (x, eps)),
8972 scm_ceiling (scm_difference (x, eps)))))
8973 {
8974 /* There's an integer within range; we want the one closest to zero */
8975 if (scm_is_false (scm_less_p (eps, scm_abs (x))))
8976 {
8977 /* zero is within range */
8978 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
8979 return flo0;
8980 else
8981 return SCM_INUM0;
8982 }
8983 else if (scm_is_true (scm_positive_p (x)))
8984 return scm_ceiling (scm_difference (x, eps));
8985 else
8986 return scm_floor (scm_sum (x, eps));
8987 }
8988 else
f92e85f7
MV
8989 {
8990 /* Use continued fractions to find closest ratio. All
8991 arithmetic is done with exact numbers.
8992 */
8993
8994 SCM ex = scm_inexact_to_exact (x);
8995 SCM int_part = scm_floor (ex);
cff5fa33
MW
8996 SCM tt = SCM_INUM1;
8997 SCM a1 = SCM_INUM0, a2 = SCM_INUM1, a = SCM_INUM0;
8998 SCM b1 = SCM_INUM1, b2 = SCM_INUM0, b = SCM_INUM0;
f92e85f7
MV
8999 SCM rx;
9000 int i = 0;
9001
f92e85f7
MV
9002 ex = scm_difference (ex, int_part); /* x = x-int_part */
9003 rx = scm_divide (ex, SCM_UNDEFINED); /* rx = 1/x */
9004
9005 /* We stop after a million iterations just to be absolutely sure
9006 that we don't go into an infinite loop. The process normally
9007 converges after less than a dozen iterations.
9008 */
9009
f92e85f7
MV
9010 while (++i < 1000000)
9011 {
9012 a = scm_sum (scm_product (a1, tt), a2); /* a = a1*tt + a2 */
9013 b = scm_sum (scm_product (b1, tt), b2); /* b = b1*tt + b2 */
73e4de09
MV
9014 if (scm_is_false (scm_zero_p (b)) && /* b != 0 */
9015 scm_is_false
f92e85f7 9016 (scm_gr_p (scm_abs (scm_difference (ex, scm_divide (a, b))),
76dae881 9017 eps))) /* abs(x-a/b) <= eps */
02164269
MV
9018 {
9019 SCM res = scm_sum (int_part, scm_divide (a, b));
605f6980 9020 if (SCM_INEXACTP (x) || SCM_INEXACTP (eps))
02164269
MV
9021 return scm_exact_to_inexact (res);
9022 else
9023 return res;
9024 }
f92e85f7
MV
9025 rx = scm_divide (scm_difference (rx, tt), /* rx = 1/(rx - tt) */
9026 SCM_UNDEFINED);
9027 tt = scm_floor (rx); /* tt = floor (rx) */
9028 a2 = a1;
9029 b2 = b1;
9030 a1 = a;
9031 b1 = b;
9032 }
9033 scm_num_overflow (s_scm_rationalize);
9034 }
f92e85f7
MV
9035}
9036#undef FUNC_NAME
9037
73e4de09
MV
9038/* conversion functions */
9039
9040int
9041scm_is_integer (SCM val)
9042{
9043 return scm_is_true (scm_integer_p (val));
9044}
9045
9046int
9047scm_is_signed_integer (SCM val, scm_t_intmax min, scm_t_intmax max)
9048{
e11e83f3 9049 if (SCM_I_INUMP (val))
73e4de09 9050 {
e11e83f3 9051 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
9052 return n >= min && n <= max;
9053 }
9054 else if (SCM_BIGP (val))
9055 {
9056 if (min >= SCM_MOST_NEGATIVE_FIXNUM && max <= SCM_MOST_POSITIVE_FIXNUM)
9057 return 0;
9058 else if (min >= LONG_MIN && max <= LONG_MAX)
d956fa6f
MV
9059 {
9060 if (mpz_fits_slong_p (SCM_I_BIG_MPZ (val)))
9061 {
9062 long n = mpz_get_si (SCM_I_BIG_MPZ (val));
9063 return n >= min && n <= max;
9064 }
9065 else
9066 return 0;
9067 }
73e4de09
MV
9068 else
9069 {
d956fa6f
MV
9070 scm_t_intmax n;
9071 size_t count;
73e4de09 9072
d956fa6f
MV
9073 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
9074 > CHAR_BIT*sizeof (scm_t_uintmax))
9075 return 0;
9076
9077 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
9078 SCM_I_BIG_MPZ (val));
73e4de09 9079
d956fa6f 9080 if (mpz_sgn (SCM_I_BIG_MPZ (val)) >= 0)
73e4de09 9081 {
d956fa6f
MV
9082 if (n < 0)
9083 return 0;
73e4de09 9084 }
73e4de09
MV
9085 else
9086 {
d956fa6f
MV
9087 n = -n;
9088 if (n >= 0)
9089 return 0;
73e4de09 9090 }
d956fa6f
MV
9091
9092 return n >= min && n <= max;
73e4de09
MV
9093 }
9094 }
73e4de09
MV
9095 else
9096 return 0;
9097}
9098
9099int
9100scm_is_unsigned_integer (SCM val, scm_t_uintmax min, scm_t_uintmax max)
9101{
e11e83f3 9102 if (SCM_I_INUMP (val))
73e4de09 9103 {
e11e83f3 9104 scm_t_signed_bits n = SCM_I_INUM (val);
73e4de09
MV
9105 return n >= 0 && ((scm_t_uintmax)n) >= min && ((scm_t_uintmax)n) <= max;
9106 }
9107 else if (SCM_BIGP (val))
9108 {
9109 if (max <= SCM_MOST_POSITIVE_FIXNUM)
9110 return 0;
9111 else if (max <= ULONG_MAX)
d956fa6f
MV
9112 {
9113 if (mpz_fits_ulong_p (SCM_I_BIG_MPZ (val)))
9114 {
9115 unsigned long n = mpz_get_ui (SCM_I_BIG_MPZ (val));
9116 return n >= min && n <= max;
9117 }
9118 else
9119 return 0;
9120 }
73e4de09
MV
9121 else
9122 {
d956fa6f
MV
9123 scm_t_uintmax n;
9124 size_t count;
73e4de09 9125
d956fa6f
MV
9126 if (mpz_sgn (SCM_I_BIG_MPZ (val)) < 0)
9127 return 0;
73e4de09 9128
d956fa6f
MV
9129 if (mpz_sizeinbase (SCM_I_BIG_MPZ (val), 2)
9130 > CHAR_BIT*sizeof (scm_t_uintmax))
73e4de09 9131 return 0;
d956fa6f
MV
9132
9133 mpz_export (&n, &count, 1, sizeof (scm_t_uintmax), 0, 0,
9134 SCM_I_BIG_MPZ (val));
73e4de09 9135
d956fa6f 9136 return n >= min && n <= max;
73e4de09
MV
9137 }
9138 }
73e4de09
MV
9139 else
9140 return 0;
9141}
9142
1713d319
MV
9143static void
9144scm_i_range_error (SCM bad_val, SCM min, SCM max)
9145{
9146 scm_error (scm_out_of_range_key,
9147 NULL,
9148 "Value out of range ~S to ~S: ~S",
9149 scm_list_3 (min, max, bad_val),
9150 scm_list_1 (bad_val));
9151}
9152
bfd7932e
MV
9153#define TYPE scm_t_intmax
9154#define TYPE_MIN min
9155#define TYPE_MAX max
9156#define SIZEOF_TYPE 0
9157#define SCM_TO_TYPE_PROTO(arg) scm_to_signed_integer (arg, scm_t_intmax min, scm_t_intmax max)
9158#define SCM_FROM_TYPE_PROTO(arg) scm_from_signed_integer (arg)
9159#include "libguile/conv-integer.i.c"
9160
9161#define TYPE scm_t_uintmax
9162#define TYPE_MIN min
9163#define TYPE_MAX max
9164#define SIZEOF_TYPE 0
9165#define SCM_TO_TYPE_PROTO(arg) scm_to_unsigned_integer (arg, scm_t_uintmax min, scm_t_uintmax max)
9166#define SCM_FROM_TYPE_PROTO(arg) scm_from_unsigned_integer (arg)
9167#include "libguile/conv-uinteger.i.c"
9168
9169#define TYPE scm_t_int8
9170#define TYPE_MIN SCM_T_INT8_MIN
9171#define TYPE_MAX SCM_T_INT8_MAX
9172#define SIZEOF_TYPE 1
9173#define SCM_TO_TYPE_PROTO(arg) scm_to_int8 (arg)
9174#define SCM_FROM_TYPE_PROTO(arg) scm_from_int8 (arg)
9175#include "libguile/conv-integer.i.c"
9176
9177#define TYPE scm_t_uint8
9178#define TYPE_MIN 0
9179#define TYPE_MAX SCM_T_UINT8_MAX
9180#define SIZEOF_TYPE 1
9181#define SCM_TO_TYPE_PROTO(arg) scm_to_uint8 (arg)
9182#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint8 (arg)
9183#include "libguile/conv-uinteger.i.c"
9184
9185#define TYPE scm_t_int16
9186#define TYPE_MIN SCM_T_INT16_MIN
9187#define TYPE_MAX SCM_T_INT16_MAX
9188#define SIZEOF_TYPE 2
9189#define SCM_TO_TYPE_PROTO(arg) scm_to_int16 (arg)
9190#define SCM_FROM_TYPE_PROTO(arg) scm_from_int16 (arg)
9191#include "libguile/conv-integer.i.c"
9192
9193#define TYPE scm_t_uint16
9194#define TYPE_MIN 0
9195#define TYPE_MAX SCM_T_UINT16_MAX
9196#define SIZEOF_TYPE 2
9197#define SCM_TO_TYPE_PROTO(arg) scm_to_uint16 (arg)
9198#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint16 (arg)
9199#include "libguile/conv-uinteger.i.c"
9200
9201#define TYPE scm_t_int32
9202#define TYPE_MIN SCM_T_INT32_MIN
9203#define TYPE_MAX SCM_T_INT32_MAX
9204#define SIZEOF_TYPE 4
9205#define SCM_TO_TYPE_PROTO(arg) scm_to_int32 (arg)
9206#define SCM_FROM_TYPE_PROTO(arg) scm_from_int32 (arg)
9207#include "libguile/conv-integer.i.c"
9208
9209#define TYPE scm_t_uint32
9210#define TYPE_MIN 0
9211#define TYPE_MAX SCM_T_UINT32_MAX
9212#define SIZEOF_TYPE 4
9213#define SCM_TO_TYPE_PROTO(arg) scm_to_uint32 (arg)
9214#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint32 (arg)
9215#include "libguile/conv-uinteger.i.c"
9216
904a78f1
MG
9217#define TYPE scm_t_wchar
9218#define TYPE_MIN (scm_t_int32)-1
9219#define TYPE_MAX (scm_t_int32)0x10ffff
9220#define SIZEOF_TYPE 4
9221#define SCM_TO_TYPE_PROTO(arg) scm_to_wchar (arg)
9222#define SCM_FROM_TYPE_PROTO(arg) scm_from_wchar (arg)
9223#include "libguile/conv-integer.i.c"
9224
bfd7932e
MV
9225#define TYPE scm_t_int64
9226#define TYPE_MIN SCM_T_INT64_MIN
9227#define TYPE_MAX SCM_T_INT64_MAX
9228#define SIZEOF_TYPE 8
9229#define SCM_TO_TYPE_PROTO(arg) scm_to_int64 (arg)
9230#define SCM_FROM_TYPE_PROTO(arg) scm_from_int64 (arg)
9231#include "libguile/conv-integer.i.c"
9232
9233#define TYPE scm_t_uint64
9234#define TYPE_MIN 0
9235#define TYPE_MAX SCM_T_UINT64_MAX
9236#define SIZEOF_TYPE 8
9237#define SCM_TO_TYPE_PROTO(arg) scm_to_uint64 (arg)
9238#define SCM_FROM_TYPE_PROTO(arg) scm_from_uint64 (arg)
9239#include "libguile/conv-uinteger.i.c"
73e4de09 9240
cd036260
MV
9241void
9242scm_to_mpz (SCM val, mpz_t rop)
9243{
9244 if (SCM_I_INUMP (val))
9245 mpz_set_si (rop, SCM_I_INUM (val));
9246 else if (SCM_BIGP (val))
9247 mpz_set (rop, SCM_I_BIG_MPZ (val));
9248 else
9249 scm_wrong_type_arg_msg (NULL, 0, val, "exact integer");
9250}
9251
9252SCM
9253scm_from_mpz (mpz_t val)
9254{
9255 return scm_i_mpz2num (val);
9256}
9257
73e4de09
MV
9258int
9259scm_is_real (SCM val)
9260{
9261 return scm_is_true (scm_real_p (val));
9262}
9263
55f26379
MV
9264int
9265scm_is_rational (SCM val)
9266{
9267 return scm_is_true (scm_rational_p (val));
9268}
9269
73e4de09
MV
9270double
9271scm_to_double (SCM val)
9272{
55f26379
MV
9273 if (SCM_I_INUMP (val))
9274 return SCM_I_INUM (val);
9275 else if (SCM_BIGP (val))
9276 return scm_i_big2dbl (val);
9277 else if (SCM_FRACTIONP (val))
9278 return scm_i_fraction2double (val);
9279 else if (SCM_REALP (val))
9280 return SCM_REAL_VALUE (val);
9281 else
7a1aba42 9282 scm_wrong_type_arg_msg (NULL, 0, val, "real number");
73e4de09
MV
9283}
9284
9285SCM
9286scm_from_double (double val)
9287{
978c52d1
LC
9288 SCM z;
9289
9290 z = PTR2SCM (scm_gc_malloc_pointerless (sizeof (scm_t_double), "real"));
9291
9292 SCM_SET_CELL_TYPE (z, scm_tc16_real);
55f26379 9293 SCM_REAL_VALUE (z) = val;
978c52d1 9294
55f26379 9295 return z;
73e4de09
MV
9296}
9297
8507ec80
MV
9298int
9299scm_is_complex (SCM val)
9300{
9301 return scm_is_true (scm_complex_p (val));
9302}
9303
9304double
9305scm_c_real_part (SCM z)
9306{
9307 if (SCM_COMPLEXP (z))
9308 return SCM_COMPLEX_REAL (z);
9309 else
9310 {
9311 /* Use the scm_real_part to get proper error checking and
9312 dispatching.
9313 */
9314 return scm_to_double (scm_real_part (z));
9315 }
9316}
9317
9318double
9319scm_c_imag_part (SCM z)
9320{
9321 if (SCM_COMPLEXP (z))
9322 return SCM_COMPLEX_IMAG (z);
9323 else
9324 {
9325 /* Use the scm_imag_part to get proper error checking and
9326 dispatching. The result will almost always be 0.0, but not
9327 always.
9328 */
9329 return scm_to_double (scm_imag_part (z));
9330 }
9331}
9332
9333double
9334scm_c_magnitude (SCM z)
9335{
9336 return scm_to_double (scm_magnitude (z));
9337}
9338
9339double
9340scm_c_angle (SCM z)
9341{
9342 return scm_to_double (scm_angle (z));
9343}
9344
9345int
9346scm_is_number (SCM z)
9347{
9348 return scm_is_true (scm_number_p (z));
9349}
9350
8ab3d8a0 9351
a5f6b751
MW
9352/* Returns log(x * 2^shift) */
9353static SCM
9354log_of_shifted_double (double x, long shift)
9355{
9356 double ans = log (fabs (x)) + shift * M_LN2;
9357
9358 if (x > 0.0 || double_is_non_negative_zero (x))
9359 return scm_from_double (ans);
9360 else
9361 return scm_c_make_rectangular (ans, M_PI);
9362}
9363
9364/* Returns log(n), for exact integer n of integer-length size */
9365static SCM
9366log_of_exact_integer_with_size (SCM n, long size)
9367{
9368 long shift = size - 2 * scm_dblprec[0];
9369
9370 if (shift > 0)
9371 return log_of_shifted_double
9372 (scm_to_double (scm_ash (n, scm_from_long(-shift))),
9373 shift);
9374 else
9375 return log_of_shifted_double (scm_to_double (n), 0);
9376}
9377
85bdb6ac 9378/* Returns log(n), for exact integer n */
a5f6b751
MW
9379static SCM
9380log_of_exact_integer (SCM n)
9381{
9382 return log_of_exact_integer_with_size
9383 (n, scm_to_long (scm_integer_length (n)));
9384}
9385
9386/* Returns log(n/d), for exact non-zero integers n and d */
9387static SCM
9388log_of_fraction (SCM n, SCM d)
9389{
9390 long n_size = scm_to_long (scm_integer_length (n));
9391 long d_size = scm_to_long (scm_integer_length (d));
9392
9393 if (abs (n_size - d_size) > 1)
9394 return (scm_difference (log_of_exact_integer_with_size (n, n_size),
9395 log_of_exact_integer_with_size (d, d_size)));
9396 else if (scm_is_false (scm_negative_p (n)))
9397 return scm_from_double
9398 (log1p (scm_to_double (scm_divide2real (scm_difference (n, d), d))));
9399 else
9400 return scm_c_make_rectangular
9401 (log1p (scm_to_double (scm_divide2real
9402 (scm_difference (scm_abs (n), d),
9403 d))),
9404 M_PI);
9405}
9406
9407
8ab3d8a0
KR
9408/* In the following functions we dispatch to the real-arg funcs like log()
9409 when we know the arg is real, instead of just handing everything to
9410 clog() for instance. This is in case clog() doesn't optimize for a
9411 real-only case, and because we have to test SCM_COMPLEXP anyway so may as
9412 well use it to go straight to the applicable C func. */
9413
2519490c
MW
9414SCM_PRIMITIVE_GENERIC (scm_log, "log", 1, 0, 0,
9415 (SCM z),
9416 "Return the natural logarithm of @var{z}.")
8ab3d8a0
KR
9417#define FUNC_NAME s_scm_log
9418{
9419 if (SCM_COMPLEXP (z))
9420 {
03976fee
AW
9421#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG \
9422 && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
9423 return scm_from_complex_double (clog (SCM_COMPLEX_VALUE (z)));
9424#else
9425 double re = SCM_COMPLEX_REAL (z);
9426 double im = SCM_COMPLEX_IMAG (z);
9427 return scm_c_make_rectangular (log (hypot (re, im)),
9428 atan2 (im, re));
9429#endif
9430 }
a5f6b751
MW
9431 else if (SCM_REALP (z))
9432 return log_of_shifted_double (SCM_REAL_VALUE (z), 0);
9433 else if (SCM_I_INUMP (z))
8ab3d8a0 9434 {
a5f6b751
MW
9435#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
9436 if (scm_is_eq (z, SCM_INUM0))
9437 scm_num_overflow (s_scm_log);
9438#endif
9439 return log_of_shifted_double (SCM_I_INUM (z), 0);
8ab3d8a0 9440 }
a5f6b751
MW
9441 else if (SCM_BIGP (z))
9442 return log_of_exact_integer (z);
9443 else if (SCM_FRACTIONP (z))
9444 return log_of_fraction (SCM_FRACTION_NUMERATOR (z),
9445 SCM_FRACTION_DENOMINATOR (z));
2519490c 9446 else
fa075d40 9447 return scm_wta_dispatch_1 (g_scm_log, z, 1, s_scm_log);
8ab3d8a0
KR
9448}
9449#undef FUNC_NAME
9450
9451
2519490c
MW
9452SCM_PRIMITIVE_GENERIC (scm_log10, "log10", 1, 0, 0,
9453 (SCM z),
9454 "Return the base 10 logarithm of @var{z}.")
8ab3d8a0
KR
9455#define FUNC_NAME s_scm_log10
9456{
9457 if (SCM_COMPLEXP (z))
9458 {
9459 /* Mingw has clog() but not clog10(). (Maybe it'd be worth using
9460 clog() and a multiply by M_LOG10E, rather than the fallback
9461 log10+hypot+atan2.) */
f328f862
LC
9462#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CLOG10 \
9463 && defined SCM_COMPLEX_VALUE
8ab3d8a0
KR
9464 return scm_from_complex_double (clog10 (SCM_COMPLEX_VALUE (z)));
9465#else
9466 double re = SCM_COMPLEX_REAL (z);
9467 double im = SCM_COMPLEX_IMAG (z);
9468 return scm_c_make_rectangular (log10 (hypot (re, im)),
9469 M_LOG10E * atan2 (im, re));
9470#endif
9471 }
a5f6b751 9472 else if (SCM_REALP (z) || SCM_I_INUMP (z))
8ab3d8a0 9473 {
a5f6b751
MW
9474#ifndef ALLOW_DIVIDE_BY_EXACT_ZERO
9475 if (scm_is_eq (z, SCM_INUM0))
9476 scm_num_overflow (s_scm_log10);
9477#endif
9478 {
9479 double re = scm_to_double (z);
9480 double l = log10 (fabs (re));
9481 if (re > 0.0 || double_is_non_negative_zero (re))
9482 return scm_from_double (l);
9483 else
9484 return scm_c_make_rectangular (l, M_LOG10E * M_PI);
9485 }
8ab3d8a0 9486 }
a5f6b751
MW
9487 else if (SCM_BIGP (z))
9488 return scm_product (flo_log10e, log_of_exact_integer (z));
9489 else if (SCM_FRACTIONP (z))
9490 return scm_product (flo_log10e,
9491 log_of_fraction (SCM_FRACTION_NUMERATOR (z),
9492 SCM_FRACTION_DENOMINATOR (z)));
2519490c 9493 else
fa075d40 9494 return scm_wta_dispatch_1 (g_scm_log10, z, 1, s_scm_log10);
8ab3d8a0
KR
9495}
9496#undef FUNC_NAME
9497
9498
2519490c
MW
9499SCM_PRIMITIVE_GENERIC (scm_exp, "exp", 1, 0, 0,
9500 (SCM z),
9501 "Return @math{e} to the power of @var{z}, where @math{e} is the\n"
9502 "base of natural logarithms (2.71828@dots{}).")
8ab3d8a0
KR
9503#define FUNC_NAME s_scm_exp
9504{
9505 if (SCM_COMPLEXP (z))
9506 {
03976fee
AW
9507#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_CEXP \
9508 && defined (SCM_COMPLEX_VALUE)
8ab3d8a0
KR
9509 return scm_from_complex_double (cexp (SCM_COMPLEX_VALUE (z)));
9510#else
9511 return scm_c_make_polar (exp (SCM_COMPLEX_REAL (z)),
9512 SCM_COMPLEX_IMAG (z));
9513#endif
9514 }
2519490c 9515 else if (SCM_NUMBERP (z))
8ab3d8a0
KR
9516 {
9517 /* When z is a negative bignum the conversion to double overflows,
9518 giving -infinity, but that's ok, the exp is still 0.0. */
9519 return scm_from_double (exp (scm_to_double (z)));
9520 }
2519490c 9521 else
fa075d40 9522 return scm_wta_dispatch_1 (g_scm_exp, z, 1, s_scm_exp);
8ab3d8a0
KR
9523}
9524#undef FUNC_NAME
9525
9526
882c8963
MW
9527SCM_DEFINE (scm_i_exact_integer_sqrt, "exact-integer-sqrt", 1, 0, 0,
9528 (SCM k),
9529 "Return two exact non-negative integers @var{s} and @var{r}\n"
9530 "such that @math{@var{k} = @var{s}^2 + @var{r}} and\n"
9531 "@math{@var{s}^2 <= @var{k} < (@var{s} + 1)^2}.\n"
9532 "An error is raised if @var{k} is not an exact non-negative integer.\n"
9533 "\n"
9534 "@lisp\n"
9535 "(exact-integer-sqrt 10) @result{} 3 and 1\n"
9536 "@end lisp")
9537#define FUNC_NAME s_scm_i_exact_integer_sqrt
9538{
9539 SCM s, r;
9540
9541 scm_exact_integer_sqrt (k, &s, &r);
9542 return scm_values (scm_list_2 (s, r));
9543}
9544#undef FUNC_NAME
9545
9546void
9547scm_exact_integer_sqrt (SCM k, SCM *sp, SCM *rp)
9548{
9549 if (SCM_LIKELY (SCM_I_INUMP (k)))
9550 {
9551 scm_t_inum kk = SCM_I_INUM (k);
9552 scm_t_inum uu = kk;
9553 scm_t_inum ss;
9554
9555 if (SCM_LIKELY (kk > 0))
9556 {
9557 do
9558 {
9559 ss = uu;
9560 uu = (ss + kk/ss) / 2;
9561 } while (uu < ss);
9562 *sp = SCM_I_MAKINUM (ss);
9563 *rp = SCM_I_MAKINUM (kk - ss*ss);
9564 }
9565 else if (SCM_LIKELY (kk == 0))
9566 *sp = *rp = SCM_INUM0;
9567 else
9568 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9569 "exact non-negative integer");
9570 }
9571 else if (SCM_LIKELY (SCM_BIGP (k)))
9572 {
9573 SCM s, r;
9574
9575 if (mpz_sgn (SCM_I_BIG_MPZ (k)) < 0)
9576 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9577 "exact non-negative integer");
9578 s = scm_i_mkbig ();
9579 r = scm_i_mkbig ();
9580 mpz_sqrtrem (SCM_I_BIG_MPZ (s), SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (k));
9581 scm_remember_upto_here_1 (k);
9582 *sp = scm_i_normbig (s);
9583 *rp = scm_i_normbig (r);
9584 }
9585 else
9586 scm_wrong_type_arg_msg ("exact-integer-sqrt", SCM_ARG1, k,
9587 "exact non-negative integer");
9588}
9589
9590
2519490c
MW
9591SCM_PRIMITIVE_GENERIC (scm_sqrt, "sqrt", 1, 0, 0,
9592 (SCM z),
9593 "Return the square root of @var{z}. Of the two possible roots\n"
ffb62a43 9594 "(positive and negative), the one with positive real part\n"
2519490c
MW
9595 "is returned, or if that's zero then a positive imaginary part.\n"
9596 "Thus,\n"
9597 "\n"
9598 "@example\n"
9599 "(sqrt 9.0) @result{} 3.0\n"
9600 "(sqrt -9.0) @result{} 0.0+3.0i\n"
9601 "(sqrt 1.0+1.0i) @result{} 1.09868411346781+0.455089860562227i\n"
9602 "(sqrt -1.0-1.0i) @result{} 0.455089860562227-1.09868411346781i\n"
9603 "@end example")
8ab3d8a0
KR
9604#define FUNC_NAME s_scm_sqrt
9605{
2519490c 9606 if (SCM_COMPLEXP (z))
8ab3d8a0 9607 {
f328f862
LC
9608#if defined HAVE_COMPLEX_DOUBLE && defined HAVE_USABLE_CSQRT \
9609 && defined SCM_COMPLEX_VALUE
2519490c 9610 return scm_from_complex_double (csqrt (SCM_COMPLEX_VALUE (z)));
8ab3d8a0 9611#else
2519490c
MW
9612 double re = SCM_COMPLEX_REAL (z);
9613 double im = SCM_COMPLEX_IMAG (z);
8ab3d8a0
KR
9614 return scm_c_make_polar (sqrt (hypot (re, im)),
9615 0.5 * atan2 (im, re));
9616#endif
9617 }
2519490c 9618 else if (SCM_NUMBERP (z))
8ab3d8a0 9619 {
2519490c 9620 double xx = scm_to_double (z);
8ab3d8a0
KR
9621 if (xx < 0)
9622 return scm_c_make_rectangular (0.0, sqrt (-xx));
9623 else
9624 return scm_from_double (sqrt (xx));
9625 }
2519490c 9626 else
fa075d40 9627 return scm_wta_dispatch_1 (g_scm_sqrt, z, 1, s_scm_sqrt);
8ab3d8a0
KR
9628}
9629#undef FUNC_NAME
9630
9631
9632
0f2d19dd
JB
9633void
9634scm_init_numbers ()
0f2d19dd 9635{
0b799eea
MV
9636 int i;
9637
713a4259
KR
9638 mpz_init_set_si (z_negative_one, -1);
9639
a261c0e9
DH
9640 /* It may be possible to tune the performance of some algorithms by using
9641 * the following constants to avoid the creation of bignums. Please, before
9642 * using these values, remember the two rules of program optimization:
9643 * 1st Rule: Don't do it. 2nd Rule (experts only): Don't do it yet. */
86d31dfe 9644 scm_c_define ("most-positive-fixnum",
d956fa6f 9645 SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM));
86d31dfe 9646 scm_c_define ("most-negative-fixnum",
d956fa6f 9647 SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM));
a261c0e9 9648
f3ae5d60
MD
9649 scm_add_feature ("complex");
9650 scm_add_feature ("inexact");
e7efe8e7 9651 flo0 = scm_from_double (0.0);
a5f6b751 9652 flo_log10e = scm_from_double (M_LOG10E);
0b799eea
MV
9653
9654 /* determine floating point precision */
55f26379 9655 for (i=2; i <= SCM_MAX_DBL_RADIX; ++i)
0b799eea
MV
9656 {
9657 init_dblprec(&scm_dblprec[i-2],i);
9658 init_fx_radix(fx_per_radix[i-2],i);
9659 }
f872b822 9660#ifdef DBL_DIG
0b799eea 9661 /* hard code precision for base 10 if the preprocessor tells us to... */
f39448c5 9662 scm_dblprec[10-2] = (DBL_DIG > 20) ? 20 : DBL_DIG;
0b799eea 9663#endif
1be6b49c 9664
cff5fa33 9665 exactly_one_half = scm_divide (SCM_INUM1, SCM_I_MAKINUM (2));
a0599745 9666#include "libguile/numbers.x"
0f2d19dd 9667}
89e00824
ML
9668
9669/*
9670 Local Variables:
9671 c-file-style: "gnu"
9672 End:
9673*/