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