diff options
author | Kevin B Kenny <kennykb@acm.org> | 2006-04-19 16:43:01 (GMT) |
---|---|---|
committer | Kevin B Kenny <kennykb@acm.org> | 2006-04-19 16:43:01 (GMT) |
commit | 80ac93388a6784f4d5c7251041dc6eabbc5f8061 (patch) | |
tree | 131734432ff738e20e51a950384a05da75b03e48 /generic/tclStrToD.c | |
parent | a4224d88345b6c501df8eb8fa26f5c7b8711c3f8 (diff) | |
download | tcl-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-x | generic/tclStrToD.c | 67 |
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 |