summaryrefslogtreecommitdiffstats
path: root/generic/tclStrToD.c
diff options
context:
space:
mode:
authorKevin B Kenny <kennykb@acm.org>2006-04-19 16:43:01 (GMT)
committerKevin B Kenny <kennykb@acm.org>2006-04-19 16:43:01 (GMT)
commit80ac93388a6784f4d5c7251041dc6eabbc5f8061 (patch)
tree131734432ff738e20e51a950384a05da75b03e48 /generic/tclStrToD.c
parenta4224d88345b6c501df8eb8fa26f5c7b8711c3f8 (diff)
downloadtcl-80ac93388a6784f4d5c7251041dc6eabbc5f8061.zip
tcl-80ac93388a6784f4d5c7251041dc6eabbc5f8061.tar.gz
tcl-80ac93388a6784f4d5c7251041dc6eabbc5f8061.tar.bz2
fix for Martin Lemburg's DST conversion bug.
http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/9a8b15a4dfc0b7a0
Diffstat (limited to 'generic/tclStrToD.c')
-rwxr-xr-xgeneric/tclStrToD.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c
index f5ff814..41d13f8 100755
--- a/generic/tclStrToD.c
+++ b/generic/tclStrToD.c
@@ -14,7 +14,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclStrToD.c,v 1.20 2006/03/21 20:03:06 dgp Exp $
+ * RCS: @(#) $Id: tclStrToD.c,v 1.21 2006/04/19 16:43:02 kennykb Exp $
*
*----------------------------------------------------------------------
*/
@@ -118,6 +118,13 @@ static CONST double pow_10_2_n[] = { /* Inexact higher powers of ten. */
1.0e+128,
1.0e+256
};
+static int n770_fp; /* Flag is 1 on Nokia N770 floating point.
+ * Nokia's floating point has the words
+ * reversed: if big-endian is 7654 3210,
+ * and little-endian is 0123 4567,
+ * then Nokia's FP is 4567 0123;
+ * little-endian within the 32-bit words
+ * but big-endian between them. */
/*
* Static functions defined in this file.
@@ -134,6 +141,7 @@ static double MakeLowPrecisionDouble(int signum,
Tcl_WideUInt significand, int nSigDigs,
int exponent);
static double MakeNaN(int signum, Tcl_WideUInt tag);
+static Tcl_WideUInt Nokia770Twiddle(Tcl_WideUInt w);
static double Pow10TimesFrExp(int exponent, double fraction,
int *machexp);
static double RefineApproximation(double approx,
@@ -1508,7 +1516,9 @@ MakeNaN(
} else {
theNaN.iv |= ((Tcl_WideUInt) NAN_START) << 48;
}
-
+ if (n770_fp) {
+ theNaN.iv = Nokia770Twiddle(theNaN.iv);
+ }
return theNaN.dv;
}
#endif
@@ -1989,9 +1999,15 @@ AbsoluteValue(
double dv;
} bitwhack;
bitwhack.dv = v;
+ if (n770_fp) {
+ bitwhack.iv = Nokia770Twiddle(bitwhack.iv);
+ }
if (bitwhack.iv & ((Tcl_WideUInt) 1 << 63)) {
*signum = 1;
bitwhack.iv &= ~((Tcl_WideUInt) 1 << 63);
+ if (n770_fp) {
+ bitwhack.iv = Nokia770Twiddle(bitwhack.iv);
+ }
v = bitwhack.dv;
} else {
*signum = 0;
@@ -2114,6 +2130,13 @@ TclInitDoubleConversion(void)
Tcl_WideUInt u;
double d;
+#ifdef IEEE_FLOATING_POINT
+ union {
+ double dv;
+ Tcl_WideUInt iv;
+ } bitwhack;
+#endif
+
/*
* Initialize table of powers of 10 expressed as wide integers.
*/
@@ -2183,6 +2206,25 @@ TclInitDoubleConversion(void)
* log((double) FLT_RADIX) / log(10.));
mantDIGIT = (mantBits + DIGIT_BIT-1) / DIGIT_BIT;
log10_DIGIT_MAX = (int) floor(DIGIT_BIT * log(2.) / log(10.));
+
+ /*
+ * Nokia 770's software-emulated floating point is "middle endian":
+ * the bytes within a 32-bit word are little-endian (like the native
+ * integers), but the two words of a 'double' are presented most
+ * significant word first.
+ */
+
+#ifdef IEEE_FLOATING_POINT
+ bitwhack.dv = 1.000000238418579;
+ /* 3ff0 0000 4000 0000 */
+ if ((bitwhack.iv >> 32) == 0x3ff00000) {
+ n770_fp = 0;
+ } else if ((bitwhack.iv & 0xffffffff) == 0x3ff00000) {
+ n770_fp = 1;
+ } else {
+ Tcl_Panic("unknown floating point word order on this machine.");
+ }
+#endif
}
/*
@@ -2623,6 +2665,9 @@ TclFormatNaN(
} bitwhack;
bitwhack.dv = value;
+ if (n770_fp) {
+ bitwhack.iv = Nokia770Twiddle(bitwhack.iv);
+ }
if (bitwhack.iv & ((Tcl_WideUInt) 1 << 63)) {
bitwhack.iv &= ~ ((Tcl_WideUInt) 1 << 63);
*buffer++ = '-';
@@ -2640,6 +2685,24 @@ TclFormatNaN(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * Nokia770Twiddle --
+ *
+ * Transpose the two words of a number for Nokia 770 floating
+ * point handling.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Tcl_WideUInt
+Nokia770Twiddle(
+ Tcl_WideUInt w /* Number to transpose */
+) {
+ return (((w >> 32) & 0xffffffff) | (w << 32));
+}
+
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4