diff options
Diffstat (limited to 'generic/tclStrToD.c')
| -rw-r--r-- | generic/tclStrToD.c | 3397 |
1 files changed, 1507 insertions, 1890 deletions
diff --git a/generic/tclStrToD.c b/generic/tclStrToD.c index 09fd1f3..cff9bdd 100644 --- a/generic/tclStrToD.c +++ b/generic/tclStrToD.c @@ -1,4 +1,6 @@ /* + *---------------------------------------------------------------------- + * * tclStrToD.c -- * * This file contains a collection of procedures for managing conversions @@ -7,25 +9,23 @@ * into strings of digits, and procedures for interconversion among * 'double' and 'mp_int' types. * - * Copyright © 2005 Kevin B. Kenny. All rights reserved. + * Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. + *---------------------------------------------------------------------- */ #include "tclInt.h" -#include "tclTomMath.h" -#include <float.h> +#include "tommath.h" #include <math.h> -#ifdef _WIN32 -#define copysign _copysign -#endif - -#ifndef PRIx64 -# define PRIx64 TCL_LL_MODIFIER "x" -#endif +/* + * Define KILL_OCTAL to suppress interpretation of numbers with leading zero + * as octal. (Ceterum censeo: numeros octonarios delendos esse.) + */ +#undef KILL_OCTAL /* * This code supports (at least hypothetically), IBM, Cray, VAX and IEEE-754 @@ -38,76 +38,48 @@ #endif /* - * Rounding controls. (Thanks a lot, Intel!) - */ - -#ifdef __i386 -/* * gcc on x86 needs access to rounding controls, because of a questionable * feature where it retains intermediate results as IEEE 'long double' values * somewhat unpredictably. It is tempting to include fpu_control.h, but that * file exists only on Linux; it is missing on Cygwin and MinGW. Most gcc-isms * and ix86-isms are factored out here. */ -# if defined(__GNUC__) -typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); - -# define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw)) -# define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw)) -# define FPU_IEEE_ROUNDING 0x027F -# define ADJUST_FPU_CONTROL_WORD -# define TCL_IEEE_DOUBLE_ROUNDING_DECL \ - fpu_control_t roundTo53Bits = FPU_IEEE_ROUNDING; \ - fpu_control_t oldRoundingMode; -# define TCL_IEEE_DOUBLE_ROUNDING \ - _FPU_GETCW(oldRoundingMode); \ - _FPU_SETCW(roundTo53Bits) -# define TCL_DEFAULT_DOUBLE_ROUNDING \ - _FPU_SETCW(oldRoundingMode) -/* - * Sun ProC needs sunmath for rounding control on x86 like gcc above. - */ -# elif defined(__sun) -# include <sunmath.h> -# define TCL_IEEE_DOUBLE_ROUNDING_DECL -# define TCL_IEEE_DOUBLE_ROUNDING \ - ieee_flags("set","precision","double",NULL) -# define TCL_DEFAULT_DOUBLE_ROUNDING \ - ieee_flags("clear","precision",NULL,NULL) - -# endif +#if defined(__GNUC__) && defined(__i386) +typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); +#define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw)) +#define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw)) +# define FPU_IEEE_ROUNDING 0x027f +# define ADJUST_FPU_CONTROL_WORD #endif -/* - * Other platforms are assumed to always operate in full IEEE mode, so we make - * the macros to go in and out of that mode do nothing. + +/* Sun ProC needs sunmath for rounding control on x86 like gcc above. + * + * */ -#ifndef TCL_IEEE_DOUBLE_ROUNDING /* !__i386 || (!__GNUC__ && !__sun) */ -# define TCL_IEEE_DOUBLE_ROUNDING_DECL -# define TCL_IEEE_DOUBLE_ROUNDING ((void) 0) -# define TCL_DEFAULT_DOUBLE_ROUNDING ((void) 0) +#if defined(__sun) && defined(__i386) && !defined(__GNUC__) +#include <sunmath.h> #endif /* - * MIPS floating-point units need special settings in control registers to use - * gradual underflow as we expect. This fix is for the MIPSpro compiler. + * MIPS floating-point units need special settings in control registers + * to use gradual underflow as we expect. This fix is for the MIPSpro + * compiler. */ - #if defined(__sgi) && defined(_COMPILER_VERSION) #include <sys/fpu.h> #endif - /* * HP's PA_RISC architecture uses 7ff4000000000000 to represent a quiet NaN. * Everyone else uses 7ff8000000000000. (Why, HP, why?) */ #ifdef __hppa -# define NAN_START 0x7FF4 -# define NAN_MASK (((Tcl_WideUInt) 1) << 50) +# define NAN_START 0x7ff4 +# define NAN_MASK (((Tcl_WideUInt) 1) << 50) #else -# define NAN_START 0x7FF8 -# define NAN_MASK (((Tcl_WideUInt) 1) << 51) +# define NAN_START 0x7ff8 +# define NAN_MASK (((Tcl_WideUInt) 1) << 51) #endif /* @@ -121,44 +93,45 @@ typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); #define TWO_OVER_3LOG10 0.28952965460216784 #define LOG10_3HALVES_PLUS_FUDGE 0.1760912590558 -/* - * Definitions of the parts of an IEEE754-format floating point number. - */ - -#define SIGN_BIT 0x80000000 - /* Mask for the sign bit in the first word of - * a double. */ -#define EXP_MASK 0x7FF00000 - /* Mask for the exponent field in the first - * word of a double. */ -#define EXP_SHIFT 20 /* Shift count to make the exponent an - * integer. */ -#define HIDDEN_BIT (((Tcl_WideUInt) 0x00100000) << 32) - /* Hidden 1 bit for the significand. */ -#define HI_ORDER_SIG_MASK 0x000FFFFF +/* Definitions of the parts of an IEEE754-format floating point number */ + +#define SIGN_BIT 0x80000000 + /* Mask for the sign bit in the first + * word of a double */ +#define EXP_MASK 0x7ff00000 + /* Mask for the exponent field in the + * first word of a double */ +#define EXP_SHIFT 20 + /* Shift count to make the exponent an + * integer */ +#define HIDDEN_BIT (((Tcl_WideUInt) 0x00100000) << 32) + /* Hidden 1 bit for the significand */ +#define HI_ORDER_SIG_MASK 0x000fffff /* Mask for the high-order part of the * significand in the first word of a - * double. */ -#define SIG_MASK (((Tcl_WideUInt) HI_ORDER_SIG_MASK << 32) \ - | 0xFFFFFFFF) + * double */ +#define SIG_MASK (((Tcl_WideUInt) HI_ORDER_SIG_MASK << 32) \ + | 0xffffffff) /* Mask for the 52-bit significand. */ -#define FP_PRECISION 53 /* Number of bits of significand plus the - * hidden bit. */ -#define EXPONENT_BIAS 0x3FF /* Bias of the exponent 0. */ - -/* - * Derived quantities. - */ - -#define TEN_PMAX 22 /* floor(FP_PRECISION*log(2)/log(5)) */ -#define QUICK_MAX 14 /* floor((FP_PRECISION-1)*log(2)/log(10))-1 */ -#define BLETCH 0x10 /* Highest power of two that is greater than - * DBL_MAX_10_EXP, divided by 16. */ -#define DIGIT_GROUP 8 /* floor(MP_DIGIT_BIT*log(2)/log(10)) */ - -/* - * Union used to dismantle floating point numbers. - */ +#define FP_PRECISION 53 + /* Number of bits of significand plus the + * hidden bit */ +#define EXPONENT_BIAS 0x3ff + /* Bias of the exponent 0 */ + +/* Derived quantities */ + +#define TEN_PMAX 22 + /* floor(FP_PRECISION*log(2)/log(5)) */ +#define QUICK_MAX 14 + /* floor((FP_PRECISION-1)*log(2)/log(10)) - 1 */ +#define BLETCH 0x10 + /* Highest power of two that is greater than + * DBL_MAX_10_EXP, divided by 16 */ +#define DIGIT_GROUP 8 + /* floor(DIGIT_BIT*log(2)/log(10)) */ + +/* Union used to dismantle floating point numbers. */ typedef union Double { struct { @@ -189,7 +162,7 @@ static int log2FLT_RADIX; /* Logarithm of the floating point radix. */ static int mantBits; /* Number of bits in a double's significand */ static mp_int pow5[9]; /* Table of powers of 5**(2**n), up to * 5**256 */ -static double tiny = 0.0; /* The smallest representable double. */ +static double tiny = 0.0; /* The smallest representable double */ 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 @@ -211,12 +184,10 @@ static int n770_fp; /* Flag is 1 on Nokia N770 floating point. * 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. */ + * little-endian within the 32-bit words + * but big-endian between them. */ -/* - * Table of powers of 5 that are small enough to fit in an mp_digit. - */ +/* Table of powers of 5 that are small enough to fit in an mp_digit. */ static const mp_digit dpow5[13] = { 1, 5, 25, 125, @@ -225,10 +196,7 @@ static const mp_digit dpow5[13] = { 244140625 }; -/* - * Table of powers: pow5_13[n] = 5**(13*2**(n+1)) - */ - +/* Table of powers: pow5_13[n] = 5**(13*2**(n+1)) */ static mp_int pow5_13[5]; /* Table of powers: 5**13, 5**26, 5**52, * 5**104, 5**208 */ static const double tens[] = { @@ -261,35 +229,34 @@ static const int log2pow5[27] = { }; #define N_LOG2POW5 27 -static const Tcl_WideUInt wuipow5[] = { - (Tcl_WideUInt) 1U, /* 5**0 */ - (Tcl_WideUInt) 5U, - (Tcl_WideUInt) 25U, - (Tcl_WideUInt) 125U, - (Tcl_WideUInt) 625U, - (Tcl_WideUInt) 3125U, /* 5**5 */ - (Tcl_WideUInt) 3125U*5U, - (Tcl_WideUInt) 3125U*25U, - (Tcl_WideUInt) 3125U*125U, - (Tcl_WideUInt) 3125U*625U, - (Tcl_WideUInt) 3125U*3125U, /* 5**10 */ - (Tcl_WideUInt) 3125U*3125U*5U, - (Tcl_WideUInt) 3125U*3125U*25U, - (Tcl_WideUInt) 3125U*3125U*125U, - (Tcl_WideUInt) 3125U*3125U*625U, - (Tcl_WideUInt) 3125U*3125U*3125U, /* 5**15 */ - (Tcl_WideUInt) 3125U*3125U*3125U*5U, - (Tcl_WideUInt) 3125U*3125U*3125U*25U, - (Tcl_WideUInt) 3125U*3125U*3125U*125U, - (Tcl_WideUInt) 3125U*3125U*3125U*625U, - (Tcl_WideUInt) 3125U*3125U*3125U*3125U, /* 5**20 */ - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*5U, - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*25U, - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*125U, - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*625U, - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*3125U, /* 5**25 */ - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*3125U*5U, - (Tcl_WideUInt) 3125U*3125U*3125U*3125U*3125U*25U /* 5**27 */ +static const Tcl_WideUInt wuipow5[27] = { + (Tcl_WideUInt) 1, /* 5**0 */ + (Tcl_WideUInt) 5, + (Tcl_WideUInt) 25, + (Tcl_WideUInt) 125, + (Tcl_WideUInt) 625, + (Tcl_WideUInt) 3125, /* 5**5 */ + (Tcl_WideUInt) 3125*5, + (Tcl_WideUInt) 3125*25, + (Tcl_WideUInt) 3125*125, + (Tcl_WideUInt) 3125*625, + (Tcl_WideUInt) 3125*3125, /* 5**10 */ + (Tcl_WideUInt) 3125*3125*5, + (Tcl_WideUInt) 3125*3125*25, + (Tcl_WideUInt) 3125*3125*125, + (Tcl_WideUInt) 3125*3125*625, + (Tcl_WideUInt) 3125*3125*3125, /* 5**15 */ + (Tcl_WideUInt) 3125*3125*3125*5, + (Tcl_WideUInt) 3125*3125*3125*25, + (Tcl_WideUInt) 3125*3125*3125*125, + (Tcl_WideUInt) 3125*3125*3125*625, + (Tcl_WideUInt) 3125*3125*3125*3125, /* 5**20 */ + (Tcl_WideUInt) 3125*3125*3125*3125*5, + (Tcl_WideUInt) 3125*3125*3125*3125*25, + (Tcl_WideUInt) 3125*3125*3125*3125*125, + (Tcl_WideUInt) 3125*3125*3125*3125*625, + (Tcl_WideUInt) 3125*3125*3125*3125*3125, /* 5**25 */ + (Tcl_WideUInt) 3125*3125*3125*3125*3125*5 /* 5**26 */ }; /* @@ -299,78 +266,72 @@ static const Tcl_WideUInt wuipow5[] = { static int AccumulateDecimalDigit(unsigned, int, Tcl_WideUInt *, mp_int *, int); static double MakeHighPrecisionDouble(int signum, - mp_int *significand, int nSigDigs, long exponent); + mp_int *significand, int nSigDigs, int exponent); static double MakeLowPrecisionDouble(int signum, Tcl_WideUInt significand, int nSigDigs, - long exponent); -#ifdef IEEE_FLOATING_POINT + int exponent); static double MakeNaN(int signum, Tcl_WideUInt tag); -#endif static double RefineApproximation(double approx, mp_int *exactSignificand, int exponent); -static mp_err MulPow5(mp_int *, unsigned, mp_int *) MP_WUR; -static int NormalizeRightward(Tcl_WideUInt *); +static void MulPow5(mp_int*, unsigned, mp_int*); +static int NormalizeRightward(Tcl_WideUInt*); static int RequiredPrecision(Tcl_WideUInt); -static void DoubleToExpAndSig(double, Tcl_WideUInt *, int *, - int *); -static void TakeAbsoluteValue(Double *, int *); -static char * FormatInfAndNaN(Double *, int *, char **); -static char * FormatZero(int *, char **); +static void DoubleToExpAndSig(double, Tcl_WideUInt*, int*, int*); +static void TakeAbsoluteValue(Double*, int*); +static char* FormatInfAndNaN(Double*, int*, char**); +static char* FormatZero(int*, char**); static int ApproximateLog10(Tcl_WideUInt, int, int); -static int BetterLog10(double, int, int *); -static void ComputeScale(int, int, int *, int *, int *, int *); -static void SetPrecisionLimits(int, int, int *, int *, int *, - int *); -static char * BumpUp(char *, char *, int *); -static int AdjustRange(double *, int); -static char * ShorteningQuickFormat(double, int, int, double, - char *, int *); -static char * StrictQuickFormat(double, int, int, double, - char *, int *); -static char * QuickConversion(double, int, int, int, int, int, int, - int *, char **); -static void CastOutPowersOf2(int *, int *, int *); -static char * ShorteningInt64Conversion(Double *, Tcl_WideUInt, +static int BetterLog10(double, int, int*); +static void ComputeScale(int, int, int*, int*, int*, int*); +static void SetPrecisionLimits(int, int, int*, int*, int*, int*); +static char* BumpUp(char*, char*, int*); +static int AdjustRange(double*, int); +static char* ShorteningQuickFormat(double, int, int, double, + char*, int*); +static char* StrictQuickFormat(double, int, int, double, + char*, int*); +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, int, int, int, int, int, int, int, int, int, - int, int, int *, char **); -static char * StrictInt64Conversion(Tcl_WideUInt, + int, int, int*, char**); +static char* StrictInt64Conversion(Double*, int, 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, mp_int *); -static char * ShorteningBignumConversionPowD(Double *dPtr, - Tcl_WideUInt bw, int b2, int b5, + int, int, int*, char**); +static int ShouldBankerRoundUpPowD(mp_int*, int, int); +static int ShouldBankerRoundUpToNextPowD(mp_int*, mp_int*, + int, int, int, mp_int*); +static char* ShorteningBignumConversionPowD(Double* dPtr, + int convType, 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( + int ilim, int ilim1, int* decpt, + char** endPtr); +static char* StrictBignumConversionPowD(Double* dPtr, int convType, 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); -static char * ShorteningBignumConversion(Double *dPtr, + 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, 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( + int ilim, int ilim1, int* decpt, + char** endPtr); +static char* StrictBignumConversion(Double* dPtr, int convType, Tcl_WideUInt bw, int b2, int s2, int s5, int k, int len, - int ilim, int ilim1, int *decpt, - char **endPtr); -static double BignumToBiasedFrExp(const mp_int *big, int *machexp); + int ilim, int ilim1, int* decpt, + char** endPtr); +static double BignumToBiasedFrExp(mp_int *big, int *machexp); static double Pow10TimesFrExp(int exponent, double fraction, int *machexp); static double SafeLdExp(double fraction, int exponent); -#ifdef IEEE_FLOATING_POINT static Tcl_WideUInt Nokia770Twiddle(Tcl_WideUInt w); -#endif /* *---------------------------------------------------------------------- @@ -399,17 +360,14 @@ static Tcl_WideUInt Nokia770Twiddle(Tcl_WideUInt w); * - TCL_PARSE_SCAN_PREFIXES: ignore the prefixes 0b and 0o that are * not part of the [scan] command's vocabulary. Use only in * combination with TCL_PARSE_INTEGER_ONLY. - * - TCL_PARSE_BINARY_ONLY: parse only in the binary format, whether - * or not a prefix is present that would lead to binary parsing. - * Use only in combination with TCL_PARSE_INTEGER_ONLY. - * - TCL_PARSE_OCTAL_ONLY: parse only in the octal format, whether + * - TCL_PARSE_OCTAL_ONLY: parse only in the octal format, whether * or not a prefix is present that would lead to octal parsing. * Use only in combination with TCL_PARSE_INTEGER_ONLY. - * - TCL_PARSE_HEXADECIMAL_ONLY: parse only in the hexadecimal format, + * - TCL_PARSE_HEXADECIMAL_ONLY: parse only in the hexadecimal format, * whether or not a prefix is present that would lead to * hexadecimal parsing. Use only in combination with * TCL_PARSE_INTEGER_ONLY. - * - TCL_PARSE_DECIMAL_ONLY: parse only in the decimal format, no + * - TCL_PARSE_DECIMAL_ONLY: parse only in the decimal format, no * matter whether a 0 prefix would normally force a different * base. * - TCL_PARSE_NO_WHITESPACE: reject any leading/trailing whitespace @@ -492,7 +450,7 @@ TclParseNumber( { enum State { INITIAL, SIGNUM, ZERO, ZERO_X, - ZERO_O, ZERO_B, ZERO_D, BINARY, + ZERO_O, ZERO_B, BINARY, HEXADECIMAL, OCTAL, BAD_OCTAL, DECIMAL, LEADING_RADIX_POINT, FRACTION, EXPONENT_START, EXPONENT_SIGNUM, EXPONENT, @@ -503,45 +461,45 @@ TclParseNumber( } state = INITIAL; enum State acceptState = INITIAL; - int signum = 0; /* Sign of the number being parsed. */ + int signum = 0; /* Sign of the number being parsed */ Tcl_WideUInt significandWide = 0; /* Significand of the number being parsed (if - * no overflow). */ + * no overflow) */ mp_int significandBig; /* Significand of the number being parsed (if - * it overflows significandWide). */ - int significandOverflow = 0;/* Flag==1 iff significandBig is used. */ + * it overflows significandWide) */ + int significandOverflow = 0;/* Flag==1 iff significandBig is used */ Tcl_WideUInt octalSignificandWide = 0; /* Significand of an octal number; needed * because we don't know whether a number with * a leading zero is octal or decimal until - * we've scanned forward to a '.' or 'e'. */ + * we've scanned forward to a '.' or 'e' */ mp_int octalSignificandBig; /* Significand of octal number once - * octalSignificandWide overflows. */ + * octalSignificandWide overflows */ int octalSignificandOverflow = 0; - /* Flag==1 if octalSignificandBig is used. */ + /* Flag==1 if octalSignificandBig is used */ int numSigDigs = 0; /* Number of significant digits in the decimal - * significand. */ + * significand */ int numTrailZeros = 0; /* Number of trailing zeroes at the current * point in the parse. */ int numDigitsAfterDp = 0; /* Number of digits scanned after the decimal - * point. */ + * point */ int exponentSignum = 0; /* Signum of the exponent of a floating point - * number. */ - long exponent = 0; /* Exponent of a floating point number. */ - const char *p; /* Pointer to next character to scan. */ - size_t len; /* Number of characters remaining after p. */ + * number */ + long exponent = 0; /* Exponent of a floating point number */ + const char *p; /* Pointer to next character to scan */ + size_t len; /* Number of characters remaining after p */ const char *acceptPoint; /* Pointer to position after last character in - * an acceptable number. */ + * an acceptable number */ size_t acceptLen; /* Number of characters following that * point. */ - int status = TCL_OK; /* Status to return to caller. */ + int status = TCL_OK; /* Status to return to caller */ char d = 0; /* Last hexadecimal digit scanned; initialized * to avoid a compiler warning. */ int shift = 0; /* Amount to shift when accumulating binary */ int explicitOctal = 0; - mp_err err = MP_OKAY; -#define MOST_BITS (UWIDE_MAX >> 1) +#define ALL_BITS (~(Tcl_WideUInt)0) +#define MOST_BITS (ALL_BITS >> 1) /* * Initialize bytes to start of the object's string rep if the caller @@ -549,20 +507,6 @@ TclParseNumber( */ if (bytes == NULL) { - if (interp == NULL && endPtrPtr == NULL) { - if (TclHasInternalRep(objPtr, &tclDictType)) { - /* A dict can never be a (single) number */ - return TCL_ERROR; - } - if (TclHasInternalRep(objPtr, &tclListType)) { - int length; - /* A list can only be a (single) number if its length == 1 */ - TclListObjLength(NULL, objPtr, &length); - if (length != 1) { - return TCL_ERROR; - } - } - } bytes = TclGetString(objPtr); } @@ -572,87 +516,6 @@ TclParseNumber( acceptLen = len; while (1) { char c = len ? *p : '\0'; - - /* - * Filter out Numeric Whitespace. Expects: - * - * ::digit:: '_' ::digit:: - * - * Verify current '_' is ok, then move on to next character, - * otherwise follow through on to error. - */ - if (c == '_' && !(flags & TCL_PARSE_NO_UNDERSCORE)) { - const char *before, *after; - - if (p==bytes) { - /* Not allowed at beginning */ - goto endgame; - } - /* - * span multiple numeric whitespace - * V - * example: 5___6 - */ - for (before=(p-1); - (before && *before=='_'); - before=(before>p ? (before-1):NULL)); - for (after=(p+1); - (after && *after && *after=='_'); - after=(*after&&*after=='_')?(after+1):NULL); - - switch (state) { - case ZERO_B: - case BINARY: - if ((before && (*before != '0' && *before != '1')) || - (after && (*after != '0' && *after != '1'))) { - /* Not a valid digit */ - goto endgame; - } - break; - case ZERO_O: - case OCTAL: - if (((before && (*before < '0' || '7' < *before))) || - ((after && (*after < '0' || '7' < *after)))) { - goto endgame; - } - break; - case FRACTION: - case ZERO: - case ZERO_D: - case DECIMAL: - case LEADING_RADIX_POINT: - case EXPONENT_START: - case EXPONENT_SIGNUM: - case EXPONENT: - if ((!before || isdigit(UCHAR(*before))) && - (!after || isdigit(UCHAR(*after)))) { - break; - } - if (after && *after=='(') { - /* could be function */ - goto continue_num; - } - goto endgame; - case ZERO_X: - case HEXADECIMAL: - if ( (!before || isxdigit(UCHAR(*before))) && - (!after || isxdigit(UCHAR(*after)))) { - break; - } - goto endgame; - default: - /* - * Not whitespace, but could be legal for other reasons. - * Continue number processing for current character. - */ - goto continue_num; - } - - /* Valid whitespace found, move on to the next character */ - goto next; - } - - continue_num: switch (state) { case INITIAL: @@ -661,7 +524,7 @@ TclParseNumber( * I, N, and whitespace. */ - if (TclIsSpaceProcM(c)) { + if (TclIsSpaceProc(c)) { if (flags & TCL_PARSE_NO_WHITESPACE) { goto endgame; } @@ -691,8 +554,6 @@ TclParseNumber( break; } else if (flags & TCL_PARSE_HEXADECIMAL_ONLY) { goto zerox; - } else if (flags & TCL_PARSE_BINARY_ONLY) { - goto zerob; } else if (flags & TCL_PARSE_OCTAL_ONLY) { goto zeroo; } else if (isdigit(UCHAR(c))) { @@ -719,18 +580,15 @@ TclParseNumber( case ZERO: /* * Scanned a leading zero (perhaps with a + or -). Acceptable - * inputs are digits, period, X, b, and E. If 8 or 9 is - * encountered, the number can't be octal. This state and the - * OCTAL state differ only in whether they recognize 'X' and 'b'. + * inputs are digits, period, X, b, and E. If 8 or 9 is encountered, + * the number can't be octal. This state and the OCTAL state + * differ only in whether they recognize 'X' and 'b'. */ acceptState = state; acceptPoint = p; acceptLen = len; if (c == 'x' || c == 'X') { - if (flags & (TCL_PARSE_OCTAL_ONLY|TCL_PARSE_BINARY_ONLY)) { - goto endgame; - } state = ZERO_X; break; } @@ -741,25 +599,15 @@ TclParseNumber( goto zeroo; } if (c == 'b' || c == 'B') { - if ((flags & TCL_PARSE_OCTAL_ONLY)) { - goto endgame; - } state = ZERO_B; break; } - if (flags & TCL_PARSE_BINARY_ONLY) { - goto zerob; - } if (c == 'o' || c == 'O') { explicitOctal = 1; state = ZERO_O; break; } - if (c == 'd' || c == 'D') { - state = ZERO_D; - break; - } -#ifdef TCL_NO_DEPRECATED +#ifdef KILL_OCTAL goto decimal; #endif /* FALLTHROUGH */ @@ -791,45 +639,29 @@ TclParseNumber( if (!octalSignificandOverflow) { /* - * Shifting by as many or more bits than are in the - * value being shifted is undefined behavior. Check - * for too large shifts first. + * Shifting by more bits than are in the value being + * shifted is at least de facto nonportable. Check for + * too large shifts first. */ if ((octalSignificandWide != 0) && (((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt)) || (octalSignificandWide > - (UWIDE_MAX >> shift)))) { + (~(Tcl_WideUInt)0 >> shift)))) { octalSignificandOverflow = 1; - err = mp_init_u64(&octalSignificandBig, + TclBNInitBignumFromWideUInt(&octalSignificandBig, octalSignificandWide); } } if (!octalSignificandOverflow) { - /* - * When the significand is 0, it is possible for the - * amount to be shifted to equal or exceed the width - * of the significand. Do not shift when the - * significand is 0 to avoid undefined behavior. - */ - - if (octalSignificandWide != 0) { - octalSignificandWide <<= shift; - } - octalSignificandWide += c - '0'; + octalSignificandWide = + (octalSignificandWide << shift) + (c - '0'); } else { - if (err == MP_OKAY) { - err = mp_mul_2d(&octalSignificandBig, shift, - &octalSignificandBig); - } - if (err == MP_OKAY) { - err = mp_add_d(&octalSignificandBig, (mp_digit)(c - '0'), - &octalSignificandBig); - } - } - if (err != MP_OKAY) { - return TCL_ERROR; + mp_mul_2d(&octalSignificandBig, shift, + &octalSignificandBig); + mp_add_d(&octalSignificandBig, (mp_digit)(c - '0'), + &octalSignificandBig); } } if (numSigDigs != 0) { @@ -858,7 +690,7 @@ TclParseNumber( goto endgame; } -#ifndef TCL_NO_DEPRECATED +#ifndef KILL_OCTAL /* * Scanned a number with a leading zero that contains an 8, 9, @@ -926,41 +758,26 @@ TclParseNumber( shift = 4 * (numTrailZeros + 1); if (!significandOverflow) { /* - * Shifting by as many or more bits than are in the - * value being shifted is undefined behavior. Check - * for too large shifts first. + * Shifting by more bits than are in the value being + * shifted is at least de facto nonportable. Check for too + * large shifts first. */ if (significandWide != 0 && ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) || - significandWide > (UWIDE_MAX >> shift))) { + significandWide > (~(Tcl_WideUInt)0 >> shift))) { significandOverflow = 1; - err = mp_init_u64(&significandBig, + TclBNInitBignumFromWideUInt(&significandBig, significandWide); } } if (!significandOverflow) { - /* - * When the significand is 0, it is possible for the - * amount to be shifted to equal or exceed the width - * of the significand. Do not shift when the - * significand is 0 to avoid undefined behavior. - */ - - if (significandWide != 0) { - significandWide <<= shift; - } - significandWide += d; - } else if (err == MP_OKAY) { - err = mp_mul_2d(&significandBig, shift, &significandBig); - if (err == MP_OKAY) { - err = mp_add_d(&significandBig, (mp_digit) d, &significandBig); - } + significandWide = (significandWide << shift) + d; + } else { + mp_mul_2d(&significandBig, shift, &significandBig); + mp_add_d(&significandBig, (mp_digit) d, &significandBig); } } - if (err != MP_OKAY) { - return TCL_ERROR; - } numTrailZeros = 0; state = HEXADECIMAL; break; @@ -969,9 +786,7 @@ TclParseNumber( acceptState = state; acceptPoint = p; acceptLen = len; - /* FALLTHRU */ case ZERO_B: - zerob: if (c == '0') { numTrailZeros++; state = BINARY; @@ -983,62 +798,37 @@ TclParseNumber( shift = numTrailZeros + 1; if (!significandOverflow) { /* - * Shifting by as many or more bits than are in the - * value being shifted is undefined behavior. Check - * for too large shifts first. + * Shifting by more bits than are in the value being + * shifted is at least de facto nonportable. Check for too + * large shifts first. */ if (significandWide != 0 && ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) || - significandWide > (UWIDE_MAX >> shift))) { + significandWide > (~(Tcl_WideUInt)0 >> shift))) { significandOverflow = 1; - err = mp_init_u64(&significandBig, + TclBNInitBignumFromWideUInt(&significandBig, significandWide); } } if (!significandOverflow) { - /* - * When the significand is 0, it is possible for the - * amount to be shifted to equal or exceed the width - * of the significand. Do not shift when the - * significand is 0 to avoid undefined behavior. - */ - - if (significandWide != 0) { - significandWide <<= shift; - } - significandWide += 1; - } else if (err == MP_OKAY) { - err = mp_mul_2d(&significandBig, shift, &significandBig); - if (err == MP_OKAY) { - err = mp_add_d(&significandBig, (mp_digit) 1, &significandBig); - } + significandWide = (significandWide << shift) + 1; + } else { + mp_mul_2d(&significandBig, shift, &significandBig); + mp_add_d(&significandBig, (mp_digit) 1, &significandBig); } } - if (err != MP_OKAY) { - return TCL_ERROR; - } numTrailZeros = 0; state = BINARY; break; - case ZERO_D: - if (c == '0') { - numTrailZeros++; - } else if ( ! isdigit(UCHAR(c))) { - goto endgame; - } - state = DECIMAL; - flags |= TCL_PARSE_INTEGER_ONLY; - /* FALLTHROUGH */ - case DECIMAL: /* * Scanned an optional + or - followed by a string of decimal * digits. */ -#ifdef TCL_NO_DEPRECATED +#ifdef KILL_OCTAL decimal: #endif acceptState = state; @@ -1248,7 +1038,7 @@ TclParseNumber( } /* FALLTHROUGH */ case sNANPAREN: - if (TclIsSpaceProcM(c)) { + if (TclIsSpaceProc(c)) { break; } if (numSigDigs < 13) { @@ -1276,7 +1066,6 @@ TclParseNumber( acceptLen = len; goto endgame; } - next: p++; len--; } @@ -1294,19 +1083,16 @@ TclParseNumber( } else { /* * Back up to the last accepting state in the lexer. - * If the last char seen is the numeric whitespace character '_', - * backup to that. */ p = acceptPoint; len = acceptLen; - if (!(flags & TCL_PARSE_NO_WHITESPACE)) { /* * Accept trailing whitespace. */ - while (len != 0 && TclIsSpaceProcM(*p)) { + while (len != 0 && TclIsSpaceProc(*p)) { p++; len--; } @@ -1325,14 +1111,13 @@ TclParseNumber( */ if (status == TCL_OK && objPtr != NULL) { - TclFreeInternalRep(objPtr); + TclFreeIntRep(objPtr); switch (acceptState) { case SIGNUM: case BAD_OCTAL: case ZERO_X: case ZERO_O: case ZERO_B: - case ZERO_D: case LEADING_RADIX_POINT: case EXPONENT_START: case EXPONENT_SIGNUM: @@ -1347,35 +1132,24 @@ TclParseNumber( case sNA: case sNANPAREN: case sNANHEX: -#endif Tcl_Panic("TclParseNumber: bad acceptState %d parsing '%s'", acceptState, bytes); +#endif case BINARY: shift = numTrailZeros; if (!significandOverflow && significandWide != 0 && ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) || significandWide > (MOST_BITS + signum) >> shift)) { significandOverflow = 1; - err = mp_init_u64(&significandBig, significandWide); + TclBNInitBignumFromWideUInt(&significandBig, significandWide); } if (shift) { if (!significandOverflow) { - /* - * When the significand is 0, it is possible for the - * amount to be shifted to equal or exceed the width - * of the significand. Do not shift when the - * significand is 0 to avoid undefined behavior. - */ - if (significandWide != 0) { - significandWide <<= shift; - } - } else if (err == MP_OKAY) { - err = mp_mul_2d(&significandBig, shift, &significandBig); + significandWide <<= shift; + } else { + mp_mul_2d(&significandBig, shift, &significandBig); } } - if (err != MP_OKAY) { - return TCL_ERROR; - } goto returnInteger; case HEXADECIMAL: @@ -1388,31 +1162,20 @@ TclParseNumber( ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) || significandWide > (MOST_BITS + signum) >> shift)) { significandOverflow = 1; - err = mp_init_u64(&significandBig, significandWide); + TclBNInitBignumFromWideUInt(&significandBig, significandWide); } if (shift) { if (!significandOverflow) { - /* - * When the significand is 0, it is possible for the - * amount to be shifted to equal or exceed the width - * of the significand. Do not shift when the - * significand is 0 to avoid undefined behavior. - */ - if (significandWide != 0) { - significandWide <<= shift; - } - } else if (err == MP_OKAY) { - err = mp_mul_2d(&significandBig, shift, &significandBig); + significandWide <<= shift; + } else { + mp_mul_2d(&significandBig, shift, &significandBig); } } - if (err != MP_OKAY) { - return TCL_ERROR; - } goto returnInteger; case OCTAL: /* - * Returning an octal integer. Final scaling step. + * Returning an octal integer. Final scaling step */ shift = 3 * numTrailZeros; @@ -1420,49 +1183,52 @@ TclParseNumber( ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) || octalSignificandWide > (MOST_BITS + signum) >> shift)) { octalSignificandOverflow = 1; - err = mp_init_u64(&octalSignificandBig, + TclBNInitBignumFromWideUInt(&octalSignificandBig, octalSignificandWide); } if (shift) { if (!octalSignificandOverflow) { - /* - * When the significand is 0, it is possible for the - * amount to be shifted to equal or exceed the width - * of the significand. Do not shift when the - * significand is 0 to avoid undefined behavior. - */ - if (octalSignificandWide != 0) { - octalSignificandWide <<= shift; - } - } else if (err == MP_OKAY) { - err = mp_mul_2d(&octalSignificandBig, shift, + octalSignificandWide <<= shift; + } else { + mp_mul_2d(&octalSignificandBig, shift, &octalSignificandBig); } } if (!octalSignificandOverflow) { - if ((err == MP_OKAY) && (octalSignificandWide > (MOST_BITS + signum))) { - err = mp_init_u64(&octalSignificandBig, + if (octalSignificandWide > + (Tcl_WideUInt)(((~(unsigned long)0) >> 1) + signum)) { +#ifndef NO_WIDE_TYPE + if (octalSignificandWide <= (MOST_BITS + signum)) { + objPtr->typePtr = &tclWideIntType; + if (signum) { + objPtr->internalRep.wideValue = + - (Tcl_WideInt) octalSignificandWide; + } else { + objPtr->internalRep.wideValue = + (Tcl_WideInt) octalSignificandWide; + } + break; + } +#endif + TclBNInitBignumFromWideUInt(&octalSignificandBig, octalSignificandWide); octalSignificandOverflow = 1; } else { objPtr->typePtr = &tclIntType; if (signum) { - objPtr->internalRep.wideValue = - (Tcl_WideInt)(-octalSignificandWide); + objPtr->internalRep.longValue = + - (long) octalSignificandWide; } else { - objPtr->internalRep.wideValue = - (Tcl_WideInt)octalSignificandWide; + objPtr->internalRep.longValue = + (long) octalSignificandWide; } } } - if ((err == MP_OKAY) && octalSignificandOverflow) { + if (octalSignificandOverflow) { if (signum) { - err = mp_neg(&octalSignificandBig, &octalSignificandBig); + mp_neg(&octalSignificandBig, &octalSignificandBig); } - TclSetBignumInternalRep(objPtr, &octalSignificandBig); - } - if (err != MP_OKAY) { - return TCL_ERROR; + TclSetBignumIntRep(objPtr, &octalSignificandBig); } break; @@ -1470,35 +1236,46 @@ TclParseNumber( case DECIMAL: significandOverflow = AccumulateDecimalDigit(0, numTrailZeros-1, &significandWide, &significandBig, significandOverflow); - if ((err == MP_OKAY) && !significandOverflow && (significandWide > MOST_BITS+signum)) { + if (!significandOverflow && (significandWide > MOST_BITS+signum)) { significandOverflow = 1; - err = mp_init_u64(&significandBig, significandWide); + TclBNInitBignumFromWideUInt(&significandBig, significandWide); } returnInteger: if (!significandOverflow) { - if ((err == MP_OKAY) && (significandWide > MOST_BITS+signum)) { - err = mp_init_u64(&significandBig, + if (significandWide > + (Tcl_WideUInt)(((~(unsigned long)0) >> 1) + signum)) { +#ifndef NO_WIDE_TYPE + if (significandWide <= MOST_BITS+signum) { + objPtr->typePtr = &tclWideIntType; + if (signum) { + objPtr->internalRep.wideValue = + - (Tcl_WideInt) significandWide; + } else { + objPtr->internalRep.wideValue = + (Tcl_WideInt) significandWide; + } + break; + } +#endif + TclBNInitBignumFromWideUInt(&significandBig, significandWide); significandOverflow = 1; } else { objPtr->typePtr = &tclIntType; if (signum) { - objPtr->internalRep.wideValue = - (Tcl_WideInt)(-significandWide); + objPtr->internalRep.longValue = + - (long) significandWide; } else { - objPtr->internalRep.wideValue = - (Tcl_WideInt)significandWide; + objPtr->internalRep.longValue = + (long) significandWide; } } } - if ((err == MP_OKAY) && significandOverflow) { + if (significandOverflow) { if (signum) { - err = mp_neg(&significandBig, &significandBig); + mp_neg(&significandBig, &significandBig); } - TclSetBignumInternalRep(objPtr, &significandBig); - } - if (err != MP_OKAY) { - return TCL_ERROR; + TclSetBignumIntRep(objPtr, &significandBig); } break; @@ -1515,45 +1292,16 @@ TclParseNumber( objPtr->typePtr = &tclDoubleType; if (exponentSignum) { - /* - * At this point exponent>=0, so the following calculation - * cannot underflow. - */ - exponent = -exponent; - } - - /* - * Adjust the exponent for the number of trailing zeros that - * have not been accumulated, and the number of digits after - * the decimal point. Pin any overflow to LONG_MAX/LONG_MIN - * respectively. - */ - - if (exponent >= 0) { - if (exponent - numDigitsAfterDp > LONG_MAX - numTrailZeros) { - exponent = LONG_MAX; - } else { - exponent = exponent - numDigitsAfterDp + numTrailZeros; - } - } else { - if (exponent + numTrailZeros < LONG_MIN + numDigitsAfterDp) { - exponent = LONG_MIN; - } else { - exponent = exponent + numTrailZeros - numDigitsAfterDp; - } + exponent = - exponent; } - - /* - * The desired number is now significandWide * 10**exponent - * or significandBig * 10**exponent, depending on whether - * the significand has overflowed a wide int. - */ if (!significandOverflow) { objPtr->internalRep.doubleValue = MakeLowPrecisionDouble( - signum, significandWide, numSigDigs, exponent); + signum, significandWide, numSigDigs, + (numTrailZeros + exponent - numDigitsAfterDp)); } else { objPtr->internalRep.doubleValue = MakeHighPrecisionDouble( - signum, &significandBig, numSigDigs, exponent); + signum, &significandBig, numSigDigs, + (numTrailZeros + exponent - numDigitsAfterDp)); } break; @@ -1575,7 +1323,7 @@ TclParseNumber( break; #endif case INITIAL: - /* This case only to silence compiler warning. */ + /* This case only to silence compiler warning */ Tcl_Panic("TclParseNumber: state INITIAL can't happen here"); } } @@ -1586,16 +1334,18 @@ TclParseNumber( if (status != TCL_OK) { if (interp != NULL) { - Tcl_Obj *msg = Tcl_ObjPrintf("expected %s but got \"", - expected); + Tcl_Obj *msg; + 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) { Tcl_AppendToObj(msg, " (looks like invalid octal number)", -1); } Tcl_SetObjResult(interp, msg); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", (void *)NULL); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", NULL); } } @@ -1645,7 +1395,7 @@ AccumulateDecimalDigit( Tcl_WideUInt w; /* - * Try wide multiplication first. + * Try wide multiplication first */ if (!bignumFlag) { @@ -1658,20 +1408,17 @@ AccumulateDecimalDigit( *wideRepPtr = digit; return 0; } else if (numZeros >= maxpow10_wide - || w > (UWIDE_MAX-digit)/pow10_wide[numZeros+1]) { + || w > ((~(Tcl_WideUInt)0)-digit)/pow10_wide[numZeros+1]) { /* - * Wide multiplication will overflow. Expand the number to a - * bignum and fall through into the bignum case. + * Wide multiplication will overflow. Expand the + * number to a bignum and fall through into the bignum case. */ - if (mp_init_u64(bignumRepPtr, w) != MP_OKAY) { - return 0; - } + TclBNInitBignumFromWideUInt(bignumRepPtr, w); } else { /* * Wide multiplication. */ - *wideRepPtr = w * pow10_wide[numZeros+1] + digit; return 0; } @@ -1686,37 +1433,32 @@ AccumulateDecimalDigit( * Up to about 8 zeros - single digit multiplication. */ - if ((mp_mul_d(bignumRepPtr, (mp_digit) pow10_wide[numZeros+1], - bignumRepPtr) != MP_OKAY) - || (mp_add_d(bignumRepPtr, (mp_digit) digit, bignumRepPtr) != MP_OKAY)) - return 0; + mp_mul_d(bignumRepPtr, (mp_digit) pow10_wide[numZeros+1], + bignumRepPtr); + mp_add_d(bignumRepPtr, (mp_digit) digit, bignumRepPtr); } else { - mp_err err; /* * More than single digit multiplication. Multiply by the appropriate * small powers of 5, and then shift. Large strings of zeroes are * eaten 256 at a time; this is less efficient than it could be, but - * seems implausible. We presume that MP_DIGIT_BIT is at least 27. The + * seems implausible. We presume that DIGIT_BIT is at least 27. The * first multiplication, by up to 10**7, is done with a one-DIGIT - * multiply (this presumes that MP_DIGIT_BIT >= 24). + * multiply (this presumes that DIGIT_BIT >= 24). */ n = numZeros + 1; - err = mp_mul_d(bignumRepPtr, (mp_digit) pow10_wide[n&0x7], bignumRepPtr); - for (i = 3; (err == MP_OKAY) && (i <= 7); ++i) { + mp_mul_d(bignumRepPtr, (mp_digit) pow10_wide[n&0x7], bignumRepPtr); + for (i=3; i<=7; ++i) { if (n & (1 << i)) { - err = mp_mul(bignumRepPtr, pow5+i, bignumRepPtr); + mp_mul(bignumRepPtr, pow5+i, bignumRepPtr); } } - while ((err == MP_OKAY) && (n >= 256)) { - err = mp_mul(bignumRepPtr, pow5+8, bignumRepPtr); + while (n >= 256) { + mp_mul(bignumRepPtr, pow5+8, bignumRepPtr); n -= 256; } - if ((err != MP_OKAY) - || (mp_mul_2d(bignumRepPtr, (int)(numZeros+1)&~0x7, bignumRepPtr) != MP_OKAY) - || (mp_add_d(bignumRepPtr, (mp_digit) digit, bignumRepPtr) != MP_OKAY)) { - return 0; - } + mp_mul_2d(bignumRepPtr, (int)(numZeros+1)&~0x7, bignumRepPtr); + mp_add_d(bignumRepPtr, (mp_digit) digit, bignumRepPtr); } return 1; @@ -1746,35 +1488,32 @@ MakeLowPrecisionDouble( int signum, /* 1 if the number is negative, 0 otherwise */ Tcl_WideUInt significand, /* Significand of the number */ int numSigDigs, /* Number of digits in the significand */ - long exponent) /* Power of ten */ + int exponent) /* Power of ten */ { - TCL_IEEE_DOUBLE_ROUNDING_DECL - - mp_int significandBig; /* Significand expressed as a bignum. */ + double retval; /* Value of the number */ + mp_int significandBig; /* Significand expressed as a bignum */ /* * With gcc on x86, the floating point rounding mode is double-extended. * This causes the result of double-precision calculations to be rounded * twice: once to the precision of double-extended and then again to the * precision of double. Double-rounding introduces gratuitous errors of 1 - * ulp, so we need to change rounding mode to 53-bits. We also make - * 'retval' volatile, so that it doesn't get promoted to a register. + * ulp, so we need to change rounding mode to 53-bits. */ - volatile double retval; /* Value of the number. */ - /* - * Test for zero significand, which requires explicit construction - * of -0.0. (Unary minus returns a positive zero.) - */ - if (significand == 0) { - return copysign(0.0, -signum); - } +#if defined(__GNUC__) && defined(__i386) + fpu_control_t roundTo53Bits = 0x027f; + fpu_control_t oldRoundingMode; + _FPU_GETCW(oldRoundingMode); + _FPU_SETCW(roundTo53Bits); +#endif +#if defined(__sun) && defined(__i386) && !defined(__GNUC__) + ieee_flags("set","precision","double",NULL); +#endif /* - * Set the FP control word for 53 bits, WARNING: It must be reset - * before returning. + * Test for the easy cases. */ - TCL_IEEE_DOUBLE_ROUNDING; if (numSigDigs <= QUICK_MAX) { if (exponent >= 0) { @@ -1785,12 +1524,10 @@ MakeLowPrecisionDouble( * without special handling. */ - retval = (double) - ((Tcl_WideInt)significand * pow10vals[exponent]); + retval = (double)(Tcl_WideInt)significand * pow10vals[exponent]; goto returnValue; } else { int diff = QUICK_MAX - numSigDigs; - if (exponent-diff <= mmaxpow) { /* * 10**exponent is not an exact integer, but @@ -1799,8 +1536,8 @@ MakeLowPrecisionDouble( * with only one roundoff. */ - volatile double factor = (double) - ((Tcl_WideInt)significand * pow10vals[diff]); + volatile double factor = + (double)(Tcl_WideInt)significand * pow10vals[diff]; retval = factor * pow10vals[exponent-diff]; goto returnValue; } @@ -1813,21 +1550,18 @@ MakeLowPrecisionDouble( * only one rounding. */ - retval = (double) - ((Tcl_WideInt)significand / pow10vals[-exponent]); + retval = (double)(Tcl_WideInt)significand / pow10vals[-exponent]; goto returnValue; } } } /* - * All the easy cases have failed. Promote the significand to bignum and + * All the easy cases have failed. Promote ths significand to bignum and * call MakeHighPrecisionDouble to do it the hard way. */ - if (mp_init_u64(&significandBig, significand) != MP_OKAY) { - return 0.0; - } + TclBNInitBignumFromWideUInt(&significandBig, significand); retval = MakeHighPrecisionDouble(0, &significandBig, numSigDigs, exponent); mp_clear(&significandBig); @@ -1845,7 +1579,12 @@ MakeLowPrecisionDouble( * On gcc on x86, restore the floating point mode word. */ - TCL_DEFAULT_DOUBLE_ROUNDING; +#if defined(__GNUC__) && defined(__i386) + _FPU_SETCW(oldRoundingMode); +#endif +#if defined(__sun) && defined(__i386) && !defined(__GNUC__) + ieee_flags("clear","precision",NULL,NULL); +#endif return retval; } @@ -1873,46 +1612,39 @@ MakeHighPrecisionDouble( int signum, /* 1=negative, 0=nonnegative */ mp_int *significand, /* Exact significand of the number */ int numSigDigs, /* Number of significant digits */ - long exponent) /* Power of 10 by which to multiply */ + int exponent) /* Power of 10 by which to multiply */ { - TCL_IEEE_DOUBLE_ROUNDING_DECL - - int machexp = 0; /* Machine exponent of a power of 10. */ + double retval; + int machexp; /* Machine exponent of a power of 10 */ /* * With gcc on x86, the floating point rounding mode is double-extended. * This causes the result of double-precision calculations to be rounded * twice: once to the precision of double-extended and then again to the * precision of double. Double-rounding introduces gratuitous errors of 1 - * ulp, so we need to change rounding mode to 53-bits. We also make - * 'retval' volatile to make sure that it doesn't get promoted to a - * register. + * ulp, so we need to change rounding mode to 53-bits. */ - volatile double retval; - /* - * A zero significand requires explicit construction of -0.0. - * (Unary minus returns positive zero.) - */ - if (mp_iszero(significand)) { - return copysign(0.0, -signum); - } +#if defined(__GNUC__) && defined(__i386) + fpu_control_t roundTo53Bits = 0x027f; + fpu_control_t oldRoundingMode; + _FPU_GETCW(oldRoundingMode); + _FPU_SETCW(roundTo53Bits); +#endif +#if defined(__sun) && defined(__i386) && !defined(__GNUC__) + ieee_flags("set","precision","double",NULL); +#endif /* - * Set the 53-bit rounding mode. WARNING: It must be reset before - * returning. + * Quick checks for over/underflow. */ - TCL_IEEE_DOUBLE_ROUNDING; - /* - * Make quick checks for over/underflow. Be careful to avoid - * integer overflow when calculating with 'exponent'. - */ - if (exponent >= 0 && exponent-1 > maxDigits-numSigDigs) { + if (numSigDigs+exponent-1 > maxDigits) { retval = HUGE_VAL; goto returnValue; - } else if (exponent < 0 && numSigDigs+exponent < minDigits+1) { - retval = 0.0; + } + if (numSigDigs+exponent-1 < minDigits) { + retval = 0; goto returnValue; } @@ -1932,9 +1664,9 @@ MakeHighPrecisionDouble( goto returnValue; } retval = SafeLdExp(retval, machexp); - if (tiny == 0.0) { - tiny = SafeLdExp(1.0, DBL_MIN_EXP * log2FLT_RADIX - mantBits); - } + if (tiny == 0.0) { + tiny = SafeLdExp(1.0, DBL_MIN_EXP * log2FLT_RADIX - mantBits); + } if (retval < tiny) { retval = tiny; } @@ -1960,8 +1692,12 @@ MakeHighPrecisionDouble( * On gcc on x86, restore the floating point mode word. */ - TCL_DEFAULT_DOUBLE_ROUNDING; - +#if defined(__GNUC__) && defined(__i386) + _FPU_SETCW(oldRoundingMode); +#endif +#if defined(__sun) && defined(__i386) && !defined(__GNUC__) + ieee_flags("clear","precision",NULL,NULL); +#endif return retval; } @@ -1980,8 +1716,8 @@ MakeHighPrecisionDouble( #ifdef IEEE_FLOATING_POINT static double MakeNaN( - int signum, /* Sign bit (1=negative, 0=nonnegative. */ - Tcl_WideUInt tags) /* Tag bits to put in the NaN. */ + int signum, /* Sign bit (1=negative, 0=nonnegative */ + Tcl_WideUInt tags) /* Tag bits to put in the NaN */ { union { Tcl_WideUInt iv; @@ -2019,41 +1755,37 @@ MakeNaN( static double RefineApproximation( - double approxResult, /* Approximate result of conversion. */ - mp_int *exactSignificand, /* Integer significand. */ - int exponent) /* Power of 10 to multiply by significand. */ + double approxResult, /* Approximate result of conversion */ + mp_int *exactSignificand, /* Integer significand */ + int exponent) /* Power of 10 to multiply by significand */ { int M2, M5; /* Powers of 2 and of 5 needed to put the * decimal and binary numbers over a common * denominator. */ - double significand; /* Sigificand of the binary number. */ - int binExponent; /* Exponent of the binary number. */ + double significand; /* Sigificand of the binary number */ + int binExponent; /* Exponent of the binary number */ int msb; /* Most significant bit position of an - * intermediate result. */ + * intermediate result */ int nDigits; /* Number of mp_digit's in an intermediate - * result. */ + * result */ mp_int twoMv; /* Approx binary value expressed as an exact - * integer scaled by the multiplier 2M. */ + * integer scaled by the multiplier 2M */ mp_int twoMd; /* Exact decimal value expressed as an exact - * integer scaled by the multiplier 2M. */ - int scale; /* Scale factor for M. */ - int multiplier; /* Power of two to scale M. */ + * integer scaled by the multiplier 2M */ + int scale; /* Scale factor for M */ + int multiplier; /* Power of two to scale M */ double num, den; /* Numerator and denominator of the correction - * term. */ - double quot; /* Correction term. */ + * term */ + double quot; /* Correction term */ double minincr; /* Lower bound on the absolute value of the * correction term. */ int roundToEven = 0; /* Flag == TRUE if we need to invoke * "round to even" functionality */ double rteSignificand; /* Significand of the round-to-even result */ int rteExponent; /* Exponent of the round-to-even result */ - int shift; /* Shift count for converting numerator - * and denominator of corrector to floating - * point */ Tcl_WideInt rteSigWide; /* Wide integer version of the significand * for testing evenness */ int i; - mp_err err = MP_OKAY; /* * The first approximation is always low. If we find that it's HUGE_VAL, @@ -2063,22 +1795,13 @@ RefineApproximation( if (approxResult == HUGE_VAL) { return approxResult; } - significand = frexp(approxResult, &binExponent); /* - * We are trying to compute a corrector term that, when added to the - * approximate result, will yield close to the exact result. - * The exact result is exactSignificand * 10**exponent. - * The approximate result is significand * 2**binExponent - * If exponent<0, we need to multiply the exact value by 10**-exponent - * to make it an integer, plus another factor of 2 to decide on rounding. - * Similarly if binExponent<FP_PRECISION, we need - * to multiply by 2**FP_PRECISION to make the approximate value an integer. - * - * Let M = 2**M2 * 5**M5 be the least common multiple of these two - * multipliers. + * Find a common denominator for the decimal and binary fractions. The + * common denominator will be 2**M2 + 5**M5. */ + significand = frexp(approxResult, &binExponent); i = mantBits - binExponent; if (i < 0) { M2 = 0; @@ -2089,153 +1812,102 @@ RefineApproximation( M5 = 0; } else { M5 = -exponent; - if (M5 - 1 > M2) { - M2 = M5 - 1; + if ((M5-1) > M2) { + M2 = M5-1; } } /* - * Compute twoMv as 2*M*v, where v is the approximate value. - * This is done by bit-whacking to calculate 2**(M2+1)*significand, - * and then multiplying by 5**M5. + * The floating point number is significand*2**binExponent. Compute the + * large integer significand*2**(binExponent+M2+1). The 2**-1 bit of the + * significand (the most significant) corresponds to the + * 2**(binExponent+M2 + 1) bit of 2*M2*v. Allocate enough digits to hold + * that quantity, then convert the significand to a large integer, scaled + * appropriately. Then multiply by the appropriate power of 5. */ msb = binExponent + M2; /* 1008 */ - nDigits = msb / MP_DIGIT_BIT + 1; - if (mp_init_size(&twoMv, nDigits) != MP_OKAY) { - return approxResult; - } - i = (msb % MP_DIGIT_BIT + 1); + nDigits = msb / DIGIT_BIT + 1; + mp_init_size(&twoMv, nDigits); + i = (msb % DIGIT_BIT + 1); twoMv.used = nDigits; significand *= SafeLdExp(1.0, i); while (--nDigits >= 0) { twoMv.dp[nDigits] = (mp_digit) significand; significand -= (mp_digit) significand; - significand = SafeLdExp(significand, MP_DIGIT_BIT); + significand = SafeLdExp(significand, DIGIT_BIT); } for (i = 0; i <= 8; ++i) { - if (M5 & (1 << i) && (mp_mul(&twoMv, pow5+i, &twoMv) != MP_OKAY)) { - mp_clear(&twoMv); - return approxResult; + if (M5 & (1 << i)) { + mp_mul(&twoMv, pow5+i, &twoMv); } } /* - * Compute twoMd as 2*M*d, where d is the exact value. - * This is done by multiplying by 5**(M5+exponent) and then multiplying - * by 2**(M5+exponent+1), which is, of course, a left shift. + * Collect the decimal significand as a high precision integer. The least + * significant bit corresponds to bit M2+exponent+1 so it will need to be + * shifted left by that many bits after being multiplied by + * 5**(M5+exponent). */ - if (mp_init_copy(&twoMd, exactSignificand) != MP_OKAY) { - mp_clear(&twoMv); - return approxResult; - } - for (i = 0; (i <= 8); ++i) { - if ((M5 + exponent) & (1 << i)) { - err = mp_mul(&twoMd, pow5+i, &twoMd); + mp_init_copy(&twoMd, exactSignificand); + for (i=0; i<=8; ++i) { + if ((M5+exponent) & (1 << i)) { + mp_mul(&twoMd, pow5+i, &twoMd); } } - if (err == MP_OKAY) { - err = mp_mul_2d(&twoMd, M2+exponent+1, &twoMd); - } - - /* - * Now let twoMd = twoMd - twoMv, the difference between the exact and - * approximate values. - */ - - if (err == MP_OKAY) { - err = mp_sub(&twoMd, &twoMv, &twoMd); - } + mp_mul_2d(&twoMd, M2+exponent+1, &twoMd); + mp_sub(&twoMd, &twoMv, &twoMd); /* * The result, 2Mv-2Md, needs to be divided by 2M to yield a correction * term. Because 2M may well overflow a double, we need to scale the - * denominator by a factor of 2**binExponent-mantBits. Place that factor - * times 1/2 ULP into twoMd. + * denominator by a factor of 2**binExponent-mantBits */ scale = binExponent - mantBits - 1; - mp_set_u64(&twoMv, 1); - for (i = 0; (i <= 8) && (err == MP_OKAY); ++i) { + + mp_set(&twoMv, 1); + for (i=0; i<=8; ++i) { if (M5 & (1 << i)) { - err = mp_mul(&twoMv, pow5+i, &twoMv); + mp_mul(&twoMv, pow5+i, &twoMv); } } multiplier = M2 + scale + 1; - if (err != MP_OKAY) { - mp_clear(&twoMd); - mp_clear(&twoMv); - return approxResult; - } else if (multiplier > 0) { - err = mp_mul_2d(&twoMv, multiplier, &twoMv); + if (multiplier > 0) { + mp_mul_2d(&twoMv, multiplier, &twoMv); } else if (multiplier < 0) { - err = mp_div_2d(&twoMv, -multiplier, &twoMv, NULL); - } - if (err != MP_OKAY) { - mp_clear(&twoMd); - mp_clear(&twoMv); - return approxResult; + mp_div_2d(&twoMv, -multiplier, &twoMv, NULL); } - /* - * Will the eventual correction term be less than, equal to, or - * greater than 1/2 ULP? - */ - switch (mp_cmp_mag(&twoMd, &twoMv)) { case MP_LT: /* - * If the error is less than 1/2 ULP, there's no correction to make. + * If the result is less than unity, the error is less than 1/2 unit in + * the last place, so there's no correction to make. */ - mp_clear(&twoMd); - mp_clear(&twoMv); + mp_clear(&twoMd); + mp_clear(&twoMv); return approxResult; case MP_EQ: /* - * If the error is exactly 1/2 ULP, we need to round to even. + * If the result is exactly unity, we need to round to even. */ roundToEven = 1; break; case MP_GT: - /* - * We need to correct the result if the error exceeds 1/2 ULP. - */ break; } - /* - * If we're in the 'round to even' case, and the significand is already - * even, we're done. Return the approximate result. - */ if (roundToEven) { rteSignificand = frexp(approxResult, &rteExponent); - rteSigWide = (Tcl_WideInt)ldexp(rteSignificand, FP_PRECISION); + rteSigWide = (Tcl_WideInt) ldexp(rteSignificand, FP_PRECISION); if ((rteSigWide & 1) == 0) { - mp_clear(&twoMd); - mp_clear(&twoMv); return approxResult; } } /* - * Reduce the numerator and denominator of the corrector term so that - * they will fit in the floating point precision. - */ - shift = mp_count_bits(&twoMv) - FP_PRECISION - 1; - if (shift > 0) { - err = mp_div_2d(&twoMv, shift, &twoMv, NULL); - if (err == MP_OKAY) { - err = mp_div_2d(&twoMd, shift, &twoMd, NULL); - } - } - if (err != MP_OKAY) { - mp_clear(&twoMd); - mp_clear(&twoMv); - return approxResult; - } - - /* * Convert the numerator and denominator of the corrector term accurately * to floating point numbers. */ @@ -2259,55 +1931,51 @@ RefineApproximation( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * MultPow5 -- * * Multiply a bignum by a power of 5. * * Side effects: - * Stores base*5**n in result. + * Stores base*5**n in result * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline mp_err -MulPow5( - mp_int *base, /* Number to multiply. */ - unsigned n, /* Power of 5 to multiply by. */ - mp_int *result) /* Place to store the result. */ +inline static void +MulPow5(mp_int* base, /* Number to multiply */ + unsigned n, /* Power of 5 to multiply by */ + mp_int* result) /* Place to store the result */ { - mp_int *p = base; + mp_int* p = base; int n13 = n / 13; int r = n % 13; - mp_err err = MP_OKAY; - if (r != 0) { - err = mp_mul_d(p, dpow5[r], result); + mp_mul_d(p, dpow5[r], result); p = result; } r = 0; - while ((err == MP_OKAY) && (n13 != 0)) { + while (n13 != 0) { if (n13 & 1) { - err = mp_mul(p, pow5_13+r, result); + mp_mul(p, pow5_13+r, result); p = result; } n13 >>= 1; ++r; } - if ((err == MP_OKAY) && (p != result)) { - err = mp_copy(p, result); + if (p != result) { + mp_copy(p, result); } - return err; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * NormalizeRightward -- * - * Shifts a number rightward until it is odd (that is, until the least - * significant bit is nonzero. + * Shifts a number rightward until it is odd (that is, until the + * least significant bit is nonzero. * * Results: * Returns the number of bit positions by which the number was shifted. @@ -2315,26 +1983,25 @@ MulPow5( * Side effects: * Shifts the number in place; *wPtr is replaced by the shifted number. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -NormalizeRightward( - Tcl_WideUInt *wPtr) /* INOUT: Number to shift. */ +inline static int +NormalizeRightward(Tcl_WideUInt* wPtr) + /* INOUT: Number to shift */ { int rv = 0; Tcl_WideUInt w = *wPtr; - - if (!(w & (Tcl_WideUInt) 0xFFFFFFFF)) { + if (!(w & (Tcl_WideUInt) 0xffffffff)) { w >>= 32; rv += 32; } - if (!(w & (Tcl_WideUInt) 0xFFFF)) { + if (!(w & (Tcl_WideUInt) 0xffff)) { w >>= 16; rv += 16; } - if (!(w & (Tcl_WideUInt) 0xFF)) { + if (!(w & (Tcl_WideUInt) 0xff)) { w >>= 8; rv += 8; } - if (!(w & (Tcl_WideUInt) 0xF)) { + if (!(w & (Tcl_WideUInt) 0xf)) { w >>= 4; rv += 4; } if (!(w & 0x3)) { @@ -2346,43 +2013,42 @@ NormalizeRightward( *wPtr = w; return rv; } - + /* - *---------------------------------------------------------------------- + *-----------------------------------------------------------------------------0 * * RequiredPrecision -- * - * Determines the number of bits needed to hold an integer. + * Determines the number of bits needed to hold an intger. * * Results: - * Returns the position of the most significant bit (0 - 63). Returns 0 - * if the number is zero. + * Returns the position of the most significant bit (0 - 63). + * Returns 0 if the number is zero. * - *---------------------------------------------------------------------- + *---------------------------------------------------------------------------- */ static int -RequiredPrecision( - Tcl_WideUInt w) /* Number to interrogate. */ +RequiredPrecision(Tcl_WideUInt w) + /* Number to interrogate */ { int rv; unsigned long wi; - - if (w & ((Tcl_WideUInt) 0xFFFFFFFF << 32)) { + if (w & ((Tcl_WideUInt) 0xffffffff << 32)) { wi = (unsigned long) (w >> 32); rv = 32; } else { wi = (unsigned long) w; rv = 0; } - if (wi & 0xFFFF0000) { + if (wi & 0xffff0000) { wi >>= 16; rv += 16; } - if (wi & 0xFF00) { + if (wi & 0xff00) { wi >>= 8; rv += 8; } - if (wi & 0xF0) { + if (wi & 0xf0) { wi >>= 4; rv += 4; } - if (wi & 0xC) { + if (wi & 0xc) { wi >>= 2; rv += 2; } if (wi & 0x2) { @@ -2393,40 +2059,38 @@ RequiredPrecision( } return rv; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * DoubleToExpAndSig -- * * Separates a 'double' into exponent and significand. * * Side effects: - * Stores the significand in '*significand' and the exponent in '*expon' - * so that dv == significand * 2.0**expon, and significand is odd. Also - * stores the position of the leftmost 1-bit in 'significand' in 'bits'. + * Stores the significand in '*significand' and the exponent in + * '*expon' so that dv == significand * 2.0**expon, and significand + * is odd. Also stores the position of the leftmost 1-bit in 'significand' + * in 'bits'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline void -DoubleToExpAndSig( - double dv, /* Number to convert. */ - Tcl_WideUInt *significand, /* OUTPUT: Significand of the number. */ - int *expon, /* OUTPUT: Exponent to multiply the number - * by. */ - int *bits) /* OUTPUT: Number of significant bits. */ +inline static void +DoubleToExpAndSig(double dv, /* Number to convert */ + Tcl_WideUInt* significand, + /* OUTPUT: Significand of the number */ + int* expon, /* OUTPUT: Exponent to multiply the number by */ + int* bits) /* OUTPUT: Number of significant bits */ { - Double d; /* Number being converted. */ - Tcl_WideUInt z; /* Significand under construction. */ - int de; /* Exponent of the number. */ - int k; /* Bit count. */ + Double d; /* Number being converted */ + Tcl_WideUInt z; /* Significand under construction */ + int de; /* Exponent of the number */ + int k; /* Bit count */ d.d = dv; - /* - * Extract exponent and significand. - */ + /* Extract exponent and significand */ de = (d.w.word0 & EXP_MASK) >> EXP_SHIFT; z = d.q & SIG_MASK; @@ -2442,25 +2106,24 @@ DoubleToExpAndSig( } *significand = z; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * TakeAbsoluteValue -- * * Takes the absolute value of a 'double' including 0, Inf and NaN * * Side effects: - * The 'double' in *d is replaced with its absolute value. The signum is - * stored in 'sign': 1 for negative, 0 for nonnegative. + * The 'double' in *d is replaced with its absolute value. The + * signum is stored in 'sign': 1 for negative, 0 for nonnegative. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline void -TakeAbsoluteValue( - Double *d, /* Number to replace with absolute value. */ - int *sign) /* Place to put the signum. */ +inline static void +TakeAbsoluteValue(Double* d, /* Number to replace with absolute value */ + int* sign) /* Place to put the signum */ { if (d->w.word0 & SIGN_BIT) { *sign = 1; @@ -2469,42 +2132,41 @@ TakeAbsoluteValue( *sign = 0; } } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * FormatInfAndNaN -- * * Bailout for formatting infinities and Not-A-Number. * * Results: - * Returns one of the strings 'Infinity' and 'NaN'. The string returned - * must be freed by the caller using 'ckfree'. + * Returns one of the strings 'Infinity' and 'NaN'. * * Side effects: - * Stores 9999 in *decpt, and sets '*endPtr' to designate the terminating - * NUL byte of the string if 'endPtr' is not NULL. + * Stores 9999 in *decpt, and sets '*endPtr' to designate the + * terminating NUL byte of the string if 'endPtr' is not NULL. * - *---------------------------------------------------------------------- + * The string returned must be freed by the caller using 'ckfree'. + * + *----------------------------------------------------------------------------- */ -static inline char * -FormatInfAndNaN( - Double *d, /* Exceptional number to format. */ - int *decpt, /* Decimal point to set to a bogus value. */ - char **endPtr) /* Pointer to the end of the formatted data */ +inline static char* +FormatInfAndNaN(Double* d, /* Exceptional number to format */ + int* decpt, /* Decimal point to set to a bogus value */ + char** endPtr) /* Pointer to the end of the formatted data */ { - char *retval; - + char* retval; *decpt = 9999; if (!(d->w.word1) && !(d->w.word0 & HI_ORDER_SIG_MASK)) { - retval = (char *)ckalloc(9); + retval = ckalloc(9); strcpy(retval, "Infinity"); if (endPtr) { *endPtr = retval + 8; } } else { - retval = (char *)ckalloc(4); + retval = ckalloc(4); strcpy(retval, "NaN"); if (endPtr) { *endPtr = retval + 3; @@ -2512,9 +2174,9 @@ FormatInfAndNaN( } return retval; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * FormatZero -- * @@ -2527,16 +2189,14 @@ FormatInfAndNaN( * Stores 1 in '*decpt' and puts a pointer to the NUL byte terminating * the string in '*endPtr' if 'endPtr' is not NULL. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -FormatZero( - int *decpt, /* Location of the decimal point. */ - char **endPtr) /* Pointer to the end of the formatted data */ +inline static char* +FormatZero(int* decpt, /* Location of the decimal point */ + char** endPtr) /* Pointer to the end of the formatted data */ { - char *retval = (char *)ckalloc(2); - + char* retval = ckalloc(2); strcpy(retval, "0"); if (endPtr) { *endPtr = retval+1; @@ -2544,31 +2204,31 @@ FormatZero( *decpt = 0; return retval; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ApproximateLog10 -- * - * Computes a two-term Taylor series approximation to the common log of a - * number, and computes the number's binary log. + * Computes a two-term Taylor series approximation to the common + * log of a number, and computes the number's binary log. * * Results: - * Return an approximation to floor(log10(bw*2**be)) that is either exact - * or 1 too high. + * Return an approximation to floor(log10(bw*2**be)) that is either + * exact or 1 too high. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -ApproximateLog10( - Tcl_WideUInt bw, /* Integer significand of the number. */ - int be, /* Power of two to scale bw. */ - int bbits) /* Number of bits of precision in bw. */ +inline static int +ApproximateLog10(Tcl_WideUInt bw, + /* Integer significand of the number */ + int be, /* Power of two to scale bw */ + int bbits) /* Number of bits of precision in bw */ { - int i; /* Log base 2 of the number. */ + int i; /* Log base 2 of the number */ int k; /* Floor(Log base 10 of the number) */ - double ds; /* Mantissa of the number. */ + double ds; /* Mantissa of the number */ Double d2; /* @@ -2582,16 +2242,17 @@ ApproximateLog10( d2.w.word0 |= (EXPONENT_BIAS) << EXP_SHIFT; i = be + bbits - 1; ds = (d2.d - 1.5) * TWO_OVER_3LOG10 - + LOG10_3HALVES_PLUS_FUDGE + LOG10_2 * i; + + LOG10_3HALVES_PLUS_FUDGE + + LOG10_2 * i; k = (int) ds; if (k > ds) { --k; } return k; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * BetterLog10 -- * @@ -2599,27 +2260,24 @@ ApproximateLog10( * 1 .. 10**(TEN_PMAX)-1 * * Side effects: - * Sets k_check to 0 if the new result is known to be exact, and to 1 if - * it may still be one too high. + * Sets k_check to 0 if the new result is known to be exact, and to + * 1 if it may still be one too high. * * Results: - * Returns the improved approximation to log10(d). + * Returns the improved approximation to log10(d) * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -BetterLog10( - double d, /* Original number to format. */ - int k, /* Characteristic(Log base 10) of the - * number. */ - int *k_check) /* Flag == 1 if k is inexact. */ +inline static int +BetterLog10(double d, /* Original number to format */ + int k, /* Characteristic(Log base 10) of the number */ + int* k_check) /* Flag == 1 if k is inexact */ { /* - * Performance hack. If k is in the range 0..TEN_PMAX, then we can use a - * powers-of-ten table to check it. + * Performance hack. If k is in the range 0..TEN_PMAX, then we can + * use a powers-of-ten table to check it. */ - if (k >= 0 && k <= TEN_PMAX) { if (d < tens[k]) { k--; @@ -2630,41 +2288,40 @@ BetterLog10( } return k; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ComputeScale -- * * Prepares to format a floating-point number as decimal. * * Parameters: - * floor(log10*x) is k (or possibly k-1). floor(log2(x) is i. The - * significand of x requires bbits bits to represent. + * floor(log10*x) is k (or possibly k-1). floor(log2(x) is i. + * The significand of x requires bbits bits to represent. * * Results: * Determines integers b2, b5, s2, s5 so that sig*2**b2*5**b5/2**s2*2**s5 - * exactly represents the value of the x/10**k. This value will lie in - * the range [1 .. 10), and allows for computing successive digits by - * multiplying sig%10 by 10. + * exactly represents the value of the x/10**k. This value will lie + * in the range [1 .. 10), and allows for computing successive digits + * by multiplying sig%10 by 10. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline void -ComputeScale( - int be, /* Exponent part of number: d = bw * 2**be. */ - int k, /* Characteristic of log10(number). */ - int *b2, /* OUTPUT: Power of 2 in the numerator. */ - int *b5, /* OUTPUT: Power of 5 in the numerator. */ - int *s2, /* OUTPUT: Power of 2 in the denominator. */ - int *s5) /* OUTPUT: Power of 5 in the denominator. */ +inline static void +ComputeScale(int be, /* Exponent part of number: d = bw * 2**be */ + int k, /* Characteristic of log10(number) */ + int* b2, /* OUTPUT: Power of 2 in the numerator */ + int* b5, /* OUTPUT: Power of 5 in the numerator */ + int* s2, /* OUTPUT: Power of 2 in the denominator */ + int* s5) /* OUTPUT: Power of 5 in the denominator */ { + /* - * Scale numerator and denominator powers of 2 so that the input binary - * number is the ratio of integers. + * Scale numerator and denominator powers of 2 so that the + * input binary number is the ratio of integers */ - if (be <= 0) { *b2 = 0; *s2 = -be; @@ -2674,10 +2331,9 @@ ComputeScale( } /* - * Scale numerator and denominator so that the output decimal number is - * the ratio of integers. + * Scale numerator and denominator so that the output decimal number + * is the ratio of integers */ - if (k >= 0) { *b5 = 0; *s5 = k; @@ -2690,44 +2346,55 @@ ComputeScale( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * SetPrecisionLimits -- * - * Determines how many digits of significance should be computed (and, - * hence, how much memory need be allocated) for formatting a floating - * point number. + * Determines how many digits of significance should be computed + * (and, hence, how much memory need be allocated) for formatting a + * floating point number. * * Given that 'k' is floor(log10(x)): - * if 'shortest' format is used, there will be at most 18 digits in the - * result. + * if 'shortest' format is used, there will be at most 18 digits in the result. * if 'F' format is used, there will be at most 'ndigits' + k + 1 digits * if 'E' format is used, there will be exactly 'ndigits' digits. * * Side effects: - * Adjusts '*ndigitsPtr' to have a valid value. Stores the maximum memory - * allocation needed in *iPtr. Sets '*iLimPtr' to the limiting number of - * digits to convert if k has been guessed correctly, and '*iLim1Ptr' to - * the limiting number of digits to convert if k has been guessed to be - * one too high. + * Adjusts '*ndigitsPtr' to have a valid value. + * Stores the maximum memory allocation needed in *iPtr. + * Sets '*iLimPtr' to the limiting number of digits to convert if k + * has been guessed correctly, and '*iLim1Ptr' to the limiting number + * of digits to convert if k has been guessed to be one too high. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline void -SetPrecisionLimits( - 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). */ - int *iPtr, /* OUT: Maximum number of digits to return. */ - int *iLimPtr, /* OUT: Number of digits of significance if - * the bignum method is used.*/ - int *iLim1Ptr) /* OUT: Number of digits of significance if - * the quick method is used. */ +inline static void +SetPrecisionLimits(int convType, + /* Type of conversion: + * TCL_DD_SHORTEST + * TCL_DD_STEELE0 + * 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) */ + int* iPtr, /* OUT: Maximum number of digits + * to return */ + int *iLimPtr,/* OUT: Number of digits of significance + * if the bignum method is used.*/ + int *iLim1Ptr) + /* OUT: Number of digits of significance + * if the quick method is used. */ { - switch (flags & TCL_DD_CONVERSION_TYPE_MASK) { + switch(convType) { + case TCL_DD_SHORTEST0: + case TCL_DD_STEELE0: + *iLimPtr = *iLim1Ptr = -1; + *iPtr = 18; + *ndigitsPtr = 0; + break; case TCL_DD_E_FORMAT: if (*ndigitsPtr <= 0) { *ndigitsPtr = 1; @@ -2743,37 +2410,37 @@ SetPrecisionLimits( } break; default: - *iLimPtr = *iLim1Ptr = -1; - *iPtr = 18; - *ndigitsPtr = 0; - break; + *iPtr = -1; + *iLimPtr = -1; + *iLim1Ptr = -1; + Tcl_Panic("impossible conversion type in TclDoubleDigits"); } } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * BumpUp -- * - * Increases a string of digits ending in a series of nines to designate - * the next higher number. xxxxb9999... -> xxxx(b+1)0000... + * Increases a string of digits ending in a series of nines to + * designate the next higher number. xxxxb9999... -> xxxx(b+1)0000... * * Results: * Returns a pointer to the end of the adjusted string. * * Side effects: - * In the case that the string consists solely of '999999', sets it to - * "1" and moves the decimal point (*kPtr) one place to the right. + * In the case that the string consists solely of '999999', sets it + * to "1" and moves the decimal point (*kPtr) one place to the right. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -BumpUp( - char *s, /* Cursor pointing one past the end of the - * string. */ - char *retval, /* Start of the string of digits. */ - int *kPtr) /* Position of the decimal point. */ + +inline static char* +BumpUp(char* s, /* Cursor pointing one past the end of the + * string */ + char* retval, /* Start of the string of digits */ + int* kPtr) /* Position of the decimal point */ { while (*--s == '9') { if (s == retval) { @@ -2788,28 +2455,27 @@ BumpUp( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * AdjustRange -- * - * Rescales a 'double' in preparation for formatting it using the 'quick' - * double-to-string method. + * Rescales a 'double' in preparation for formatting it using the + * 'quick' double-to-string method. * * Results: - * Returns the precision that has been lost in the prescaling as a count - * of units in the least significant place. + * Returns the precision that has been lost in the prescaling as + * a count of units in the least significant place. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -AdjustRange( - double *dPtr, /* INOUT: Number to adjust. */ - int k) /* IN: floor(log10(d)) */ +inline static int +AdjustRange(double* dPtr, /* INOUT: Number to adjust */ + int k) /* IN: floor(log10(d)) */ { int ieps; /* Number of roundoff errors that have - * accumulated. */ - double d = *dPtr; /* Number to adjust. */ + * accumulated */ + double d = *dPtr; /* Number to adjust */ double ds; int i, j, j1; @@ -2819,8 +2485,7 @@ AdjustRange( /* * The number must be reduced to bring it into range. */ - - ds = tens[k & 0xF]; + ds = tens[k & 0xf]; j = k >> 4; if (j & BLETCH) { j &= (BLETCH-1); @@ -2838,10 +2503,9 @@ AdjustRange( d /= ds; } else if ((j1 = -k) != 0) { /* - * The number must be increased to bring it into range. + * The number must be increased to bring it into range */ - - d *= tens[j1 & 0xF]; + d *= tens[j1 & 0xf]; i = 0; for (j = j1>>4; j; j>>=1) { if (j & 1) { @@ -2857,52 +2521,52 @@ AdjustRange( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShorteningQuickFormat -- * - * Returns a 'quick' format of a double precision number to a string of - * digits, preferring a shorter string of digits if the shorter string is - * still within 1/2 ulp of the number. + * Returns a 'quick' format of a double precision number to a string + * of digits, preferring a shorter string of digits if the shorter + * string is still within 1/2 ulp of the number. * * Results: - * Returns the string of digits. Returns NULL if the 'quick' method fails - * and the bignum method must be used. + * Returns the string of digits. Returns NULL if the 'quick' method + * fails and the bignum method must be used. * * Side effects: * Stores the position of the decimal point at '*kPtr'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -ShorteningQuickFormat( - double d, /* Number to convert. */ - int k, /* floor(log10(d)) */ - int ilim, /* Number of significant digits to return. */ - double eps, /* Estimated roundoff error. */ - char *retval, /* Buffer to receive the digit string. */ - int *kPtr) /* Pointer to stash the position of the - * decimal point. */ +inline static char* +ShorteningQuickFormat(double d, /* Number to convert */ + int k, /* floor(log10(d)) */ + int ilim, /* Number of significant digits to return */ + double eps, + /* Estimated roundoff error */ + char* retval, + /* Buffer to receive the digit string */ + int* kPtr) + /* Pointer to stash the position of + * the decimal point */ { - char *s = retval; /* Cursor in the return value. */ - int digit; /* Current digit. */ + char* s = retval; /* Cursor in the return value */ + int digit; /* Current digit */ int i; eps = 0.5 / tens[ilim-1] - eps; i = 0; for (;;) { - /* - * Convert a digit. - */ + /* Convert a digit */ digit = (int) d; d -= digit; *s++ = '0' + digit; /* - * Truncate the conversion if the string of digits is within 1/2 ulp - * of the actual value. + * Truncate the conversion if the string of digits is within + * 1/2 ulp of the actual value. */ if (d < eps) { @@ -2916,7 +2580,7 @@ ShorteningQuickFormat( /* * Bail out if the conversion fails to converge to a sufficiently - * precise value. + * precise value */ if (++i >= ilim) { @@ -2933,44 +2597,40 @@ ShorteningQuickFormat( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * StrictQuickFormat -- * - * Convert a double precision number of a string of a precise number of - * digits, using the 'quick' double precision method. + * Convert a double precision number of a string of a precise number + * of digits, using the 'quick' double precision method. * * Results: - * Returns the digit string, or NULL if the bignum method must be used to - * do the formatting. + * Returns the digit string, or NULL if the bignum method must be + * used to do the formatting. * * Side effects: * Stores the position of the decimal point in '*kPtr'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -StrictQuickFormat( - double d, /* Number to convert. */ - int k, /* floor(log10(d)) */ - int ilim, /* Number of significant digits to return. */ - double eps, /* Estimated roundoff error. */ - char *retval, /* Start of the digit string. */ - int *kPtr) /* Pointer to stash the position of the - * decimal point. */ +inline static char* +StrictQuickFormat(double d, /* Number to convert */ + int k, /* floor(log10(d)) */ + int ilim, /* Number of significant digits to return */ + double eps, /* Estimated roundoff error */ + char* retval, /* Start of the digit string */ + int* kPtr) /* Pointer to stash the position of + * the decimal point */ { - char *s = retval; /* Cursor in the return value. */ - int digit; /* Current digit of the answer. */ + char* s = retval; /* Cursor in the return value */ + int digit; /* Current digit of the answer */ int i; eps *= tens[ilim-1]; i = 1; for (;;) { - /* - * Extract a digit. - */ - + /* Extract a digit */ digit = (int) d; d -= digit; if (d == 0.0) { @@ -2979,10 +2639,9 @@ StrictQuickFormat( *s++ = '0' + digit; /* - * When the given digit count is reached, handle trailing strings of 0 - * and 9. + * When the given digit count is reached, handle trailing strings + * of 0 and 9. */ - if (i == ilim) { if (d > 0.5 + eps) { *kPtr = k; @@ -2999,17 +2658,14 @@ StrictQuickFormat( } } - /* - * Advance to the next digit. - */ - + /* Advance to the next digit */ ++i; d *= 10.0; } } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * QuickConversion -- * @@ -3018,72 +2674,67 @@ StrictQuickFormat( * therefore be used for the intermediate results. * * Results: - * Returns the converted string, or NULL if the bignum method must be - * used. + * Returns the converted string, or NULL if the bignum method must + * be used. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -QuickConversion( - 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: - * TCL_DD_SHORTEST */ - int len, /* Length of the return value. */ - int ilim, /* Number of digits to store. */ - int ilim1, /* Number of digits to store if we misguessed - * k. */ - int *decpt, /* OUTPUT: Location of the decimal point. */ - char **endPtr) /* OUTPUT: Pointer to the terminal null - * byte. */ +inline static char* +QuickConversion(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: + * TCL_DD_SHORTEN_FLAG */ + int len, /* Length of the return value */ + int ilim, /* Number of digits to store */ + int ilim1, /* Number of digits to store if we + * musguessed k */ + int* decpt, /* OUTPUT: Location of the decimal point */ + char** endPtr) /* OUTPUT: Pointer to the terminal null byte */ { int ieps; /* Number of 1-ulp roundoff errors that have - * accumulated in the calculation. */ - Double eps; /* Estimated roundoff error. */ - char *retval; /* Returned string. */ - char *end; /* Pointer to the terminal null byte in the - * returned string. */ + * accumulated in the calculation*/ + Double eps; /* Estimated roundoff error */ + 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). + * Bring d into the range [1 .. 10) */ - ieps = AdjustRange(&e, k); d = e; /* - * If the guessed value of k didn't get d into range, adjust it by one. If - * that leaves us outside the range in which quick format is accurate, - * bail out. + * If the guessed value of k didn't get d into range, adjust it + * by one. If that leaves us outside the range in which quick format + * is accurate, bail out. */ - if (k_check && d < 1. && ilim > 0) { if (ilim1 < 0) { return NULL; } ilim = ilim1; --k; - d = d * 10.0; + d *= 10.0; ++ieps; } /* - * Compute estimated roundoff error. + * Compute estimated roundoff error */ - eps.d = ieps * d + 7.; eps.w.word0 -= (FP_PRECISION-1) << EXP_SHIFT; /* - * Handle the peculiar case where the result has no significant digits. + * Handle the peculiar case where the result has no significant + * digits. */ - - retval = (char *)ckalloc(len + 1); + retval = ckalloc(len + 1); if (ilim == 0) { - d = d - 5.; + d -= 5.; if (d > eps.d) { *retval = '1'; *decpt = k; @@ -3097,11 +2748,9 @@ QuickConversion( } } - /* - * Format the digit string. - */ + /* Format the digit string */ - if (flags & TCL_DD_SHORTEST) { + if (flags & TCL_DD_SHORTEN_FLAG) { end = ShorteningQuickFormat(d, k, ilim, eps.d, retval, decpt); } else { end = StrictQuickFormat(d, k, ilim, eps.d, retval, decpt); @@ -3118,97 +2767,106 @@ QuickConversion( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * CastOutPowersOf2 -- * - * Adjust the factors 'b2', 'm2', and 's2' to cast out common powers of 2 - * from numerator and denominator in preparation for the 'bignum' method - * of floating point conversion. + * Adjust the factors 'b2', 'm2', and 's2' to cast out common powers + * of 2 from numerator and denominator in preparation for the 'bignum' + * method of floating point conversion. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline void -CastOutPowersOf2( - int *b2, /* Power of 2 to multiply the significand. */ - int *m2, /* Power of 2 to multiply 1/2 ulp. */ - int *s2) /* Power of 2 to multiply the common - * denominator. */ +inline static void +CastOutPowersOf2(int* b2, /* Power of 2 to multiply the significand */ + int* m2, /* Power of 2 to multiply 1/2 ulp */ + int* s2) /* Power of 2 to multiply the common + * denominator */ { int i; - if (*m2 > 0 && *s2 > 0) { /* Find the smallest power of 2 in the - * numerator. */ - if (*m2 < *s2) { /* Find the lowest common denominator. */ + * numerator */ + if (*m2 < *s2) { /* Find the lowest common denominatorr */ i = *m2; } else { i = *s2; } - *b2 -= i; /* Reduce to lowest terms. */ + *b2 -= i; /* Reduce to lowest terms */ *m2 -= i; *s2 -= i; } } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShorteningInt64Conversion -- * - * Converts a double-precision number to the shortest string of digits - * that reconverts exactly to the given number, or to 'ilim' digits if - * that will yield a shorter result. The numerator and denominator in - * David Gay's conversion algorithm are known to fit in Tcl_WideUInt, - * giving considerably faster arithmetic than mp_int's. + * Converts a double-precision number to the shortest string of + * digits that reconverts exactly to the given number, or to + * 'ilim' digits if that will yield a shorter result. The numerator and + * denominator in David Gay's conversion algorithm are known to fit + * in Tcl_WideUInt, giving considerably faster arithmetic than mp_int's. * * Results: - * Returns the string of significant decimal digits, in newly allocated - * memory + * Returns the string of significant decimal digits, in newly + * allocated memory * * Side effects: - * Stores the location of the decimal point in '*decpt' and the location - * of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the + * location of the terminal null byte in '*endPtr'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -ShorteningInt64Conversion( - Double *dPtr, /* Original number to convert. */ - Tcl_WideUInt bw, /* Integer significand. */ - int b2, int b5, /* Scale factor for the significand in the - * numerator. */ - int m2plus, int m2minus, int m5, - /* Scale factors for 1/2 ulp in the numerator - * (will be different if bw == 1. */ - int s2, int s5, /* Scale factors for the denominator. */ - int k, /* Number of output digits before the decimal - * point. */ - int len, /* Number of digits to allocate. */ - int ilim, /* Number of digits to convert if b >= s */ - int ilim1, /* Number of digits to convert if b < s */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - char **endPtr) /* OUTPUT: Position of the terminal '\0' at - * the end of the returned string. */ +inline static 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 */ + int m2plus, int m2minus, int m5, + /* Scale factors for 1/2 ulp in + * the numerator (will be different if + * bw == 1 */ + int s2, int s5, + /* Scale factors for the denominator */ + int k, + /* Number of output digits before the decimal + * point */ + int len, + /* Number of digits to allocate */ + int ilim, + /* Number of digits to convert if b >= s */ + int ilim1, + /* Number of digits to convert if b < s */ + int* decpt, + /* OUTPUT: Position of the decimal point */ + char** endPtr) + /* OUTPUT: Position of the terminal '\0' + * at the end of the returned string */ { - char *retval = (char *)ckalloc(len + 1); - /* Output buffer. */ + + char* retval = ckalloc(len + 1); + /* Output buffer */ Tcl_WideUInt b = (bw * wuipow5[b5]) << b2; - /* Numerator of the fraction being - * converted. */ + /* Numerator of the fraction being converted */ Tcl_WideUInt S = wuipow5[s5] << s2; /* Denominator of the fraction being - * converted. */ - Tcl_WideUInt mplus, mminus; /* Ranges for testing whether the result is - * within roundoff of being exact. */ - int digit; /* Current output digit. */ - char *s = retval; /* Cursor in the output buffer. */ - int i; /* Current position in the output buffer. */ + * converted */ + Tcl_WideUInt mplus, mminus; /* Ranges for testing whether the result + * is within roundoff of being exact */ + int digit; /* Current output digit */ + char* s = retval; /* Cursor in the output buffer */ + int i; /* Current position in the output buffer */ - /* - * Adjust if the logarithm was guessed wrong. - */ + /* Adjust if the logarithm was guessed wrong */ if (b < S) { b = 10 * b; @@ -3217,16 +2875,12 @@ ShorteningInt64Conversion( --k; } - /* - * Compute roundoff ranges. - */ + /* Compute roundoff ranges */ mplus = wuipow5[m5] << m2plus; mminus = wuipow5[m5] << m2minus; - /* - * Loop through the digits. - */ + /* Loop through the digits */ i = 1; for (;;) { @@ -3240,15 +2894,17 @@ ShorteningInt64Conversion( * Does the current digit put us on the low side of the exact value * but within within roundoff of being exact? */ - - if (b < mplus || (b == mplus + if (b < mplus + || (b == mplus + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { /* - * Make sure we shouldn't be rounding *up* instead, in case the - * next number above is closer. + * Make sure we shouldn't be rounding *up* instead, + * in case the next number above is closer */ - - if (2 * b > S || (2 * b == S && (digit & 1) != 0)) { + if (2 * b > S + || (2 * b == S + && (digit & 1) != 0)) { ++digit; if (digit == 10) { *s++ = '9'; @@ -3257,9 +2913,7 @@ ShorteningInt64Conversion( } } - /* - * Stash the current digit. - */ + /* Stash the current digit */ *s++ = '0' + digit; break; @@ -3269,8 +2923,9 @@ ShorteningInt64Conversion( * Does one plus the current digit put us within roundoff of the * number? */ - - if (b > S - mminus || (b == S - mminus + if (b > S - mminus + || (b == S - mminus + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { if (digit == 9) { *s++ = '9'; @@ -3285,18 +2940,16 @@ ShorteningInt64Conversion( /* * Have we converted all the requested digits? */ - *s++ = '0' + digit; if (i == ilim) { - if (2*b > S || (2*b == S && (digit & 1) != 0)) { + if (2*b > S + || (2*b == S && (digit & 1) != 0)) { s = BumpUp(s, retval, &k); } break; } - /* - * Advance to the next digit. - */ + /* Advance to the next digit */ b = 10 * b; mplus = 10 * mplus; @@ -3308,7 +2961,6 @@ ShorteningInt64Conversion( * Endgame - store the location of the decimal point and the end of the * string. */ - *s = '\0'; *decpt = k; if (endPtr) { @@ -3318,58 +2970,69 @@ ShorteningInt64Conversion( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * StrictInt64Conversion -- * - * Converts a double-precision number to a fixed-length string of 'ilim' - * digits that reconverts exactly to the given number. ('ilim' should be - * replaced with 'ilim1' in the case where log10(d) has been - * overestimated). The numerator and denominator in David Gay's - * conversion algorithm are known to fit in Tcl_WideUInt, giving - * considerably faster arithmetic than mp_int's. + * Converts a double-precision number to a fixed-length string of + * 'ilim' digits that reconverts exactly to the given number. + * ('ilim' should be replaced with 'ilim1' in the case where + * log10(d) has been overestimated). The numerator and + * denominator in David Gay's conversion algorithm are known to fit + * in Tcl_WideUInt, giving considerably faster arithmetic than mp_int's. * * Results: - * Returns the string of significant decimal digits, in newly allocated - * memory + * Returns the string of significant decimal digits, in newly + * allocated memory * * Side effects: - * Stores the location of the decimal point in '*decpt' and the location - * of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the + * location of the terminal null byte in '*endPtr'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -StrictInt64Conversion( - Tcl_WideUInt bw, /* Integer significand. */ - int b2, int b5, /* Scale factor for the significand in the - * numerator. */ - int s2, int s5, /* Scale factors for the denominator. */ - int k, /* Number of output digits before the decimal - * point. */ - int len, /* Number of digits to allocate. */ - int ilim, /* Number of digits to convert if b >= s */ - int ilim1, /* Number of digits to convert if b < s */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - char **endPtr) /* OUTPUT: Position of the terminal '\0' at - * the end of the returned string. */ +inline static 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 */ + int s2, int s5, + /* Scale factors for the denominator */ + int k, + /* Number of output digits before the decimal + * point */ + int len, + /* Number of digits to allocate */ + int ilim, + /* Number of digits to convert if b >= s */ + int ilim1, + /* Number of digits to convert if b < s */ + int* decpt, + /* OUTPUT: Position of the decimal point */ + char** endPtr) + /* OUTPUT: Position of the terminal '\0' + * at the end of the returned string */ { - char *retval = (char *)ckalloc(len + 1); - /* Output buffer. */ + + char* retval = ckalloc(len + 1); + /* Output buffer */ Tcl_WideUInt b = (bw * wuipow5[b5]) << b2; - /* Numerator of the fraction being - * converted. */ + /* Numerator of the fraction being converted */ Tcl_WideUInt S = wuipow5[s5] << s2; /* Denominator of the fraction being - * converted. */ - int digit; /* Current output digit. */ - char *s = retval; /* Cursor in the output buffer. */ - int i; /* Current position in the output buffer. */ + * converted */ + int digit; /* Current output digit */ + char* s = retval; /* Cursor in the output buffer */ + int i; /* Current position in the output buffer */ - /* - * Adjust if the logarithm was guessed wrong. - */ + /* Adjust if the logarithm was guessed wrong */ if (b < S) { b = 10 * b; @@ -3377,9 +3040,7 @@ StrictInt64Conversion( --k; } - /* - * Loop through the digits. - */ + /* Loop through the digits */ i = 1; for (;;) { @@ -3392,10 +3053,10 @@ StrictInt64Conversion( /* * Have we converted all the requested digits? */ - *s++ = '0' + digit; if (i == ilim) { - if (2*b > S || (2*b == S && (digit & 1) != 0)) { + if (2*b > S + || (2*b == S && (digit & 1) != 0)) { s = BumpUp(s, retval, &k); } else { while (*--s == '0') { @@ -3406,9 +3067,7 @@ StrictInt64Conversion( break; } - /* - * Advance to the next digit. - */ + /* Advance to the next digit */ b = 10 * b; ++i; @@ -3418,7 +3077,6 @@ StrictInt64Conversion( * Endgame - store the location of the decimal point and the end of the * string. */ - *s = '\0'; *decpt = k; if (endPtr) { @@ -3428,30 +3086,30 @@ StrictInt64Conversion( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShouldBankerRoundUpPowD -- * - * Test whether bankers' rounding should round a digit up. Assumption is - * made that the denominator of the fraction being tested is a power of - * 2**MP_DIGIT_BIT. + * Test whether bankers' rounding should round a digit up. Assumption + * is made that the denominator of the fraction being tested is + * a power of 2**DIGIT_BIT. * * Results: - * Returns 1 iff the fraction is more than 1/2, or if the fraction is - * exactly 1/2 and the digit is odd. + * Returns 1 iff the fraction is more than 1/2, or if the fraction + * is exactly 1/2 and the digit is odd. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -ShouldBankerRoundUpPowD( - mp_int *b, /* Numerator of the fraction. */ - int sd, /* Denominator is 2**(sd*MP_DIGIT_BIT). */ - int isodd) /* 1 if the digit is odd, 0 if even. */ +inline static int +ShouldBankerRoundUpPowD(mp_int* b, + /* Numerator of the fraction */ + int sd, /* Denominator is 2**(sd*DIGIT_BIT) */ + int isodd) + /* 1 if the digit is odd, 0 if even */ { int i; - static const mp_digit topbit = ((mp_digit)1) << (MP_DIGIT_BIT - 1); - + static const mp_digit topbit = (1<<(DIGIT_BIT-1)); if (b->used < sd || (b->dp[sd-1] & topbit) == 0) { return 0; } @@ -3467,37 +3125,45 @@ ShouldBankerRoundUpPowD( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShouldBankerRoundUpToNextPowD -- * - * Tests whether bankers' rounding will round down in the "denominator is - * a power of 2**MP_DIGIT" case. + * Tests whether bankers' rounding will round down in the + * "denominator is a power of 2**MP_DIGIT" case. * * Results: * Returns 1 if the rounding will be performed - which increases the * digit by one - and 0 otherwise. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -ShouldBankerRoundUpToNextPowD( - mp_int *b, /* Numerator of the fraction. */ - mp_int *m, /* Numerator of the rounding tolerance. */ - int sd, /* Common denominator is 2**(sd*MP_DIGIT_BIT). */ - int isodd, /* 1 if the integer significand is odd. */ - mp_int *temp) /* Work area for the calculation. */ +inline static int +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 */ { int i; /* - * Compare B and S-m - which is the same as comparing B+m and S - which we - * do by computing b+m and doing a bitwhack compare against - * 2**(MP_DIGIT_BIT*sd) + * Compare B and S-m -- which is the same as comparing B+m and S -- + * which we do by computing b+m and doing a bitwhack compare against + * 2**(DIGIT_BIT*sd) */ - - if ((mp_add(b, m, temp) != MP_OKAY) || (temp->used <= sd)) { /* Too few digits to be > s */ + mp_add(b, m, temp); + if (temp->used <= sd) { /* too few digits to be > S */ return 0; } if (temp->used > sd+1 || temp->dp[sd] > 1) { @@ -3505,91 +3171,98 @@ ShouldBankerRoundUpToNextPowD( return 1; } for (i = sd-1; i >= 0; --i) { - /* Check for ==s */ + /* check for ==s */ if (temp->dp[i] != 0) { /* > s */ return 1; } } + if (convType == TCL_DD_STEELE0) { + /* biased rounding */ + return 0; + } return isodd; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShorteningBignumConversionPowD -- * - * Converts a double-precision number to the shortest string of digits - * that reconverts exactly to the given number, or to 'ilim' digits if - * that will yield a shorter result. The denominator in David Gay's - * conversion algorithm is known to be a power of 2**MP_DIGIT_BIT, and hence - * the division in the main loop may be replaced by a digit shift and - * mask. + * Converts a double-precision number to the shortest string of + * digits that reconverts exactly to the given number, or to + * 'ilim' digits if that will yield a shorter result. The denominator + * in David Gay's conversion algorithm is known to be a power of + * 2**DIGIT_BIT, and hence the division in the main loop may be replaced + * by a digit shift and mask. * * Results: - * Returns the string of significant decimal digits, in newly allocated - * memory + * Returns the string of significant decimal digits, in newly + * allocated memory * * Side effects: - * Stores the location of the decimal point in '*decpt' and the location - * of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the + * location of the terminal null byte in '*endPtr'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -ShorteningBignumConversionPowD( - Double *dPtr, /* Original number to convert. */ - Tcl_WideUInt bw, /* Integer significand. */ - int b2, int b5, /* Scale factor for the significand in the - * numerator. */ - int m2plus, int m2minus, int m5, - /* Scale factors for 1/2 ulp in the numerator - * (will be different if bw == 1). */ - int sd, /* Scale factor for the denominator. */ - int k, /* Number of output digits before the decimal - * point. */ - int len, /* Number of digits to allocate. */ - int ilim, /* Number of digits to convert if b >= s */ - int ilim1, /* Number of digits to convert if b < s */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - char **endPtr) /* OUTPUT: Position of the terminal '\0' at - * the end of the returned string. */ +inline static 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 */ + int m2plus, int m2minus, int m5, + /* Scale factors for 1/2 ulp in + * the numerator (will be different if + * bw == 1 */ + int sd, + /* Scale factor for the denominator */ + int k, + /* Number of output digits before the decimal + * point */ + int len, + /* Number of digits to allocate */ + int ilim, + /* Number of digits to convert if b >= s */ + int ilim1, + /* Number of digits to convert if b < s */ + int* decpt, + /* OUTPUT: Position of the decimal point */ + char** endPtr) + /* OUTPUT: Position of the terminal '\0' + * at the end of the returned string */ { - char *retval = (char *)ckalloc(len + 1); - /* Output buffer. */ - mp_int b; /* Numerator of the fraction being - * converted. */ - mp_int mplus, mminus; /* Bounds for roundoff. */ - mp_digit digit; /* Current output digit. */ - char *s = retval; /* Cursor in the output buffer. */ - int i; /* Index in the output buffer. */ + + char* retval = ckalloc(len + 1); + /* Output buffer */ + mp_int b; /* Numerator of the fraction being converted */ + mp_int mplus, mminus; /* Bounds for roundoff */ + mp_digit digit; /* Current output digit */ + char* s = retval; /* Cursor in the output buffer */ + int i; /* Index in the output buffer */ mp_int temp; int r1; - mp_err err = MP_OKAY; /* * b = bw * 2**b2 * 5**b5 * mminus = 5**m5 */ - if ((retval == NULL) || (mp_init_u64(&b, bw) != MP_OKAY)) { - return NULL; - } - if (mp_init_set(&mminus, 1) != MP_OKAY) { - mp_clear(&b); - return NULL; - } - err = MulPow5(&b, b5, &b); - if (err == MP_OKAY) { - err = mp_mul_2d(&b, b2, &b); - } + TclBNInitBignumFromWideUInt(&b, bw); + mp_init_set_int(&mminus, 1); + MulPow5(&b, b5, &b); + mp_mul_2d(&b, b2, &b); - /* - * Adjust if the logarithm was guessed wrong. - */ + /* Adjust if the logarithm was guessed wrong */ - if ((err == MP_OKAY) && (b.used <= sd)) { - err = mp_mul_d(&b, 10, &b); + if (b.used <= sd) { + mp_mul_d(&b, 10, &b); ++m2plus; ++m2minus; ++m5; ilim = ilim1; --k; @@ -3600,26 +3273,16 @@ ShorteningBignumConversionPowD( * mplus = 5**m5 * 2**m2plus */ - if (err == MP_OKAY) { - err = mp_mul_2d(&mminus, m2minus, &mminus); - } - if (err == MP_OKAY) { - err = MulPow5(&mminus, m5, &mminus); - } - if ((err == MP_OKAY) && (m2plus > m2minus)) { - err = mp_init_copy(&mplus, &mminus); - if (err == MP_OKAY) { - err = mp_mul_2d(&mplus, m2plus-m2minus, &mplus); - } - } - if (err == MP_OKAY) { - err = mp_init(&temp); + mp_mul_2d(&mminus, m2minus, &mminus); + MulPow5(&mminus, m5, &mminus); + if (m2plus > m2minus) { + mp_init_copy(&mplus, &mminus); + mp_mul_2d(&mplus, m2plus-m2minus, &mplus); } + mp_init(&temp); - /* - * Loop through the digits. Do division and mod by s == 2**(sd*MP_DIGIT_BIT) - * by mp_digit extraction. - */ + /* Loop through the digits. Do division and mod by s == 2**(sd*DIGIT_BIT) + * by mp_digit extraction */ i = 0; for (;;) { @@ -3639,13 +3302,14 @@ ShorteningBignumConversionPowD( */ r1 = mp_cmp_mag(&b, (m2plus > m2minus)? &mplus : &mminus); - if (r1 == MP_LT || (r1 == MP_EQ + if (r1 == MP_LT + || (r1 == MP_EQ + && convType != TCL_DD_STEELE0 && (dPtr->w.word1 & 1) == 0)) { /* - * Make sure we shouldn't be rounding *up* instead, in case the - * next number above is closer. + * Make sure we shouldn't be rounding *up* instead, + * in case the next number above is closer */ - if (ShouldBankerRoundUpPowD(&b, sd, digit&1)) { ++digit; if (digit == 10) { @@ -3655,9 +3319,7 @@ ShorteningBignumConversionPowD( } } - /* - * Stash the last digit. - */ + /* Stash the last digit */ *s++ = '0' + digit; break; @@ -3669,7 +3331,8 @@ ShorteningBignumConversionPowD( */ if (ShouldBankerRoundUpToNextPowD(&b, &mminus, sd, - dPtr->w.word1 & 1, &temp)) { + convType, dPtr->w.word1 & 1, + &temp)) { if (digit == 9) { *s++ = '9'; s = BumpUp(s, retval, &k); @@ -3683,7 +3346,6 @@ ShorteningBignumConversionPowD( /* * Have we converted all the requested digits? */ - *s++ = '0' + digit; if (i == ilim) { if (ShouldBankerRoundUpPowD(&b, sd, digit&1)) { @@ -3692,18 +3354,12 @@ ShorteningBignumConversionPowD( break; } - /* - * Advance to the next digit. - */ + /* Advance to the next digit */ - if (err == MP_OKAY) { - err = mp_mul_d(&b, 10, &b); - } - if (err == MP_OKAY) { - err = mp_mul_d(&mminus, 10, &mminus); - } - if ((err == MP_OKAY) && (m2plus > m2minus)) { - err = mp_mul_2d(&mminus, m2plus-m2minus, &mplus); + mp_mul_d(&b, 10, &b); + mp_mul_d(&mminus, 10, &mminus); + if (m2plus > m2minus) { + mp_mul_2d(&mminus, m2plus-m2minus, &mplus); } ++i; } @@ -3712,94 +3368,101 @@ ShorteningBignumConversionPowD( * Endgame - store the location of the decimal point and the end of the * string. */ - if (m2plus > m2minus) { mp_clear(&mplus); } - mp_clear_multi(&b, &mminus, &temp, (void *)NULL); + mp_clear_multi(&b, &mminus, &temp, NULL); *s = '\0'; *decpt = k; if (endPtr) { *endPtr = s; } - return (err == MP_OKAY) ? retval : NULL; + return retval; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * StrictBignumConversionPowD -- * - * Converts a double-precision number to a fixed-lengt string of 'ilim' - * digits (or 'ilim1' if log10(d) has been overestimated). The - * denominator in David Gay's conversion algorithm is known to be a power - * of 2**MP_DIGIT_BIT, and hence the division in the main loop may be - * replaced by a digit shift and mask. + * Converts a double-precision number to a fixed-lengt string of + * 'ilim' digits (or 'ilim1' if log10(d) has been overestimated.) + * The denominator in David Gay's conversion algorithm is known to + * be a power of 2**DIGIT_BIT, and hence the division in the main + * loop may be replaced by a digit shift and mask. * * Results: - * Returns the string of significant decimal digits, in newly allocated - * memory. + * Returns the string of significant decimal digits, in newly + * allocated memory. * * Side effects: - * Stores the location of the decimal point in '*decpt' and the location - * of the terminal null byte in '*endPtr'. + * Stores the location of the decimal point in '*decpt' and the + * location of the terminal null byte in '*endPtr'. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -StrictBignumConversionPowD( - Tcl_WideUInt bw, /* Integer significand. */ - int b2, int b5, /* Scale factor for the significand in the - * numerator. */ - int sd, /* Scale factor for the denominator. */ - int k, /* Number of output digits before the decimal - * point. */ - int len, /* Number of digits to allocate. */ - int ilim, /* Number of digits to convert if b >= s */ - int ilim1, /* Number of digits to convert if b < s */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - char **endPtr) /* OUTPUT: Position of the terminal '\0' at - * the end of the returned string. */ +inline static 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 */ + int sd, + /* Scale factor for the denominator */ + int k, + /* Number of output digits before the decimal + * point */ + int len, + /* Number of digits to allocate */ + int ilim, + /* Number of digits to convert if b >= s */ + int ilim1, + /* Number of digits to convert if b < s */ + int* decpt, + /* OUTPUT: Position of the decimal point */ + char** endPtr) + /* OUTPUT: Position of the terminal '\0' + * at the end of the returned string */ { - char *retval = (char *)ckalloc(len + 1); - /* Output buffer. */ - mp_int b; /* Numerator of the fraction being - * converted. */ - mp_digit digit; /* Current output digit. */ - char *s = retval; /* Cursor in the output buffer. */ - int i; /* Index in the output buffer. */ - mp_err err; + + char* retval = ckalloc(len + 1); + /* Output buffer */ + mp_int b; /* Numerator of the fraction being converted */ + 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 */ - if (mp_init_u64(&b, bw) != MP_OKAY) { - return NULL; - } - err = MulPow5(&b, b5, &b); - if (err == MP_OKAY) { - err = mp_mul_2d(&b, b2, &b); - } + TclBNInitBignumFromWideUInt(&b, bw); + MulPow5(&b, b5, &b); + mp_mul_2d(&b, b2, &b); - /* - * Adjust if the logarithm was guessed wrong. - */ + /* Adjust if the logarithm was guessed wrong */ - if ((err == MP_OKAY) && (b.used <= sd)) { - err = mp_mul_d(&b, 10, &b); + if (b.used <= sd) { + mp_mul_d(&b, 10, &b); ilim = ilim1; --k; } + mp_init(&temp); /* - * Loop through the digits. Do division and mod by s == 2**(sd*MP_DIGIT_BIT) - * by mp_digit extraction. + * Loop through the digits. Do division and mod by s == 2**(sd*DIGIT_BIT) + * by mp_digit extraction */ i = 1; - while (err == MP_OKAY) { + for (;;) { if (b.used <= sd) { digit = 0; } else { @@ -3807,31 +3470,28 @@ StrictBignumConversionPowD( if (b.used > sd+1 || digit >= 10) { Tcl_Panic("wrong digit!"); } - --b.used; - mp_clamp(&b); + --b.used; mp_clamp(&b); } /* * Have we converted all the requested digits? */ - *s++ = '0' + digit; if (i == ilim) { if (ShouldBankerRoundUpPowD(&b, sd, digit&1)) { s = BumpUp(s, retval, &k); + } else { + while (*--s == '0') { + /* do nothing */ + } + ++s; } - while (*--s == '0') { - /* do nothing */ - } - ++s; break; } - /* - * Advance to the next digit. - */ + /* Advance to the next digit */ - err = mp_mul_d(&b, 10, &b); + mp_mul_d(&b, 10, &b); ++i; } @@ -3839,8 +3499,7 @@ StrictBignumConversionPowD( * Endgame - store the location of the decimal point and the end of the * string. */ - - mp_clear(&b); + mp_clear_multi(&b, &temp, NULL); *s = '\0'; *decpt = k; if (endPtr) { @@ -3850,7 +3509,7 @@ StrictBignumConversionPowD( } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShouldBankerRoundUp -- * @@ -3860,74 +3519,82 @@ StrictBignumConversionPowD( * Results: * Returns 1 if the number needs to be rounded up, 0 otherwise. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -ShouldBankerRoundUp( - mp_int *twor, /* 2x the remainder from thd division that - * produced the last digit. */ - mp_int *S, /* Denominator. */ - int isodd) /* Flag == 1 if the last digit is odd. */ +inline static int +ShouldBankerRoundUp(mp_int* twor, + /* 2x the remainder from thd division that + * produced the last digit */ + mp_int* S, /* Denominator */ + int isodd) /* Flag == 1 if the last digit is odd */ { int r = mp_cmp_mag(twor, S); - switch (r) { + case MP_LT: + return 0; case MP_EQ: return isodd; case MP_GT: return 1; - default: - return 0; } + Tcl_Panic("in ShouldBankerRoundUp, trichotomy fails!"); + return 0; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShouldBankerRoundUpToNext -- * - * Tests whether the remainder is great enough to force rounding to the - * next higher digit. + * Tests whether the remainder is great enough to force rounding + * to the next higher digit. * * Results: * Returns 1 if the number should be rounded up, 0 otherwise. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline int -ShouldBankerRoundUpToNext( - mp_int *b, /* Remainder from the division that produced +inline static int +ShouldBankerRoundUpToNext(mp_int* b, + /* Remainder from the division that produced * the last digit. */ - mp_int *m, /* Numerator of the rounding tolerance. */ - mp_int *S, /* Denominator. */ - int isodd) /* 1 if the integer significand is odd. */ + 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 r; - mp_int temp; - - /* - * Compare b and S-m: this is the same as comparing B+m and S. - */ - - if ((mp_init(&temp) != MP_OKAY) || (mp_add(b, m, &temp) != MP_OKAY)) { - return 0; - } - r = mp_cmp_mag(&temp, S); - mp_clear(&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); switch(r) { + case MP_LT: + return 0; case MP_EQ: - return isodd; + if (convType == TCL_DD_STEELE0) { + return 0; + } else { + return isodd; + } case MP_GT: return 1; - default: - return 0; } + Tcl_Panic("in ShouldBankerRoundUpToNext, trichotomy fails!"); + return 0; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ShorteningBignumConversion -- * @@ -3938,97 +3605,90 @@ ShouldBankerRoundUpToNext( * Returns the string of digits. * * Side effects: - * Stores the position of the decimal point in *decpt. Stores a pointer - * to the end of the number in *endPtr. + * Stores the position of the decimal point in *decpt. + * Stores a pointer to the end of the number in *endPtr. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -ShorteningBignumConversion( - Double *dPtr, /* Original number being converted. */ - 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. */ - int s2, int s5, /* Scale factors for denominator. */ - int k, /* Guessed position of the decimal point. */ - int len, /* Size of the digit buffer to allocate. */ - int ilim, /* Number of digits to convert if b >= s */ - int ilim1, /* Number of digits to convert if b < s */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - char **endPtr) /* OUTPUT: Pointer to the end of the number */ +inline static 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 */ + int s2, int s5, + /* Scale factors for denominator */ + int k, + /* Guessed position of the decimal point */ + int len, + /* Size of the digit buffer to allocate */ + int ilim, + /* Number of digits to convert if b >= s */ + int ilim1, + /* Number of digits to convert if b < s */ + int* decpt, + /* OUTPUT: Position of the decimal point */ + char** endPtr) + /* OUTPUT: Pointer to the end of the number */ { - char *retval = (char *)ckalloc(len+1); - /* Buffer of digits to return. */ - char *s = retval; /* Cursor in the return value. */ - mp_int b; /* Numerator of the result. */ - mp_int mminus; /* 1/2 ulp below the result. */ - mp_int mplus; /* 1/2 ulp above the result. */ - mp_int S; /* Denominator of the result. */ - mp_int dig; /* Current digit of the result. */ - int digit; /* Current digit of the result. */ - int minit = 1; /* Fudge factor for when we misguess k. */ + char* retval = ckalloc(len+1); + /* Buffer of digits to return */ + char* s = retval; /* Cursor in the return value */ + mp_int b; /* Numerator of the result */ + mp_int mminus; /* 1/2 ulp below the result */ + mp_int mplus; /* 1/2 ulp above the result */ + 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; - mp_err err; /* * b = bw * 2**b2 * 5**b5 * S = 2**s2 * 5*s5 */ - if ((retval == NULL) || (mp_init_u64(&b, bw) != MP_OKAY)) { - return NULL; - } - err = mp_mul_2d(&b, b2, &b); - if (err == MP_OKAY) { - err = mp_init_set(&S, 1); - } - if (err == MP_OKAY) { - err = MulPow5(&S, s5, &S); - } - if (err == MP_OKAY) { - err = mp_mul_2d(&S, s2, &S); - } + TclBNInitBignumFromWideUInt(&b, bw); + mp_mul_2d(&b, b2, &b); + mp_init_set_int(&S, 1); + MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S); /* - * Handle the case where we guess the position of the decimal point wrong. + * Handle the case where we guess the position of the decimal point + * wrong. */ - if ((err == MP_OKAY) && (mp_cmp_mag(&b, &S) == MP_LT)) { - err = mp_mul_d(&b, 10, &b); + if (mp_cmp_mag(&b, &S) == MP_LT) { + mp_mul_d(&b, 10, &b); minit = 10; ilim =ilim1; --k; } - /* - * mminus = 2**m2minus * 5**m5 - */ + /* mminus = 2**m2minus * 5**m5 */ - if (err == MP_OKAY) { - err = mp_init_set(&mminus, minit); - } - if (err == MP_OKAY) { - err = mp_mul_2d(&mminus, m2minus, &mminus); - } - if ((err == MP_OKAY) && (m2plus > m2minus)) { - err = mp_init_copy(&mplus, &mminus); - if (err == MP_OKAY) { - err = mp_mul_2d(&mplus, m2plus-m2minus, &mplus); - } + mp_init_set_int(&mminus, minit); + mp_mul_2d(&mminus, m2minus, &mminus); + if (m2plus > m2minus) { + mp_init_copy(&mplus, &mminus); + mp_mul_2d(&mplus, m2plus-m2minus, &mplus); } + mp_init(&temp); - /* - * Loop through the digits. - */ + /* Loop through the digits */ - if (err == MP_OKAY) { - err = mp_init(&dig); - } + mp_init(&dig); i = 1; - while (err == MP_OKAY) { - err = mp_div(&b, &S, &dig, &b); + for (;;) { + mp_div(&b, &S, &dig, &b); if (dig.used > 1 || dig.dp[0] >= 10) { Tcl_Panic("wrong digit!"); } @@ -4040,8 +3700,11 @@ ShorteningBignumConversion( */ r1 = mp_cmp_mag(&b, (m2plus > m2minus)? &mplus : &mminus); - if (r1 == MP_LT || (r1 == MP_EQ && (dPtr->w.word1 & 1) == 0)) { - err = mp_mul_2d(&b, 1, &b); + if (r1 == MP_LT + || (r1 == MP_EQ + && convType != TCL_DD_STEELE0 + && (dPtr->w.word1 & 1) == 0)) { + mp_mul_2d(&b, 1, &b); if (ShouldBankerRoundUp(&b, &S, digit&1)) { ++digit; if (digit == 10) { @@ -4055,12 +3718,12 @@ ShorteningBignumConversion( } /* - * Does the current digit leave us with a remainder large enough to - * commit to rounding up to the next higher digit? + * Does the current digit leave us with a remainder large enough + * to commit to rounding up to the next higher digit? */ - if (ShouldBankerRoundUpToNext(&b, &mminus, &S, - dPtr->w.word1 & 1)) { + if (ShouldBankerRoundUpToNext(&b, &mminus, &S, convType, + dPtr->w.word1 & 1, &temp)) { ++digit; if (digit == 10) { *s++ = '9'; @@ -4071,47 +3734,36 @@ ShorteningBignumConversion( break; } - /* - * Have we converted all the requested digits? - */ + /* Have we converted all the requested digits? */ *s++ = '0' + digit; - if ((err == MP_OKAY) && (i == ilim)) { - err = mp_mul_2d(&b, 1, &b); + if (i == ilim) { + mp_mul_2d(&b, 1, &b); if (ShouldBankerRoundUp(&b, &S, digit&1)) { s = BumpUp(s, retval, &k); } break; } - /* - * Advance to the next digit. - */ + /* Advance to the next digit */ - if ((err == MP_OKAY) && (s5 > 0)) { - /* - * Can possibly shorten the denominator. - */ + if (s5 > 0) { - err = mp_mul_2d(&b, 1, &b); - if (err == MP_OKAY) { - err = mp_mul_2d(&mminus, 1, &mminus); - } - if ((err == MP_OKAY) && (m2plus > m2minus)) { - err = mp_mul_2d(&mplus, 1, &mplus); - } - if (err == MP_OKAY) { - err = mp_div_d(&S, 5, &S, NULL); + /* Can possibly shorten the denominator */ + mp_mul_2d(&b, 1, &b); + mp_mul_2d(&mminus, 1, &mminus); + if (m2plus > m2minus) { + mp_mul_2d(&mplus, 1, &mplus); } + mp_div_d(&S, 5, &S, NULL); --s5; - /* - * IDEA: It might possibly be a win to fall back to int64_t - * arithmetic here if S < 2**64/10. But it's a win only for - * a fairly narrow range of magnitudes so perhaps not worth - * bothering. We already know that we shorten the - * denominator by at least 1 mp_digit, perhaps 2, as we do - * the conversion for 17 digits of significance. + * IDEA: It might possibly be a win to fall back to + * int64 arithmetic here if S < 2**64/10. But it's + * a win only for a fairly narrow range of magnitudes + * so perhaps not worth bothering. We already know that + * we shorten the denominator by at least 1 mp_digit, perhaps + * 2. as we do the conversion for 17 digits of significance. * Possible savings: * 10**26 1 trip through loop before fallback possible * 10**27 1 trip @@ -4130,310 +3782,311 @@ ShorteningBignumConversion( * 10**40 14 trips * 10**41 15 trips * 10**42 16 trips - * thereafter no gain. + * thereafter no gain. */ - } else if (err == MP_OKAY) { - err = mp_mul_d(&b, 10, &b); - if (err == MP_OKAY) { - err = mp_mul_d(&mminus, 10, &mminus); - } - if ((err == MP_OKAY) && (m2plus > m2minus)) { - err = mp_mul_2d(&mplus, 10, &mplus); + } else { + mp_mul_d(&b, 10, &b); + mp_mul_d(&mminus, 10, &mminus); + if (m2plus > m2minus) { + mp_mul_2d(&mplus, 10, &mplus); } } ++i; } + /* * Endgame - store the location of the decimal point and the end of the * string. */ - if (m2plus > m2minus) { mp_clear(&mplus); } - mp_clear_multi(&b, &mminus, &dig, &S, (void *)NULL); + mp_clear_multi(&b, &mminus, &temp, &dig, &S, NULL); *s = '\0'; *decpt = k; if (endPtr) { *endPtr = s; } return retval; + } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * StrictBignumConversion -- * - * Convert a floating point number to a fixed-length digit string using - * the multiprecision method. + * Convert a floating point number to a fixed-length digit string + * using the multiprecision method. * * Results: * Returns the string of digits. * * Side effects: - * Stores the position of the decimal point in *decpt. Stores a pointer - * to the end of the number in *endPtr. + * Stores the position of the decimal point in *decpt. + * Stores a pointer to the end of the number in *endPtr. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ -static inline char * -StrictBignumConversion( - Tcl_WideUInt bw, /* Integer significand and exponent. */ - int b2, /* Scale factor for the significand. */ - int s2, int s5, /* Scale factors for denominator. */ - int k, /* Guessed position of the decimal point. */ - int len, /* Size of the digit buffer to allocate. */ - int ilim, /* Number of digits to convert if b >= s */ - int ilim1, /* Number of digits to convert if b < s */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - char **endPtr) /* OUTPUT: Pointer to the end of the number */ +inline static 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 */ + int k, /* Guessed position of the decimal point */ + int len, /* Size of the digit buffer to allocate */ + int ilim, + /* Number of digits to convert if b >= s */ + int ilim1, + /* Number of digits to convert if b < s */ + int* decpt, + /* OUTPUT: Position of the decimal point */ + char** endPtr) + /* OUTPUT: Pointer to the end of the number */ { - char *retval = (char *)ckalloc(len+1); - /* Buffer of digits to return. */ - char *s = retval; /* Cursor in the return value. */ - mp_int b; /* Numerator of the result. */ - mp_int S; /* Denominator of the result. */ - mp_int dig; /* Current digit of the result. */ - int digit; /* Current digit of the result. */ - int g; /* Size of the current digit ground. */ + char* retval = ckalloc(len+1); + /* Buffer of digits to return */ + char* s = retval; /* Cursor in the return value */ + mp_int b; /* Numerator of the result */ + 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 groun */ int i, j; - mp_err err; /* * b = bw * 2**b2 * 5**b5 * S = 2**s2 * 5*s5 */ - if (mp_init(&dig) != MP_OKAY) { - return NULL; - } - if (mp_init_u64(&b, bw) != MP_OKAY) { - mp_clear(&dig); - return NULL; - } - err = mp_mul_2d(&b, b2, &b); - if (err == MP_OKAY) { - err = mp_init_set(&S, 1); - } - if (err == MP_OKAY) { - err = MulPow5(&S, s5, &S); - if (err == MP_OKAY) { - err = mp_mul_2d(&S, s2, &S); - } - } + mp_init_multi(&temp, &dig, NULL); + TclBNInitBignumFromWideUInt(&b, bw); + mp_mul_2d(&b, b2, &b); + mp_init_set_int(&S, 1); + MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S); /* - * Handle the case where we guess the position of the decimal point wrong. + * Handle the case where we guess the position of the decimal point + * wrong. */ - if ((mp_cmp_mag(&b, &S) == MP_LT) && (mp_mul_d(&b, 10, &b) == MP_OKAY)) { + if (mp_cmp_mag(&b, &S) == MP_LT) { + mp_mul_d(&b, 10, &b); ilim =ilim1; --k; } - /* - * Convert the leading digit. - */ + /* Convert the leading digit */ i = 0; - err = mp_div(&b, &S, &dig, &b); + mp_div(&b, &S, &dig, &b); if (dig.used > 1 || dig.dp[0] >= 10) { Tcl_Panic("wrong digit!"); } digit = dig.dp[0]; - /* - * Is a single digit all that was requested? - */ + /* Is a single digit all that was requested? */ *s++ = '0' + digit; if (++i >= ilim) { - if ((mp_mul_2d(&b, 1, &b) == MP_OKAY) && ShouldBankerRoundUp(&b, &S, digit&1)) { + mp_mul_2d(&b, 1, &b); + if (ShouldBankerRoundUp(&b, &S, digit&1)) { s = BumpUp(s, retval, &k); } } else { - while (err == MP_OKAY) { - /* - * Shift by a group of digits. - */ + + for (;;) { + + /* Shift by a group of digits. */ g = ilim - i; if (g > DIGIT_GROUP) { g = DIGIT_GROUP; } if (s5 >= g) { - err = mp_div_d(&S, dpow5[g], &S, NULL); + mp_div_d(&S, dpow5[g], &S, NULL); s5 -= g; } else if (s5 > 0) { - err = mp_div_d(&S, dpow5[s5], &S, NULL); - if (err == MP_OKAY) { - err = mp_mul_d(&b, dpow5[g - s5], &b); - } + mp_div_d(&S, dpow5[s5], &S, NULL); + mp_mul_d(&b, dpow5[g - s5], &b); s5 = 0; } else { - err = mp_mul_d(&b, dpow5[g], &b); - } - if (err == MP_OKAY) { - err = mp_mul_2d(&b, g, &b); + mp_mul_d(&b, dpow5[g], &b); } + mp_mul_2d(&b, g, &b); /* - * As with the shortening bignum conversion, it's possible at this - * point that we will have reduced the denominator to less than - * 2**64/10, at which point it would be possible to fall back to - * to int64_t arithmetic. But the potential payoff is tremendously - * less - unless we're working in F format - because we know that - * three groups of digits will always suffice for %#.17e, the - * longest format that doesn't introduce empty precision. - * - * Extract the next group of digits. + * As with the shortening bignum conversion, it's possible at + * this point that we will have reduced the denominator to + * less than 2**64/10, at which point it would be possible to + * fall back to to int64 arithmetic. But the potential payoff + * is tremendously less - unless we're working in F format - + * because we know that three groups of digits will always + * suffice for %#.17e, the longest format that doesn't introduce + * empty precision. */ + /* Extract the next group of digits */ - if ((err != MP_OKAY) || (mp_div(&b, &S, &dig, &b) != MP_OKAY) || (dig.used > 1)) { + mp_div(&b, &S, &dig, &b); + if (dig.used > 1) { Tcl_Panic("wrong digit!"); } digit = dig.dp[0]; for (j = g-1; j >= 0; --j) { int t = itens[j]; - *s++ = digit / t + '0'; digit %= t; } i += g; - /* - * Have we converted all the requested digits? - */ + /* Have we converted all the requested digits? */ if (i == ilim) { - if ((mp_mul_2d(&b, 1, &b) == MP_OKAY) && ShouldBankerRoundUp(&b, &S, digit&1)) { + mp_mul_2d(&b, 1, &b); + if (ShouldBankerRoundUp(&b, &S, digit&1)) { s = BumpUp(s, retval, &k); + } else { + while (*--s == '0') { + /* do nothing */ + } + ++s; } - break; + break; } } } - while (*--s == '0') { - /* do nothing */ - } - ++s; - /* * Endgame - store the location of the decimal point and the end of the * string. */ - - mp_clear_multi(&b, &S, &dig, (void *)NULL); + mp_clear_multi(&b, &S, &temp, &dig, NULL); *s = '\0'; *decpt = k; if (endPtr) { *endPtr = s; } return retval; + } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * TclDoubleDigits -- * - * Core of Tcl's conversion of double-precision floating point numbers to - * decimal. + * Core of Tcl's conversion of double-precision floating point numbers + * to decimal. * * Results: * Returns a newly-allocated string of digits. * * Side effects: * Sets *decpt to the index of the character in the string before the - * place that the decimal point should go. If 'endPtr' is not NULL, sets - * endPtr to point to the terminating '\0' byte of the string. Sets *sign - * to 1 if a minus sign should be printed with the number, or 0 if a plus - * sign (or no sign) should appear. + * place that the decimal point should go. If 'endPtr' is not NULL, + * sets endPtr to point to the terminating '\0' byte of the string. + * Sets *sign to 1 if a minus sign should be printed with the number, + * or 0 if a plus sign (or no sign) should appear. * - * This function is a service routine that produces the string of digits for - * floating-point-to-decimal conversion. It can do a number of things + * This function is a service routine that produces the string of digits + * for floating-point-to-decimal conversion. It can do a number of things * according to the 'flags' argument. Valid values for 'flags' include: - * TCL_DD_SHORTEST - This is the default for floating point conversion if - * ::tcl_precision is 0. It constructs the shortest string of - * digits that will reconvert to the given number when scanned. + * TCL_DD_SHORTEST - This is the default for floating point conversion + * if ::tcl_precision is 0. It constructs the shortest string + * of digits that will reconvert to the given number when scanned. * 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_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, - * choosing the one that is closest to the given number (and - * resolving ties with 'round to even'). It is allowed to return - * fewer than 'ndigits' if the number converts exactly; if the - * TCL_DD_E_FORMAT|TCL_DD_SHORTEST is supplied instead, it - * also returns fewer digits if the shorter string will still - * reconvert without loss to the given input number. In any case, - * strings of trailing zeroes are suppressed. - * TCL_DD_F_FORMAT - This value is used to prepare numbers for %f format - * conversion. It requests that conversion proceed until + * 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, choosing the one that is closest to the + * given number (and resolving ties with 'round to even'). + * It is allowed to return fewer than 'ndigits' if the number + * converts exactly; if the TCL_DD_E_FORMAT|TCL_DD_SHORTEN_FLAG + * is supplied instead, it also returns fewer digits if the + * shorter string will still reconvert to the given input number. + * In any case, strings of trailing zeroes are suppressed. + * TCL_DD_F_FORMAT - This value is used to prepare numbers for %f + * format conversion. It requests that conversion proceed until * 'ndigits' digits after the decimal point have been converted. * It is possible for this format to result in a zero-length - * string if the number is sufficiently small. Again, it is - * permissible for TCL_DD_F_FORMAT to return fewer digits for a - * number that converts exactly, and changing the argument to - * TCL_DD_F_FORMAT|TCL_DD_SHORTEST will allow the routine - * also to return fewer digits if the shorter string will still - * reconvert without loss to the given input number. Strings of - * trailing zeroes are suppressed. - * - * To any of these flags may be OR'ed TCL_DD_NO_QUICK; this flag requires - * all calculations to be done in exact arithmetic. Normally, E and F - * format with fewer than about 14 digits will be done with a quick - * floating point approximation and fall back on the exact arithmetic - * only if the input number is close enough to the midpoint between two - * decimal strings that more precision is needed to resolve which string - * is correct. + * string if the number is sufficiently small. Again, it + * is permissible for TCL_DD_F_FORMAT to return fewer digits + * for a number that converts exactly, and changing the + * argument to TCL_DD_F_FORMAT|TCL_DD_SHORTEN_FLAG will allow + * the routine also to return fewer digits if the shorter string + * will still reconvert without loss to the given input number. + * Strings of trailing zeroes are suppressed. + * + * To any of these flags may be OR'ed TCL_DD_NO_QUICK; this flag + * requires all calculations to be done in exact arithmetic. Normally, + * E and F format with fewer than about 14 digits will be done with + * a quick floating point approximation and fall back on the exact + * arithmetic only if the input number is close enough to the + * midpoint between two decimal strings that more precision is needed + * to resolve which string is correct. * * The value stored in the 'decpt' argument on return may be negative - * (indicating that the decimal point falls to the left of the string) or - * greater than the length of the string. In addition, the value -9999 is used - * as a sentinel to indicate that the string is one of the special values - * "Infinity" and "NaN", and that no decimal point should be inserted. + * (indicating that the decimal point falls to the left of the string) + * or greater than the length of the string. In addition, the value -9999 + * is used as a sentinel to indicate that the string is one of the special + * values "Infinity" and "NaN", and that no decimal point should be inserted. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ - -char * -TclDoubleDigits( - double dv, /* Number to convert. */ - int ndigits, /* Number of digits requested. */ - int flags, /* Conversion flags. */ - int *decpt, /* OUTPUT: Position of the decimal point. */ - int *sign, /* OUTPUT: 1 if the result is negative. */ - char **endPtr) /* OUTPUT: If not NULL, receives a pointer to - * one character beyond the end of the - * returned string. */ +char* +TclDoubleDigits(double dv, /* Number to convert */ + int ndigits, /* Number of digits requested */ + int flags, /* Conversion flags */ + int* decpt, /* OUTPUT: Position of the decimal point */ + int* sign, /* OUTPUT: 1 if the result is negative */ + char** endPtr) /* OUTPUT: If not NULL, receives a pointer + * to one character beyond the end + * of the returned string */ { - Double d; /* Union for deconstructing doubles. */ - Tcl_WideUInt bw; /* Integer significand. */ + int convType = (flags & TCL_DD_CONVERSION_TYPE_MASK); + /* Type of conversion being performed + * TCL_DD_SHORTEST0 + * TCL_DD_STEELE0 + * TCL_DD_E_FORMAT + * 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 */ - int bbits; /* Number of bits needed to represent b. */ + int bbits; /* Number of bits needed to represent b */ int denorm; /* Flag == 1 iff the input number was - * denormalized. */ - int k; /* Estimate of floor(log10(d)). */ - int k_check; /* Flag == 1 if d is near enough to a power of - * ten that k must be checked. */ + * denormalized */ + int k; /* Estimate of floor(log10(d)) */ + int k_check; /* Flag == 1 if d is near enough to a + * power of ten that k must be checked */ int b2, b5, s2, s5; /* Powers of 2 and 5 in the numerator and - * denominator of intermediate results. */ - int ilim = -1, ilim1 = -1; /* Number of digits to convert, and number to - * convert if log10(d) has been - * overestimated. */ - char *retval; /* Return value from this function. */ + * denominator of intermediate results */ + int ilim = -1, ilim1 = -1; /* Number of digits to convert, and number + * to convert if log10(d) has been + * overestimated */ + char* retval; /* Return value from this function */ int i = -1; - /* - * Put the input number into a union for bit-whacking. - */ + /* Put the input number into a union for bit-whacking */ d.d = dv; @@ -4452,10 +4105,10 @@ TclDoubleDigits( /* * Unpack the floating point into a wide integer and an exponent. - * Determine the number of bits that the big integer requires, and compute - * a quick approximation (which may be one too high) of ceil(log10(d.d)). + * Determine the number of bits that the big integer requires, and + * compute a quick approximation (which may be one too high) of + * ceil(log10(d.d)). */ - denorm = ((d.w.word0 & EXP_MASK) == 0); DoubleToExpAndSig(d.d, &bw, &be, &bbits); k = ApproximateLog10(bw, be, bbits); @@ -4465,70 +4118,71 @@ TclDoubleDigits( * d is the number to convert. * bw are significand and exponent: d == bw*2**be, * bbits is the length of bw: 2**bbits-1 <= bw < 2**bbits - * k is either ceil(log10(d)) or ceil(log10(d))+1. k_check is 0 if we - * know that k is exactly ceil(log10(d)) and 1 if we need to check. + * k is either ceil(log10(d)) or ceil(log10(d))+1. k_check is 0 + * if we know that k is exactly ceil(log10(d)) and 1 if we need to + * check. * We want a rational number * r = b * 10**(1-k) = bw * 2**b2 * 5**b5 / (2**s2 / 5**s5), * with b2, b5, s2, s5 >= 0. Note that the most significant decimal - * digit is floor(r) and that successive digits can be obtained by - * setting r <- 10*floor(r) (or b <= 10 * (b % S)). Find appropriate - * b2, b5, s2, s5. + * digit is floor(r) and that successive digits can be obtained + * by setting r <- 10*floor(r) (or b <= 10 * (b % S)). + * Find appropriate b2, b5, s2, s5. */ ComputeScale(be, k, &b2, &b5, &s2, &s5); /* - * Correct an incorrect caller-supplied 'ndigits'. Also determine: + * 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 ndigits for E format. - * ilim = The number of significant digits to convert if k has been - * 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 'ndigits' for E format, but it's 'ndigits-1' for F - * format. + * shortest and Steele, 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 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 format. */ - SetPrecisionLimits(flags, k, &ndigits, &i, &ilim, &ilim1); + SetPrecisionLimits(convType, k, &ndigits, &i, &ilim, &ilim1); /* - * Try to do low-precision conversion in floating point rather than - * resorting to expensive multiprecision arithmetic. + * Try to do low-precision conversion in floating point rather + * than resorting to expensive multiprecision arithmetic */ - if (ilim >= 0 && ilim <= QUICK_MAX && !(flags & TCL_DD_NO_QUICK)) { - retval = QuickConversion(d.d, k, k_check, flags, i, ilim, ilim1, - decpt, endPtr); - if (retval != NULL) { + if ((retval = QuickConversion(d.d, k, k_check, flags, + i, ilim, ilim1, + decpt, endPtr)) != NULL) { return retval; } } /* - * For shortening conversions, determine the upper and lower bounds for - * the remainder at which we can stop. - * m+ = (2**m2plus * 5**m5) / (2**s2 * 5**s5) is the limit on the high - * side, and - * m- = (2**m2minus * 5**m5) / (2**s2 * 5**s5) is the limit on the low - * side. - * We may need to increase s2 to put m2plus, m2minus, b2 over a common - * denominator. + * For shortening conversions, determine the upper and lower bounds + * for the remainder at which we can stop. + * m+ = (2**m2plus * 5**m5) / (2**s2 * 5**s5) is the limit on the + * high side, and + * m- = (2**m2minus * 5**m5) / (2**s2 * 5**s5) is the limit on the + * low side. + * We may need to increase s2 to put m2plus, m2minus, b2 over a + * common denominator. */ - if (flags & TCL_DD_SHORTEST) { + if (flags & TCL_DD_SHORTEN_FLAG) { int m2minus = b2; int m2plus; int m5 = b5; int len = i; /* - * Find the quantity i so that (2**i*5**b5)/(2**s2*5**s5) is 1/2 unit - * in the least significant place of the floating point number. + * Find the quantity i so that (2**i*5**b5)/(2**s2*5**s5) + * is 1/2 unit in the least significant place of the floating + * point number. */ - if (denorm) { i = be + EXPONENT_BIAS + (FP_PRECISION-1); } else { @@ -4539,16 +4193,14 @@ TclDoubleDigits( /* * Reduce the fractions to lowest terms, since the above calculation - * may have left excess powers of 2 in numerator and denominator. + * may have left excess powers of 2 in numerator and denominator */ - CastOutPowersOf2(&b2, &m2minus, &s2); /* * In the special case where bw==1, the nearest floating point number * to it on the low side is 1/4 ulp below it. Adjust accordingly. */ - m2plus = m2minus; if (!denorm && bw == 1) { ++b2; @@ -4556,56 +4208,60 @@ TclDoubleDigits( ++m2plus; } - if (s5+1 < N_LOG2POW5 && s2+1 + log2pow5[s5+1] < 64) { + if (s5+1 < N_LOG2POW5 + && s2+1 + log2pow5[s5+1] <= 64) { /* - * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit word, - * then all our intermediate calculations can be done using exact - * 64-bit arithmetic with no need for expensive multiprecision - * operations. (This will be true for all numbers in the range - * [1.0e-3 .. 1.0e+24]). + * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit + * word, then all our intermediate calculations can be done + * using exact 64-bit arithmetic with no need for expensive + * multiprecision operations. (This will be true for all numbers + * in the range [1.0e-3 .. 1.0e+24]). */ - return ShorteningInt64Conversion(&d, bw, b2, b5, m2plus, - m2minus, m5, s2, s5, k, len, ilim, ilim1, decpt, endPtr); + return ShorteningInt64Conversion(&d, convType, bw, b2, b5, + m2plus, m2minus, m5, + s2, s5, k, len, ilim, ilim1, + decpt, endPtr); } else if (s5 == 0) { /* - * The denominator is a power of 2, so we can replace division by - * digit shifts. First we round up s2 to a multiple of MP_DIGIT_BIT, - * and adjust m2 and b2 accordingly. Then we launch into a version - * of the comparison that's specialized for the 'power of mp_digit - * in the denominator' case. + * The denominator is a power of 2, so we can replace division + * by digit shifts. First we round up s2 to a multiple of + * DIGIT_BIT, and adjust m2 and b2 accordingly. Then we launch + * into a version of the comparison that's specialized for + * the 'power of mp_digit in the denominator' case. */ - - if (s2 % MP_DIGIT_BIT != 0) { - int delta = MP_DIGIT_BIT - (s2 % MP_DIGIT_BIT); - + if (s2 % DIGIT_BIT != 0) { + int delta = DIGIT_BIT - (s2 % DIGIT_BIT); b2 += delta; m2plus += delta; m2minus += delta; s2 += delta; } - return ShorteningBignumConversionPowD(&d, bw, b2, b5, - m2plus, m2minus, m5, s2/MP_DIGIT_BIT, k, len, ilim, ilim1, - decpt, endPtr); + return ShorteningBignumConversionPowD(&d, convType, bw, b2, b5, + m2plus, m2minus, m5, + s2/DIGIT_BIT, k, len, + ilim, ilim1, decpt, endPtr); } else { + /* - * Alas, there's no helpful special case; use full-up bignum - * arithmetic for the conversion. + * Alas, there's no helpful special case; use full-up + * bignum arithmetic for the conversion */ - return ShorteningBignumConversion(&d, bw, b2, m2plus, - m2minus, s2, s5, k, len, ilim, ilim1, decpt, endPtr); + return ShorteningBignumConversion(&d, convType, bw, + b2, m2plus, m2minus, + s2, s5, k, len, + ilim, ilim1, decpt, endPtr); + } + } else { - /* - * Non-shortening conversion. - */ + + /* Non-shortening conversion */ int len = i; - /* - * Reduce numerator and denominator to lowest terms. - */ + /* Reduce numerator and denominator to lowest terms */ if (b2 >= s2 && s2 > 0) { b2 -= s2; s2 = 0; @@ -4613,46 +4269,48 @@ TclDoubleDigits( s2 -= b2; b2 = 0; } - if (s5+1 < N_LOG2POW5 && s2+1 + log2pow5[s5+1] < 64) { + if (s5+1 < N_LOG2POW5 + && s2+1 + log2pow5[s5+1] <= 64) { /* - * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit word, - * then all our intermediate calculations can be done using exact - * 64-bit arithmetic with no need for expensive multiprecision - * operations. + * If 10*2**s2*5**s5 == 2**(s2+1)+5**(s5+1) fits in a 64-bit + * word, then all our intermediate calculations can be done + * using exact 64-bit arithmetic with no need for expensive + * multiprecision operations. */ - return StrictInt64Conversion(bw, b2, b5, s2, s5, k, - len, ilim, ilim1, decpt, endPtr); + return StrictInt64Conversion(&d, convType, bw, b2, b5, + s2, s5, k, len, ilim, ilim1, + decpt, endPtr); + } else if (s5 == 0) { /* - * The denominator is a power of 2, so we can replace division by - * digit shifts. First we round up s2 to a multiple of MP_DIGIT_BIT, - * and adjust m2 and b2 accordingly. Then we launch into a version - * of the comparison that's specialized for the 'power of mp_digit - * in the denominator' case. + * The denominator is a power of 2, so we can replace division + * by digit shifts. First we round up s2 to a multiple of + * DIGIT_BIT, and adjust m2 and b2 accordingly. Then we launch + * into a version of the comparison that's specialized for + * the 'power of mp_digit in the denominator' case. */ - - if (s2 % MP_DIGIT_BIT != 0) { - int delta = MP_DIGIT_BIT - (s2 % MP_DIGIT_BIT); - + if (s2 % DIGIT_BIT != 0) { + int delta = DIGIT_BIT - (s2 % DIGIT_BIT); b2 += delta; s2 += delta; } - return StrictBignumConversionPowD(bw, b2, b5, - s2/MP_DIGIT_BIT, k, len, ilim, ilim1, decpt, endPtr); + return StrictBignumConversionPowD(&d, convType, bw, b2, b5, + s2/DIGIT_BIT, k, len, + ilim, ilim1, decpt, endPtr); } else { /* - * There are no helpful special cases, but at least we know in - * advance how many digits we will convert. We can run the - * conversion in steps of DIGIT_GROUP digits, so as to have many - * fewer mp_int divisions. + * There are no helpful special cases, but at least we know + * in advance how many digits we will convert. We can run the + * conversion in steps of DIGIT_GROUP digits, so as to + * have many fewer mp_int divisions. */ - - return StrictBignumConversion(bw, b2, s2, s5, k, - len, ilim, ilim1, decpt, endPtr); + return StrictBignumConversion(&d, convType, bw, b2, s2, s5, + k, len, ilim, ilim1, decpt, endPtr); } } } + /* *---------------------------------------------------------------------- @@ -4680,13 +4338,14 @@ TclInitDoubleConversion(void) int x; Tcl_WideUInt u; double d; + #ifdef IEEE_FLOATING_POINT union { double dv; Tcl_WideUInt iv; } bitwhack; #endif - mp_err err = MP_OKAY; + #if defined(__sgi) && defined(_COMPILER_VERSION) union fpc_csr mipsCR; @@ -4711,8 +4370,8 @@ TclInitDoubleConversion(void) pow10_wide[i] = u; /* - * Determine how many bits of precision a double has, and how many decimal - * digits that represents. + * Determine how many bits of precision a double has, and how many + * decimal digits that represents. */ if (frexp((double) FLT_RADIX, &log2FLT_RADIX) != 0.5) { @@ -4723,8 +4382,8 @@ TclInitDoubleConversion(void) d = 1.0; /* - * Initialize a table of powers of ten that can be exactly represented in - * a double. + * Initialize a table of powers of ten that can be exactly represented + * in a double. */ x = (int) (DBL_MANT_DIG * log((double) FLT_RADIX) / log(5.0)); @@ -4743,19 +4402,16 @@ TclInitDoubleConversion(void) */ for (i=0; i<9; ++i) { - err = err || mp_init(pow5 + i); + mp_init(pow5 + i); } - mp_set_u64(pow5, 5); + mp_set(pow5, 5); for (i=0; i<8; ++i) { - err = err || mp_sqr(pow5+i, pow5+i+1); + mp_sqr(pow5+i, pow5+i+1); } - err = err || mp_init_u64(pow5_13, 1220703125); + mp_init_set_int(pow5_13, 1220703125); for (i = 1; i < 5; ++i) { - err = err || mp_init(pow5_13 + i); - err = err || mp_sqr(pow5_13 + i - 1, pow5_13 + i); - } - if (err != MP_OKAY) { - Tcl_Panic("out of memory"); + mp_init(pow5_13 + i); + mp_sqr(pow5_13 + i - 1, pow5_13 + i); } /* @@ -4769,7 +4425,7 @@ TclInitDoubleConversion(void) + 0.5 * log(10.)) / log(10.)); minDigits = (int) floor((DBL_MIN_EXP - DBL_MANT_DIG) * log((double) FLT_RADIX) / log(10.)); - log10_DIGIT_MAX = (int) floor(MP_DIGIT_BIT * log(2.) / log(10.)); + log10_DIGIT_MAX = (int) floor(DIGIT_BIT * log(2.) / log(10.)); /* * Nokia 770's software-emulated floating point is "middle endian": the @@ -4781,9 +4437,9 @@ TclInitDoubleConversion(void) #ifdef IEEE_FLOATING_POINT bitwhack.dv = 1.000000238418579; /* 3ff0 0000 4000 0000 */ - if ((bitwhack.iv >> 32) == 0x3FF00000) { + if ((bitwhack.iv >> 32) == 0x3ff00000) { n770_fp = 0; - } else if ((bitwhack.iv & 0xFFFFFFFF) == 0x3FF00000) { + } else if ((bitwhack.iv & 0xffffffff) == 0x3ff00000) { n770_fp = 1; } else { Tcl_Panic("unknown floating point word order on this machine"); @@ -4812,13 +4468,10 @@ TclFinalizeDoubleConversion(void) { int i; - ckfree(pow10_wide); + ckfree((char *) pow10_wide); for (i=0; i<9; ++i) { mp_clear(pow5 + i); } - for (i=0; i < 5; ++i) { - mp_clear(pow5_13 + i); - } } /* @@ -4841,49 +4494,42 @@ TclFinalizeDoubleConversion(void) int Tcl_InitBignumFromDouble( - Tcl_Interp *interp, /* For error message. */ - double d, /* Number to convert. */ - void *big) /* Place to store the result. */ + Tcl_Interp *interp, /* For error message */ + double d, /* Number to convert */ + mp_int *b) /* Place to store the result */ { double fract; int expt; - mp_err err; - mp_int *b = (mp_int *)big; /* * Infinite values can't convert to bignum. */ - if (isinf(d)) { + if (TclIsInfinite(d)) { if (interp != NULL) { const char *s = "integer value too large to represent"; Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1)); - Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (void *)NULL); + Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, NULL); } return TCL_ERROR; } - fract = frexp(d, &expt); + fract = frexp(d,&expt); if (expt <= 0) { - err = mp_init(b); + mp_init(b); mp_zero(b); } else { - Tcl_WideInt w = (Tcl_WideInt)ldexp(fract, mantBits); + Tcl_WideInt w = (Tcl_WideInt) ldexp(fract, mantBits); int shift = expt - mantBits; - err = mp_init_i64(b, w); - if (err != MP_OKAY) { - /* just skip */ - } else if (shift < 0) { - err = mp_div_2d(b, -shift, b, NULL); + TclBNInitBignumFromWideInt(b, w); + if (shift < 0) { + mp_div_2d(b, -shift, b, NULL); } else if (shift > 0) { - err = mp_mul_2d(b, shift, b); + mp_mul_2d(b, shift, b); } } - if (err != MP_OKAY) { - return TCL_ERROR; - } return TCL_OK; } @@ -4904,13 +4550,11 @@ Tcl_InitBignumFromDouble( double TclBignumToDouble( - const void *big) /* Integer to convert. */ + mp_int *a) /* Integer to convert. */ { mp_int b; int bits, shift, i, lsb; double r; - mp_err err; - const mp_int *a = (const mp_int *)big; /* @@ -4921,10 +4565,10 @@ TclBignumToDouble( bits = mp_count_bits(a); if (bits > DBL_MAX_EXP*log2FLT_RADIX) { errno = ERANGE; - if (mp_isneg(a)) { - return -HUGE_VAL; - } else { + if (a->sign == MP_ZPOS) { return HUGE_VAL; + } else { + return -HUGE_VAL; } } shift = mantBits - bits; @@ -4939,13 +4583,11 @@ TclBignumToDouble( * 'rounded to even'. */ - err = mp_init(&b); - if (err != MP_OKAY) { - /* just skip */ - } else if (shift == 0) { - err = mp_copy(a, &b); + mp_init(&b); + if (shift == 0) { + mp_copy(a, &b); } else if (shift > 0) { - err = mp_mul_2d(a, shift, &b); + mp_mul_2d(a, shift, &b); } else if (shift < 0) { lsb = mp_cnt_lsb(a); if (lsb == -1-shift) { @@ -4954,12 +4596,12 @@ TclBignumToDouble( * Round to even */ - err = mp_div_2d(a, -shift, &b, NULL); - if ((err == MP_OKAY) && mp_isodd(&b)) { - if (mp_isneg(&b)) { - err = mp_sub_d(&b, 1, &b); + mp_div_2d(a, -shift, &b, NULL); + if (mp_isodd(&b)) { + if (b.sign == MP_ZPOS) { + mp_add_d(&b, 1, &b); } else { - err = mp_add_d(&b, 1, &b); + mp_sub_d(&b, 1, &b); } } } else { @@ -4968,15 +4610,13 @@ TclBignumToDouble( * Ordinary rounding */ - err = mp_div_2d(a, -1-shift, &b, NULL); - if (err != MP_OKAY) { - /* just skip */ - } else if (mp_isneg(&b)) { - err = mp_sub_d(&b, 1, &b); + mp_div_2d(a, -1-shift, &b, NULL); + if (b.sign == MP_ZPOS) { + mp_add_d(&b, 1, &b); } else { - err = mp_add_d(&b, 1, &b); + mp_sub_d(&b, 1, &b); } - err = mp_div_2d(&b, 1, &b, NULL); + mp_div_2d(&b, 1, &b, NULL); } } @@ -4984,12 +4624,9 @@ TclBignumToDouble( * Accumulate the result, one mp_digit at a time. */ - if (err != MP_OKAY) { - return 0.0; - } r = 0.0; - for (i = b.used-1; i>=0; --i) { - r = ldexp(r, MP_DIGIT_BIT) + b.dp[i]; + for (i=b.used-1 ; i>=0 ; --i) { + r = ldexp(r, DIGIT_BIT) + b.dp[i]; } mp_clear(&b); @@ -5003,15 +4640,15 @@ TclBignumToDouble( * Return the result with the appropriate sign. */ - if (mp_isneg(a)) { - return -r; - } else { + if (a->sign == MP_ZPOS) { return r; + } else { + return -r; } } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * TclCeil -- * @@ -5021,21 +4658,19 @@ TclBignumToDouble( * Results: * Returns the floating point number. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ double TclCeil( - const void *big) /* Integer to convert. */ + mp_int *a) /* Integer to convert. */ { double r = 0.0; mp_int b; - mp_err err; - const mp_int *a = (const mp_int *)big; - err = mp_init(&b); - if ((err == MP_OKAY) && mp_isneg(a)) { - err = mp_neg(a, &b); + mp_init(&b); + if (mp_cmp_d(a, 0) == MP_LT) { + mp_neg(a, &b); r = -TclFloor(&b); } else { int bits = mp_count_bits(a); @@ -5045,29 +4680,22 @@ TclCeil( } else { int i, exact = 1, shift = mantBits - bits; - if (err != MP_OKAY) { - /* just skip */ - } else if (shift > 0) { - err = mp_mul_2d(a, shift, &b); + if (shift > 0) { + mp_mul_2d(a, shift, &b); } else if (shift < 0) { mp_int d; - err = mp_init(&d); - if (err == MP_OKAY) { - err = mp_div_2d(a, -shift, &b, &d); - } + mp_init(&d); + mp_div_2d(a, -shift, &b, &d); exact = mp_iszero(&d); mp_clear(&d); } else { - err = mp_copy(a, &b); - } - if ((err == MP_OKAY) && !exact) { - err = mp_add_d(&b, 1, &b); + mp_copy(a, &b); } - if (err != MP_OKAY) { - return 0.0; + if (!exact) { + mp_add_d(&b, 1, &b); } for (i=b.used-1 ; i>=0 ; --i) { - r = ldexp(r, MP_DIGIT_BIT) + b.dp[i]; + r = ldexp(r, DIGIT_BIT) + b.dp[i]; } r = ldexp(r, bits - mantBits); } @@ -5075,33 +4703,31 @@ TclCeil( mp_clear(&b); return r; } - + /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * TclFloor -- * - * Computes the largest floating point number less than or equal to the - * mp_int argument. + * Computes the largest floating point number less than or equal to + * the mp_int argument. * * Results: * Returns the floating point value. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ double TclFloor( - const void *big) /* Integer to convert. */ + mp_int *a) /* Integer to convert. */ { double r = 0.0; mp_int b; - mp_err err; - const mp_int *a = (const mp_int *)big; - err = mp_init(&b); - if ((err == MP_OKAY) && mp_isneg(a)) { - err = mp_neg(a, &b); + mp_init(&b); + if (mp_cmp_d(a, 0) == MP_LT) { + mp_neg(a, &b); r = -TclCeil(&b); } else { int bits = mp_count_bits(a); @@ -5112,17 +4738,14 @@ TclFloor( int i, shift = mantBits - bits; if (shift > 0) { - err = mp_mul_2d(a, shift, &b); + mp_mul_2d(a, shift, &b); } else if (shift < 0) { - err = mp_div_2d(a, -shift, &b, NULL); + mp_div_2d(a, -shift, &b, NULL); } else { - err = mp_copy(a, &b); - } - if (err != MP_OKAY) { - return 0.0; + mp_copy(a, &b); } for (i=b.used-1 ; i>=0 ; --i) { - r = ldexp(r, MP_DIGIT_BIT) + b.dp[i]; + r = ldexp(r, DIGIT_BIT) + b.dp[i]; } r = ldexp(r, bits - mantBits); } @@ -5153,15 +4776,14 @@ TclFloor( static double BignumToBiasedFrExp( - const mp_int *a, /* Integer to convert. */ - int *machexp) /* Power of two. */ + mp_int *a, /* Integer to convert */ + int *machexp) /* Power of two */ { mp_int b; int bits; int shift; int i; double r; - mp_err err = MP_OKAY; /* * Determine how many bits we need, and extract that many from the input. @@ -5170,15 +4792,13 @@ BignumToBiasedFrExp( bits = mp_count_bits(a); shift = mantBits - 2 - bits; - if (mp_init(&b)) { - return 0.0; - } + mp_init(&b); if (shift > 0) { - err = mp_mul_2d(a, shift, &b); + mp_mul_2d(a, shift, &b); } else if (shift < 0) { - err = mp_div_2d(a, -shift, &b, NULL); + mp_div_2d(a, -shift, &b, NULL); } else { - err = mp_copy(a, &b); + mp_copy(a, &b); } /* @@ -5186,10 +4806,8 @@ BignumToBiasedFrExp( */ r = 0.0; - if (err == MP_OKAY) { - for (i=b.used-1; i>=0; --i) { - r = ldexp(r, MP_DIGIT_BIT) + b.dp[i]; - } + for (i=b.used-1; i>=0; --i) { + r = ldexp(r, DIGIT_BIT) + b.dp[i]; } mp_clear(&b); @@ -5198,7 +4816,7 @@ BignumToBiasedFrExp( */ *machexp = bits - mantBits + 2; - return (mp_isneg(a) ? -r : r); + return ((a->sign == MP_ZPOS) ? r : -r); } /* @@ -5223,8 +4841,8 @@ BignumToBiasedFrExp( static double Pow10TimesFrExp( - int exponent, /* Power of 10 to multiply by. */ - double fraction, /* Significand of multiplicand. */ + int exponent, /* Power of 10 to multiply by */ + double fraction, /* Significand of multiplicand */ int *machexp) /* On input, exponent of multiplicand. On * output, exponent of result. */ { @@ -5234,10 +4852,10 @@ Pow10TimesFrExp( if (exponent > 0) { /* - * Multiply by 10**exponent. + * Multiply by 10**exponent */ - retval = frexp(retval * pow10vals[exponent & 0xF], &j); + retval = frexp(retval * pow10vals[exponent&0xf], &j); expt += j; for (i=4; i<9; ++i) { if (exponent & (1<<i)) { @@ -5247,10 +4865,10 @@ Pow10TimesFrExp( } } else if (exponent < 0) { /* - * Divide by 10**-exponent. + * Divide by 10**-exponent */ - retval = frexp(retval / pow10vals[(-exponent) & 0xF], &j); + retval = frexp(retval / pow10vals[(-exponent) & 0xf], &j); expt += j; for (i=4; i<9; ++i) { if ((-exponent) & (1<<i)) { @@ -5328,23 +4946,23 @@ TclFormatNaN( #else union { double dv; - uint64_t iv; + Tcl_WideUInt iv; } bitwhack; bitwhack.dv = value; if (n770_fp) { bitwhack.iv = Nokia770Twiddle(bitwhack.iv); } - if (bitwhack.iv & (UINT64_C(1) << 63)) { - bitwhack.iv &= ~ (UINT64_C(1) << 63); + if (bitwhack.iv & ((Tcl_WideUInt) 1 << 63)) { + bitwhack.iv &= ~ ((Tcl_WideUInt) 1 << 63); *buffer++ = '-'; } *buffer++ = 'N'; *buffer++ = 'a'; *buffer++ = 'N'; - bitwhack.iv &= ((UINT64_C(1)) << 51) - 1; + bitwhack.iv &= (((Tcl_WideUInt) 1) << 51) - 1; if (bitwhack.iv != 0) { - snprintf(buffer, TCL_DOUBLE_SPACE, "(%" PRIx64 ")", bitwhack.iv); + sprintf(buffer, "(%" TCL_LL_MODIFIER "x)", bitwhack.iv); } else { *buffer = '\0'; } @@ -5356,27 +4974,26 @@ TclFormatNaN( * * Nokia770Twiddle -- * - * Transpose the two words of a number for Nokia 770 floating point - * handling. + * Transpose the two words of a number for Nokia 770 floating + * point handling. * *---------------------------------------------------------------------- */ -#ifdef IEEE_FLOATING_POINT + static Tcl_WideUInt Nokia770Twiddle( - Tcl_WideUInt w) /* Number to transpose. */ + Tcl_WideUInt w) /* Number to transpose */ { - return (((w >> 32) & 0xFFFFFFFF) | (w << 32)); + return (((w >> 32) & 0xffffffff) | (w << 32)); } -#endif /* *---------------------------------------------------------------------- * * TclNokia770Doubles -- * - * Transpose the two words of a number for Nokia 770 floating point - * handling. + * Transpose the two words of a number for Nokia 770 floating + * point handling. * *---------------------------------------------------------------------- */ |
