[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] GNU Guile branch, master, updated. release_1-9-15-65-g4a
From: |
Andy Wingo |
Subject: |
[Guile-commits] GNU Guile branch, master, updated. release_1-9-15-65-g4a46bc2 |
Date: |
Sat, 12 Feb 2011 11:56:25 +0000 |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".
http://git.savannah.gnu.org/cgit/guile.git/commit/?id=4a46bc2a5f9a0d992c67e0be3eab64077b8421a6
The branch, master has been updated
via 4a46bc2a5f9a0d992c67e0be3eab64077b8421a6 (commit)
via bc3d34f58785f843f588d3ed5dc76adf45e9811e (commit)
via 18104cac0b9943d941668aa3d84f3dc65643c83e (commit)
via 1ce7279a0656fdadfdae220327a97dbf1a3291c6 (commit)
via 1a3152f7df494e7469f5d12ee9a9a10356c56004 (commit)
from e66ff09adb22a42a859956a8da89785e2dbc3b52 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 4a46bc2a5f9a0d992c67e0be3eab64077b8421a6
Author: Mark H Weaver <address@hidden>
Date: Thu Feb 10 15:40:57 2011 -0500
Fixes and improvements to number-theoretic division operators
* libguile/numbers.c (scm_euclidean_quotient, scm_euclidean_divide,
scm_centered_quotient, scm_centered_divide): Fix bug in inum/inum
case, where (quotient most-negative-fixnum -1) would not be converted
to a bignum.
(scm_euclidean_quotient): Be more anal-retentive about calling
scm_remember_upto_here_1 after mpz_sgn, (even though mpz_sgn is
documented as being implemented as a macro and certainly won't
do any allocation). It's better to be safe than sorry here.
(scm_euclidean_quotient, scm_centered_quotient): In the bignum/inum
case, check if the divisor is 1, since this will allow us to avoid
allocating a new bignum.
(scm_euclidean_divide, scm_centered_quotient, scm_centered_divide):
When computing the intermediate truncated quotient (xx / yy) and
remainder, use (xx % yy) instead of (xx - qq * yy), on the theory that
the compiler is more likely to handle this case intelligently and
maybe combine the operations.
(scm_euclidean_divide): In the bignum/inum case, we know that the
remainder will fit in an fixnum, so don't bother allocating a bignum
for it.
(scm_euclidean_quotient, scm_euclidean_remainder,
scm_euclidean_divide, scm_centered_quotient, scm_centered_remainder,
scm_centered_divide): Minor stylistic changes.
* test-suite/tests/numbers.test: Rework testing framework for
number-theoretic division operators to be more efficient and
comprehensive in its testing of code paths and problem cases.
commit bc3d34f58785f843f588d3ed5dc76adf45e9811e
Author: Mark H Weaver <address@hidden>
Date: Thu Feb 10 14:35:02 2011 -0500
Add comment about handling of exactness specifiers
* libguile/numbers.c: Add discussion on the handling of exactness
specifiers to the comment above the string-to-number conversion
functions.
commit 18104cac0b9943d941668aa3d84f3dc65643c83e
Author: Mark H Weaver <address@hidden>
Date: Thu Feb 10 14:24:39 2011 -0500
Fix extensibility of 1-argument atan
* libguile/numbers.c (scm_atan): Call SCM_WTA_DISPATCH_1 instead of
SCM_WTA_DISPATCH_2 if the second argument is unbound. Arguably,
SCM_WTA_DISPATCH_* should handle that case gracefully, but currently
it doesn't.
commit 1ce7279a0656fdadfdae220327a97dbf1a3291c6
Author: Mark H Weaver <address@hidden>
Date: Thu Feb 10 14:15:52 2011 -0500
Fix mistake in comment in tags.h
* libguile/tags.h: Fix comment in discussion of data representation.
tc3-code #0b110 indicates a small integer and #0b100 indicates a
non-integer immediate. Previously, these were reversed.
commit 1a3152f7df494e7469f5d12ee9a9a10356c56004
Author: Mark H Weaver <address@hidden>
Date: Thu Feb 10 14:12:12 2011 -0500
Bump copyright date in REPL version string
* module/system/repl/common.scm (*version*): Add 2011 to copyright
date range.
-----------------------------------------------------------------------
Summary of changes:
libguile/numbers.c | 137 ++++++++++++++--------
libguile/tags.h | 4 +-
module/system/repl/common.scm | 2 +-
test-suite/tests/numbers.test | 261 +++++++++++++++++++++++------------------
4 files changed, 241 insertions(+), 163 deletions(-)
diff --git a/libguile/numbers.c b/libguile/numbers.c
index bd9870f..05840ef 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -1089,6 +1089,7 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_quotient,
"euclidean-quotient", 2, 0, 0,
{
if (SCM_LIKELY (SCM_I_INUMP (x)))
{
+ scm_t_inum xx = SCM_I_INUM (x);
if (SCM_LIKELY (SCM_I_INUMP (y)))
{
scm_t_inum yy = SCM_I_INUM (y);
@@ -1096,7 +1097,6 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_quotient,
"euclidean-quotient", 2, 0, 0,
scm_num_overflow (s_scm_euclidean_quotient);
else
{
- scm_t_inum xx = SCM_I_INUM (x);
scm_t_inum qq = xx / yy;
if (xx < qq * yy)
{
@@ -1105,19 +1105,25 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_quotient,
"euclidean-quotient", 2, 0, 0,
else
qq++;
}
- return SCM_I_MAKINUM (qq);
+ if (SCM_LIKELY (SCM_FIXABLE (qq)))
+ return SCM_I_MAKINUM (qq);
+ else
+ return scm_i_inum2big (qq);
}
}
else if (SCM_BIGP (y))
{
- if (SCM_I_INUM (x) >= 0)
+ if (xx >= 0)
return SCM_INUM0;
else
- return SCM_I_MAKINUM (- mpz_sgn (SCM_I_BIG_MPZ (y)));
+ {
+ scm_t_inum qq = - mpz_sgn (SCM_I_BIG_MPZ (y));
+ scm_remember_upto_here_1 (y);
+ return SCM_I_MAKINUM (qq);
+ }
}
else if (SCM_REALP (y))
- return scm_i_inexact_euclidean_quotient
- (SCM_I_INUM (x), SCM_REAL_VALUE (y));
+ return scm_i_inexact_euclidean_quotient (xx, SCM_REAL_VALUE (y));
else if (SCM_FRACTIONP (y))
return scm_i_slow_exact_euclidean_quotient (x, y);
else
@@ -1131,6 +1137,8 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_quotient,
"euclidean-quotient", 2, 0, 0,
scm_t_inum yy = SCM_I_INUM (y);
if (SCM_UNLIKELY (yy == 0))
scm_num_overflow (s_scm_euclidean_quotient);
+ else if (SCM_UNLIKELY (yy == 1))
+ return x;
else
{
SCM q = scm_i_mkbig ();
@@ -1246,6 +1254,7 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_remainder,
"euclidean-remainder", 2, 0, 0,
{
if (SCM_LIKELY (SCM_I_INUMP (x)))
{
+ scm_t_inum xx = SCM_I_INUM (x);
if (SCM_LIKELY (SCM_I_INUMP (y)))
{
scm_t_inum yy = SCM_I_INUM (y);
@@ -1253,7 +1262,7 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_remainder,
"euclidean-remainder", 2, 0, 0,
scm_num_overflow (s_scm_euclidean_remainder);
else
{
- scm_t_inum rr = SCM_I_INUM (x) % yy;
+ scm_t_inum rr = xx % yy;
if (rr >= 0)
return SCM_I_MAKINUM (rr);
else if (yy > 0)
@@ -1264,7 +1273,6 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_remainder,
"euclidean-remainder", 2, 0, 0,
}
else if (SCM_BIGP (y))
{
- scm_t_inum xx = SCM_I_INUM (x);
if (xx >= 0)
return x;
else if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
@@ -1284,8 +1292,7 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_remainder,
"euclidean-remainder", 2, 0, 0,
}
}
else if (SCM_REALP (y))
- return scm_i_inexact_euclidean_remainder
- (SCM_I_INUM (x), SCM_REAL_VALUE (y));
+ return scm_i_inexact_euclidean_remainder (xx, SCM_REAL_VALUE (y));
else if (SCM_FRACTIONP (y))
return scm_i_slow_exact_euclidean_remainder (x, y);
else
@@ -1420,6 +1427,7 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_divide,
"euclidean/", 2, 0, 0,
{
if (SCM_LIKELY (SCM_I_INUMP (x)))
{
+ scm_t_inum xx = SCM_I_INUM (x);
if (SCM_LIKELY (SCM_I_INUMP (y)))
{
scm_t_inum yy = SCM_I_INUM (y);
@@ -1427,9 +1435,10 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_divide,
"euclidean/", 2, 0, 0,
scm_num_overflow (s_scm_euclidean_divide);
else
{
- scm_t_inum xx = SCM_I_INUM (x);
scm_t_inum qq = xx / yy;
- scm_t_inum rr = xx - qq * yy;
+ scm_t_inum rr = xx % yy;
+ SCM q;
+
if (rr < 0)
{
if (yy > 0)
@@ -1437,13 +1446,15 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_divide,
"euclidean/", 2, 0, 0,
else
{ rr -= yy; qq++; }
}
- return scm_values (scm_list_2 (SCM_I_MAKINUM (qq),
- SCM_I_MAKINUM (rr)));
+ if (SCM_LIKELY (SCM_FIXABLE (qq)))
+ q = SCM_I_MAKINUM (qq);
+ else
+ q = scm_i_inum2big (qq);
+ return scm_values (scm_list_2 (q, SCM_I_MAKINUM (rr)));
}
}
else if (SCM_BIGP (y))
{
- scm_t_inum xx = SCM_I_INUM (x);
if (xx >= 0)
return scm_values (scm_list_2 (SCM_INUM0, x));
else if (mpz_sgn (SCM_I_BIG_MPZ (y)) > 0)
@@ -1464,8 +1475,7 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_divide,
"euclidean/", 2, 0, 0,
}
}
else if (SCM_REALP (y))
- return scm_i_inexact_euclidean_divide
- (SCM_I_INUM (x), SCM_REAL_VALUE (y));
+ return scm_i_inexact_euclidean_divide (xx, SCM_REAL_VALUE (y));
else if (SCM_FRACTIONP (y))
return scm_i_slow_exact_euclidean_divide (x, y);
else
@@ -1482,19 +1492,19 @@ SCM_PRIMITIVE_GENERIC (scm_euclidean_divide,
"euclidean/", 2, 0, 0,
else
{
SCM q = scm_i_mkbig ();
- SCM r = scm_i_mkbig ();
+ scm_t_inum rr;
if (yy > 0)
- mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
- SCM_I_BIG_MPZ (x), yy);
+ rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
+ SCM_I_BIG_MPZ (x), yy);
else
{
- mpz_fdiv_qr_ui (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (r),
- SCM_I_BIG_MPZ (x), -yy);
+ rr = mpz_fdiv_q_ui (SCM_I_BIG_MPZ (q),
+ SCM_I_BIG_MPZ (x), -yy);
mpz_neg (SCM_I_BIG_MPZ (q), SCM_I_BIG_MPZ (q));
}
scm_remember_upto_here_1 (x);
return scm_values (scm_list_2 (scm_i_normbig (q),
- scm_i_normbig (r)));
+ SCM_I_MAKINUM (rr)));
}
}
else if (SCM_BIGP (y))
@@ -1607,6 +1617,7 @@ SCM_PRIMITIVE_GENERIC (scm_centered_quotient,
"centered-quotient", 2, 0, 0,
{
if (SCM_LIKELY (SCM_I_INUMP (x)))
{
+ scm_t_inum xx = SCM_I_INUM (x);
if (SCM_LIKELY (SCM_I_INUMP (y)))
{
scm_t_inum yy = SCM_I_INUM (y);
@@ -1614,9 +1625,8 @@ SCM_PRIMITIVE_GENERIC (scm_centered_quotient,
"centered-quotient", 2, 0, 0,
scm_num_overflow (s_scm_centered_quotient);
else
{
- scm_t_inum xx = SCM_I_INUM (x);
scm_t_inum qq = xx / yy;
- scm_t_inum rr = xx - qq * yy;
+ scm_t_inum rr = xx % yy;
if (SCM_LIKELY (xx > 0))
{
if (SCM_LIKELY (yy > 0))
@@ -1643,19 +1653,20 @@ SCM_PRIMITIVE_GENERIC (scm_centered_quotient,
"centered-quotient", 2, 0, 0,
qq++;
}
}
- return SCM_I_MAKINUM (qq);
+ if (SCM_LIKELY (SCM_FIXABLE (qq)))
+ return SCM_I_MAKINUM (qq);
+ else
+ return scm_i_inum2big (qq);
}
}
else if (SCM_BIGP (y))
{
/* Pass a denormalized bignum version of x (even though it
can fit in a fixnum) to scm_i_bigint_centered_quotient */
- return scm_i_bigint_centered_quotient
- (scm_i_long2big (SCM_I_INUM (x)), y);
+ return scm_i_bigint_centered_quotient (scm_i_long2big (xx), y);
}
else if (SCM_REALP (y))
- return scm_i_inexact_centered_quotient
- (SCM_I_INUM (x), SCM_REAL_VALUE (y));
+ return scm_i_inexact_centered_quotient (xx, SCM_REAL_VALUE (y));
else if (SCM_FRACTIONP (y))
return scm_i_slow_exact_centered_quotient (x, y);
else
@@ -1669,6 +1680,8 @@ SCM_PRIMITIVE_GENERIC (scm_centered_quotient,
"centered-quotient", 2, 0, 0,
scm_t_inum yy = SCM_I_INUM (y);
if (SCM_UNLIKELY (yy == 0))
scm_num_overflow (s_scm_centered_quotient);
+ else if (SCM_UNLIKELY (yy == 1))
+ return x;
else
{
SCM q = scm_i_mkbig ();
@@ -1833,6 +1846,7 @@ SCM_PRIMITIVE_GENERIC (scm_centered_remainder,
"centered-remainder", 2, 0, 0,
{
if (SCM_LIKELY (SCM_I_INUMP (x)))
{
+ scm_t_inum xx = SCM_I_INUM (x);
if (SCM_LIKELY (SCM_I_INUMP (y)))
{
scm_t_inum yy = SCM_I_INUM (y);
@@ -1840,7 +1854,6 @@ SCM_PRIMITIVE_GENERIC (scm_centered_remainder,
"centered-remainder", 2, 0, 0,
scm_num_overflow (s_scm_centered_remainder);
else
{
- scm_t_inum xx = SCM_I_INUM (x);
scm_t_inum rr = xx % yy;
if (SCM_LIKELY (xx > 0))
{
@@ -1875,12 +1888,10 @@ SCM_PRIMITIVE_GENERIC (scm_centered_remainder,
"centered-remainder", 2, 0, 0,
{
/* Pass a denormalized bignum version of x (even though it
can fit in a fixnum) to scm_i_bigint_centered_remainder */
- return scm_i_bigint_centered_remainder
- (scm_i_long2big (SCM_I_INUM (x)), y);
+ return scm_i_bigint_centered_remainder (scm_i_long2big (xx), y);
}
else if (SCM_REALP (y))
- return scm_i_inexact_centered_remainder
- (SCM_I_INUM (x), SCM_REAL_VALUE (y));
+ return scm_i_inexact_centered_remainder (xx, SCM_REAL_VALUE (y));
else if (SCM_FRACTIONP (y))
return scm_i_slow_exact_centered_remainder (x, y);
else
@@ -2062,6 +2073,7 @@ SCM_PRIMITIVE_GENERIC (scm_centered_divide, "centered/",
2, 0, 0,
{
if (SCM_LIKELY (SCM_I_INUMP (x)))
{
+ scm_t_inum xx = SCM_I_INUM (x);
if (SCM_LIKELY (SCM_I_INUMP (y)))
{
scm_t_inum yy = SCM_I_INUM (y);
@@ -2069,9 +2081,10 @@ SCM_PRIMITIVE_GENERIC (scm_centered_divide, "centered/",
2, 0, 0,
scm_num_overflow (s_scm_centered_divide);
else
{
- scm_t_inum xx = SCM_I_INUM (x);
scm_t_inum qq = xx / yy;
- scm_t_inum rr = xx - qq * yy;
+ scm_t_inum rr = xx % yy;
+ SCM q;
+
if (SCM_LIKELY (xx > 0))
{
if (SCM_LIKELY (yy > 0))
@@ -2098,20 +2111,21 @@ SCM_PRIMITIVE_GENERIC (scm_centered_divide,
"centered/", 2, 0, 0,
{ qq++; rr -= yy; }
}
}
- return scm_values (scm_list_2 (SCM_I_MAKINUM (qq),
- SCM_I_MAKINUM (rr)));
+ if (SCM_LIKELY (SCM_FIXABLE (qq)))
+ q = SCM_I_MAKINUM (qq);
+ else
+ q = scm_i_inum2big (qq);
+ return scm_values (scm_list_2 (q, SCM_I_MAKINUM (rr)));
}
}
else if (SCM_BIGP (y))
{
/* Pass a denormalized bignum version of x (even though it
can fit in a fixnum) to scm_i_bigint_centered_divide */
- return scm_i_bigint_centered_divide
- (scm_i_long2big (SCM_I_INUM (x)), y);
+ return scm_i_bigint_centered_divide (scm_i_long2big (xx), y);
}
else if (SCM_REALP (y))
- return scm_i_inexact_centered_divide
- (SCM_I_INUM (x), SCM_REAL_VALUE (y));
+ return scm_i_inexact_centered_divide (xx, SCM_REAL_VALUE (y));
else if (SCM_FRACTIONP (y))
return scm_i_slow_exact_centered_divide (x, y);
else
@@ -3834,14 +3848,15 @@ scm_bigprint (SCM exp, SCM port, scm_print_state
*pstate SCM_UNUSED)
* in R5RS. Thus, the functions resemble syntactic units (<ureal R>,
* <uinteger R>, ...) that are used to build up numbers in the grammar. Some
* points should be noted about the implementation:
+ *
* * Each function keeps a local index variable 'idx' that points at the
* current position within the parsed string. The global index is only
* updated if the function could parse the corresponding syntactic unit
* successfully.
+ *
* * Similarly, the functions keep track of indicators of inexactness ('#',
- * '.' or exponents) using local variables ('hash_seen', 'x'). Again, the
- * global exactness information is only updated after each part has been
- * successfully parsed.
+ * '.' or exponents) using local variables ('hash_seen', 'x').
+ *
* * Sequences of digits are parsed into temporary variables holding fixnums.
* Only if these fixnums would overflow, the result variables are updated
* using the standard functions scm_add, scm_product, scm_divide etc. Then,
@@ -3850,6 +3865,34 @@ scm_bigprint (SCM exp, SCM port, scm_print_state *pstate
SCM_UNUSED)
* digits, a number 1234567890 would be parsed in two parts 12345 and 67890,
* and the result was computed as 12345 * 100000 + 67890. In other words,
* only every five digits two bignum operations were performed.
+ *
+ * Notes on the handling of exactness specifiers:
+ *
+ * When parsing non-real complex numbers, we apply exactness specifiers on
+ * per-component basis, as is done in PLT Scheme. For complex numbers
+ * written in rectangular form, exactness specifiers are applied to the
+ * real and imaginary parts before calling scm_make_rectangular. For
+ * complex numbers written in polar form, exactness specifiers are applied
+ * to the magnitude and angle before calling scm_make_polar.
+ *
+ * There are two kinds of exactness specifiers: forced and implicit. A
+ * forced exactness specifier is a "#e" or "#i" prefix at the beginning of
+ * the entire number, and applies to both components of a complex number.
+ * "#e" causes each component to be made exact, and "#i" causes each
+ * component to be made inexact. If no forced exactness specifier is
+ * present, then the exactness of each component is determined
+ * independently by the presence or absence of a decimal point or hash mark
+ * within that component. If a decimal point or hash mark is present, the
+ * component is made inexact, otherwise it is made exact.
+ *
+ * After the exactness specifiers have been applied to each component, they
+ * are passed to either scm_make_rectangular or scm_make_polar to produce
+ * the final result. Note that this will result in a real number if the
+ * imaginary part, magnitude, or angle is an exact 0.
+ *
+ * For example, (string->number "#i5.0+0i") does the equivalent of:
+ *
+ * (make-rectangular (exact->inexact 5) (exact->inexact 0))
*/
enum t_exactness {NO_EXACTNESS, INEXACT, EXACT};
@@ -7025,7 +7068,7 @@ SCM_PRIMITIVE_GENERIC (scm_atan, "atan", 1, 1, 0,
scm_c_make_rectangular (0, 2));
}
else
- SCM_WTA_DISPATCH_2 (g_scm_atan, z, y, SCM_ARG1, s_scm_atan);
+ SCM_WTA_DISPATCH_1 (g_scm_atan, z, SCM_ARG1, s_scm_atan);
}
else if (scm_is_real (z))
{
diff --git a/libguile/tags.h b/libguile/tags.h
index 9e0e305..39d2eaa 100644
--- a/libguile/tags.h
+++ b/libguile/tags.h
@@ -258,8 +258,8 @@ typedef scm_t_uintptr scm_t_bits;
*
* If the cell holds a scheme pair, then we already know that the first
* scm_t_bits variable of the cell will hold a scheme object with one of the
- * following tc3-codes: #b000 (non-immediate), #b010 (small integer), #b100
- * (small integer), #b110 (non-integer immediate). All these tc3-codes have
+ * following tc3-codes: #b000 (non-immediate), #b010 (small integer), #b110
+ * (small integer), #b100 (non-integer immediate). All these tc3-codes have
* in common, that their least significant bit is #b0. This fact is used by
* the garbage collector to identify cells that hold pairs. The remaining
* tc3-codes are assigned as follows: #b001 (class instance or, more
diff --git a/module/system/repl/common.scm b/module/system/repl/common.scm
index e03bf93..5405bb8 100644
--- a/module/system/repl/common.scm
+++ b/module/system/repl/common.scm
@@ -36,7 +36,7 @@
(define *version*
(format #f "GNU Guile ~A
-Copyright (C) 1995-2010 Free Software Foundation, Inc.
+Copyright (C) 1995-2011 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 1c4630e..f738189 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -4116,6 +4116,7 @@
(pass-if "-100i swings back to 45deg down"
(eqv-loosely? +7.071-7.071i (sqrt -100.0i))))
+
;;;
;;; euclidean/
;;; euclidean-quotient
@@ -4127,130 +4128,164 @@
(with-test-prefix "Number-theoretic division"
- ;; Tests that (lo <= x < hi),
+ ;; Tests that (lo <1 x <2 hi),
;; but allowing for imprecision
;; if x is inexact.
- (define (test-within-range? lo hi x)
+ (define (test-within-range? lo <1 x <2 hi)
(if (exact? x)
- (and (<= lo x) (< x hi))
+ (and (<1 lo x) (<2 x hi))
(let ((lo (- lo test-epsilon))
(hi (+ hi test-epsilon)))
(<= lo x hi))))
- ;; (cartesian-product-map list '(a b) '(1 2))
- ;; ==> ((a 1) (a 2) (b 1) (b 2))
- (define (cartesian-product-map f . lsts)
- (define (cartmap rev-head lsts)
- (if (null? lsts)
- (list (apply f (reverse rev-head)))
- (append-map (lambda (x) (cartmap (cons x rev-head) (cdr lsts)))
- (car lsts))))
- (cartmap '() lsts))
-
- (define (cartesian-product-for-each f . lsts)
- (define (cartfor rev-head lsts)
- (if (null? lsts)
- (apply f (reverse rev-head))
- (for-each (lambda (x) (cartfor (cons x rev-head) (cdr lsts)))
- (car lsts))))
- (cartfor '() lsts))
-
- (define (safe-euclidean-quotient x y)
- (cond ((not (and (real? x) (real? y))) (throw 'wrong-type-arg))
- ((zero? y) (throw 'divide-by-zero))
- ((nan? y) (nan))
- ((positive? y) (floor (/ x y)))
- ((negative? y) (ceiling (/ x y)))
- (else (throw 'unknown-problem))))
-
- (define (safe-euclidean-remainder x y)
- (let ((q (safe-euclidean-quotient x y)))
- (- x (* y q))))
-
(define (valid-euclidean-answer? x y q r)
- (if (and (finite? x) (finite? y))
- (and (eq? (exact? q)
- (exact? r)
- (and (exact? x) (exact? y)))
- (integer? q)
- (test-eqv? r (- x (* q y)))
- (test-within-range? 0 (abs y) r))
- (and (test-eqv? q (safe-euclidean-quotient x y))
- (test-eqv? r (safe-euclidean-remainder x y)))))
-
- (define (safe-centered-quotient x y)
- (cond ((not (and (real? x) (real? y))) (throw 'wrong-type-arg))
- ((zero? y) (throw 'divide-by-zero))
- ((nan? y) (nan))
- ((positive? y) (floor (+ 1/2 (/ x y))))
- ((negative? y) (ceiling (+ -1/2 (/ x y))))
- (else (throw 'unknown-problem))))
-
- (define (safe-centered-remainder x y)
- (let ((q (safe-centered-quotient x y)))
- (- x (* y q))))
+ (and (eq? (exact? q)
+ (exact? r)
+ (and (exact? x) (exact? y)))
+ (test-eqv? r (- x (* q y)))
+ (if (and (finite? x) (finite? y))
+ (and (integer? q)
+ (test-within-range? 0 <= r < (abs y)))
+ (test-eqv? q (/ x y)))))
(define (valid-centered-answer? x y q r)
- (if (and (finite? x) (finite? y))
- (and (eq? (exact? q)
- (exact? r)
- (and (exact? x) (exact? y)))
- (integer? q)
- (test-eqv? r (- x (* q y)))
- (test-within-range? (* -1/2 (abs y))
- (* +1/2 (abs y))
- r))
- (and (test-eqv? q (safe-centered-quotient x y))
- (test-eqv? r (safe-centered-remainder x y)))))
-
- (define test-numerators
- (append (cartesian-product-map * '(1 -1)
- '(123 125 127 130 3 5 10
- 123.2 125.0 127.2 130.0
- 123/7 125/7 127/7 130/7))
- (cartesian-product-map * '(1 -1)
- '(123 125 127 130 3 5 10)
- (list 1
- (+ 1 most-positive-fixnum)
- (+ 2 most-positive-fixnum)))
- (list 0 +0.0 -0.0 +inf.0 -inf.0 +nan.0
- most-negative-fixnum
- (1+ most-positive-fixnum)
- (1- most-negative-fixnum))))
-
- (define test-denominators
- (list 10 5 10/7 127/2 10.0 63.5
- -10 -5 -10/7 -127/2 -10.0 -63.5
- +inf.0 -inf.0 +nan.0 most-negative-fixnum
- (+ 1 most-positive-fixnum) (+ -1 most-negative-fixnum)
- (+ 2 most-positive-fixnum) (+ -2 most-negative-fixnum)))
+ (and (eq? (exact? q)
+ (exact? r)
+ (and (exact? x) (exact? y)))
+ (test-eqv? r (- x (* q y)))
+ (if (and (finite? x) (finite? y))
+ (and (integer? q)
+ (test-within-range?
+ (* -1/2 (abs y)) <= r < (* +1/2 (abs y))))
+ (test-eqv? q (/ x y)))))
+
+ (define (for lsts f) (apply for-each f lsts))
+
+ (define big (expt 10 (1+ (inexact->exact (ceiling (log10 fixnum-max))))))
+
+ (define (run-division-tests quo+rem quo rem valid-answer?)
+ (define (test n d)
+ (run-test (list n d) #t
+ (lambda ()
+ (let-values (((q r) (quo+rem n d)))
+ (and (test-eqv? q (quo n d))
+ (test-eqv? r (rem n d))
+ (valid-answer? n d q r))))))
+ (define (test+/- n d)
+ (test n d )
+ (test n (- d))
+ (cond ((not (zero? n))
+ (test (- n) d )
+ (test (- n) (- d)))))
+
+ (define (test-for-exception n d exception)
+ (let ((name (list n d)))
+ (pass-if-exception name exception (quo+rem n d))
+ (pass-if-exception name exception (quo n d))
+ (pass-if-exception name exception (rem n d))))
+
+ (run-test "documented?" #t
+ (lambda ()
+ (and (documented? quo+rem)
+ (documented? quo)
+ (documented? rem))))
+
+ (with-test-prefix "inum / inum"
+ (with-test-prefix "fixnum-min / -1"
+ (test fixnum-min -1))
+ (for '((1 2 5 10)) ;; denominators
+ (lambda (d)
+ (for '((0 1 2 5 10)) ;; multiples
+ (lambda (m)
+ (for '((-2 -1 0 1 2 3 4 5 7 10
+ 12 15 16 19 20)) ;; offsets
+ (lambda (b)
+ (test+/- (+ b (* m d))
+ d))))))))
+
+ (with-test-prefix "inum / big"
+ (with-test-prefix "fixnum-min / -fixnum-min"
+ (test fixnum-min (- fixnum-min)))
+ (with-test-prefix "fixnum-max / (2*fixnum-max)"
+ (test+/- fixnum-max (* 2 fixnum-max)))
+ (for `((0 1 2 10 ,(1- fixnum-max) ,fixnum-max))
+ (lambda (n)
+ (test n (1+ fixnum-max))
+ (test (- n) (1+ fixnum-max))
+ (test n (1- fixnum-min))
+ (test (- n) (1- fixnum-min)))))
+
+ (with-test-prefix "big / inum"
+ (with-test-prefix "-fixnum-min / fixnum-min"
+ (test (- fixnum-min) fixnum-min))
+ (for '((1 4 5 10)) ;; denominators
+ (lambda (d)
+ (for `((1 2 5 ,@(if (even? d)
+ '(1/2 3/2 5/2)
+ '()))) ;; multiples
+ (lambda (m)
+ (for '((-2 -1 0 1 2)) ;; offsets
+ (lambda (b)
+ (test+/- (+ b (* m d big))
+ d))))))))
+
+ (with-test-prefix "big / big"
+ (for `((,big ,(1+ big))) ;; denominators
+ (lambda (d)
+ (for `((1 2 5 ,@(if (even? d)
+ '(1/2 3/2 5/2)
+ '()))) ;; multiples
+ (lambda (m)
+ (for '((-2 -1 0 1 2)) ;; offsets
+ (lambda (b)
+ (test+/- (+ b (* m d))
+ d))))))))
+
+ (with-test-prefix "inexact"
+ (for '((0.5 1.5 2.25 5.75)) ;; denominators
+ (lambda (d)
+ (for '((0 1 2 5 1/2 3/2 5/2)) ;; multiples
+ (lambda (m)
+ (for '((-2 -1 0 1 2)) ;; offsets
+ (lambda (b)
+ (test+/- (+ b (* m d))
+ d))))))))
+
+ (with-test-prefix "fractions"
+ (for '((1/10 16/3 10/7)) ;; denominators
+ (lambda (d)
+ (for '((0 1 2 5 1/2 3/2 5/2)) ;; multiples
+ (lambda (m)
+ (for '((-2/9 -1/11 0 1/3 2/3)) ;; offsets
+ (lambda (b)
+ (test+/- (+ b (* m d))
+ d))))))))
+
+ (with-test-prefix "mixed types"
+ (for `((10 ,big 12.0 10/7 +inf.0 -inf.0 +nan.0)) ;; denominators
+ (lambda (d)
+ (for `((25 ,(* 3/2 big) 130.0 15/7
+ 0 0.0 -0.0 +inf.0 -inf.0 +nan.0)) ;; numerators
+ (lambda (n)
+ (test+/- n d))))))
+
+ (with-test-prefix "divide by zero"
+ (for `((0 0.0 +0.0)) ;; denominators
+ (lambda (d)
+ (for `((15 ,(* 3/2 big) 18.0 33/7
+ 0 0.0 -0.0 +inf.0 -inf.0 +nan.0)) ;; numerators
+ (lambda (n)
+ (test-for-exception
+ n d exception:numerical-overflow)))))))
(with-test-prefix "euclidean/"
- (pass-if (documented? euclidean/))
- (pass-if (documented? euclidean-quotient))
- (pass-if (documented? euclidean-remainder))
-
- (cartesian-product-for-each
- (lambda (n d)
- (run-test (list 'euclidean/ n d) #t
- (lambda ()
- (let-values (((q r) (euclidean/ n d)))
- (and (test-eqv? q (euclidean-quotient n d))
- (test-eqv? r (euclidean-remainder n d))
- (valid-euclidean-answer? n d q r))))))
- test-numerators test-denominators))
+ (run-division-tests euclidean/
+ euclidean-quotient
+ euclidean-remainder
+ valid-euclidean-answer?))
(with-test-prefix "centered/"
- (pass-if (documented? centered/))
- (pass-if (documented? centered-quotient))
- (pass-if (documented? centered-remainder))
-
- (cartesian-product-for-each
- (lambda (n d)
- (run-test (list 'centered/ n d) #t
- (lambda ()
- (let-values (((q r) (centered/ n d)))
- (and (test-eqv? q (centered-quotient n d))
- (test-eqv? r (centered-remainder n d))
- (valid-centered-answer? n d q r))))))
- test-numerators test-denominators)))
+ (run-division-tests centered/
+ centered-quotient
+ centered-remainder
+ valid-centered-answer?)))
hooks/post-receive
--
GNU Guile
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Guile-commits] GNU Guile branch, master, updated. release_1-9-15-65-g4a46bc2,
Andy Wingo <=