summaryrefslogtreecommitdiffstats
path: root/generic/tclStrToD.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclStrToD.c')
-rw-r--r--[-rwxr-xr-x]generic/tclStrToD.c110
1 files changed, 70 insertions, 40 deletions
diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c
index 377d44f..883e2ea 100755..100644
--- a/generic/tclStrToD.c
+++ b/generic/tclStrToD.c
@@ -192,8 +192,6 @@ static int maxDigits; /* The maximum number of digits to the left of
* the decimal point of a double. */
static int minDigits; /* The maximum number of digits to the right
* of the decimal point in a double. */
-static int mantDIGIT; /* Number of mp_digit's needed to hold the
- * significand of a double. */
static const double pow_10_2_n[] = { /* Inexact higher powers of ten. */
1.0,
100.0,
@@ -249,15 +247,6 @@ static const int itens [] = {
100000000
};
-static const Tcl_WideUInt wtens[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000,
- (Tcl_WideUInt) 1000000*10, (Tcl_WideUInt) 1000000*100,
- (Tcl_WideUInt) 1000000*1000, (Tcl_WideUInt) 1000000*10000,
- (Tcl_WideUInt) 1000000*100000, (Tcl_WideUInt) 1000000*1000000,
- (Tcl_WideUInt) 1000000*1000000*10, (Tcl_WideUInt) 1000000*1000000*100,
- (Tcl_WideUInt) 1000000*1000000*1000,(Tcl_WideUInt) 1000000*1000000*10000
-};
-
static const double bigtens[] = {
1e016, 1e032, 1e064, 1e128, 1e256
};
@@ -571,7 +560,7 @@ TclParseNumber(
* I, N, and whitespace.
*/
- if (isspace(UCHAR(c))) {
+ if (TclIsSpaceProc(c)) {
if (flags & TCL_PARSE_NO_WHITESPACE) {
goto endgame;
}
@@ -1091,7 +1080,7 @@ TclParseNumber(
}
/* FALLTHROUGH */
case sNANPAREN:
- if (isspace(UCHAR(c))) {
+ if (TclIsSpaceProc(c)) {
break;
}
if (numSigDigs < 13) {
@@ -1101,7 +1090,10 @@ TclParseNumber(
d = 10 + c - 'a';
} else if (c >= 'A' && c <= 'F') {
d = 10 + c - 'A';
+ } else {
+ goto endgame;
}
+ numSigDigs++;
significandWide = (significandWide << 4) + d;
state = sNANHEX;
break;
@@ -1142,7 +1134,7 @@ TclParseNumber(
* Accept trailing whitespace.
*/
- while (len != 0 && isspace(UCHAR(*p))) {
+ while (len != 0 && TclIsSpaceProc(*p)) {
p++;
len--;
}
@@ -1247,7 +1239,7 @@ TclParseNumber(
if (!octalSignificandOverflow) {
if (octalSignificandWide >
(Tcl_WideUInt)(((~(unsigned long)0) >> 1) + signum)) {
-#ifndef NO_WIDE_TYPE
+#ifndef TCL_WIDE_INT_IS_LONG
if (octalSignificandWide <= (MOST_BITS + signum)) {
objPtr->typePtr = &tclWideIntType;
if (signum) {
@@ -1294,7 +1286,7 @@ TclParseNumber(
if (!significandOverflow) {
if (significandWide >
(Tcl_WideUInt)(((~(unsigned long)0) >> 1) + signum)) {
-#ifndef NO_WIDE_TYPE
+#ifndef TCL_WIDE_INT_IS_LONG
if (significandWide <= MOST_BITS+signum) {
objPtr->typePtr = &tclWideIntType;
if (signum) {
@@ -1384,11 +1376,9 @@ TclParseNumber(
if (status != TCL_OK) {
if (interp != NULL) {
- Tcl_Obj *msg;
+ Tcl_Obj *msg = Tcl_ObjPrintf("expected %s but got \"",
+ expected);
- TclNewLiteralStringObj(msg, "expected ");
- Tcl_AppendToObj(msg, expected, -1);
- Tcl_AppendToObj(msg, " but got \"", -1);
Tcl_AppendLimitedToObj(msg, bytes, numBytes, 50, "");
Tcl_AppendToObj(msg, "\"", -1);
if (state == BAD_OCTAL) {
@@ -2710,7 +2700,7 @@ StrictQuickFormat(
inline static char *
QuickConversion(
- double d, /* Number to format. */
+ double e, /* Number to format. */
int k, /* floor(log10(d)), approximately. */
int k_check, /* 0 if k is exact, 1 if it may be too high */
int flags, /* Flags passed to dtoa:
@@ -2729,12 +2719,14 @@ QuickConversion(
char *retval; /* Returned string. */
char *end; /* Pointer to the terminal null byte in the
* returned string. */
+ volatile double d; /* Workaround for a bug in mingw gcc 3.4.5 */
/*
* Bring d into the range [1 .. 10).
*/
- ieps = AdjustRange(&d, k);
+ ieps = AdjustRange(&e, k);
+ d = e;
/*
* If the guessed value of k didn't get d into range, adjust it by one. If
@@ -3818,7 +3810,7 @@ ShorteningBignumConversion(
if (m2plus > m2minus) {
mp_clear(&mplus);
}
- mp_clear_multi(&b, &mminus, &temp, NULL);
+ mp_clear_multi(&b, &mminus, &temp, &dig, &S, NULL);
*s = '\0';
*decpt = k;
if (endPtr) {
@@ -3875,6 +3867,7 @@ StrictBignumConversion(
* S = 2**s2 * 5*s5
*/
+ mp_init_multi(&temp, &dig, NULL);
TclBNInitBignumFromWideUInt(&b, bw);
mp_mul_2d(&b, b2, &b);
mp_init_set_int(&S, 1);
@@ -3889,13 +3882,11 @@ StrictBignumConversion(
ilim =ilim1;
--k;
}
- mp_init(&temp);
/*
* Convert the leading digit.
*/
- mp_init(&dig);
i = 0;
mp_div(&b, &S, &dig, &b);
if (dig.used > 1 || dig.dp[0] >= 10) {
@@ -3983,7 +3974,7 @@ StrictBignumConversion(
* string.
*/
- mp_clear_multi(&b, &temp, NULL);
+ mp_clear_multi(&b, &S, &temp, &dig, NULL);
*s = '\0';
*decpt = k;
if (endPtr) {
@@ -4368,8 +4359,7 @@ TclInitDoubleConversion(void)
maxpow10_wide = (int)
floor(sizeof(Tcl_WideUInt) * CHAR_BIT * log(2.) / log(10.));
- pow10_wide = (Tcl_WideUInt *)
- ckalloc((maxpow10_wide + 1) * sizeof(Tcl_WideUInt));
+ pow10_wide = ckalloc((maxpow10_wide + 1) * sizeof(Tcl_WideUInt));
u = 1;
for (i = 0; i < maxpow10_wide; ++i) {
pow10_wide[i] = u;
@@ -4433,7 +4423,6 @@ TclInitDoubleConversion(void)
+ 0.5 * log(10.)) / log(10.));
minDigits = (int) floor((DBL_MIN_EXP - DBL_MANT_DIG)
* log((double) FLT_RADIX) / log(10.));
- mantDIGIT = (mantBits + DIGIT_BIT-1) / DIGIT_BIT;
log10_DIGIT_MAX = (int) floor(DIGIT_BIT * log(2.) / log(10.));
/*
@@ -4477,10 +4466,13 @@ TclFinalizeDoubleConversion(void)
{
int i;
- ckfree((char *) pow10_wide);
+ ckfree(pow10_wide);
for (i=0; i<9; ++i) {
mp_clear(pow5 + i);
}
+ for (i=0; i < 5; ++i) {
+ mp_clear(pow5_13 + i);
+ }
}
/*
@@ -4562,12 +4554,13 @@ TclBignumToDouble(
const mp_int *a) /* Integer to convert. */
{
mp_int b;
- int bits, shift, i;
+ int bits, shift, i, lsb;
double r;
+
/*
- * Determine how many bits we need, and extract that many from the input.
- * Round to nearest unit in the last place.
+ * We need a 'mantBits'-bit significand. Determine what shift will
+ * give us that.
*/
bits = mp_count_bits(a);
@@ -4579,17 +4572,54 @@ TclBignumToDouble(
return -HUGE_VAL;
}
}
- shift = mantBits + 1 - bits;
+ shift = mantBits - bits;
+
+ /*
+ * If shift > 0, shift the significand left by the requisite number of
+ * bits. If shift == 0, the significand is already exactly 'mantBits'
+ * in length. If shift < 0, we will need to shift the significand right
+ * by the requisite number of bits, and round it. If the '1-shift'
+ * least significant bits are 0, but the 'shift'th bit is nonzero,
+ * then the significand lies exactly between two values and must be
+ * 'rounded to even'.
+ */
+
mp_init(&b);
- if (shift > 0) {
+ if (shift == 0) {
+ mp_copy(a, &b);
+ } else if (shift > 0) {
mp_mul_2d(a, shift, &b);
} else if (shift < 0) {
- mp_div_2d(a, -shift, &b, NULL);
- } else {
- mp_copy(a, &b);
+ lsb = mp_cnt_lsb(a);
+ if (lsb == -1-shift) {
+
+ /*
+ * Round to even
+ */
+
+ mp_div_2d(a, -shift, &b, NULL);
+ if (mp_isodd(&b)) {
+ if (b.sign == MP_ZPOS) {
+ mp_add_d(&b, 1, &b);
+ } else {
+ mp_sub_d(&b, 1, &b);
+ }
+ }
+ } else {
+
+ /*
+ * Ordinary rounding
+ */
+
+ mp_div_2d(a, -1-shift, &b, NULL);
+ if (b.sign == MP_ZPOS) {
+ mp_add_d(&b, 1, &b);
+ } else {
+ mp_sub_d(&b, 1, &b);
+ }
+ mp_div_2d(&b, 1, &b, NULL);
+ }
}
- mp_add_d(&b, 1, &b);
- mp_div_2d(&b, 1, &b, NULL);
/*
* Accumulate the result, one mp_digit at a time.