diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2015-06-23 20:42:23 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2015-06-23 20:42:23 (GMT) |
commit | 99ec0939cf2a6ead9546a36c42a3224eaf050f59 (patch) | |
tree | 6b5f08c6c2eaa9bafd991c4d53eeae05638d8d07 /generic/tclStrToD.c | |
parent | 0209d2d2a896ee892e318d614994716b750404f9 (diff) | |
parent | 7cd09ac45001b00f1ea4a4e82eee8d78484c7822 (diff) | |
download | tcl-99ec0939cf2a6ead9546a36c42a3224eaf050f59.zip tcl-99ec0939cf2a6ead9546a36c42a3224eaf050f59.tar.gz tcl-99ec0939cf2a6ead9546a36c42a3224eaf050f59.tar.bz2 |
merge trunk
Diffstat (limited to 'generic/tclStrToD.c')
-rw-r--r-- | generic/tclStrToD.c | 39 |
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. |