* [PATCH] Miscellaneous fixes and improvements
@ 2011-02-10 21:01 Mark H Weaver
2011-02-12 11:35 ` Andy Wingo
0 siblings, 1 reply; 2+ messages in thread
From: Mark H Weaver @ 2011-02-10 21:01 UTC (permalink / raw)
To: guile-devel
[-- Attachment #1: Type: text/plain, Size: 291 bytes --]
Hello all,
Here are some miscellaneous fixes. The only non-trivial patch here is
the last one, which includes (among other things) another rework of the
testing framework for number-theoretic division operators.
More sigificant patches are on the way after this.
Best,
Mark
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Bump copyright date in REPL version string --]
[-- Type: text/x-diff, Size: 896 bytes --]
From 884d3ef84d2256fbf149dfa057a845f424ee8e62 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Thu, 10 Feb 2011 14:12:12 -0500
Subject: [PATCH] Bump copyright date in REPL version string
* module/system/repl/common.scm (*version*): Add 2011 to copyright
date range.
---
module/system/repl/common.scm | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
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
--
1.5.6.5
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: Fix mistake in comment in tags.h --]
[-- Type: text/x-diff, Size: 1353 bytes --]
From 0ac06209456175b73b565b2a94a0b097cdd4891b Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Thu, 10 Feb 2011 14:15:52 -0500
Subject: [PATCH] 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.
---
libguile/tags.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
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
--
1.5.6.5
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: Fix extensibility of 1-argument atan --]
[-- Type: text/x-diff, Size: 989 bytes --]
From 724a8e49fb46fd525b4d82ffaa71d3fd18975ff9 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Thu, 10 Feb 2011 14:24:39 -0500
Subject: [PATCH] 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.
---
libguile/numbers.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libguile/numbers.c b/libguile/numbers.c
index bd9870f..e4e5140 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -7025,7 +7025,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))
{
--
1.5.6.5
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: Add comment about handling of exactness specifiers --]
[-- Type: text/x-diff, Size: 3651 bytes --]
From 84256f94221ec31f0b8140c7da826ae5bc1494d8 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Thu, 10 Feb 2011 14:35:02 -0500
Subject: [PATCH] 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.
---
libguile/numbers.c | 35 ++++++++++++++++++++++++++++++++---
1 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/libguile/numbers.c b/libguile/numbers.c
index e4e5140..1aed0c2 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -3834,14 +3834,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 +3851,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};
--
1.5.6.5
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: Fixes and improvements to number-theoretic division operators --]
[-- Type: text/x-diff, Size: 23400 bytes --]
From 65ede1a8ea1d1ba91f892c17a35642b86f92fa26 Mon Sep 17 00:00:00 2001
From: Mark H Weaver <mhw@netris.org>
Date: Thu, 10 Feb 2011 15:40:57 -0500
Subject: [PATCH] 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.
---
libguile/numbers.c | 100 +++++++++-------
test-suite/tests/numbers.test | 261 +++++++++++++++++++++++------------------
2 files changed, 205 insertions(+), 156 deletions(-)
diff --git a/libguile/numbers.c b/libguile/numbers.c
index 1aed0c2..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
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?)))
--
1.5.6.5
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-02-12 11:35 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-10 21:01 [PATCH] Miscellaneous fixes and improvements Mark H Weaver
2011-02-12 11:35 ` Andy Wingo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).