summaryrefslogtreecommitdiffstats
path: root/generic/tclUtil.c
diff options
context:
space:
mode:
authorandreas_kupries <akupries@shaw.ca>2010-11-30 20:59:27 (GMT)
committerandreas_kupries <akupries@shaw.ca>2010-11-30 20:59:27 (GMT)
commit94ead3bc1f6658967c1ea17f52b7d885f1534ca9 (patch)
tree1690548d2a2cd82215101f59ba6632c4b01cc523 /generic/tclUtil.c
parent881d5025bf794494317b6490233cde4438ed8d5e (diff)
downloadtcl-94ead3bc1f6658967c1ea17f52b7d885f1534ca9.zip
tcl-94ead3bc1f6658967c1ea17f52b7d885f1534ca9.tar.gz
tcl-94ead3bc1f6658967c1ea17f52b7d885f1534ca9.tar.bz2
* generic/tclInt.decls: Backport of Kevin B. Kenny's work on
* generic/tclInt.h: the Tcl Head, with help from Jeff Hobbs. * generic/tclStrToD.c: * generic/tclTest.c: * generic/tclTomMath.decls: * generic/tclUtil.c: * tests/util.test: * unix/Makefile.in: * win/Makefile.in: * win/makefile.vc: Rewrite of Tcl_PrintDouble and TclDoubleDigits that (a) fixes a severe performance problem with floating point shimmering reported by Karl Lehenbauer, (b) allows TclDoubleDigits to generate the digit strings for 'e' and 'f' format, so that it can be used for tcl_precision != 0 (and possibly later for [format]), (c) fixes [Bug 3120139] by making TclPrintDouble inherently locale-independent, (d) adds test cases to util.test for correct rounding in difficult cases of TclDoubleDigits where fixed- precision results are requested. (e) adds test cases to util.test for the controversial aspects of [Bug 3105247]. As a side effect, two more modules from libtommath (bn_mp_set_int.c and bn_mp_init_set_int.c) are brought into the build, since the new code uses them. * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclTomMathDecls.h: Regenerated.
Diffstat (limited to 'generic/tclUtil.c')
-rw-r--r--generic/tclUtil.c74
1 files changed, 24 insertions, 50 deletions
diff --git a/generic/tclUtil.c b/generic/tclUtil.c
index e4083fc..2a23fd2 100644
--- a/generic/tclUtil.c
+++ b/generic/tclUtil.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclUtil.c,v 1.97.2.7 2010/11/30 18:16:02 hobbs Exp $
+ * RCS: @(#) $Id: tclUtil.c,v 1.97.2.8 2010/11/30 20:59:28 andreas_kupries Exp $
*/
#include "tclInt.h"
@@ -2232,22 +2232,14 @@ Tcl_PrintDouble(
* at least TCL_DOUBLE_SPACE characters. */
{
char *p, c;
- int exp;
+ int exponent;
int signum;
- char buffer[TCL_DOUBLE_SPACE];
- Tcl_UniChar ch;
+ char* digits;
+ char* end;
int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int)sizeof(int));
/*
- * If *precisionPtr == 0, then use TclDoubleDigits to develop a decimal
- * significand and exponent, then format it in E or F format as
- * appropriate. If *precisionPtr != 0, use the native sprintf and then add
- * a trailing ".0" if there is no decimal point in the rep.
- */
-
- if (*precisionPtr == 0) {
- /*
* Handle NaN.
*/
@@ -2261,10 +2253,14 @@ Tcl_PrintDouble(
*/
if (TclIsInfinite(value)) {
+ /*
+ * Remember to copy the terminating NUL too.
+ */
+
if (value < 0) {
- strcpy(dst, "-Inf");
+ memcpy(dst, "-Inf", 5);
} else {
- strcpy(dst, "Inf");
+ memcpy(dst, "Inf", 4);
}
return;
}
@@ -2273,12 +2269,18 @@ Tcl_PrintDouble(
* Ordinary (normal and denormal) values.
*/
- exp = TclDoubleDigits(buffer, value, &signum);
+ if (*precisionPtr == 0) {
+ digits = TclDoubleDigits(value, -1, TCL_DD_SHORTEST,
+ &exponent, &signum, &end);
+ } else {
+ digits = TclDoubleDigits(value, *precisionPtr, TCL_DD_E_FORMAT,
+ &exponent, &signum, &end);
+ }
if (signum) {
*dst++ = '-';
}
- p = buffer;
- if (exp < -3 || exp > 17) {
+ p = digits;
+ if (exponent < -4 || exponent > 16) {
/*
* E format for numbers < 1e-3 or >= 1e17.
*/
@@ -2292,17 +2294,17 @@ Tcl_PrintDouble(
c = *++p;
}
}
- sprintf(dst, "e%+d", exp-1);
+ sprintf(dst, "e%+d", exponent);
} else {
/*
* F format for others.
*/
- if (exp <= 0) {
+ if (exponent < 0) {
*dst++ = '0';
}
c = *p;
- while (exp-- > 0) {
+ while (exponent-- >= 0) {
if (c != '\0') {
*dst++ = c;
c = *++p;
@@ -2314,7 +2316,7 @@ Tcl_PrintDouble(
if (c == '\0') {
*dst++ = '0';
} else {
- while (++exp < 0) {
+ while (++exponent < -1) {
*dst++ = '0';
}
while (c != '\0') {
@@ -2324,35 +2326,7 @@ Tcl_PrintDouble(
}
*dst++ = '\0';
}
- } else {
- /*
- * tcl_precision is supplied, pass it to the native sprintf.
- */
-
- sprintf(dst, "%.*g", *precisionPtr, value);
-
- /*
- * If the ASCII result looks like an integer, add ".0" so that it
- * doesn't look like an integer anymore. This prevents floating-point
- * values from being converted to integers unintentionally. Check for
- * ASCII specifically to speed up the function.
- */
-
- for (p = dst; *p != 0;) {
- if (UCHAR(*p) < 0x80) {
- c = *p++;
- } else {
- p += Tcl_UtfToUniChar(p, &ch);
- c = UCHAR(ch);
- }
- if ((c == '.') || isalpha(UCHAR(c))) { /* INTL: ISO only. */
- return;
- }
- }
- p[0] = '.';
- p[1] = '0';
- p[2] = 0;
- }
+ ckfree(digits);
}
/*