Cleaned up and added String routines

This commit is contained in:
waldemar%netscape.com 2000-02-02 08:47:54 +00:00
Родитель 666c772717
Коммит 1216266a7a
4 изменённых файлов: 812 добавлений и 508 удалений

Просмотреть файл

@ -63,7 +63,7 @@ using namespace JavaScript;
// On a machine with IEEE extended-precision registers, it is
// necessary to specify double-precision (53-bit) rounding precision
// before invoking strToD or dToA. If the machine uses (the equivalent
// before invoking strToDouble or doubleToAscii. If the machine uses (the equivalent
// of) Intel 80x87 arithmetic, the call
// _control87(PC_53, MCW_PC);
// does this with many compilers. Whether this or another call is
@ -72,9 +72,9 @@ using namespace JavaScript;
// file.
// strToD for IEEE-arithmetic machines.
// strToDouble for IEEE-arithmetic machines.
//
// This strToD returns a nearest machine number to the input decimal
// This strToDouble returns a nearest machine number to the input decimal
// string. With IEEE arithmetic, ties are broken by the IEEE round-even
// rule. Otherwise ties are broken by biased rounding (add half and chop).
//
@ -108,18 +108,13 @@ using namespace JavaScript;
// #define Sudden_Underflow for IEEE-format machines without gradual
// underflow (i.e., that flush to zero on underflow).
// #define No_leftright to omit left-right logic in fast floating-point
// computation of dToA.
// computation of doubleToAscii.
// #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
// #define ROUND_BIASED for IEEE-format with biased rounding.
// #define Inaccurate_Divide for IEEE-format with correctly rounded
// products but inaccurate quotients, e.g., for Intel i860.
// #define NATIVE_INT64 on machines that have "long long"
// 64-bit integer types int64 and uint64.
// #define INFNAN_CHECK on IEEE systems to cause strToD to check for
// Infinity and NaN (case insensitively). On some systems (e.g.,
// some HP systems), it may be necessary to #define NAN_WORD0
// appropriately -- to the most significant word of a quiet NaN.
// (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
// #define JS_THREADSAFE if the system offers preemptively scheduled
// multiple threads. In this case, you must provide (or suitably
// #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
@ -128,8 +123,8 @@ using namespace JavaScript;
// powers of 5; omitting this lock would introduce a small
// probability of wasting memory, but would otherwise be harmless.)
// You must also invoke freeDToA(s) to free the value s returned by
// dToA. You may do so whether or not JS_THREADSAFE is #defined.
// #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strToD that
// doubleToAscii. You may do so whether or not JS_THREADSAFE is #defined.
// #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strToDouble that
// avoids underflows on inputs whose result does not underflow.
#ifdef IS_LITTLE_ENDIAN
@ -139,14 +134,6 @@ using namespace JavaScript;
#endif
#ifndef __MATH_H__
//#include "math.h"
#endif
#if defined(IEEE_8087) + defined(IEEE_MC68k) != 1
Exactly one of IEEE_8087 or IEEE_MC68k should be defined.
#endif
// Stefan Hanske <sh990154@mail.uni-greifswald.de> reports:
// ARM is a little endian architecture but 64 bit double words are stored
// differently: the 32 bit words are in little endian byte order, the two words
@ -218,6 +205,34 @@ Exactly one of IEEE_8087 or IEEE_MC68k should be defined.
#endif
//
// Double-precision constants
//
double JS::positiveInfinity;
double JS::negativeInfinity;
double JS::nan;
struct InitNumerics {InitNumerics();};
static InitNumerics initNumerics;
InitNumerics::InitNumerics()
{
word0(positiveInfinity) = Exp_mask;
word1(positiveInfinity) = 0;
word0(negativeInfinity) = Exp_mask | Sign_bit;
word1(negativeInfinity) = 0;
word0(nan) = 0x7FFFFFFF;
word1(nan) = 0xFFFFFFFF;
}
//
// Portable double-precision floating point to string and back conversions
//
// Return the absolute difference between x and the adjacent greater-magnitude double number (ignoring exponent overflows).
double JS::ulp(double x)
{
@ -325,6 +340,9 @@ static int lo0bits(uint32 &y)
}
uint32 *JS::BigInt::freeLists[maxLgGrossSize+1];
// Allocate a BigInt with 2^lgGrossSize words. The BigInt must not currently contain a number.
void JS::BigInt::allocate(uint lgGrossSize)
{
@ -1030,39 +1048,12 @@ static const double tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128,
#endif
};
// The factor of 2^53 in tinytens[4] helps us avoid setting the underflow
// flag unnecessarily. It leads to a song and dance at the end of strToD.
// flag unnecessarily. It leads to a song and dance at the end of strToDouble.
const int32 Scale_Bit = 0x10;
const int n_bigtens = 5;
#ifdef INFNAN_CHECK
#ifndef NAN_WORD0
#define NAN_WORD0 0x7ff80000
#endif
#ifndef NAN_WORD1
#define NAN_WORD1 0
#endif
static int match(const char **sp, char *t)
{
int c, d;
const char *s = *sp;
while (d = *t++) {
if ((c = *++s) >= 'A' && c <= 'Z')
c += 'a' - 'A';
if (c != d)
return 0;
}
*sp = s + 1;
return 1;
}
#endif // INFNAN_CHECK
#ifdef JS_THREADSAFE
static bool initialized = false;
@ -1078,15 +1069,15 @@ static void InitDtoa(void)
// Return as a double-precision floating-point number the value represented by the character
// string s00. The string is scanned up to the first unrecognized character.
// If se is not nil, return a pointer to the character terminating the scan in se.
// If no number can be formed, set se to s00 and return zero.
double JS::strToD(const char *s00, char **se)
// string str. The string is scanned up to the first unrecognized character. The character
// sequences 'Infinity', '+Infinity', '-Infinity', and 'NaN' are also recognized.
// Return a pointer to the character terminating the scan in numEnd.
// If no number can be formed, set numEnd to str and return zero.
double JS::strToDouble(const char *str, const char *&numEnd)
{
int32 scale;
int32 bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0;
bool negative;
const char *s, *s0, *s1;
double aadj, aadj1, adj, rv, rv0;
int32 L;
@ -1097,36 +1088,53 @@ double JS::strToD(const char *s00, char **se)
#endif
nz0 = nz = 0;
negative = false;
bool negative = false;
bool haveSign = false;
rv = 0.;
for (s = s00;;s++)
for (s = str;; s++)
switch (*s) {
case '-':
case '-':
negative = true;
// no break
case '+':
case '+':
haveSign = true;
if (*++s)
goto break2;
// no break
case 0:
s = s00;
case 0:
s = str;
goto ret;
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
continue;
default:
default:
goto break2;
}
break2:
if (*s == '0') {
break2:
switch (*s) {
case '0':
nz0 = 1;
while (*++s == '0') ;
if (!*s)
goto ret;
break;
case 'I':
if (!std::strncmp(s+1, "nfinity", 7)) {
rv = positiveInfinity;
s += 8;
goto ret;
}
break;
case 'N':
if (!haveSign && !std::strncmp(s+1, "aN", 2)) {
rv = nan;
s += 3;
goto ret;
}
}
s0 = s;
y = z = 0;
@ -1150,7 +1158,7 @@ break2:
goto dig_done;
}
for (; c >= '0' && c <= '9'; c = *++s) {
have_dig:
have_dig:
nz++;
if (c -= '0') {
nf += nz;
@ -1167,14 +1175,14 @@ break2:
}
}
}
dig_done:
dig_done:
e = 0;
if (c == 'e' || c == 'E') {
if (!nd && !nz && !nz0) {
s = s00;
s = str;
goto ret;
}
s00 = s;
str = s;
esign = 0;
switch (c = *++s) {
case '-':
@ -1202,31 +1210,11 @@ dig_done:
e = 0;
}
else
s = s00;
s = str;
}
if (!nd) {
if (!nz && !nz0) {
#ifdef INFNAN_CHECK
// Check for Nan and Infinity
switch (c) {
case 'i':
case 'I':
if (match(&s,"nfinity")) {
word0(rv) = 0x7ff00000;
word1(rv) = 0;
goto ret;
}
break;
case 'n':
case 'N':
if (match(&s, "an")) {
word0(rv) = NAN_WORD0;
word1(rv) = NAN_WORD1;
goto ret;
}
}
#endif // INFNAN_CHECK
s = s00;
s = str;
}
goto ret;
}
@ -1277,10 +1265,9 @@ dig_done:
rv *= tens[i];
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
ovfl:
ovfl:
// Return infinity.
word0(rv) = Exp_mask;
word1(rv) = 0;
rv = positiveInfinity;
goto ret;
}
e1 >>= 4;
@ -1339,7 +1326,7 @@ dig_done:
rv *= tinytens[j];
#endif
if (!rv) {
undfl:
undfl:
rv = 0.;
goto ret;
}
@ -1463,7 +1450,7 @@ dig_done:
#ifdef Avoid_Underflow
dsign = 2;
#endif
drop_down:
drop_down:
// boundary case -- decrement exponent
#ifdef Sudden_Underflow
L = word0(rv) & Exp_mask;
@ -1524,11 +1511,11 @@ dig_done:
aadj1 = dsign ? aadj : -aadj;
#ifdef Check_FLT_ROUNDS
switch (FLT_ROUNDS) {
case 2: // towards +infinity
case 2: // towards +infinity
aadj1 -= 0.5;
break;
case 0: // towards 0
case 3: // towards -infinity
case 0: // towards 0
case 3: // towards -infinity
aadj1 += 0.5;
}
#else
@ -1641,14 +1628,186 @@ dig_done:
#endif // Avoid_Underflow
}
ret:
if (se)
*se = (char *)s;
numEnd = s;
return negative ? -rv : rv;
}
// A version of strToDouble that takes a char16 string that begins at str and ends just
// before strEnd. The char16 string does not have to be null-terminated.
// Leading Unicode whitespace is skipped.
double JS::stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd)
{
const char16 *str1 = skipWhiteSpace(str, strEnd);
// dToA for IEEE arithmetic (dmg): convert double to ASCII string.
CharAutoPtr cstr(new char[strEnd - str1 + 1]);
char *q = cstr.get();
for (const char16 *p = str1; p != strEnd; p++) {
char16 ch = *p;
if (uint16(ch) >> 8)
break;
*q++ = char(ch);
}
*q = '\0';
const char *estr;
double value = strToDouble(cstr.get(), estr);
ptrdiff_t i = estr - cstr.get();
numEnd = i ? str1 + i : str;
return value;
}
class BinaryDigitReader
{
uint base; // Base of number; must be a power of 2
uint digit; // Current digit value in radix given by base
uint digitMask; // Mask to extract the next bit from digit
const char16 *digits; // Pointer to the remaining digits
const char16 *digitsEnd; // Pointer to first non-digit
public:
BinaryDigitReader(uint base, const char16 *digitsBegin, const char16 *digitsEnd):
base(base), digitMask(0), digits(digitsBegin), digitsEnd(digitsEnd) {}
int next();
};
// Return the next binary digit from the number or -1 if done.
int BinaryDigitReader::next()
{
if (digitMask == 0) {
if (digits == digitsEnd)
return -1;
uint c = *digits++;
if ('0' <= c && c <= '9')
digit = c - '0';
else if ('a' <= c && c <= 'z')
digit = c - 'a' + 10;
else digit = c - 'A' + 10;
digitMask = base >> 1;
}
int bit = (digit & digitMask) != 0;
digitMask >>= 1;
return bit;
}
// Read an integer from a char16 string that begins at str and ends just before strEnd.
// The char16 string does not have to be null-terminated. The integer is returned as a double,
// which is guaranteed to be the closest double number to the given input when base is 10 or a power of 2.
// May experience roundoff errors for very large numbers of a different radix.
// Return a pointer to the character just past the integer in numEnd.
// If the string does not have a number in it, set numEnd to str and return 0.
// Leading Unicode whitespace is skipped.
double JS::stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base)
{
const char16 *str1 = skipWhiteSpace(str, strEnd);
bool negative = (*str1 == '-');
if (negative || *str1 == '+')
str1++;
if ((base == 0 || base == 16) && *str1 == '0' && (str1[1] == 'X' || str1[1] == 'x')) {
// Skip past hex prefix.
base = 16;
str1 += 2;
}
if (base == 0)
base = 10; // Default to decimal.
// Find some prefix of the string that's a number in the given base.
const char16 *start = str1; // Mark - if string is empty, we return 0.
double value = 0.0;
while (true) {
uint digit;
char16 c = *str1;
if ('0' <= c && c <= '9')
digit = uint(c) - '0';
else if ('a' <= c && c <= 'z')
digit = uint(c) - 'a' + 10;
else if ('A' <= c && c <= 'Z')
digit = uint(c) - 'A' + 10;
else
break;
if (digit >= base)
break;
value = value*base + digit;
str1++;
}
if (value >= 9007199254740992.0) {
if (base == 10) {
// If we're accumulating a decimal number and the number is >= 2^53, then
// the result from the repeated multiply-add above may be inaccurate. Call
// stringToDouble to get the correct answer.
const char16 *numEnd2;
value = stringToDouble(start, str1, numEnd2);
ASSERT(numEnd2 == str1);
} else if (base == 2 || base == 4 || base == 8 || base == 16 || base == 32) {
// The number may also be inaccurate for one of these bases. This
// happens if the addition in value*base + digit causes a round-down
// to an even least significant mantissa bit when the first dropped bit
// is a one. If any of the following digits in the number (which haven't
// been added in yet) are nonzero then the correct action would have
// been to round up instead of down. An example of this occurs when
// reading the number 0x1000000000000081, which rounds to 0x1000000000000000
// instead of 0x1000000000000100.
BinaryDigitReader bdr(base, start, str1);
value = 0.0;
// Skip leading zeros.
int bit;
do {
bit = bdr.next();
} while (bit == 0);
if (bit == 1) {
// Gather the 53 significant bits (including the leading 1)
value = 1.0;
for (int j = 52; j; --j) {
bit = bdr.next();
if (bit < 0)
goto done;
value = value*2 + bit;
}
// bit2 is the 54th bit (the first dropped from the mantissa)
int bit2 = bdr.next();
if (bit2 >= 0) {
double factor = 2.0;
int sticky = 0; // sticky is 1 if any bit beyond the 54th is 1
int bit3;
while ((bit3 = bdr.next()) >= 0) {
sticky |= bit3;
factor *= 2;
}
value += bit2 & (bit | sticky);
value *= factor;
}
done:;
}
}
}
// We don't worry about inaccurate numbers for any other base.
if (str1 == start)
numEnd = str;
else {
numEnd = str1;
if (negative)
value = -value;
}
return value;
}
// doubleToAscii for IEEE arithmetic (dmg): convert double to ASCII string.
//
// Inspired by "How to Print Floating-Point Numbers Accurately" by
// Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
@ -1687,15 +1846,15 @@ dig_done:
// when the number is exactly halfway between two representable values. For example,
// rounding 2.5 to zero digits after the decimal point will return 3 and not 2.
// 2.49 will still round to 2, and 2.51 will still round to 3.
// bufsize should be at least 20 for modes 0 and 1. For the other modes,
// bufsize should be two greater than the maximum number of output characters expected.
static bool dToA(double d, int mode, bool biasUp, int ndigits,
int *decpt, bool *negative, char **rve, char *buf, size_t bufsize)
// The buffer should be at least 20 bytes for modes 0 and 1. For the other modes,
// the buffer's size should be two greater than the maximum number of output characters expected.
// Return a pointer to the resulting string's trailing null.
static char *doubleToAscii(double d, int mode, bool biasUp, int ndigits,
int *decpt, bool *negative, char *buf)
{
/* Arguments ndigits, decpt, negative are similar to those
of ecvt and fcvt; trailing zeros are suppressed from
the returned string. If not null, *rve is set to point
to the end of the return value. If d is +-Infinity or NaN,
the returned string. If d is +-Infinity or NaN,
then *decpt is set to 9999.
mode:
@ -1753,28 +1912,14 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
// Infinity or NaN
*decpt = 9999;
s = !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN";
if ((s[0] == 'I' && bufsize < 9) || (s[0] == 'N' && bufsize < 4)) {
ASSERT(false);
return false;
}
std::strcpy(buf, s);
if (rve) {
*rve = buf[3] ? buf + 8 : buf + 3;
ASSERT(**rve == '\0');
}
return true;
return buf[3] ? buf + 8 : buf + 3;
}
if (!d) {
no_digits:
*decpt = 1;
if (bufsize < 2) {
ASSERT(false);
return false;
}
buf[0] = '0'; buf[1] = '\0'; // copy "0" to buffer
if (rve)
*rve = buf + 1;
return true;
return buf + 1;
}
BigInt b;
@ -1870,24 +2015,24 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
leftright = 1;
ilim = ilim1 = 0;
switch (mode) {
case 0:
case 1:
case 0:
case 1:
ilim = ilim1 = -1;
i = 18;
ndigits = 0;
break;
case 2:
case 2:
leftright = 0;
// no break
case 4:
case 4:
if (ndigits <= 0)
ndigits = 1;
ilim = ilim1 = i = ndigits;
break;
case 3:
case 3:
leftright = 0;
// no break
case 5:
case 5:
i = ndigits + k + 1;
ilim = i;
ilim1 = i - 1;
@ -1897,12 +2042,6 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
// ilim is the maximum number of significant digits we want, based on k and ndigits.
// ilim1 is the maximum number of significant digits we want, based on k and ndigits,
// when it turns out that k was computed too high by one.
// Ensure space for at least i+1 characters, including trailing null.
if (bufsize <= (size_t)i) {
ASSERT(false);
return false;
}
s = buf;
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@ -1999,7 +2138,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
#ifndef No_leftright
}
#endif
fast_failed:
fast_failed:
s = buf;
d = d2;
k = k0;
@ -2033,7 +2172,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
if (i == ilim) {
d += d;
if ((d > ds) || (d == ds && (L & 1 || biasUp))) {
bump_up:
bump_up:
while (*--s == '9')
if (s == buf) {
k++;
@ -2238,7 +2377,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
}
if (j1 > 0) {
if (dig == '9') { // possible if i == 1
round_9_up:
round_9_up:
*s++ = '9';
goto roundoff;
}
@ -2267,7 +2406,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
b.pow2Mul(1);
j = b.cmp(S);
if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) {
roundoff:
roundoff:
while (*--s == '9')
if (s == buf) {
k++;
@ -2285,45 +2424,40 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
// S, mLow, and mHigh are destroyed at the end of this block scope.
}
ret1:
ASSERT(s < buf + bufsize);
*s = '\0';
if (rve)
*rve = s;
*decpt = k + 1;
return true;
return s;
}
// Mapping of DToStrMode -> dToA mode
static const int dToAModes[] = {
0, // DTOSTR_STANDARD
0, // DTOSTR_STANDARD_EXPONENTIAL
3, // DTOSTR_FIXED
2, // DTOSTR_EXPONENTIAL
2}; // DTOSTR_PRECISION
// Mapping of DToStrMode -> doubleToAscii mode
static const int doubleToAsciiModes[] = {
0, // dtosStandard
0, // dtosStandardExponential
3, // dtosFixed
2, // dtosExponential
2}; // dtosPrecision
// Convert dval according to the given mode and return a pointer to the resulting ASCII string.
// Convert value according to the given mode and return a pointer to the resulting ASCII string.
// The result is held somewhere in buffer, but not necessarily at the beginning. The size of
// buffer is given in bufferSize, and must be at least as large as given by the above macros.
char *JS::dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision, double d)
// buffer is given in bufferSize, and must be at least as large as given by dtosStandardBufferSize
// or dtosVariableBufferSize, whichever is appropriate.
char *JS::doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision)
{
int decPt; // Position of decimal point relative to first digit returned by dToA
bool negative; // True if the sign bit was set in d
int nDigits; // Number of significand digits returned by dToA
char *numBegin = buffer+2; // Pointer to the digits returned by dToA; the +2 leaves space for
int decPt; // Position of decimal point relative to first digit returned by doubleToAscii
bool negative; // True if the sign bit was set in value
int nDigits; // Number of significand digits returned by doubleToAscii
char *numBegin = buffer+2; // Pointer to the digits returned by doubleToAscii; the +2 leaves space for
// the sign and/or decimal point
char *numEnd; // Pointer past the digits returned by dToA
char *numEnd; // Pointer past the digits returned by doubleToAscii
ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL ? DTOSTR_STANDARD_BUFFER_SIZE :
DTOSTR_VARIABLE_BUFFER_SIZE(precision)));
ASSERT(bufferSize >= (size_t)(mode <= dtosStandardExponential ? dtosStandardBufferSize : dtosVariableBufferSize(precision)));
if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21))
mode = DTOSTR_STANDARD; // Change mode here rather than below because the buffer may not be large enough to hold a large integer.
if (!dToA(d, dToAModes[mode], mode >= DTOSTR_FIXED, precision, &decPt, &negative, &numEnd, numBegin, bufferSize-2))
return 0;
if (mode == dtosFixed && (value >= 1e21 || value <= -1e21))
mode = dtosStandard; // Change mode here rather than below because the buffer may not be large enough to hold a large integer.
numEnd = doubleToAscii(value, doubleToAsciiModes[mode], mode >= dtosFixed, precision, &decPt, &negative, numBegin);
nDigits = numEnd - numBegin;
// If Infinity, -Infinity, or NaN, return the string regardless of the mode.
@ -2334,34 +2468,34 @@ char *JS::dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision
char *q;
switch (mode) {
case DTOSTR_STANDARD:
if (decPt < -5 || decPt > 21)
exponentialNotation = true;
else
minNDigits = decPt;
break;
case DTOSTR_FIXED:
if (precision >= 0)
minNDigits = decPt + precision;
else
minNDigits = decPt;
break;
case DTOSTR_EXPONENTIAL:
ASSERT(precision > 0);
minNDigits = precision;
// Fall through
case DTOSTR_STANDARD_EXPONENTIAL:
case dtosStandard:
if (decPt < -5 || decPt > 21)
exponentialNotation = true;
break;
else
minNDigits = decPt;
break;
case DTOSTR_PRECISION:
ASSERT(precision > 0);
minNDigits = precision;
if (decPt < -5 || decPt > precision)
exponentialNotation = true;
break;
case dtosFixed:
if (precision >= 0)
minNDigits = decPt + precision;
else
minNDigits = decPt;
break;
case dtosExponential:
ASSERT(precision > 0);
minNDigits = precision;
// Fall through
case dtosStandardExponential:
exponentialNotation = true;
break;
case dtosPrecision:
ASSERT(precision > 0);
minNDigits = precision;
if (decPt < -5 || decPt > precision)
exponentialNotation = true;
break;
}
// If the number has fewer than minNDigits, pad it with zeros at the end
@ -2412,9 +2546,9 @@ char *JS::dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision
// If negative and neither -0.0 nor NaN, output a leading '-'.
if (negative &&
!(word0(d) == Sign_bit && word1(d) == 0) &&
!((word0(d) & Exp_mask) == Exp_mask &&
(word1(d) || (word0(d) & Frac_mask)))) {
!(word0(value) == Sign_bit && word1(value) == 0) &&
!((word0(value) & Exp_mask) == Exp_mask &&
(word1(value) || (word0(value) & Frac_mask)))) {
*--numBegin = '-';
}
return numBegin;
@ -2430,47 +2564,42 @@ inline char baseDigit(uint32 digit)
}
// Convert d to a string in the given base. The integral part of d will be printed exactly
// Convert value to a string in the given base. The integral part of value will be printed exactly
// in that base, regardless of how large it is, because there is no exponential notation for non-base-ten
// numbers. The fractional part will be rounded to as few digits as possible while still preserving
// the round-trip property (analogous to that of printing decimal numbers). In other words, if one were
// to read the resulting string in via a hypothetical base-number-reading routine that rounds to the nearest
// IEEE double (and to an even significand if there are two equally near doubles), then the result would
// equal d (except for -0.0, which converts to "0", and NaN, which is not equal to itself).
// equal value (except for -0.0, which converts to "0", and NaN, which is not equal to itself).
//
// Store the result in the given buffer, which must have at least DTOBASESTR_BUFFER_SIZE bytes.
void JS::dToBaseStr(char *buffer, uint base, double d)
// Store the result in the given buffer, which must have at least dtobasesBufferSize bytes.
// Return the number of characters stored.
size_t JS::doubleToBaseStr(char *buffer, double value, uint base)
{
char *p; // Pointer to current position in the buffer
char *pInt; // Pointer to the beginning of the integer part of the string
char *q;
uint32 digit;
double di; // d truncated to an integer
double df; // The fractional part of d
ASSERT(base >= 2 && base <= 36);
p = buffer;
if (d < 0.0
char *p = buffer; // Pointer to current position in the buffer
if (value < 0.0
#ifdef XP_PC
&& !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) // Visual C++ doesn't know how to compare against NaN
&& !((word0(value) & Exp_mask) == Exp_mask && ((word0(value) & Frac_mask) || word1(value))) // Visual C++ doesn't know how to compare against NaN
#endif
) {
*p++ = '-';
d = -d;
value = -value;
}
// Check for Infinity and NaN
if ((word0(d) & Exp_mask) == Exp_mask) {
std::strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN");
return;
if ((word0(value) & Exp_mask) == Exp_mask) {
std::strcpy(p, !word1(value) && !(word0(value) & Frac_mask) ? "Infinity" : "NaN");
return std::strlen(buffer);
}
// Output the integer part of d with the digits in reverse order.
pInt = p;
di = floor(d);
if (di <= 4294967295.0) {
uint32 n = (uint32)di;
// Output the integer part of value with the digits in reverse order.
char *pInt = p; // Pointer to the beginning of the integer part of the string
double valueInt = floor(value); // value truncated to an integer
uint32 digit;
if (valueInt <= 4294967295.0) {
uint32 n = (uint32)valueInt;
if (n)
do {
uint32 m = n / base;
@ -2482,9 +2611,9 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
else *p++ = '0';
} else {
int32 e;
int32 bits; // Number of significant bits in di; not used.
int32 bits; // Number of significant bits in valueInt; not used.
BigInt b;
b.init(di, e, bits);
b.init(valueInt, e, bits);
b.pow2Mul(e);
do {
digit = b.divRem(base);
@ -2492,32 +2621,32 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
*p++ = baseDigit(digit);
} while (!b.isZero());
}
// Reverse the digits of the integer part of d.
q = p-1;
// Reverse the digits of the integer part of value.
char *q = p-1;
while (q > pInt) {
char ch = *pInt;
*pInt++ = *q;
*q-- = ch;
}
df = d - di;
if (df != 0.0) {
double valueFrac = value - valueInt; // The fractional part of value
if (valueFrac != 0.0) {
// We have a fraction.
*p++ = '.';
int32 e, bbits;
BigInt b;
b.init(df, e, bbits);
b.init(valueFrac, e, bbits);
ASSERT(e < 0);
// At this point df = b * 2^e. e must be less than zero because 0 < df < 1.
// At this point valueFrac = b * 2^e. e must be less than zero because 0 < valueFrac < 1.
int32 s2 = -int32(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1);
int32 s2 = -int32(word0(value) >> Exp_shift1 & Exp_mask>>Exp_shift1);
#ifndef Sudden_Underflow
if (!s2)
s2 = -1;
#endif
s2 += Bias + P;
// 1/2^s2 = (nextDouble(d) - d)/2
// 1/2^s2 = (nextDouble(value) - value)/2
ASSERT(-s2 < e);
BigInt mLow;
@ -2525,13 +2654,13 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
bool useMHigh = false; // If false, assume that mHigh == mLow
mLow.init(1);
if (!word1(d) && !(word0(d) & Bndry_mask)
if (!word1(value) && !(word0(value) & Bndry_mask)
#ifndef Sudden_Underflow
&& word0(d) & (Exp_mask & Exp_mask << 1)
&& word0(value) & (Exp_mask & Exp_mask << 1)
#endif
) {
// The special case. Here we want to be within a quarter of the last input
// significant digit instead of one half of it when the output string's value is less than d.
// significant digit instead of one half of it when the output string's value is less than value.
s2 += Log2P;
useMHigh = true;
mHigh.init(1u<<Log2P);
@ -2544,9 +2673,9 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
// At this point we have the following:
// s = 2^s2;
// 1 > df = b/2^s2 > 0;
// (d - prevDouble(d))/2 = mLow/2^s2;
// (nextDouble(d) - d)/2 = mHigh/2^s2.
// 1 > valueFrac = b/2^s2 > 0;
// (value - prevDouble(value))/2 = mLow/2^s2;
// (nextDouble(value) - value)/2 = mHigh/2^s2.
bool done = false;
do {
@ -2558,7 +2687,7 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
if (useMHigh)
mHigh.mulAdd(base, 0);
// Do we yet have the shortest string that will round to d?
// Do we yet have the shortest string that will round to value?
j = b.cmp(mLow);
// j is b/2^s2 compared with mLow/2^s2.
{
@ -2569,7 +2698,7 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
// j1 is b/2^s2 compared with 1 - mHigh/2^s2.
#ifndef ROUND_BIASED
if (j1 == 0 && !(word1(d) & 1)) {
if (j1 == 0 && !(word1(value) & 1)) {
if (j > 0)
digit++;
done = true;
@ -2577,12 +2706,12 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
#endif
if (j < 0 || (j == 0
#ifndef ROUND_BIASED
&& !(word1(d) & 1)
&& !(word1(value) & 1)
#endif
)) {
if (j1 > 0) {
// Either dig or dig+1 would work here as the least significant digit.
// Use whichever would produce an output value closer to d.
// Use whichever would produce an output value closer to value.
b.pow2Mul(1);
j1 = b.cmp(s);
if (j1 > 0) // The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
@ -2598,6 +2727,17 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
*p++ = baseDigit(digit);
} while (!done);
}
ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE);
ASSERT(p < buffer + dtobasesBufferSize);
*p = '\0';
return size_t(p - buffer);
}
// A version of doubleToStr that appends to the end of String dst.
void JS::printDouble(String &dst, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
dst += doubleToStr(buffer, sizeof buffer, value, mode, precision);
}

Просмотреть файл

@ -37,6 +37,14 @@ using std::atan;
namespace JavaScript {
//
// Double-precision constants
//
extern double positiveInfinity;
extern double negativeInfinity;
extern double nan;
//
// Portable double-precision floating point to string and back conversions
//
@ -100,32 +108,36 @@ namespace JavaScript {
//
// Some of the modes take an integer parameter <precision>.
//
// Keep this in sync with number_constants[].
// Keep this in sync with doubleToAsciiModes[].
enum DToStrMode {
DTOSTR_STANDARD, // Either fixed or exponential format; round-trip
DTOSTR_STANDARD_EXPONENTIAL, // Always exponential format; round-trip
DTOSTR_FIXED, // Round to <precision> digits after the decimal point; exponential if number is large
DTOSTR_EXPONENTIAL, // Always exponential format; <precision> significant digits
DTOSTR_PRECISION // Either fixed or exponential format; <precision> significant digits
dtosStandard, // Either fixed or exponential format; round-trip
dtosStandardExponential, // Always exponential format; round-trip
dtosFixed, // Round to <precision> digits after the decimal point; exponential if number is large
dtosExponential, // Always exponential format; <precision> significant digits
dtosPrecision // Either fixed or exponential format; <precision> significant digits
};
// Maximum number of characters (including trailing null) that a DTOSTR_STANDARD or DTOSTR_STANDARD_EXPONENTIAL
// Maximum number of characters (including trailing null) that a dtosStandard or dtosStandardExponential
// conversion can produce. This maximum is reached for a number like -1.2345678901234567e+123.
const int DTOSTR_STANDARD_BUFFER_SIZE = 25;
const int dtosStandardBufferSize = 25;
// Maximum number of characters (including trailing null) that one of the other conversions
// can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point.
#define DTOSTR_VARIABLE_BUFFER_SIZE(precision) ((precision)+24 > DTOSTR_STANDARD_BUFFER_SIZE ? (precision)+24 : DTOSTR_STANDARD_BUFFER_SIZE)
#define dtosVariableBufferSize(precision) ((precision)+24 > dtosStandardBufferSize ? (precision)+24 : dtosStandardBufferSize)
// "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
// which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
// the output string and malloc fewer bytes depending on d and base, but why bother?
const int DTOBASESTR_BUFFER_SIZE = 1078;
const int dtobasesBufferSize = 1078;
double strToD(const char *s00, char **se);
char *dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision, double dval);
void dToBaseStr(char *buffer, uint base, double d);
double strToDouble(const char *str, const char *&numEnd);
double stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd);
double stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base);
char *doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision);
size_t doubleToBaseStr(char *buffer, double value, uint base);
void printDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline String &operator+=(String &s, double value) {printDouble(s, value); return s;}
}
#endif

Просмотреть файл

@ -63,7 +63,7 @@ using namespace JavaScript;
// On a machine with IEEE extended-precision registers, it is
// necessary to specify double-precision (53-bit) rounding precision
// before invoking strToD or dToA. If the machine uses (the equivalent
// before invoking strToDouble or doubleToAscii. If the machine uses (the equivalent
// of) Intel 80x87 arithmetic, the call
// _control87(PC_53, MCW_PC);
// does this with many compilers. Whether this or another call is
@ -72,9 +72,9 @@ using namespace JavaScript;
// file.
// strToD for IEEE-arithmetic machines.
// strToDouble for IEEE-arithmetic machines.
//
// This strToD returns a nearest machine number to the input decimal
// This strToDouble returns a nearest machine number to the input decimal
// string. With IEEE arithmetic, ties are broken by the IEEE round-even
// rule. Otherwise ties are broken by biased rounding (add half and chop).
//
@ -108,18 +108,13 @@ using namespace JavaScript;
// #define Sudden_Underflow for IEEE-format machines without gradual
// underflow (i.e., that flush to zero on underflow).
// #define No_leftright to omit left-right logic in fast floating-point
// computation of dToA.
// computation of doubleToAscii.
// #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
// #define ROUND_BIASED for IEEE-format with biased rounding.
// #define Inaccurate_Divide for IEEE-format with correctly rounded
// products but inaccurate quotients, e.g., for Intel i860.
// #define NATIVE_INT64 on machines that have "long long"
// 64-bit integer types int64 and uint64.
// #define INFNAN_CHECK on IEEE systems to cause strToD to check for
// Infinity and NaN (case insensitively). On some systems (e.g.,
// some HP systems), it may be necessary to #define NAN_WORD0
// appropriately -- to the most significant word of a quiet NaN.
// (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
// #define JS_THREADSAFE if the system offers preemptively scheduled
// multiple threads. In this case, you must provide (or suitably
// #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
@ -128,8 +123,8 @@ using namespace JavaScript;
// powers of 5; omitting this lock would introduce a small
// probability of wasting memory, but would otherwise be harmless.)
// You must also invoke freeDToA(s) to free the value s returned by
// dToA. You may do so whether or not JS_THREADSAFE is #defined.
// #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strToD that
// doubleToAscii. You may do so whether or not JS_THREADSAFE is #defined.
// #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strToDouble that
// avoids underflows on inputs whose result does not underflow.
#ifdef IS_LITTLE_ENDIAN
@ -139,14 +134,6 @@ using namespace JavaScript;
#endif
#ifndef __MATH_H__
//#include "math.h"
#endif
#if defined(IEEE_8087) + defined(IEEE_MC68k) != 1
Exactly one of IEEE_8087 or IEEE_MC68k should be defined.
#endif
// Stefan Hanske <sh990154@mail.uni-greifswald.de> reports:
// ARM is a little endian architecture but 64 bit double words are stored
// differently: the 32 bit words are in little endian byte order, the two words
@ -218,6 +205,34 @@ Exactly one of IEEE_8087 or IEEE_MC68k should be defined.
#endif
//
// Double-precision constants
//
double JS::positiveInfinity;
double JS::negativeInfinity;
double JS::nan;
struct InitNumerics {InitNumerics();};
static InitNumerics initNumerics;
InitNumerics::InitNumerics()
{
word0(positiveInfinity) = Exp_mask;
word1(positiveInfinity) = 0;
word0(negativeInfinity) = Exp_mask | Sign_bit;
word1(negativeInfinity) = 0;
word0(nan) = 0x7FFFFFFF;
word1(nan) = 0xFFFFFFFF;
}
//
// Portable double-precision floating point to string and back conversions
//
// Return the absolute difference between x and the adjacent greater-magnitude double number (ignoring exponent overflows).
double JS::ulp(double x)
{
@ -325,6 +340,9 @@ static int lo0bits(uint32 &y)
}
uint32 *JS::BigInt::freeLists[maxLgGrossSize+1];
// Allocate a BigInt with 2^lgGrossSize words. The BigInt must not currently contain a number.
void JS::BigInt::allocate(uint lgGrossSize)
{
@ -1030,39 +1048,12 @@ static const double tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128,
#endif
};
// The factor of 2^53 in tinytens[4] helps us avoid setting the underflow
// flag unnecessarily. It leads to a song and dance at the end of strToD.
// flag unnecessarily. It leads to a song and dance at the end of strToDouble.
const int32 Scale_Bit = 0x10;
const int n_bigtens = 5;
#ifdef INFNAN_CHECK
#ifndef NAN_WORD0
#define NAN_WORD0 0x7ff80000
#endif
#ifndef NAN_WORD1
#define NAN_WORD1 0
#endif
static int match(const char **sp, char *t)
{
int c, d;
const char *s = *sp;
while (d = *t++) {
if ((c = *++s) >= 'A' && c <= 'Z')
c += 'a' - 'A';
if (c != d)
return 0;
}
*sp = s + 1;
return 1;
}
#endif // INFNAN_CHECK
#ifdef JS_THREADSAFE
static bool initialized = false;
@ -1078,15 +1069,15 @@ static void InitDtoa(void)
// Return as a double-precision floating-point number the value represented by the character
// string s00. The string is scanned up to the first unrecognized character.
// If se is not nil, return a pointer to the character terminating the scan in se.
// If no number can be formed, set se to s00 and return zero.
double JS::strToD(const char *s00, char **se)
// string str. The string is scanned up to the first unrecognized character. The character
// sequences 'Infinity', '+Infinity', '-Infinity', and 'NaN' are also recognized.
// Return a pointer to the character terminating the scan in numEnd.
// If no number can be formed, set numEnd to str and return zero.
double JS::strToDouble(const char *str, const char *&numEnd)
{
int32 scale;
int32 bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0;
bool negative;
const char *s, *s0, *s1;
double aadj, aadj1, adj, rv, rv0;
int32 L;
@ -1097,36 +1088,53 @@ double JS::strToD(const char *s00, char **se)
#endif
nz0 = nz = 0;
negative = false;
bool negative = false;
bool haveSign = false;
rv = 0.;
for (s = s00;;s++)
for (s = str;; s++)
switch (*s) {
case '-':
case '-':
negative = true;
// no break
case '+':
case '+':
haveSign = true;
if (*++s)
goto break2;
// no break
case 0:
s = s00;
case 0:
s = str;
goto ret;
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
continue;
default:
default:
goto break2;
}
break2:
if (*s == '0') {
break2:
switch (*s) {
case '0':
nz0 = 1;
while (*++s == '0') ;
if (!*s)
goto ret;
break;
case 'I':
if (!std::strncmp(s+1, "nfinity", 7)) {
rv = positiveInfinity;
s += 8;
goto ret;
}
break;
case 'N':
if (!haveSign && !std::strncmp(s+1, "aN", 2)) {
rv = nan;
s += 3;
goto ret;
}
}
s0 = s;
y = z = 0;
@ -1150,7 +1158,7 @@ break2:
goto dig_done;
}
for (; c >= '0' && c <= '9'; c = *++s) {
have_dig:
have_dig:
nz++;
if (c -= '0') {
nf += nz;
@ -1167,14 +1175,14 @@ break2:
}
}
}
dig_done:
dig_done:
e = 0;
if (c == 'e' || c == 'E') {
if (!nd && !nz && !nz0) {
s = s00;
s = str;
goto ret;
}
s00 = s;
str = s;
esign = 0;
switch (c = *++s) {
case '-':
@ -1202,31 +1210,11 @@ dig_done:
e = 0;
}
else
s = s00;
s = str;
}
if (!nd) {
if (!nz && !nz0) {
#ifdef INFNAN_CHECK
// Check for Nan and Infinity
switch (c) {
case 'i':
case 'I':
if (match(&s,"nfinity")) {
word0(rv) = 0x7ff00000;
word1(rv) = 0;
goto ret;
}
break;
case 'n':
case 'N':
if (match(&s, "an")) {
word0(rv) = NAN_WORD0;
word1(rv) = NAN_WORD1;
goto ret;
}
}
#endif // INFNAN_CHECK
s = s00;
s = str;
}
goto ret;
}
@ -1277,10 +1265,9 @@ dig_done:
rv *= tens[i];
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
ovfl:
ovfl:
// Return infinity.
word0(rv) = Exp_mask;
word1(rv) = 0;
rv = positiveInfinity;
goto ret;
}
e1 >>= 4;
@ -1339,7 +1326,7 @@ dig_done:
rv *= tinytens[j];
#endif
if (!rv) {
undfl:
undfl:
rv = 0.;
goto ret;
}
@ -1463,7 +1450,7 @@ dig_done:
#ifdef Avoid_Underflow
dsign = 2;
#endif
drop_down:
drop_down:
// boundary case -- decrement exponent
#ifdef Sudden_Underflow
L = word0(rv) & Exp_mask;
@ -1524,11 +1511,11 @@ dig_done:
aadj1 = dsign ? aadj : -aadj;
#ifdef Check_FLT_ROUNDS
switch (FLT_ROUNDS) {
case 2: // towards +infinity
case 2: // towards +infinity
aadj1 -= 0.5;
break;
case 0: // towards 0
case 3: // towards -infinity
case 0: // towards 0
case 3: // towards -infinity
aadj1 += 0.5;
}
#else
@ -1641,14 +1628,186 @@ dig_done:
#endif // Avoid_Underflow
}
ret:
if (se)
*se = (char *)s;
numEnd = s;
return negative ? -rv : rv;
}
// A version of strToDouble that takes a char16 string that begins at str and ends just
// before strEnd. The char16 string does not have to be null-terminated.
// Leading Unicode whitespace is skipped.
double JS::stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd)
{
const char16 *str1 = skipWhiteSpace(str, strEnd);
// dToA for IEEE arithmetic (dmg): convert double to ASCII string.
CharAutoPtr cstr(new char[strEnd - str1 + 1]);
char *q = cstr.get();
for (const char16 *p = str1; p != strEnd; p++) {
char16 ch = *p;
if (uint16(ch) >> 8)
break;
*q++ = char(ch);
}
*q = '\0';
const char *estr;
double value = strToDouble(cstr.get(), estr);
ptrdiff_t i = estr - cstr.get();
numEnd = i ? str1 + i : str;
return value;
}
class BinaryDigitReader
{
uint base; // Base of number; must be a power of 2
uint digit; // Current digit value in radix given by base
uint digitMask; // Mask to extract the next bit from digit
const char16 *digits; // Pointer to the remaining digits
const char16 *digitsEnd; // Pointer to first non-digit
public:
BinaryDigitReader(uint base, const char16 *digitsBegin, const char16 *digitsEnd):
base(base), digitMask(0), digits(digitsBegin), digitsEnd(digitsEnd) {}
int next();
};
// Return the next binary digit from the number or -1 if done.
int BinaryDigitReader::next()
{
if (digitMask == 0) {
if (digits == digitsEnd)
return -1;
uint c = *digits++;
if ('0' <= c && c <= '9')
digit = c - '0';
else if ('a' <= c && c <= 'z')
digit = c - 'a' + 10;
else digit = c - 'A' + 10;
digitMask = base >> 1;
}
int bit = (digit & digitMask) != 0;
digitMask >>= 1;
return bit;
}
// Read an integer from a char16 string that begins at str and ends just before strEnd.
// The char16 string does not have to be null-terminated. The integer is returned as a double,
// which is guaranteed to be the closest double number to the given input when base is 10 or a power of 2.
// May experience roundoff errors for very large numbers of a different radix.
// Return a pointer to the character just past the integer in numEnd.
// If the string does not have a number in it, set numEnd to str and return 0.
// Leading Unicode whitespace is skipped.
double JS::stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base)
{
const char16 *str1 = skipWhiteSpace(str, strEnd);
bool negative = (*str1 == '-');
if (negative || *str1 == '+')
str1++;
if ((base == 0 || base == 16) && *str1 == '0' && (str1[1] == 'X' || str1[1] == 'x')) {
// Skip past hex prefix.
base = 16;
str1 += 2;
}
if (base == 0)
base = 10; // Default to decimal.
// Find some prefix of the string that's a number in the given base.
const char16 *start = str1; // Mark - if string is empty, we return 0.
double value = 0.0;
while (true) {
uint digit;
char16 c = *str1;
if ('0' <= c && c <= '9')
digit = uint(c) - '0';
else if ('a' <= c && c <= 'z')
digit = uint(c) - 'a' + 10;
else if ('A' <= c && c <= 'Z')
digit = uint(c) - 'A' + 10;
else
break;
if (digit >= base)
break;
value = value*base + digit;
str1++;
}
if (value >= 9007199254740992.0) {
if (base == 10) {
// If we're accumulating a decimal number and the number is >= 2^53, then
// the result from the repeated multiply-add above may be inaccurate. Call
// stringToDouble to get the correct answer.
const char16 *numEnd2;
value = stringToDouble(start, str1, numEnd2);
ASSERT(numEnd2 == str1);
} else if (base == 2 || base == 4 || base == 8 || base == 16 || base == 32) {
// The number may also be inaccurate for one of these bases. This
// happens if the addition in value*base + digit causes a round-down
// to an even least significant mantissa bit when the first dropped bit
// is a one. If any of the following digits in the number (which haven't
// been added in yet) are nonzero then the correct action would have
// been to round up instead of down. An example of this occurs when
// reading the number 0x1000000000000081, which rounds to 0x1000000000000000
// instead of 0x1000000000000100.
BinaryDigitReader bdr(base, start, str1);
value = 0.0;
// Skip leading zeros.
int bit;
do {
bit = bdr.next();
} while (bit == 0);
if (bit == 1) {
// Gather the 53 significant bits (including the leading 1)
value = 1.0;
for (int j = 52; j; --j) {
bit = bdr.next();
if (bit < 0)
goto done;
value = value*2 + bit;
}
// bit2 is the 54th bit (the first dropped from the mantissa)
int bit2 = bdr.next();
if (bit2 >= 0) {
double factor = 2.0;
int sticky = 0; // sticky is 1 if any bit beyond the 54th is 1
int bit3;
while ((bit3 = bdr.next()) >= 0) {
sticky |= bit3;
factor *= 2;
}
value += bit2 & (bit | sticky);
value *= factor;
}
done:;
}
}
}
// We don't worry about inaccurate numbers for any other base.
if (str1 == start)
numEnd = str;
else {
numEnd = str1;
if (negative)
value = -value;
}
return value;
}
// doubleToAscii for IEEE arithmetic (dmg): convert double to ASCII string.
//
// Inspired by "How to Print Floating-Point Numbers Accurately" by
// Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
@ -1687,15 +1846,15 @@ dig_done:
// when the number is exactly halfway between two representable values. For example,
// rounding 2.5 to zero digits after the decimal point will return 3 and not 2.
// 2.49 will still round to 2, and 2.51 will still round to 3.
// bufsize should be at least 20 for modes 0 and 1. For the other modes,
// bufsize should be two greater than the maximum number of output characters expected.
static bool dToA(double d, int mode, bool biasUp, int ndigits,
int *decpt, bool *negative, char **rve, char *buf, size_t bufsize)
// The buffer should be at least 20 bytes for modes 0 and 1. For the other modes,
// the buffer's size should be two greater than the maximum number of output characters expected.
// Return a pointer to the resulting string's trailing null.
static char *doubleToAscii(double d, int mode, bool biasUp, int ndigits,
int *decpt, bool *negative, char *buf)
{
/* Arguments ndigits, decpt, negative are similar to those
of ecvt and fcvt; trailing zeros are suppressed from
the returned string. If not null, *rve is set to point
to the end of the return value. If d is +-Infinity or NaN,
the returned string. If d is +-Infinity or NaN,
then *decpt is set to 9999.
mode:
@ -1753,28 +1912,14 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
// Infinity or NaN
*decpt = 9999;
s = !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN";
if ((s[0] == 'I' && bufsize < 9) || (s[0] == 'N' && bufsize < 4)) {
ASSERT(false);
return false;
}
std::strcpy(buf, s);
if (rve) {
*rve = buf[3] ? buf + 8 : buf + 3;
ASSERT(**rve == '\0');
}
return true;
return buf[3] ? buf + 8 : buf + 3;
}
if (!d) {
no_digits:
*decpt = 1;
if (bufsize < 2) {
ASSERT(false);
return false;
}
buf[0] = '0'; buf[1] = '\0'; // copy "0" to buffer
if (rve)
*rve = buf + 1;
return true;
return buf + 1;
}
BigInt b;
@ -1870,24 +2015,24 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
leftright = 1;
ilim = ilim1 = 0;
switch (mode) {
case 0:
case 1:
case 0:
case 1:
ilim = ilim1 = -1;
i = 18;
ndigits = 0;
break;
case 2:
case 2:
leftright = 0;
// no break
case 4:
case 4:
if (ndigits <= 0)
ndigits = 1;
ilim = ilim1 = i = ndigits;
break;
case 3:
case 3:
leftright = 0;
// no break
case 5:
case 5:
i = ndigits + k + 1;
ilim = i;
ilim1 = i - 1;
@ -1897,12 +2042,6 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
// ilim is the maximum number of significant digits we want, based on k and ndigits.
// ilim1 is the maximum number of significant digits we want, based on k and ndigits,
// when it turns out that k was computed too high by one.
// Ensure space for at least i+1 characters, including trailing null.
if (bufsize <= (size_t)i) {
ASSERT(false);
return false;
}
s = buf;
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@ -1999,7 +2138,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
#ifndef No_leftright
}
#endif
fast_failed:
fast_failed:
s = buf;
d = d2;
k = k0;
@ -2033,7 +2172,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
if (i == ilim) {
d += d;
if ((d > ds) || (d == ds && (L & 1 || biasUp))) {
bump_up:
bump_up:
while (*--s == '9')
if (s == buf) {
k++;
@ -2238,7 +2377,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
}
if (j1 > 0) {
if (dig == '9') { // possible if i == 1
round_9_up:
round_9_up:
*s++ = '9';
goto roundoff;
}
@ -2267,7 +2406,7 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
b.pow2Mul(1);
j = b.cmp(S);
if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) {
roundoff:
roundoff:
while (*--s == '9')
if (s == buf) {
k++;
@ -2285,45 +2424,40 @@ static bool dToA(double d, int mode, bool biasUp, int ndigits,
// S, mLow, and mHigh are destroyed at the end of this block scope.
}
ret1:
ASSERT(s < buf + bufsize);
*s = '\0';
if (rve)
*rve = s;
*decpt = k + 1;
return true;
return s;
}
// Mapping of DToStrMode -> dToA mode
static const int dToAModes[] = {
0, // DTOSTR_STANDARD
0, // DTOSTR_STANDARD_EXPONENTIAL
3, // DTOSTR_FIXED
2, // DTOSTR_EXPONENTIAL
2}; // DTOSTR_PRECISION
// Mapping of DToStrMode -> doubleToAscii mode
static const int doubleToAsciiModes[] = {
0, // dtosStandard
0, // dtosStandardExponential
3, // dtosFixed
2, // dtosExponential
2}; // dtosPrecision
// Convert dval according to the given mode and return a pointer to the resulting ASCII string.
// Convert value according to the given mode and return a pointer to the resulting ASCII string.
// The result is held somewhere in buffer, but not necessarily at the beginning. The size of
// buffer is given in bufferSize, and must be at least as large as given by the above macros.
char *JS::dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision, double d)
// buffer is given in bufferSize, and must be at least as large as given by dtosStandardBufferSize
// or dtosVariableBufferSize, whichever is appropriate.
char *JS::doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision)
{
int decPt; // Position of decimal point relative to first digit returned by dToA
bool negative; // True if the sign bit was set in d
int nDigits; // Number of significand digits returned by dToA
char *numBegin = buffer+2; // Pointer to the digits returned by dToA; the +2 leaves space for
int decPt; // Position of decimal point relative to first digit returned by doubleToAscii
bool negative; // True if the sign bit was set in value
int nDigits; // Number of significand digits returned by doubleToAscii
char *numBegin = buffer+2; // Pointer to the digits returned by doubleToAscii; the +2 leaves space for
// the sign and/or decimal point
char *numEnd; // Pointer past the digits returned by dToA
char *numEnd; // Pointer past the digits returned by doubleToAscii
ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL ? DTOSTR_STANDARD_BUFFER_SIZE :
DTOSTR_VARIABLE_BUFFER_SIZE(precision)));
ASSERT(bufferSize >= (size_t)(mode <= dtosStandardExponential ? dtosStandardBufferSize : dtosVariableBufferSize(precision)));
if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21))
mode = DTOSTR_STANDARD; // Change mode here rather than below because the buffer may not be large enough to hold a large integer.
if (!dToA(d, dToAModes[mode], mode >= DTOSTR_FIXED, precision, &decPt, &negative, &numEnd, numBegin, bufferSize-2))
return 0;
if (mode == dtosFixed && (value >= 1e21 || value <= -1e21))
mode = dtosStandard; // Change mode here rather than below because the buffer may not be large enough to hold a large integer.
numEnd = doubleToAscii(value, doubleToAsciiModes[mode], mode >= dtosFixed, precision, &decPt, &negative, numBegin);
nDigits = numEnd - numBegin;
// If Infinity, -Infinity, or NaN, return the string regardless of the mode.
@ -2334,34 +2468,34 @@ char *JS::dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision
char *q;
switch (mode) {
case DTOSTR_STANDARD:
if (decPt < -5 || decPt > 21)
exponentialNotation = true;
else
minNDigits = decPt;
break;
case DTOSTR_FIXED:
if (precision >= 0)
minNDigits = decPt + precision;
else
minNDigits = decPt;
break;
case DTOSTR_EXPONENTIAL:
ASSERT(precision > 0);
minNDigits = precision;
// Fall through
case DTOSTR_STANDARD_EXPONENTIAL:
case dtosStandard:
if (decPt < -5 || decPt > 21)
exponentialNotation = true;
break;
else
minNDigits = decPt;
break;
case DTOSTR_PRECISION:
ASSERT(precision > 0);
minNDigits = precision;
if (decPt < -5 || decPt > precision)
exponentialNotation = true;
break;
case dtosFixed:
if (precision >= 0)
minNDigits = decPt + precision;
else
minNDigits = decPt;
break;
case dtosExponential:
ASSERT(precision > 0);
minNDigits = precision;
// Fall through
case dtosStandardExponential:
exponentialNotation = true;
break;
case dtosPrecision:
ASSERT(precision > 0);
minNDigits = precision;
if (decPt < -5 || decPt > precision)
exponentialNotation = true;
break;
}
// If the number has fewer than minNDigits, pad it with zeros at the end
@ -2412,9 +2546,9 @@ char *JS::dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision
// If negative and neither -0.0 nor NaN, output a leading '-'.
if (negative &&
!(word0(d) == Sign_bit && word1(d) == 0) &&
!((word0(d) & Exp_mask) == Exp_mask &&
(word1(d) || (word0(d) & Frac_mask)))) {
!(word0(value) == Sign_bit && word1(value) == 0) &&
!((word0(value) & Exp_mask) == Exp_mask &&
(word1(value) || (word0(value) & Frac_mask)))) {
*--numBegin = '-';
}
return numBegin;
@ -2430,47 +2564,42 @@ inline char baseDigit(uint32 digit)
}
// Convert d to a string in the given base. The integral part of d will be printed exactly
// Convert value to a string in the given base. The integral part of value will be printed exactly
// in that base, regardless of how large it is, because there is no exponential notation for non-base-ten
// numbers. The fractional part will be rounded to as few digits as possible while still preserving
// the round-trip property (analogous to that of printing decimal numbers). In other words, if one were
// to read the resulting string in via a hypothetical base-number-reading routine that rounds to the nearest
// IEEE double (and to an even significand if there are two equally near doubles), then the result would
// equal d (except for -0.0, which converts to "0", and NaN, which is not equal to itself).
// equal value (except for -0.0, which converts to "0", and NaN, which is not equal to itself).
//
// Store the result in the given buffer, which must have at least DTOBASESTR_BUFFER_SIZE bytes.
void JS::dToBaseStr(char *buffer, uint base, double d)
// Store the result in the given buffer, which must have at least dtobasesBufferSize bytes.
// Return the number of characters stored.
size_t JS::doubleToBaseStr(char *buffer, double value, uint base)
{
char *p; // Pointer to current position in the buffer
char *pInt; // Pointer to the beginning of the integer part of the string
char *q;
uint32 digit;
double di; // d truncated to an integer
double df; // The fractional part of d
ASSERT(base >= 2 && base <= 36);
p = buffer;
if (d < 0.0
char *p = buffer; // Pointer to current position in the buffer
if (value < 0.0
#ifdef XP_PC
&& !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) // Visual C++ doesn't know how to compare against NaN
&& !((word0(value) & Exp_mask) == Exp_mask && ((word0(value) & Frac_mask) || word1(value))) // Visual C++ doesn't know how to compare against NaN
#endif
) {
*p++ = '-';
d = -d;
value = -value;
}
// Check for Infinity and NaN
if ((word0(d) & Exp_mask) == Exp_mask) {
std::strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN");
return;
if ((word0(value) & Exp_mask) == Exp_mask) {
std::strcpy(p, !word1(value) && !(word0(value) & Frac_mask) ? "Infinity" : "NaN");
return std::strlen(buffer);
}
// Output the integer part of d with the digits in reverse order.
pInt = p;
di = floor(d);
if (di <= 4294967295.0) {
uint32 n = (uint32)di;
// Output the integer part of value with the digits in reverse order.
char *pInt = p; // Pointer to the beginning of the integer part of the string
double valueInt = floor(value); // value truncated to an integer
uint32 digit;
if (valueInt <= 4294967295.0) {
uint32 n = (uint32)valueInt;
if (n)
do {
uint32 m = n / base;
@ -2482,9 +2611,9 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
else *p++ = '0';
} else {
int32 e;
int32 bits; // Number of significant bits in di; not used.
int32 bits; // Number of significant bits in valueInt; not used.
BigInt b;
b.init(di, e, bits);
b.init(valueInt, e, bits);
b.pow2Mul(e);
do {
digit = b.divRem(base);
@ -2492,32 +2621,32 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
*p++ = baseDigit(digit);
} while (!b.isZero());
}
// Reverse the digits of the integer part of d.
q = p-1;
// Reverse the digits of the integer part of value.
char *q = p-1;
while (q > pInt) {
char ch = *pInt;
*pInt++ = *q;
*q-- = ch;
}
df = d - di;
if (df != 0.0) {
double valueFrac = value - valueInt; // The fractional part of value
if (valueFrac != 0.0) {
// We have a fraction.
*p++ = '.';
int32 e, bbits;
BigInt b;
b.init(df, e, bbits);
b.init(valueFrac, e, bbits);
ASSERT(e < 0);
// At this point df = b * 2^e. e must be less than zero because 0 < df < 1.
// At this point valueFrac = b * 2^e. e must be less than zero because 0 < valueFrac < 1.
int32 s2 = -int32(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1);
int32 s2 = -int32(word0(value) >> Exp_shift1 & Exp_mask>>Exp_shift1);
#ifndef Sudden_Underflow
if (!s2)
s2 = -1;
#endif
s2 += Bias + P;
// 1/2^s2 = (nextDouble(d) - d)/2
// 1/2^s2 = (nextDouble(value) - value)/2
ASSERT(-s2 < e);
BigInt mLow;
@ -2525,13 +2654,13 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
bool useMHigh = false; // If false, assume that mHigh == mLow
mLow.init(1);
if (!word1(d) && !(word0(d) & Bndry_mask)
if (!word1(value) && !(word0(value) & Bndry_mask)
#ifndef Sudden_Underflow
&& word0(d) & (Exp_mask & Exp_mask << 1)
&& word0(value) & (Exp_mask & Exp_mask << 1)
#endif
) {
// The special case. Here we want to be within a quarter of the last input
// significant digit instead of one half of it when the output string's value is less than d.
// significant digit instead of one half of it when the output string's value is less than value.
s2 += Log2P;
useMHigh = true;
mHigh.init(1u<<Log2P);
@ -2544,9 +2673,9 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
// At this point we have the following:
// s = 2^s2;
// 1 > df = b/2^s2 > 0;
// (d - prevDouble(d))/2 = mLow/2^s2;
// (nextDouble(d) - d)/2 = mHigh/2^s2.
// 1 > valueFrac = b/2^s2 > 0;
// (value - prevDouble(value))/2 = mLow/2^s2;
// (nextDouble(value) - value)/2 = mHigh/2^s2.
bool done = false;
do {
@ -2558,7 +2687,7 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
if (useMHigh)
mHigh.mulAdd(base, 0);
// Do we yet have the shortest string that will round to d?
// Do we yet have the shortest string that will round to value?
j = b.cmp(mLow);
// j is b/2^s2 compared with mLow/2^s2.
{
@ -2569,7 +2698,7 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
// j1 is b/2^s2 compared with 1 - mHigh/2^s2.
#ifndef ROUND_BIASED
if (j1 == 0 && !(word1(d) & 1)) {
if (j1 == 0 && !(word1(value) & 1)) {
if (j > 0)
digit++;
done = true;
@ -2577,12 +2706,12 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
#endif
if (j < 0 || (j == 0
#ifndef ROUND_BIASED
&& !(word1(d) & 1)
&& !(word1(value) & 1)
#endif
)) {
if (j1 > 0) {
// Either dig or dig+1 would work here as the least significant digit.
// Use whichever would produce an output value closer to d.
// Use whichever would produce an output value closer to value.
b.pow2Mul(1);
j1 = b.cmp(s);
if (j1 > 0) // The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
@ -2598,6 +2727,17 @@ void JS::dToBaseStr(char *buffer, uint base, double d)
*p++ = baseDigit(digit);
} while (!done);
}
ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE);
ASSERT(p < buffer + dtobasesBufferSize);
*p = '\0';
return size_t(p - buffer);
}
// A version of doubleToStr that appends to the end of String dst.
void JS::printDouble(String &dst, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
dst += doubleToStr(buffer, sizeof buffer, value, mode, precision);
}

Просмотреть файл

@ -37,6 +37,14 @@ using std::atan;
namespace JavaScript {
//
// Double-precision constants
//
extern double positiveInfinity;
extern double negativeInfinity;
extern double nan;
//
// Portable double-precision floating point to string and back conversions
//
@ -100,32 +108,36 @@ namespace JavaScript {
//
// Some of the modes take an integer parameter <precision>.
//
// Keep this in sync with number_constants[].
// Keep this in sync with doubleToAsciiModes[].
enum DToStrMode {
DTOSTR_STANDARD, // Either fixed or exponential format; round-trip
DTOSTR_STANDARD_EXPONENTIAL, // Always exponential format; round-trip
DTOSTR_FIXED, // Round to <precision> digits after the decimal point; exponential if number is large
DTOSTR_EXPONENTIAL, // Always exponential format; <precision> significant digits
DTOSTR_PRECISION // Either fixed or exponential format; <precision> significant digits
dtosStandard, // Either fixed or exponential format; round-trip
dtosStandardExponential, // Always exponential format; round-trip
dtosFixed, // Round to <precision> digits after the decimal point; exponential if number is large
dtosExponential, // Always exponential format; <precision> significant digits
dtosPrecision // Either fixed or exponential format; <precision> significant digits
};
// Maximum number of characters (including trailing null) that a DTOSTR_STANDARD or DTOSTR_STANDARD_EXPONENTIAL
// Maximum number of characters (including trailing null) that a dtosStandard or dtosStandardExponential
// conversion can produce. This maximum is reached for a number like -1.2345678901234567e+123.
const int DTOSTR_STANDARD_BUFFER_SIZE = 25;
const int dtosStandardBufferSize = 25;
// Maximum number of characters (including trailing null) that one of the other conversions
// can produce. This maximum is reached for TO_FIXED, which can generate up to 21 digits before the decimal point.
#define DTOSTR_VARIABLE_BUFFER_SIZE(precision) ((precision)+24 > DTOSTR_STANDARD_BUFFER_SIZE ? (precision)+24 : DTOSTR_STANDARD_BUFFER_SIZE)
#define dtosVariableBufferSize(precision) ((precision)+24 > dtosStandardBufferSize ? (precision)+24 : dtosStandardBufferSize)
// "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
// which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
// the output string and malloc fewer bytes depending on d and base, but why bother?
const int DTOBASESTR_BUFFER_SIZE = 1078;
const int dtobasesBufferSize = 1078;
double strToD(const char *s00, char **se);
char *dToStr(char *buffer, size_t bufferSize, DToStrMode mode, int precision, double dval);
void dToBaseStr(char *buffer, uint base, double d);
double strToDouble(const char *str, const char *&numEnd);
double stringToDouble(const char16 *str, const char16 *strEnd, const char16 *&numEnd);
double stringToInteger(const char16 *str, const char16 *strEnd, const char16 *&numEnd, uint base);
char *doubleToStr(char *buffer, size_t bufferSize, double value, DToStrMode mode, int precision);
size_t doubleToBaseStr(char *buffer, double value, uint base);
void printDouble(String &dst, double value, DToStrMode mode = dtosStandard, int precision = 0);
inline String &operator+=(String &s, double value) {printDouble(s, value); return s;}
}
#endif