summaryrefslogtreecommitdiffstats
path: root/generic/tclStrToD.c
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2019-03-02 18:15:36 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2019-03-02 18:15:36 (GMT)
commit10591b96c8e649549d81f6672d42003de5450043 (patch)
treefa88e5b3da77dd983e8d37ecf1aa14cb93c9fa20 /generic/tclStrToD.c
parentc561b0e117976a55bb05357fe5b1d45bb5fdad4a (diff)
downloadtcl-10591b96c8e649549d81f6672d42003de5450043.zip
tcl-10591b96c8e649549d81f6672d42003de5450043.tar.gz
tcl-10591b96c8e649549d81f6672d42003de5450043.tar.bz2
Various tommath/numeric related optimizations:
- Remove the DD_STEEL formatter: it isn't used anywhere in Tcl, and not recommended. - Remove double limit-checks, which are already done inside mp_to_unsigned_bin_n()
Diffstat (limited to 'generic/tclStrToD.c')
-rw-r--r--generic/tclStrToD.c138
1 files changed, 45 insertions, 93 deletions
diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c
index 0770b88..ef1fcf4 100644
--- a/generic/tclStrToD.c
+++ b/generic/tclStrToD.c
@@ -320,36 +320,36 @@ static char * StrictQuickFormat(double, int, int, double,
static char * QuickConversion(double, int, int, int, int, int, int,
int *, char **);
static void CastOutPowersOf2(int *, int *, int *);
-static char * ShorteningInt64Conversion(Double *, int, Tcl_WideUInt,
+static char * ShorteningInt64Conversion(Double *, Tcl_WideUInt,
int, int, int, int, int, int, int, int, int,
int, int, int *, char **);
-static char * StrictInt64Conversion(Double *, int, Tcl_WideUInt,
+static char * StrictInt64Conversion(Double *, Tcl_WideUInt,
int, int, int, int, int, int,
int, int, int *, char **);
static int ShouldBankerRoundUpPowD(mp_int *, int, int);
static int ShouldBankerRoundUpToNextPowD(mp_int *, mp_int *,
- int, int, int, mp_int *);
+ int, int, mp_int *);
static char * ShorteningBignumConversionPowD(Double *dPtr,
- int convType, Tcl_WideUInt bw, int b2, int b5,
+ Tcl_WideUInt bw, int b2, int b5,
int m2plus, int m2minus, int m5,
int sd, int k, int len,
int ilim, int ilim1, int *decpt,
char **endPtr);
-static char * StrictBignumConversionPowD(Double *dPtr, int convType,
+static char * StrictBignumConversionPowD(Double *dPtr,
Tcl_WideUInt bw, int b2, int b5,
int sd, int k, int len,
int ilim, int ilim1, int *decpt,
char **endPtr);
static int ShouldBankerRoundUp(mp_int *, mp_int *, int);
static int ShouldBankerRoundUpToNext(mp_int *, mp_int *,
- mp_int *, int, int, mp_int *);
-static char * ShorteningBignumConversion(Double *dPtr, int convType,
+ mp_int *, int);
+static char * ShorteningBignumConversion(Double *dPtr,
Tcl_WideUInt bw, int b2,
int m2plus, int m2minus,
int s2, int s5, int k, int len,
int ilim, int ilim1, int *decpt,
char **endPtr);
-static char * StrictBignumConversion(Double *dPtr, int convType,
+static char * StrictBignumConversion(Double *dPtr,
Tcl_WideUInt bw, int b2,
int s2, int s5, int k, int len,
int ilim, int ilim1, int *decpt,
@@ -2410,9 +2410,8 @@ ComputeScale(
static inline void
SetPrecisionLimits(
- int convType, /* Type of conversion: TCL_DD_SHORTEST,
- * TCL_DD_STEELE0, TCL_DD_E_FMT,
- * TCL_DD_F_FMT. */
+ int flags, /* Type of conversion: TCL_DD_SHORTEST,
+ * TCL_DD_E_FMT, TCL_DD_F_FMT. */
int k, /* Floor(log10(number to convert)) */
int *ndigitsPtr, /* IN/OUT: Number of digits requested (will be
* adjusted if needed). */
@@ -2422,13 +2421,7 @@ SetPrecisionLimits(
int *iLim1Ptr) /* OUT: Number of digits of significance if
* the quick method is used. */
{
- switch (convType) {
- case TCL_DD_SHORTEST0:
- case TCL_DD_STEELE0:
- *iLimPtr = *iLim1Ptr = -1;
- *iPtr = 18;
- *ndigitsPtr = 0;
- break;
+ switch (flags & TCL_DD_CONVERSION_TYPE_MASK) {
case TCL_DD_E_FORMAT:
if (*ndigitsPtr <= 0) {
*ndigitsPtr = 1;
@@ -2444,10 +2437,10 @@ SetPrecisionLimits(
}
break;
default:
- *iPtr = -1;
- *iLimPtr = -1;
- *iLim1Ptr = -1;
- Tcl_Panic("impossible conversion type in TclDoubleDigits");
+ *iLimPtr = *iLim1Ptr = -1;
+ *iPtr = 18;
+ *ndigitsPtr = 0;
+ break;
}
}
@@ -2877,8 +2870,6 @@ CastOutPowersOf2(
static inline char *
ShorteningInt64Conversion(
Double *dPtr, /* Original number to convert. */
- int convType, /* Type of conversion (shortest, Steele,
- * E format, F format). */
Tcl_WideUInt bw, /* Integer significand. */
int b2, int b5, /* Scale factor for the significand in the
* numerator. */
@@ -2945,7 +2936,7 @@ ShorteningInt64Conversion(
*/
if (b < mplus || (b == mplus
- && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) {
+ && (dPtr->w.word1 & 1) == 0)) {
/*
* Make sure we shouldn't be rounding *up* instead, in case the
* next number above is closer.
@@ -2974,7 +2965,7 @@ ShorteningInt64Conversion(
*/
if (b > S - mminus || (b == S - mminus
- && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) {
+ && (dPtr->w.word1 & 1) == 0)) {
if (digit == 9) {
*s++ = '9';
s = BumpUp(s, retval, &k);
@@ -3046,8 +3037,6 @@ ShorteningInt64Conversion(
static inline char *
StrictInt64Conversion(
Double *dPtr, /* Original number to convert. */
- int convType, /* Type of conversion (shortest, Steele,
- * E format, F format). */
Tcl_WideUInt bw, /* Integer significand. */
int b2, int b5, /* Scale factor for the significand in the
* numerator. */
@@ -3156,7 +3145,7 @@ ShouldBankerRoundUpPowD(
int isodd) /* 1 if the digit is odd, 0 if even. */
{
int i;
- static const mp_digit topbit = 1 << (DIGIT_BIT - 1);
+ static const mp_digit topbit = ((mp_digit)1) << (DIGIT_BIT - 1);
if (b->used < sd || (b->dp[sd-1] & topbit) == 0) {
return 0;
@@ -3192,9 +3181,6 @@ ShouldBankerRoundUpToNextPowD(
mp_int *b, /* Numerator of the fraction. */
mp_int *m, /* Numerator of the rounding tolerance. */
int sd, /* Common denominator is 2**(sd*DIGIT_BIT). */
- int convType, /* Conversion type: STEELE defeats
- * round-to-even (not sure why one wants to do
- * this; I copied it from Gay). FIXME */
int isodd, /* 1 if the integer significand is odd. */
mp_int *temp) /* Work area for the calculation. */
{
@@ -3220,10 +3206,6 @@ ShouldBankerRoundUpToNextPowD(
return 1;
}
}
- if (convType == TCL_DD_STEELE0) {
- /* Biased rounding. */
- return 0;
- }
return isodd;
}
@@ -3253,8 +3235,6 @@ ShouldBankerRoundUpToNextPowD(
static inline char *
ShorteningBignumConversionPowD(
Double *dPtr, /* Original number to convert. */
- int convType, /* Type of conversion (shortest, Steele,
- * E format, F format). */
Tcl_WideUInt bw, /* Integer significand. */
int b2, int b5, /* Scale factor for the significand in the
* numerator. */
@@ -3340,7 +3320,7 @@ ShorteningBignumConversionPowD(
r1 = mp_cmp_mag(&b, (m2plus > m2minus)? &mplus : &mminus);
if (r1 == MP_LT || (r1 == MP_EQ
- && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) {
+ && (dPtr->w.word1 & 1) == 0)) {
/*
* Make sure we shouldn't be rounding *up* instead, in case the
* next number above is closer.
@@ -3368,7 +3348,7 @@ ShorteningBignumConversionPowD(
* number?
*/
- if (ShouldBankerRoundUpToNextPowD(&b, &mminus, sd, convType,
+ if (ShouldBankerRoundUpToNextPowD(&b, &mminus, sd,
dPtr->w.word1 & 1, &temp)) {
if (digit == 9) {
*s++ = '9';
@@ -3446,8 +3426,6 @@ ShorteningBignumConversionPowD(
static inline char *
StrictBignumConversionPowD(
Double *dPtr, /* Original number to convert. */
- int convType, /* Type of conversion (shortest, Steele,
- * E format, F format). */
Tcl_WideUInt bw, /* Integer significand. */
int b2, int b5, /* Scale factor for the significand in the
* numerator. */
@@ -3468,7 +3446,6 @@ StrictBignumConversionPowD(
mp_digit digit; /* Current output digit. */
char *s = retval; /* Cursor in the output buffer. */
int i; /* Index in the output buffer. */
- mp_int temp;
/*
* b = bw * 2**b2 * 5**b5
@@ -3487,7 +3464,6 @@ StrictBignumConversionPowD(
ilim = ilim1;
--k;
}
- mp_init(&temp);
/*
* Loop through the digits. Do division and mod by s == 2**(sd*DIGIT_BIT)
@@ -3536,7 +3512,7 @@ StrictBignumConversionPowD(
* string.
*/
- mp_clear_multi(&b, &temp, NULL);
+ mp_clear(&b);
*s = '\0';
*decpt = k;
if (endPtr) {
@@ -3600,29 +3576,24 @@ ShouldBankerRoundUpToNext(
* the last digit. */
mp_int *m, /* Numerator of the rounding tolerance. */
mp_int *S, /* Denominator. */
- int convType, /* Conversion type: STEELE0 defeats
- * round-to-even. (Not sure why one would want
- * this; I coped it from Gay). FIXME */
- int isodd, /* 1 if the integer significand is odd. */
- mp_int *temp) /* Work area needed for the calculation. */
+ int isodd) /* 1 if the integer significand is odd. */
{
int r;
+ mp_int temp;
/*
* Compare b and S-m: this is the same as comparing B+m and S.
*/
- mp_add(b, m, temp);
- r = mp_cmp_mag(temp, S);
+ mp_init(&temp);
+ mp_add(b, m, &temp);
+ r = mp_cmp_mag(&temp, S);
+ mp_clear(&temp);
switch(r) {
case MP_LT:
return 0;
case MP_EQ:
- if (convType == TCL_DD_STEELE0) {
- return 0;
- } else {
- return isodd;
- }
+ return isodd;
case MP_GT:
return 1;
}
@@ -3651,7 +3622,6 @@ ShouldBankerRoundUpToNext(
static inline char *
ShorteningBignumConversion(
Double *dPtr, /* Original number being converted. */
- int convType, /* Conversion type. */
Tcl_WideUInt bw, /* Integer significand and exponent. */
int b2, /* Scale factor for the significand. */
int m2plus, int m2minus, /* Scale factors for 1/2 ulp in numerator. */
@@ -3672,7 +3642,6 @@ ShorteningBignumConversion(
mp_int S; /* Denominator of the result. */
mp_int dig; /* Current digit of the result. */
int digit; /* Current digit of the result. */
- mp_int temp; /* Work area. */
int minit = 1; /* Fudge factor for when we misguess k. */
int i;
int r1;
@@ -3708,7 +3677,6 @@ ShorteningBignumConversion(
mp_init_copy(&mplus, &mminus);
mp_mul_2d(&mplus, m2plus-m2minus, &mplus);
}
- mp_init(&temp);
/*
* Loop through the digits.
@@ -3729,8 +3697,7 @@ ShorteningBignumConversion(
*/
r1 = mp_cmp_mag(&b, (m2plus > m2minus)? &mplus : &mminus);
- if (r1 == MP_LT || (r1 == MP_EQ
- && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) {
+ if (r1 == MP_LT || (r1 == MP_EQ && (dPtr->w.word1 & 1) == 0)) {
mp_mul_2d(&b, 1, &b);
if (ShouldBankerRoundUp(&b, &S, digit&1)) {
++digit;
@@ -3749,8 +3716,8 @@ ShorteningBignumConversion(
* commit to rounding up to the next higher digit?
*/
- if (ShouldBankerRoundUpToNext(&b, &mminus, &S, convType,
- dPtr->w.word1 & 1, &temp)) {
+ if (ShouldBankerRoundUpToNext(&b, &mminus, &S,
+ dPtr->w.word1 & 1)) {
++digit;
if (digit == 10) {
*s++ = '9';
@@ -3837,7 +3804,7 @@ ShorteningBignumConversion(
if (m2plus > m2minus) {
mp_clear(&mplus);
}
- mp_clear_multi(&b, &mminus, &temp, &dig, &S, NULL);
+ mp_clear_multi(&b, &mminus, &dig, &S, NULL);
*s = '\0';
*decpt = k;
if (endPtr) {
@@ -3867,7 +3834,6 @@ ShorteningBignumConversion(
static inline char *
StrictBignumConversion(
Double *dPtr, /* Original number being converted. */
- int convType, /* Conversion type. */
Tcl_WideUInt bw, /* Integer significand and exponent. */
int b2, /* Scale factor for the significand. */
int s2, int s5, /* Scale factors for denominator. */
@@ -3885,7 +3851,6 @@ StrictBignumConversion(
mp_int S; /* Denominator of the result. */
mp_int dig; /* Current digit of the result. */
int digit; /* Current digit of the result. */
- mp_int temp; /* Work area. */
int g; /* Size of the current digit ground. */
int i, j;
@@ -3894,7 +3859,7 @@ StrictBignumConversion(
* S = 2**s2 * 5*s5
*/
- mp_init_multi(&temp, &dig, NULL);
+ mp_init_multi(&dig, NULL);
TclInitBignumFromWideUInt(&b, bw);
mp_mul_2d(&b, b2, &b);
mp_init_set_int(&S, 1);
@@ -4001,7 +3966,7 @@ StrictBignumConversion(
* string.
*/
- mp_clear_multi(&b, &S, &temp, &dig, NULL);
+ mp_clear_multi(&b, &S, &dig, NULL);
*s = '\0';
*decpt = k;
if (endPtr) {
@@ -4037,15 +4002,6 @@ StrictBignumConversion(
* For floating point numbers that are exactly between two
* decimal numbers, it resolves using the 'round to even' rule.
* With this value, the 'ndigits' parameter is ignored.
- * TCL_DD_STEELE - This value is not recommended and may be removed in
- * the future. It follows the conversion algorithm outlined in
- * "How to Print Floating-Point Numbers Accurately" by Guy
- * L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90,
- * pp. 112-126]. This rule has the effect of rendering 1e23 as
- * 9.9999999999999999e22 - which is a 'better' approximation in
- * the sense that it will reconvert correctly even if a
- * subsequent input conversion is 'round up' or 'round down'
- * rather than 'round to nearest', but is surprising otherwise.
* TCL_DD_E_FORMAT - This value is used to prepare numbers for %e format
* conversion (or for default floating->string if tcl_precision
* is not 0). It constructs a string of at most 'ndigits' digits,
@@ -4096,10 +4052,6 @@ TclDoubleDigits(
* one character beyond the end of the
* returned string. */
{
- int convType = (flags & TCL_DD_CONVERSION_TYPE_MASK);
- /* Type of conversion being performed:
- * TCL_DD_SHORTEST0, TCL_DD_STEELE0,
- * TCL_DD_E_FORMAT, or TCL_DD_F_FORMAT. */
Double d; /* Union for deconstructing doubles. */
Tcl_WideUInt bw; /* Integer significand. */
int be; /* Power of 2 by which b must be multiplied */
@@ -4167,18 +4119,18 @@ TclDoubleDigits(
* Correct an incorrect caller-supplied 'ndigits'. Also determine:
* i = The maximum number of decimal digits that will be returned in the
* formatted string. This is k + 1 + ndigits for F format, 18 for
- * shortest and Steele, and ndigits for E format.
+ * shortest, and ndigits for E format.
* ilim = The number of significant digits to convert if k has been
- * guessed correctly. This is -1 for shortest and Steele (which
+ * guessed correctly. This is -1 for shortest (which
* stop when all significance has been lost), 'ndigits' for E
* format, and 'k + 1 + ndigits' for F format.
* ilim1 = The minimum number of significant digits to convert if k has
- * been guessed 1 too high. This, too, is -1 for shortest and
- * Steele, and 'ndigits' for E format, but it's 'ndigits-1' for F
+ * been guessed 1 too high. This, too, is -1 for shortest,
+ * and 'ndigits' for E format, but it's 'ndigits-1' for F
* format.
*/
- SetPrecisionLimits(convType, k, &ndigits, &i, &ilim, &ilim1);
+ SetPrecisionLimits(flags, k, &ndigits, &i, &ilim, &ilim1);
/*
* Try to do low-precision conversion in floating point rather than
@@ -4251,7 +4203,7 @@ TclDoubleDigits(
* [1.0e-3 .. 1.0e+24]).
*/
- return ShorteningInt64Conversion(&d, convType, bw, b2, b5, m2plus,
+ return ShorteningInt64Conversion(&d, bw, b2, b5, m2plus,
m2minus, m5, s2, s5, k, len, ilim, ilim1, decpt, endPtr);
} else if (s5 == 0) {
/*
@@ -4270,7 +4222,7 @@ TclDoubleDigits(
m2minus += delta;
s2 += delta;
}
- return ShorteningBignumConversionPowD(&d, convType, bw, b2, b5,
+ return ShorteningBignumConversionPowD(&d, bw, b2, b5,
m2plus, m2minus, m5, s2/DIGIT_BIT, k, len, ilim, ilim1,
decpt, endPtr);
} else {
@@ -4279,7 +4231,7 @@ TclDoubleDigits(
* arithmetic for the conversion.
*/
- return ShorteningBignumConversion(&d, convType, bw, b2, m2plus,
+ return ShorteningBignumConversion(&d, bw, b2, m2plus,
m2minus, s2, s5, k, len, ilim, ilim1, decpt, endPtr);
}
} else {
@@ -4307,7 +4259,7 @@ TclDoubleDigits(
* operations.
*/
- return StrictInt64Conversion(&d, convType, bw, b2, b5, s2, s5, k,
+ return StrictInt64Conversion(&d, bw, b2, b5, s2, s5, k,
len, ilim, ilim1, decpt, endPtr);
} else if (s5 == 0) {
/*
@@ -4324,7 +4276,7 @@ TclDoubleDigits(
b2 += delta;
s2 += delta;
}
- return StrictBignumConversionPowD(&d, convType, bw, b2, b5,
+ return StrictBignumConversionPowD(&d, bw, b2, b5,
s2/DIGIT_BIT, k, len, ilim, ilim1, decpt, endPtr);
} else {
/*
@@ -4334,7 +4286,7 @@ TclDoubleDigits(
* fewer mp_int divisions.
*/
- return StrictBignumConversion(&d, convType, bw, b2, s2, s5, k,
+ return StrictBignumConversion(&d, bw, b2, s2, s5, k,
len, ilim, ilim1, decpt, endPtr);
}
}