summaryrefslogtreecommitdiffstats
path: root/generic/tclStrToD.c
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2015-06-23 20:42:23 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2015-06-23 20:42:23 (GMT)
commit99ec0939cf2a6ead9546a36c42a3224eaf050f59 (patch)
tree6b5f08c6c2eaa9bafd991c4d53eeae05638d8d07 /generic/tclStrToD.c
parent0209d2d2a896ee892e318d614994716b750404f9 (diff)
parent7cd09ac45001b00f1ea4a4e82eee8d78484c7822 (diff)
downloadtcl-99ec0939cf2a6ead9546a36c42a3224eaf050f59.zip
tcl-99ec0939cf2a6ead9546a36c42a3224eaf050f59.tar.gz
tcl-99ec0939cf2a6ead9546a36c42a3224eaf050f59.tar.bz2
merge trunk
Diffstat (limited to 'generic/tclStrToD.c')
-rw-r--r--generic/tclStrToD.c39
1 files changed, 31 insertions, 8 deletions
diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c
index 30a72ba..a18c8ef 100644
--- a/generic/tclStrToD.c
+++ b/generic/tclStrToD.c
@@ -1478,7 +1478,7 @@ MakeLowPrecisionDouble(
* Test for the easy cases.
*/
- if (numSigDigs <= DBL_DIG) {
+ if (numSigDigs <= QUICK_MAX) {
if (exponent >= 0) {
if (exponent <= mmaxpow) {
/*
@@ -1491,7 +1491,7 @@ MakeLowPrecisionDouble(
((Tcl_WideInt)significand * pow10vals[exponent]);
goto returnValue;
} else {
- int diff = DBL_DIG - numSigDigs;
+ int diff = QUICK_MAX - numSigDigs;
if (exponent-diff <= mmaxpow) {
/*
@@ -1728,6 +1728,12 @@ RefineApproximation(
double quot; /* Correction term. */
double minincr; /* Lower bound on the absolute value of the
* correction term. */
+ int roundToEven; /* Flag == TRUE if we need to invoke
+ * "round to even" functionality */
+ double rteSignificand; /* Significand of the round-to-even result */
+ int rteExponent; /* Exponent of the round-to-even result */
+ Tcl_WideInt rteSigWide; /* Wide integer version of the significand
+ * for testing evenness */
int i;
/*
@@ -1823,17 +1829,34 @@ RefineApproximation(
mp_div_2d(&twoMv, -multiplier, &twoMv, NULL);
}
- /*
- * If the result is less than unity, the error is less than 1/2 unit in
- * the last place, so there's no correction to make.
- */
-
- if (mp_cmp_mag(&twoMd, &twoMv) == MP_LT) {
+ switch (mp_cmp_mag(&twoMd, &twoMv)) {
+ case MP_LT:
+ /*
+ * If the result is less than unity, the error is less than 1/2 unit in
+ * the last place, so there's no correction to make.
+ */
mp_clear(&twoMd);
mp_clear(&twoMv);
return approxResult;
+ case MP_EQ:
+ /*
+ * If the result is exactly unity, we need to round to even.
+ */
+ roundToEven = 1;
+ break;
+ case MP_GT:
+ roundToEven = 0;
+ break;
}
+ if (roundToEven) {
+ rteSignificand = frexp(approxResult, &rteExponent);
+ rteSigWide = (Tcl_WideInt) ldexp(rteSignificand, FP_PRECISION);
+ if ((rteSigWide & 1) == 0) {
+ return approxResult;
+ }
+ }
+
/*
* Convert the numerator and denominator of the corrector term accurately
* to floating point numbers.