gecko-dev/js/js2/numerics.cpp

2767 lines
79 KiB
C++
Raw Normal View History

2000-01-29 08:24:40 +00:00
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape Public
// License Version 1.1 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of
// the License at http://www.mozilla.org/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 1998 Netscape Communications Corporation. All
// Rights Reserved.
#include <cstdlib>
#include <cstring>
#include <cfloat>
#include "numerics.h"
#include "jstypes.h"
2000-01-29 08:24:40 +00:00
namespace JS = JavaScript;
using namespace JavaScript;
using namespace JSTypes;
2000-01-29 08:24:40 +00:00
//
// Portable double-precision floating point to string and back conversions
//
// ****************************************************************
//
// The author of this software is David M. Gay.
//
// Copyright (c) 1991 by Lucent Technologies.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose without fee is hereby granted, provided that this entire notice
// is included in all copies of any software which is or includes a copy
// or modification of this software and in all copies of the supporting
// documentation for such software.
//
// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
// REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
// OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
//
// ***************************************************************
/* Please send bug reports to
David M. Gay
Bell Laboratories, Room 2C-463
600 Mountain Avenue
Murray Hill, NJ 07974-0636
U.S.A.
dmg@bell-labs.com
*/
// On a machine with IEEE extended-precision registers, it is
// necessary to specify double-precision (53-bit) rounding precision
2000-02-02 08:47:54 +00:00
// before invoking strToDouble or doubleToAscii. If the machine uses (the equivalent
2000-01-29 08:24:40 +00:00
// of) Intel 80x87 arithmetic, the call
// _control87(PC_53, MCW_PC);
// does this with many compilers. Whether this or another call is
// appropriate depends on the compiler; for this to work, it may be
// necessary to #include "float.h" or another system-dependent header
// file.
2000-02-02 08:47:54 +00:00
// strToDouble for IEEE-arithmetic machines.
2000-01-29 08:24:40 +00:00
//
2000-02-02 08:47:54 +00:00
// This strToDouble returns a nearest machine number to the input decimal
2000-01-29 08:24:40 +00:00
// string. With IEEE arithmetic, ties are broken by the IEEE round-even
// rule. Otherwise ties are broken by biased rounding (add half and chop).
//
// Inspired loosely by William D. Clinger's paper "How to Read Floating
// Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
//
// Modifications:
//
// 1. We only require IEEE double-precision
// arithmetic (not IEEE double-extended).
// 2. We get by with floating-point arithmetic in a case that
// Clinger missed -- when we're computing d * 10^n
// for a small integer d and the integer n is not too
// much larger than 22 (the maximum integer k for which
// we can represent 10^k exactly), we may be able to
// compute (d*10^k) * 10^(e-k) with just one roundoff.
// 3. Rather than a bit-at-a-time adjustment of the binary
// result in the hard case, we use floating-point
// arithmetic to determine the adjustment to within
// one bit; only in really hard cases do we need to
// compute a second residual.
// 4. Because of 3., we don't need a large table of powers of 10
// for ten-to-e (just some small tables, e.g. of 10^k
// for 0 <= k <= 22).
// #define IEEE_8087 for IEEE-arithmetic machines where the least
// significant byte has the lowest address.
// #define IEEE_MC68k for IEEE-arithmetic machines where the most
// significant byte has the lowest address.
// #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
2000-02-02 08:47:54 +00:00
// computation of doubleToAscii.
2000-01-29 08:24:40 +00:00
// #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 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
// by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
// in pow5Mul, ensures lazy evaluation of only one copy of high
// 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
2000-02-02 08:47:54 +00:00
// 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
2000-01-29 08:24:40 +00:00
// avoids underflows on inputs whose result does not underflow.
#ifdef IS_LITTLE_ENDIAN
#define IEEE_8087
#else
#define IEEE_MC68k
#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
// are stored in big endian`s way.
#if defined (IEEE_8087) && !defined(__arm)
#define word0(x) ((uint32 *)&x)[1]
#define word1(x) ((uint32 *)&x)[0]
#else
#define word0(x) ((uint32 *)&x)[0]
#define word1(x) ((uint32 *)&x)[1]
#endif
// The following definition of Storeinc is appropriate for MIPS processors.
// An alternative that might be better on some machines is
// #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
#if defined(IEEE_8087)
#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
((unsigned short *)a)[0] = (unsigned short)c, a++)
#else
#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
((unsigned short *)a)[1] = (unsigned short)c, a++)
#endif
// #define P DBL_MANT_DIG
// Ten_pmax = floor(P*log(2)/log(5))
// Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16
// Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1)
// Int_max = floor(P*log(FLT_RADIX)/log(10) - 1)
#define Exp_shift 20
#define Exp_shift1 20
#define Exp_msk1 0x100000
#define Exp_msk11 0x100000
#define Exp_mask 0x7ff00000
#define P 53
#define Bias 1023
#define Emin (-1022)
#define Exp_1 0x3ff00000
#define Exp_11 0x3ff00000
#define Ebits 11
#define Frac_mask 0xfffff
#define Frac_mask1 0xfffff
#define Ten_pmax 22
#define Bletch 0x10
#define Bndry_mask 0xfffff
#define Bndry_mask1 0xfffff
#define LSB 1
#define Sign_bit 0x80000000
#define Log2P 1
#define Tiny0 0
#define Tiny1 1
#define Quick_max 14
#define Int_max 14
#define Infinite(x) (word0(x) == 0x7ff00000) // sufficient test for here
#ifndef NO_IEEE_Scale
#define Avoid_Underflow
#endif
#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
#define Big1 0xffffffff
#ifdef JS_THREADSAFE
static PRLock *freelist_lock;
#define ACQUIRE_DTOA_LOCK(n) PR_Lock(freelist_lock)
#define FREE_DTOA_LOCK(n) PR_Unlock(freelist_lock)
#else
#define ACQUIRE_DTOA_LOCK(n)
#define FREE_DTOA_LOCK(n)
#endif
2000-02-02 08:47:54 +00:00
//
// 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;
}
const JSValue JSTypes::kUndefinedValue;
const JSValue JSTypes::kNaNValue = JSValue(nan);
const JSValue JSTypes::kTrueValue = JSValue(true);
const JSValue JSTypes::kFalseValue = JSValue(false);
const JSValue JSTypes::kNullValue = JSValue(JSValue::Tag::null_tag);
const JSValue JSTypes::kNegativeZero = JSValue(-0.0);
const JSValue JSTypes::kPositiveZero = JSValue(0.0);
const JSValue JSTypes::kNegativeInfinity = JSValue(negativeInfinity);
const JSValue JSTypes::kPositiveInfinity = JSValue(positiveInfinity);
2000-02-02 08:47:54 +00:00
//
// Portable double-precision floating point to string and back conversions
//
2000-01-29 08:24:40 +00:00
// Return the absolute difference between x and the adjacent greater-magnitude double number (ignoring exponent overflows).
double JS::ulp(double x)
{
int32 L;
double a;
L = int32((word0(x) & Exp_mask) - (P-1)*Exp_msk1);
#ifndef Sudden_Underflow
if (L > 0) {
#endif
word0(a) = uint32(L);
word1(a) = 0;
#ifndef Sudden_Underflow
}
else {
L = -L >> Exp_shift;
if (L < Exp_shift) {
word0(a) = 0x80000u >> L;
word1(a) = 0;
}
else {
word0(a) = 0;
L -= Exp_shift;
word1(a) = L >= 31 ? 1u : 1u << (31 - L);
}
}
#endif
return a;
}
// Return the number (0 through 32) of most significant zero bits in x.
int JS::hi0bits(uint32 x)
{
int k = 0;
if (!(x & 0xffff0000)) {
k = 16;
x <<= 16;
}
if (!(x & 0xff000000)) {
k += 8;
x <<= 8;
}
if (!(x & 0xf0000000)) {
k += 4;
x <<= 4;
}
if (!(x & 0xc0000000)) {
k += 2;
x <<= 2;
}
if (!(x & 0x80000000)) {
k++;
if (!(x & 0x40000000))
return 32;
}
return k;
}
// Return the number (0 through 32) of least significant zero bits in y.
// Also shift y to the right past these 0 through 32 zeros so that y's
// least significant bit will be set unless y was originally zero.
static int lo0bits(uint32 &y)
{
int k;
uint32 x = y;
if (x & 7) {
if (x & 1)
return 0;
if (x & 2) {
y = x >> 1;
return 1;
}
y = x >> 2;
return 2;
}
k = 0;
if (!(x & 0xffff)) {
k = 16;
x >>= 16;
}
if (!(x & 0xff)) {
k += 8;
x >>= 8;
}
if (!(x & 0xf)) {
k += 4;
x >>= 4;
}
if (!(x & 0x3)) {
k += 2;
x >>= 2;
}
if (!(x & 1)) {
k++;
x >>= 1;
if (!x & 1)
return 32;
}
y = x;
return k;
}
2000-02-02 08:47:54 +00:00
uint32 *JS::BigInt::freeLists[maxLgGrossSize+1];
2000-01-29 08:24:40 +00:00
// Allocate a BigInt with 2^lgGrossSize words. The BigInt must not currently contain a number.
void JS::BigInt::allocate(uint lgGrossSize)
{
ASSERT(lgGrossSize <= maxLgGrossSize);
BigInt::lgGrossSize = lgGrossSize;
negative = false;
grossSize = 1u << lgGrossSize;
size = 0;
words = 0;
ACQUIRE_DTOA_LOCK(0);
uint32 *w = freeLists[lgGrossSize];
if (w) {
freeLists[lgGrossSize] = *reinterpret_cast<uint32 **>(w);
FREE_DTOA_LOCK(0);
} else {
FREE_DTOA_LOCK(0);
w = static_cast<uint32 *>(STD::malloc(max(uint32(grossSize*sizeof(uint32)), uint32(sizeof(uint32 *)))));
2000-01-29 08:24:40 +00:00
if (!w) {
std::bad_alloc outOfMemory;
throw outOfMemory;
}
}
words = w;
}
// Recycle this BigInt's words array, which must be non-nil.
void JS::BigInt::recycle()
{
ASSERT(words);
uint bucket = lgGrossSize;
uint32 *w = words;
ACQUIRE_DTOA_LOCK(0);
*reinterpret_cast<uint32 **>(w) = freeLists[bucket];
freeLists[bucket] = w;
FREE_DTOA_LOCK(0);
}
// Copy b into this BigInt, which must be uninitialized.
void JS::BigInt::initCopy(const BigInt &b)
{
allocate(b.lgGrossSize);
negative = b.negative;
size = b.size;
std::copy(b.words, b.words+size, words);
}
// Move b into this BigInt. The original words array of this BigInt is recycled
// and must be non-nil. After the move b has no value.
void JS::BigInt::move(BigInt &b)
{
recycle();
lgGrossSize = b.lgGrossSize;
2000-02-05 00:39:58 +00:00
negative = b.negative;
2000-01-29 08:24:40 +00:00
grossSize = b.grossSize;
2000-02-05 00:39:58 +00:00
size = b.size;
2000-01-29 08:24:40 +00:00
words = b.words;
b.words = 0;
}
// Change this BigInt's lgGrossSize to the given value without affecting the BigInt value
// contained. This BigInt must currently have a value that will fit in the new lgGrossSize.
void JS::BigInt::setLgGrossSize(uint lgGrossSize)
{
ASSERT(words);
BigInt b(lgGrossSize);
ASSERT(size <= b.grossSize);
std::copy(words, words+size, b.words);
move(b);
}
// Set the BigInt to the given integer value.
// The BigInt must not currently have a value.
void JS::BigInt::init(uint32 i)
{
ASSERT(!words);
allocate(1); // Allocate two words to allow a little room for growth.
if (i) {
size = 1;
words[0] = i;
} else
size = 0;
}
// Convert d into the form b*2^e, where b is an odd integer. b is the BigInt returned
// in this, and e is the returned binary exponent. Return the number of significant
// bits in b in bits. d must be finite and nonzero.
void JS::BigInt::init(double d, int32 &e, int32 &bits)
{
allocate(1);
uint32 *x = words;
uint32 z = word0(d) & Frac_mask;
word0(d) &= 0x7fffffff; // clear sign bit, which we ignore
int32 de = (int32)(word0(d) >> Exp_shift);
#ifdef Sudden_Underflow
z |= Exp_msk11;
#else
if (de)
z |= Exp_msk1;
#endif
uint32 y = word1(d);
int k;
int i;
if (y) {
if ((k = lo0bits(y)) != 0) {
x[0] = y | z << (32 - k);
z >>= k;
}
else
x[0] = y;
i = (x[1] = z) ? 2 : 1;
} else {
ASSERT(z);
k = lo0bits(z);
x[0] = z;
i = 1;
k += 32;
}
size = uint32(i);
#ifndef Sudden_Underflow
if (de) {
#endif
e = de - Bias - (P-1) + k;
bits = P - k;
#ifndef Sudden_Underflow
} else {
e = de - Bias - (P-1) + 1 + k;
bits = 32*i - hi0bits(x[i-1]);
}
#endif
}
// Let this = this*m + a. Both a and m must be between 0 and 65535 inclusive.
void JS::BigInt::mulAdd(uint m, uint a)
{
#ifdef NATIVE_INT64
uint64 carry, y;
#else
uint32 carry, y;
uint32 xi, z;
#endif
ASSERT(m <= 0xFFFF && a <= 0xFFFF);
uint32 sz = size;
uint32 *x = words;
carry = a;
for (uint32 i = 0; i != sz; i++) {
#ifdef NATIVE_INT64
y = *x * (uint64)m + carry;
carry = y >> 32;
*x++ = (uint32)(y & 0xffffffffUL);
#else
xi = *x;
y = (xi & 0xffff) * m + carry;
z = (xi >> 16) * m + (y >> 16);
carry = z >> 16;
*x++ = (z << 16) + (y & 0xffff);
#endif
}
if (carry) {
if (sz >= grossSize)
setLgGrossSize(lgGrossSize+1);
words[sz++] = (uint32)carry;
size = sz;
}
}
// Let this = this*m.
void JS::BigInt::operator*=(const BigInt &m)
{
const BigInt *a;
const BigInt *b;
if (size >= m.size) {
a = this;
b = &m;
} else {
a = &m;
b = this;
}
uint k = a->lgGrossSize;
uint32 wa = a->size;
uint32 wb = b->size;
uint32 wc = wa + wb;
if (wc > a->grossSize)
k++;
BigInt c(k);
uint32 *xc;
uint32 *xce;
for (xc = c.words, xce = xc + wc; xc < xce; xc++)
*xc = 0;
const uint32 *xa = a->words;
const uint32 *xae = xa + wa;
const uint32 *xb = b->words;
const uint32 *xbe = xb + wb;
uint32 *xc0 = c.words;
uint32 y;
#ifdef NATIVE_INT64
for (; xb < xbe; xc0++) {
if ((y = *xb++) != 0) {
const uint32 *x = xa;
xc = xc0;
uint64 carry = 0;
do {
uint64 z = *x++ * (uint64)y + *xc + carry;
carry = z >> 32;
*xc++ = (uint32)(z & 0xffffffffUL);
} while (x < xae);
*xc = (uint32)carry;
}
}
#else
for (; xb < xbe; xb++, xc0++) {
uint32 carry;
uint32 z, z2;
const uint32 *x;
if ((y = *xb & 0xffff) != 0) {
x = xa;
xc = xc0;
carry = 0;
do {
z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
carry = z >> 16;
z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
carry = z2 >> 16;
Storeinc(xc, z2, z);
} while (x < xae);
*xc = carry;
}
if ((y = *xb >> 16) != 0) {
x = xa;
xc = xc0;
carry = 0;
z2 = *xc;
do {
z = (*x & 0xffff) * y + (*xc >> 16) + carry;
carry = z >> 16;
Storeinc(xc, z, z2);
z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
carry = z2 >> 16;
} while (x < xae);
*xc = z2;
}
}
#endif
for (xc0 = c.words, xc = xc0 + wc; wc && !*--xc; --wc) ;
c.size = wc;
move(c);
}
// Let this = this * 2^k. k must be nonnegative.
void JS::BigInt::pow2Mul(int32 k)
{
ASSERT(k >= 0);
uint32 n = uint32(k) >> 5;
uint k1 = lgGrossSize;
uint32 n1 = n + size + 1;
uint32 i;
for (i = grossSize; n1 > i; i <<= 1)
k1++;
BigInt b1(k1);
uint32 *x1 = b1.words;
for (i = 0; i < n; i++)
*x1++ = 0;
uint32 *x = words;
uint32 *xe = x + size;
if (k &= 0x1f) {
k1 = uint(32 - k);
uint32 z = 0;
while (x != xe) {
*x1++ = *x << k | z;
z = *x++ >> k1;
}
if ((*x1 = z) != 0)
++n1;
}
else
while (x != xe)
*x1++ = *x++;
b1.size = n1 - 1;
move(b1);
}
// 'p5s' points to a linked list of Bigints that are powers of 625.
// This list grows on demand, and it can only grow: it won't change
// in any other way. So if we read 'p5s' or the 'next' field of
// some BigInt on the list, and it is not NULL, we know it won't
// change to NULL or some other value. Only when the value of
// 'p5s' or 'next' is NULL do we need to acquire the lock and add
// a new BigInt to the list.
struct PowerOf625 {
PowerOf625 *next;
BigInt b;
};
static PowerOf625 *p5s;
#ifdef JS_THREADSAFE
static PRLock *p5s_lock;
#endif
// Let this = this * 5^k. k must be nonnegative.
void JS::BigInt::pow5Mul(int32 k)
{
static const uint p05[3] = {5, 25, 125};
ASSERT(k >= 0);
int32 i = k & 3;
if (i)
mulAdd(p05[i-1], 0);
if (!(k >>= 2))
return;
PowerOf625 *p5 = p5s;
if (!p5) {
auto_ptr<PowerOf625> p(new PowerOf625);
p->next = 0;
p->b.init(625);
#ifdef JS_THREADSAFE
// We take great care to not call init() and recycle() while holding the lock.
// lock and check again
PR_Lock(p5s_lock);
if (!(p5 = p5s)) {
#endif
// first time
p5 = p.release();
p5s = p5;
#ifdef JS_THREADSAFE
}
PR_Unlock(p5s_lock);
#endif
}
for (;;) {
if (k & 1)
*this *= p5->b;
if (!(k >>= 1))
break;
PowerOf625 *p51 = p5->next;
if (!p51) {
auto_ptr<PowerOf625> p(new PowerOf625);
p->next = 0;
p->b = p5->b;
p->b *= p5->b;
#ifdef JS_THREADSAFE
PR_Lock(p5s_lock);
if (!(p51 = p5->next)) {
#endif
p51 = p.release();
p5->next = p51;
#ifdef JS_THREADSAFE
}
PR_Unlock(p5s_lock);
#endif
}
p5 = p51;
}
}
// Return -1, 0, or 1 depending on whether this<b, this==b, or this>b, respectively.
int JS::BigInt::cmp(const BigInt &b) const
{
uint32 i = size;
uint32 j = b.size;
#ifdef DEBUG
if (i > 1 && !words[i-1])
NOT_REACHED("cmp called with words[size-1] == 0");
if (j > 1 && !b.words[j-1])
NOT_REACHED("cmp called with b.words[b.size-1] == 0");
#endif
if (i != j)
return i<j ? -1 : 1;
const uint32 *xa0 = words;
const uint32 *xa = xa0 + j;
const uint32 *xb = b.words + j;
while (xa != xa0) {
if (*--xa != *--xb)
return *xa < *xb ? -1 : 1;
}
return 0;
}
// Initialize this BigInt to m-n. This BigInt must not have a previous value.
void JS::BigInt::initDiff(const BigInt &m, const BigInt &n)
{
ASSERT(!words && this != &m && this != &n);
int i = m.cmp(n);
if (!i)
init(0);
else {
const BigInt *a;
const BigInt *b;
if (i < 0) {
a = &n;
b = &m;
} else {
a = &m;
b = &n;
}
allocate(a->lgGrossSize);
negative = i < 0;
uint32 wa = a->size;
const uint32 *xa = a->words;
const uint32 *xae = xa + wa;
const uint32 *xb = b->words;
const uint32 *xbe = xb + b->size;
uint32 *xc = words;
#ifdef NATIVE_INT64
uint64 borrow = 0;
uint64 y;
while (xb < xbe) {
y = (uint64)*xa++ - *xb++ - borrow;
borrow = y >> 32 & 1UL;
*xc++ = (uint32)(y & 0xffffffffUL);
}
while (xa < xae) {
y = *xa++ - borrow;
borrow = y >> 32 & 1UL;
*xc++ = (uint32)(y & 0xffffffffUL);
}
#else
uint32 borrow = 0;
uint32 y;
uint32 z;
while (xb < xbe) {
y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(xc, z, y);
}
while (xa < xae) {
y = (*xa & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*xa++ >> 16) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(xc, z, y);
}
#endif
while (!*--xc)
wa--;
size = wa;
}
}
// Return floor(this/2^k) and set this to be the remainder.
// The returned quotient must be less than 2^32.
uint32 JS::BigInt::quoRem2(int32 k)
{
int32 n = k >> 5;
k &= 0x1F;
uint32 mask = (1u<<k) - 1;
int32 w = int32(size) - n;
if (w <= 0)
return 0;
ASSERT(w <= 2);
uint32 *bx = words;
uint32 *bxe = bx + n;
uint32 result = *bxe >> k;
*bxe &= mask;
if (w == 2) {
ASSERT(!(bxe[1] & ~mask));
if (k)
result |= bxe[1] << (32 - k);
}
n++;
while (!*bxe && bxe != bx) {
n--;
bxe--;
}
size = uint32(n);
return result;
}
// Return floor(this/S) and set this to be the remainder. As added restrictions, this must not have
// more words than S, the most significant word of S must not start with a 1 bit, and the
// returned quotient must be less than 36.
int32 JS::BigInt::quoRem(const BigInt &S)
{
#ifdef NATIVE_INT64
uint64 borrow, carry, y, ys;
#else
uint32 borrow, carry, y, ys;
uint32 si, z, zs;
#endif
2000-02-19 09:32:45 +00:00
uint32 n = S.size;
2000-01-29 08:24:40 +00:00
ASSERT(size <= n && n);
if (size < n)
return 0;
const uint32 *sx = S.words;
const uint32 *sxe = sx + --n;
uint32 *bx = words;
uint32 *bxe = bx + n;
ASSERT(*sxe <= 0x7FFFFFFF);
uint32 q = *bxe / (*sxe + 1); // ensure q <= true quotient
ASSERT(q < 36);
if (q) {
borrow = 0;
carry = 0;
do {
#ifdef NATIVE_INT64
ys = *sx++ * (uint64)q + carry;
carry = ys >> 32;
y = *bx - (ys & 0xffffffffUL) - borrow;
borrow = y >> 32 & 1UL;
*bx++ = (uint32)(y & 0xffffffffUL);
#else
si = *sx++;
ys = (si & 0xffff) * q + carry;
zs = (si >> 16) * q + (ys >> 16);
carry = zs >> 16;
y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*bx >> 16) - (zs & 0xffff) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(bx, z, y);
#endif
} while (sx <= sxe);
if (!*bxe) {
bx = words;
while (--bxe > bx && !*bxe)
--n;
2000-02-19 09:32:45 +00:00
size = n;
2000-01-29 08:24:40 +00:00
}
}
if (cmp(S) >= 0) {
q++;
borrow = 0;
carry = 0;
bx = words;
sx = S.words;
do {
#ifdef NATIVE_INT64
ys = *sx++ + carry;
carry = ys >> 32;
y = *bx - (ys & 0xffffffffUL) - borrow;
borrow = y >> 32 & 1UL;
*bx++ = (uint32)(y & 0xffffffffUL);
#else
si = *sx++;
ys = (si & 0xffff) + carry;
zs = (si >> 16) + (ys >> 16);
carry = zs >> 16;
y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
borrow = (y & 0x10000) >> 16;
z = (*bx >> 16) - (zs & 0xffff) - borrow;
borrow = (z & 0x10000) >> 16;
Storeinc(bx, z, y);
#endif
} while (sx <= sxe);
bx = words;
bxe = bx + n;
if (!*bxe) {
while (--bxe > bx && !*bxe)
--n;
2000-02-19 09:32:45 +00:00
size = n;
2000-01-29 08:24:40 +00:00
}
}
return int32(q);
}
// Let this = floor(this / divisor), and return the remainder. this must be nonnegative.
// divisor must be between 1 and 65536.
uint32 JS::BigInt::divRem(uint32 divisor)
{
uint32 n = size;
uint32 remainder = 0;
ASSERT(divisor > 0 && divisor <= 65536);
if (!n)
return 0; // this is zero
uint32 *bx = words;
uint32 *bp = bx + n;
do {
uint32 a = *--bp;
uint32 dividend = remainder << 16 | a >> 16;
uint32 quotientHi = dividend / divisor;
uint32 quotientLo;
remainder = dividend - quotientHi*divisor;
ASSERT(quotientHi <= 0xFFFF && remainder < divisor);
dividend = remainder << 16 | (a & 0xFFFF);
quotientLo = dividend / divisor;
remainder = dividend - quotientLo*divisor;
ASSERT(quotientLo <= 0xFFFF && remainder < divisor);
*bp = quotientHi << 16 | quotientLo;
} while (bp != bx);
// Decrease the size of the number if its most significant word is now zero.
if (bx[n-1] == 0)
size--;
return remainder;
}
double JS::BigInt::b2d(int32 &e) const
{
double d;
const uint32 *xa0 = words;
const uint32 *xa = xa0 + size;
ASSERT(size);
uint32 y = *--xa;
ASSERT(y);
int k = hi0bits(y);
e = 32 - k;
if (k < Ebits) {
word0(d) = Exp_1 | y >> (Ebits - k);
uint32 w = xa > xa0 ? *--xa : 0;
word1(d) = y << (32-Ebits + k) | w >> (Ebits - k);
} else {
uint32 z = xa > xa0 ? *--xa : 0;
if (k -= Ebits) {
word0(d) = Exp_1 | y << k | z >> (32 - k);
y = xa > xa0 ? *--xa : 0;
word1(d) = z << k | y >> (32 - k);
}
else {
word0(d) = Exp_1 | y;
word1(d) = z;
}
}
return d;
}
double JS::BigInt::ratio(const BigInt &denominator) const
{
int32 ka, kb;
double da = b2d(ka);
double db = denominator.b2d(kb);
int32 k = ka - kb + 32*int32(size - denominator.size);
if (k > 0)
word0(da) += k*Exp_msk1;
else
word0(db) -= k*Exp_msk1;
return da / db;
}
void JS::BigInt::s2b(const char *s, int32 nd0, int32 nd, uint32 y9)
{
int32 i;
int32 x, y;
x = (nd + 8) / 9;
uint k = 0;
for (y = 1; x > y; y <<= 1, k++) ;
ASSERT(!words);
allocate(k);
words[0] = y9;
size = 1;
i = 9;
if (9 < nd0) {
s += 9;
do mulAdd(10, uint(*s++ - '0'));
while (++i < nd0);
s++;
} else
s += 10;
for (; i < nd; i++)
mulAdd(10, uint(*s++ - '0'));
}
static const double tens[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22
};
static const double bigtens[] = {1e16, 1e32, 1e64, 1e128, 1e256};
static const double tinytens[] = {1e-16, 1e-32, 1e-64, 1e-128,
#ifdef Avoid_Underflow
9007199254740992.e-256
#else
1e-256
#endif
};
// The factor of 2^53 in tinytens[4] helps us avoid setting the underflow
2000-02-02 08:47:54 +00:00
// flag unnecessarily. It leads to a song and dance at the end of strToDouble.
2000-01-29 08:24:40 +00:00
const int32 Scale_Bit = 0x10;
const int n_bigtens = 5;
#ifdef JS_THREADSAFE
static bool initialized = false;
// hacked replica of nspr _PR_InitDtoa
static void InitDtoa(void)
{
freelist_lock = PR_NewLock();
p5s_lock = PR_NewLock();
initialized = true;
}
#endif
// Return as a double-precision floating-point number the value represented by the character
2000-02-02 08:47:54 +00:00
// 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)
2000-01-29 08:24:40 +00:00
{
int32 scale;
int32 bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0;
const char *s, *s0, *s1;
double aadj, aadj1, adj, rv, rv0;
int32 L;
uint32 y, z;
#ifdef JS_THREADSAFE
if (!initialized) InitDtoa();
#endif
nz0 = nz = 0;
2000-02-02 08:47:54 +00:00
bool negative = false;
bool haveSign = false;
2000-01-29 08:24:40 +00:00
rv = 0.;
2000-02-02 08:47:54 +00:00
for (s = str;; s++)
2000-01-29 08:24:40 +00:00
switch (*s) {
2000-02-02 08:47:54 +00:00
case '-':
2000-01-29 08:24:40 +00:00
negative = true;
// no break
2000-02-02 08:47:54 +00:00
case '+':
haveSign = true;
2000-01-29 08:24:40 +00:00
if (*++s)
goto break2;
// no break
2000-02-02 08:47:54 +00:00
case 0:
s = str;
2000-01-29 08:24:40 +00:00
goto ret;
2000-02-02 08:47:54 +00:00
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
2000-01-29 08:24:40 +00:00
continue;
2000-02-02 08:47:54 +00:00
default:
2000-01-29 08:24:40 +00:00
goto break2;
}
2000-02-02 08:47:54 +00:00
break2:
switch (*s) {
case '0':
2000-01-29 08:24:40 +00:00
nz0 = 1;
while (*++s == '0') ;
if (!*s)
goto ret;
2000-02-02 08:47:54 +00:00
break;
case 'I':
2000-02-03 08:25:01 +00:00
if (!STD::strncmp(s+1, "nfinity", 7)) {
2000-02-02 08:47:54 +00:00
rv = positiveInfinity;
s += 8;
goto ret;
}
break;
case 'N':
2000-02-03 08:25:01 +00:00
if (!haveSign && !STD::strncmp(s+1, "aN", 2)) {
2000-02-02 08:47:54 +00:00
rv = nan;
s += 3;
goto ret;
}
2000-01-29 08:24:40 +00:00
}
s0 = s;
y = z = 0;
for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
if (nd < 9)
y = 10*y + c - '0';
else if (nd < 16)
z = 10*z + c - '0';
nd0 = nd;
if (c == '.') {
c = *++s;
if (!nd) {
for (; c == '0'; c = *++s)
nz++;
if (c > '0' && c <= '9') {
s0 = s;
nf += nz;
nz = 0;
goto have_dig;
}
goto dig_done;
}
for (; c >= '0' && c <= '9'; c = *++s) {
2000-02-02 08:47:54 +00:00
have_dig:
2000-01-29 08:24:40 +00:00
nz++;
if (c -= '0') {
nf += nz;
for (i = 1; i < nz; i++)
if (nd++ < 9)
y *= 10;
else if (nd <= DBL_DIG + 1)
z *= 10;
if (nd++ < 9)
y = 10*y + c;
else if (nd <= DBL_DIG + 1)
z = 10*z + c;
nz = 0;
}
}
}
2000-02-02 08:47:54 +00:00
dig_done:
2000-01-29 08:24:40 +00:00
e = 0;
if (c == 'e' || c == 'E') {
if (!nd && !nz && !nz0) {
2000-02-02 08:47:54 +00:00
s = str;
2000-01-29 08:24:40 +00:00
goto ret;
}
2000-02-02 08:47:54 +00:00
str = s;
2000-01-29 08:24:40 +00:00
esign = 0;
switch (c = *++s) {
case '-':
esign = 1;
case '+':
c = *++s;
}
if (c >= '0' && c <= '9') {
while (c == '0')
c = *++s;
if (c > '0' && c <= '9') {
L = c - '0';
s1 = s;
while ((c = *++s) >= '0' && c <= '9')
L = 10*L + c - '0';
if (s - s1 > 8 || L > 19999)
// Avoid confusion from exponents so large that e might overflow.
e = 19999; // safe for 16 bit ints
else
e = (int32)L;
if (esign)
e = -e;
}
else
e = 0;
}
else
2000-02-02 08:47:54 +00:00
s = str;
2000-01-29 08:24:40 +00:00
}
if (!nd) {
if (!nz && !nz0) {
2000-02-02 08:47:54 +00:00
s = str;
2000-01-29 08:24:40 +00:00
}
goto ret;
}
e1 = e -= nf;
// Now we have nd0 digits, starting at s0, followed by a
// decimal point, followed by nd-nd0 digits. The number we're
// after is the integer represented by those digits times 10**e
if (!nd0)
nd0 = nd;
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
rv = y;
if (k > 9)
rv = tens[k - 9] * rv + z;
if (nd <= DBL_DIG && FLT_ROUNDS == 1) {
if (!e)
goto ret;
if (e > 0) {
if (e <= Ten_pmax) {
rv *= tens[e];
goto ret;
}
i = DBL_DIG - nd;
if (e <= Ten_pmax + i) {
// A fancier test would sometimes let us do this for larger i values.
e -= i;
rv *= tens[i];
rv *= tens[e];
goto ret;
}
}
#ifndef Inaccurate_Divide
else if (e >= -Ten_pmax) {
rv /= tens[-e];
goto ret;
}
#endif
}
e1 += nd - k;
scale = 0;
// Get starting approximation = rv * 10**e1
if (e1 > 0) {
if ((i = e1 & 15) != 0)
rv *= tens[i];
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
2000-02-02 08:47:54 +00:00
ovfl:
2000-01-29 08:24:40 +00:00
// Return infinity.
2000-02-02 08:47:54 +00:00
rv = positiveInfinity;
2000-01-29 08:24:40 +00:00
goto ret;
}
e1 >>= 4;
for (j = 0; e1 > 1; j++, e1 >>= 1)
if (e1 & 1)
rv *= bigtens[j];
// The last multiplication could overflow.
word0(rv) -= P*Exp_msk1;
rv *= bigtens[j];
if ((z = word0(rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P))
goto ovfl;
if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
// set to largest number
// (Can't trust DBL_MAX)
word0(rv) = Big0;
word1(rv) = Big1;
}
else
word0(rv) += P*Exp_msk1;
}
}
else if (e1 < 0) {
e1 = -e1;
if ((i = e1 & 15) != 0)
rv /= tens[i];
if (e1 &= ~15) {
e1 >>= 4;
if (e1 >= 1 << n_bigtens)
goto undfl;
#ifdef Avoid_Underflow
if (e1 & Scale_Bit)
scale = P;
for (j = 0; e1 > 0; j++, e1 >>= 1)
if (e1 & 1)
rv *= tinytens[j];
if (scale && (j = P + 1 - int32((word0(rv) & Exp_mask) >> Exp_shift)) > 0) {
// scaled rv is denormal; zap j low bits
if (j >= 32) {
word1(rv) = 0;
word0(rv) &= 0xffffffff << (j-32);
if (!word0(rv))
word0(rv) = 1;
}
else
word1(rv) &= 0xffffffff << j;
}
#else
for (j = 0; e1 > 1; j++, e1 >>= 1)
if (e1 & 1)
rv *= tinytens[j];
// The last multiplication could underflow.
rv0 = rv;
rv *= tinytens[j];
if (!rv) {
rv = 2.*rv0;
rv *= tinytens[j];
#endif
if (!rv) {
2000-02-02 08:47:54 +00:00
undfl:
2000-01-29 08:24:40 +00:00
rv = 0.;
goto ret;
}
#ifndef Avoid_Underflow
word0(rv) = Tiny0;
word1(rv) = Tiny1;
// The refinement below will clean this approximation up.
}
#endif
}
}
// Now the hard part -- adjusting rv to the correct value.
// Put digits into bd: true value = bd * 10^e
{
BigInt bd0;
bd0.s2b(s0, nd0, nd, y);
for (;;) {
BigInt bs;
BigInt bd = bd0;
BigInt bb;
bb.init(rv, bbe, bbbits); // rv = bb * 2^bbe
bs.init(1);
if (e >= 0) {
bb2 = bb5 = 0;
bd2 = bd5 = e;
}
else {
bb2 = bb5 = -e;
bd2 = bd5 = 0;
}
if (bbe >= 0)
bb2 += bbe;
else
bd2 -= bbe;
bs2 = bb2;
#ifdef Sudden_Underflow
j = P + 1 - bbbits;
#else
#ifdef Avoid_Underflow
j = bbe - scale;
#else
j = bbe;
#endif
i = j + bbbits - 1; // logb(rv)
if (i < Emin) // denormal
j += P - Emin;
else
j = P + 1 - bbbits;
#endif
bb2 += j;
bd2 += j;
#ifdef Avoid_Underflow
bd2 += scale;
#endif
i = bb2 < bd2 ? bb2 : bd2;
if (i > bs2)
i = bs2;
if (i > 0) {
bb2 -= i;
bd2 -= i;
bs2 -= i;
}
if (bb5 > 0) {
bs.pow5Mul(bb5);
bb *= bs;
}
if (bb2 > 0)
bb.pow2Mul(bb2);
if (bd5 > 0)
bd.pow5Mul(bd5);
if (bd2 > 0)
bd.pow2Mul(bd2);
if (bs2 > 0)
bs.pow2Mul(bs2);
BigInt delta;
delta.initDiff(bb, bd);
dsign = delta.negative;
delta.negative = false;
i = delta.cmp(bs);
if (i < 0) {
// Error is less than half an ulp -- check for special case of mantissa a power of two.
if (dsign || word1(rv) || word0(rv) & Bndry_mask
#ifdef Avoid_Underflow
|| (word0(rv) & Exp_mask) <= Exp_msk1 + P*Exp_msk1
#else
|| (word0(rv) & Exp_mask) <= Exp_msk1
#endif
) {
#ifdef Avoid_Underflow
if (delta.isZero())
dsign = 2;
#endif
break;
}
delta.pow2Mul(Log2P);
if (delta.cmp(bs) > 0)
goto drop_down;
break;
}
if (i == 0) {
// exactly half-way between
if (dsign) {
if ((word0(rv) & Bndry_mask1) == Bndry_mask1
&& word1(rv) == 0xffffffff) {
//boundary case -- increment exponent
word0(rv) = (word0(rv) & Exp_mask) + Exp_msk1;
word1(rv) = 0;
#ifdef Avoid_Underflow
dsign = 0;
#endif
break;
}
}
else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
#ifdef Avoid_Underflow
dsign = 2;
#endif
2000-02-02 08:47:54 +00:00
drop_down:
2000-01-29 08:24:40 +00:00
// boundary case -- decrement exponent
#ifdef Sudden_Underflow
L = word0(rv) & Exp_mask;
if (L <= Exp_msk1)
goto undfl;
L -= Exp_msk1;
#else
L = int32((word0(rv) & Exp_mask) - Exp_msk1);
#endif
word0(rv) = uint32(L) | Bndry_mask1;
word1(rv) = 0xffffffff;
break;
}
#ifndef ROUND_BIASED
if (!(word1(rv) & LSB))
break;
#endif
if (dsign)
rv += ulp(rv);
#ifndef ROUND_BIASED
else {
rv -= ulp(rv);
#ifndef Sudden_Underflow
if (!rv)
goto undfl;
#endif
}
#ifdef Avoid_Underflow
dsign = 1 - dsign;
#endif
#endif
break;
}
if ((aadj = delta.ratio(bs)) <= 2.) {
if (dsign)
aadj = aadj1 = 1.;
else if (word1(rv) || word0(rv) & Bndry_mask) {
#ifndef Sudden_Underflow
if (word1(rv) == Tiny1 && !word0(rv))
goto undfl;
#endif
aadj = 1.;
aadj1 = -1.;
}
else {
// special case -- power of FLT_RADIX to be
// rounded down...
if (aadj < 2./FLT_RADIX)
aadj = 1./FLT_RADIX;
else
aadj *= 0.5;
aadj1 = -aadj;
}
}
else {
aadj *= 0.5;
aadj1 = dsign ? aadj : -aadj;
#ifdef Check_FLT_ROUNDS
switch (FLT_ROUNDS) {
2000-02-02 08:47:54 +00:00
case 2: // towards +infinity
2000-01-29 08:24:40 +00:00
aadj1 -= 0.5;
break;
2000-02-02 08:47:54 +00:00
case 0: // towards 0
case 3: // towards -infinity
2000-01-29 08:24:40 +00:00
aadj1 += 0.5;
}
#else
if (FLT_ROUNDS == 0)
aadj1 += 0.5;
#endif
}
y = word0(rv) & Exp_mask;
// Check for overflow
if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
rv0 = rv;
word0(rv) -= P*Exp_msk1;
adj = aadj1 * ulp(rv);
rv += adj;
if ((word0(rv) & Exp_mask) >=
Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
if (word0(rv0) == Big0 && word1(rv0) == Big1)
goto ovfl;
word0(rv) = Big0;
word1(rv) = Big1;
continue;
}
else
word0(rv) += P*Exp_msk1;
}
else {
#ifdef Sudden_Underflow
if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
rv0 = rv;
word0(rv) += P*Exp_msk1;
adj = aadj1 * ulp(rv);
rv += adj;
if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1)
goto undfl;
word0(rv) = Tiny0;
word1(rv) = Tiny1;
continue;
} else
word0(rv) -= P*Exp_msk1;
} else {
adj = aadj1 * ulp(rv);
rv += adj;
}
#else
// Compute adj so that the IEEE rounding rules will
// correctly round rv + adj in some half-way cases.
// If rv * ulp(rv) is denormalized (i.e.,
// y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
// trouble from bits lost to denormalization;
// example: 1.2e-307 .
#ifdef Avoid_Underflow
if (y <= P*Exp_msk1 && aadj > 1.)
#else
if (y <= (P-1)*Exp_msk1 && aadj > 1.)
#endif
{
aadj1 = (double)(int32)(aadj + 0.5);
if (!dsign)
aadj1 = -aadj1;
}
#ifdef Avoid_Underflow
if (scale && y <= P*Exp_msk1)
word0(aadj1) += (P+1)*Exp_msk1 - y;
#endif
adj = aadj1 * ulp(rv);
rv += adj;
#endif
}
z = word0(rv) & Exp_mask;
#ifdef Avoid_Underflow
if (!scale)
#endif
if (y == z) {
// Can we stop now?
L = (int32)aadj;
aadj -= L;
// The tolerances below are conservative.
if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
if (aadj < .4999999 || aadj > .5000001)
break;
}
else if (aadj < .4999999/FLT_RADIX)
break;
}
}
#ifdef Avoid_Underflow
if (scale) {
word0(rv0) = Exp_1 - P*Exp_msk1;
word1(rv0) = 0;
if ((word0(rv) & Exp_mask) <= P*Exp_msk1
&& word1(rv) & 1
&& dsign != 2) {
if (dsign) {
#ifdef Sudden_Underflow
// rv will be 0, but this would give the
// right result if only rv *= rv0 worked.
word0(rv) += P*Exp_msk1;
word0(rv0) = Exp_1 - 2*P*Exp_msk1;
#endif
rv += ulp(rv);
}
else
word1(rv) &= ~1;
}
rv *= rv0;
}
#endif // Avoid_Underflow
}
ret:
2000-02-02 08:47:54 +00:00
numEnd = s;
2000-01-29 08:24:40 +00:00
return negative ? -rv : rv;
}
2000-02-02 08:47:54 +00:00
// 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);
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)
2000-02-03 08:25:01 +00:00
int bit2;
2000-02-02 08:47:54 +00:00
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)
2000-02-03 08:25:01 +00:00
bit2 = bdr.next();
2000-02-02 08:47:54 +00:00
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;
}
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
// doubleToAscii for IEEE arithmetic (dmg): convert double to ASCII string.
2000-01-29 08:24:40 +00:00
//
// 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].
//
// Modifications:
// 1. Rather than iterating, we use a simple numeric overestimate
// to determine k = floor(log10(d)). We scale relevant
// quantities using O(log2(k)) rather than O(k) multiplications.
// 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
// try to generate digits strictly left to right. Instead, we
// compute with fewer bits and propagate the carry if necessary
// when rounding the final digit up. This is often faster.
// 3. Under the assumption that input will be rounded nearest,
// mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
// That is, we allow equality in stopping tests when the
// round-nearest rule will give the same floating-point value
// as would satisfaction of the stopping test with strict
// inequality.
// 4. We remove common factors of powers of 2 from relevant
// quantities.
// 5. When converting floating-point integers less than 1e16,
// we use floating-point arithmetic rather than resorting
// to multiple-precision integers.
// 6. When asked to produce fewer than 15 digits, we first try
// to get by with floating-point arithmetic; we resort to
// multiple-precision integer arithmetic only if we cannot
// guarantee that the floating-point calculation has given
// the correctly rounded result. For k requested digits and
// "uniformly" distributed input, the probability is
// something like 10^(k-15) that we must resort to the int32
// calculation.
///
// Always emits at least one digit.
// If biasUp is set, then rounding in modes 2 and 3 will round away from zero
// 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.
2000-02-02 08:47:54 +00:00
// 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)
2000-01-29 08:24:40 +00:00
{
/* Arguments ndigits, decpt, negative are similar to those
of ecvt and fcvt; trailing zeros are suppressed from
2000-02-02 08:47:54 +00:00
the returned string. If d is +-Infinity or NaN,
2000-01-29 08:24:40 +00:00
then *decpt is set to 9999.
mode:
0 ==> shortest string that yields d when read in
and rounded to nearest.
1 ==> like 0, but with Steele & White stopping rule;
e.g. with IEEE P754 arithmetic , mode 0 gives
1e23 whereas mode 1 gives 9.999999999999999e22.
2 ==> max(1,ndigits) significant digits. This gives a
return value similar to that of ecvt, except
that trailing zeros are suppressed.
3 ==> through ndigits past the decimal point. This
gives a return value similar to that from fcvt,
except that trailing zeros are suppressed, and
ndigits can be negative.
4-9 should give the same return values as 2-3, i.e.,
4 <= mode <= 9 ==> same return as mode
2 + (mode & 1). These modes are mainly for
debugging; often they run slower but sometimes
faster than modes 2-3.
4,5,8,9 ==> left-to-right digit generation.
6-9 ==> don't try fast floating-point estimate
(if applicable).
Values of mode other than 0-9 are treated as mode 0.
Sufficient space is allocated to the return value
to hold the suppressed trailing zeros.
*/
int32 bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
try_quick;
int32 L;
#ifndef Sudden_Underflow
int32 denorm;
uint32 x;
#endif
double d2, ds, eps;
char *s;
#ifdef JS_THREADSAFE
if (!initialized) InitDtoa();
#endif
if (word0(d) & Sign_bit) {
// set negative for everything, including 0's and NaNs
*negative = true;
word0(d) &= ~Sign_bit; // clear sign bit
}
else
*negative = false;
if ((word0(d) & Exp_mask) == Exp_mask) {
// Infinity or NaN
*decpt = 9999;
2000-02-19 09:26:59 +00:00
strcpy(buf, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN");
2000-02-02 08:47:54 +00:00
return buf[3] ? buf + 8 : buf + 3;
2000-01-29 08:24:40 +00:00
}
if (!d) {
no_digits:
*decpt = 1;
buf[0] = '0'; buf[1] = '\0'; // copy "0" to buffer
2000-02-02 08:47:54 +00:00
return buf + 1;
2000-01-29 08:24:40 +00:00
}
BigInt b;
b.init(d, be, bbits);
#ifdef Sudden_Underflow
i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
if ((i = (int32)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {
#endif
d2 = d;
word0(d2) &= Frac_mask1;
word0(d2) |= Exp_11;
/* log(x) ~=~ log(1.5) + (x-1.5)/1.5
* log10(x) = log(x) / log(10)
* ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
* log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
*
* This suggests computing an approximation k to log10(d) by
*
* k = (i - Bias)*0.301029995663981
* + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
*
* We want k to be too large rather than too small.
* The error in the first-order Taylor series approximation
* is in our favor, so we just round up the constant enough
* to compensate for any error in the multiplication of
* (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
* and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
* adding 1e-13 to the constant term more than suffices.
* Hence we adjust the constant term to 0.1760912590558.
* (We could get a more accurate k by invoking log10,
* but this is probably not worthwhile.)
*/
i -= Bias;
#ifndef Sudden_Underflow
denorm = 0;
}
else {
// d is denormalized
i = bbits + be + (Bias + (P-1) - 1);
x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) : word1(d) << (32 - i);
d2 = x;
word0(d2) -= 31*Exp_msk1; // adjust exponent
i -= (Bias + (P-1) - 1) + 1;
denorm = 1;
}
#endif
// At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f.
ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
k = (int32)ds;
if (ds < 0. && ds != k)
k--; // want k = floor(ds)
k_check = 1;
if (k >= 0 && k <= Ten_pmax) {
if (d < tens[k])
k--;
k_check = 0;
}
// At this point floor(log10(d)) <= k <= floor(log10(d))+1.
// If k_check is zero, we're guaranteed that k = floor(log10(d)).
j = bbits - i - 1;
// At this point d = b/2^j, where b is an odd integer.
if (j >= 0) {
b2 = 0;
s2 = j;
}
else {
b2 = -j;
s2 = 0;
}
if (k >= 0) {
b5 = 0;
s5 = k;
s2 += k;
}
else {
b2 -= k;
b5 = -k;
s5 = 0;
}
// At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
// b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0.
if (mode < 0 || mode > 9)
mode = 0;
try_quick = 1;
if (mode > 5) {
mode -= 4;
try_quick = 0;
}
leftright = 1;
ilim = ilim1 = 0;
switch (mode) {
2000-02-02 08:47:54 +00:00
case 0:
case 1:
2000-01-29 08:24:40 +00:00
ilim = ilim1 = -1;
i = 18;
ndigits = 0;
break;
2000-02-02 08:47:54 +00:00
case 2:
2000-01-29 08:24:40 +00:00
leftright = 0;
// no break
2000-02-02 08:47:54 +00:00
case 4:
2000-01-29 08:24:40 +00:00
if (ndigits <= 0)
ndigits = 1;
ilim = ilim1 = i = ndigits;
break;
2000-02-02 08:47:54 +00:00
case 3:
2000-01-29 08:24:40 +00:00
leftright = 0;
// no break
2000-02-02 08:47:54 +00:00
case 5:
2000-01-29 08:24:40 +00:00
i = ndigits + k + 1;
ilim = i;
ilim1 = i - 1;
if (i <= 0)
i = 1;
}
// 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.
s = buf;
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
// Try to get by with floating-point arithmetic.
i = 0;
d2 = d;
k0 = k;
ilim0 = ilim;
ieps = 2; // conservative
// Divide d by 10^k, keeping track of the roundoff error and avoiding overflows.
if (k > 0) {
ds = tens[k&0xf];
j = k >> 4;
if (j & Bletch) {
// prevent overflows
j &= Bletch - 1;
d /= bigtens[n_bigtens-1];
ieps++;
}
for (; j; j >>= 1, i++)
if (j & 1) {
ieps++;
ds *= bigtens[i];
}
d /= ds;
}
else if ((j1 = -k) != 0) {
d *= tens[j1 & 0xf];
for (j = j1 >> 4; j; j >>= 1, i++)
if (j & 1) {
ieps++;
d *= bigtens[i];
}
}
// Check that k was computed correctly.
if (k_check && d < 1. && ilim > 0) {
if (ilim1 <= 0)
goto fast_failed;
ilim = ilim1;
k--;
d *= 10.;
ieps++;
}
// eps bounds the cumulative error.
eps = ieps*d + 7.;
word0(eps) -= (P-1)*Exp_msk1;
if (ilim == 0) {
d -= 5.;
if (d > eps)
goto one_digit;
if (d < -eps)
goto no_digits;
goto fast_failed;
}
#ifndef No_leftright
if (leftright) {
// Use Steele & White method of only generating digits needed.
eps = 0.5/tens[ilim-1] - eps;
for (i = 0;;) {
L = (int32)d;
d -= L;
*s++ = char('0' + L);
if (d < eps)
goto ret1;
if (1. - d < eps)
goto bump_up;
if (++i >= ilim)
break;
eps *= 10.;
d *= 10.;
}
}
else {
#endif
// Generate ilim digits, then fix them up.
eps *= tens[ilim-1];
for (i = 1;; i++, d *= 10.) {
L = (int32)d;
d -= L;
*s++ = char('0' + L);
if (i == ilim) {
if (d > 0.5 + eps)
goto bump_up;
else if (d < 0.5 - eps) {
while (*--s == '0') ;
s++;
goto ret1;
}
break;
}
}
#ifndef No_leftright
}
#endif
2000-02-02 08:47:54 +00:00
fast_failed:
2000-01-29 08:24:40 +00:00
s = buf;
d = d2;
k = k0;
ilim = ilim0;
}
// Do we have a "small" integer?
if (be >= 0 && k <= Int_max) {
// Yes.
ds = tens[k];
if (ndigits < 0 && ilim <= 0) {
if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds))
goto no_digits;
one_digit:
*s++ = '1';
k++;
goto ret1;
}
for (i = 1;; i++) {
L = (int32) (d / ds);
d -= L*ds;
#ifdef Check_FLT_ROUNDS
// If FLT_ROUNDS == 2, L will usually be high by 1
if (d < 0) {
L--;
d += ds;
}
#endif
*s++ = char('0' + L);
if (i == ilim) {
d += d;
if ((d > ds) || (d == ds && (L & 1 || biasUp))) {
2000-02-02 08:47:54 +00:00
bump_up:
2000-01-29 08:24:40 +00:00
while (*--s == '9')
if (s == buf) {
k++;
*s = '0';
break;
}
++*s++;
}
break;
}
if (!(d *= 10.))
break;
}
goto ret1;
}
{
m2 = b2;
m5 = b5;
BigInt mLow; // If spec_case is false, assume that mLow == mHigh
BigInt mHigh;
if (leftright) {
if (mode < 2) {
i =
#ifndef Sudden_Underflow
denorm ? be + (Bias + (P-1) - 1 + 1) :
#endif
1 + P - bbits;
// i is 1 plus the number of trailing zero bits in d's significand. Thus,
// (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k.
}
else {
j = ilim - 1;
if (m5 >= j)
m5 -= j;
else {
s5 += j -= m5;
b5 += j;
m5 = 0;
}
if ((i = ilim) < 0) {
m2 -= i;
i = 0;
}
// (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k.
}
b2 += i;
s2 += i;
mHigh.init(1);
// (mHigh * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
// input (when mode < 2) significant digit, divided by 10^k.
}
// We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in
// b2, m2, and s2 without changing the equalities.
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
b2 -= i;
m2 -= i;
s2 -= i;
}
// Fold b5 into b and m5 into mHigh.
if (b5 > 0) {
if (leftright) {
if (m5 > 0) {
mHigh.pow5Mul(m5);
b *= mHigh;
}
if ((j = b5 - m5) != 0)
b.pow5Mul(j);
}
else
b.pow5Mul(b5);
}
// Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
// (mHigh * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k.
BigInt S;
S.init(1);
if (s5 > 0)
S.pow5Mul(s5);
// Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
// (mHigh * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k.
// Check for special case that d is a normalized power of 2.
bool spec_case = false;
if (mode < 2) {
if (!word1(d) && !(word0(d) & Bndry_mask)
#ifndef Sudden_Underflow
&& word0(d) & (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 decimal output string's value is less than d.
b2 += Log2P;
s2 += Log2P;
spec_case = true;
}
}
// Arrange for convenient computation of quotients:
// shift left if necessary so divisor has 4 leading 0 bits.
//
// Perhaps we should just compute leading 28 bits of S once
// and for all and pass them and a shift to quoRem, so it
// can do shifts and ors to compute the numerator for q.
if ((i = ((s5 ? 32 - hi0bits(S.word(S.nWords()-1)) : 1) + s2) & 0x1f) != 0)
i = 32 - i;
// i is the number of leading zero bits in the most significant word of S*2^s2.
if (i > 4) {
i -= 4;
b2 += i;
m2 += i;
s2 += i;
}
else if (i < 4) {
i += 28;
b2 += i;
m2 += i;
s2 += i;
}
// Now S*2^s2 has exactly four leading zero bits in its most significant word.
if (b2 > 0)
b.pow2Mul(b2);
if (s2 > 0)
S.pow2Mul(s2);
// Now we have d/10^k = b/S and
// (mHigh * 2^m2) / S = maximum acceptable error, divided by 10^k.
if (k_check) {
if (b.cmp(S) < 0) {
k--;
b.mulAdd(10, 0); // we botched the k estimate
if (leftright)
mHigh.mulAdd(10, 0);
ilim = ilim1;
}
}
// At this point 1 <= d/10^k = b/S < 10.
if (ilim <= 0 && mode > 2) {
// We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
// Output either zero or the minimum nonzero output depending on which is closer to d.
// Always emit at least one digit. If the number appears to be zero
// using the current mode, then emit one '0' digit and set decpt to 1.
if (ilim < 0)
goto no_digits;
S.mulAdd(5, 0);
if ((i = b.cmp(S)) < 0 || (i == 0 && !biasUp))
goto no_digits;
goto one_digit;
}
if (leftright) {
if (m2 > 0)
mHigh.pow2Mul(m2);
// Compute mLow -- check for special case that d is a normalized power of 2.
if (spec_case) {
mLow = mHigh;
mHigh.pow2Mul(Log2P);
}
// mLow/S = maximum acceptable error, divided by 10^k, if the output is less than d.
// mHigh/S = maximum acceptable error, divided by 10^k, if the output is greater than d.
for (i = 1;;i++) {
dig = b.quoRem(S) + '0';
// Do we yet have the shortest decimal string that will round to d?
j = b.cmp(spec_case ? mLow : mHigh);
// j is b/S compared with mLow/S.
{
BigInt delta;
delta.initDiff(S, mHigh);
j1 = delta.negative ? 1 : b.cmp(delta);
}
// j1 is b/S compared with 1 - mHigh/S.
#ifndef ROUND_BIASED
if (j1 == 0 && !mode && !(word1(d) & 1)) {
if (dig == '9')
goto round_9_up;
if (j > 0)
dig++;
*s++ = (char)dig;
goto ret;
}
#endif
if ((j < 0) || (j == 0 && !mode
#ifndef ROUND_BIASED
&& !(word1(d) & 1)
#endif
)) {
if (j1 > 0) {
// Either dig or dig+1 would work here as the least significant decimal digit.
// Use whichever would produce a decimal value closer to d.
b.pow2Mul(1);
j1 = b.cmp(S);
if (((j1 > 0) || (j1 == 0 && (dig & 1 || biasUp)))
&& (dig++ == '9'))
goto round_9_up;
}
*s++ = (char)dig;
goto ret;
}
if (j1 > 0) {
if (dig == '9') { // possible if i == 1
2000-02-02 08:47:54 +00:00
round_9_up:
2000-01-29 08:24:40 +00:00
*s++ = '9';
goto roundoff;
}
*s++ = char(dig + 1);
goto ret;
}
*s++ = (char)dig;
if (i == ilim)
break;
b.mulAdd(10, 0);
if (spec_case)
mLow.mulAdd(10, 0);
mHigh.mulAdd(10, 0);
}
}
else
for (i = 1;; i++) {
*s++ = (char)(dig = b.quoRem(S) + '0');
if (i >= ilim)
break;
b.mulAdd(10, 0);
}
// Round off last digit
b.pow2Mul(1);
j = b.cmp(S);
if ((j > 0) || (j == 0 && (dig & 1 || biasUp))) {
2000-02-02 08:47:54 +00:00
roundoff:
2000-01-29 08:24:40 +00:00
while (*--s == '9')
if (s == buf) {
k++;
*s++ = '1';
goto ret;
}
++*s++;
}
else {
// Strip trailing zeros
while (*--s == '0') ;
s++;
}
ret: ;
// S, mLow, and mHigh are destroyed at the end of this block scope.
}
ret1:
*s = '\0';
*decpt = k + 1;
2000-02-02 08:47:54 +00:00
return s;
2000-01-29 08:24:40 +00:00
}
2000-02-02 08:47:54 +00:00
// Mapping of DToStrMode -> doubleToAscii mode
static const int doubleToAsciiModes[] = {
0, // dtosStandard
0, // dtosStandardExponential
3, // dtosFixed
2, // dtosExponential
2}; // dtosPrecision
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
// Convert value according to the given mode and return a pointer to the resulting ASCII string.
2000-01-29 08:24:40 +00:00
// The result is held somewhere in buffer, but not necessarily at the beginning. The size of
2000-02-02 08:47:54 +00:00
// buffer is given in bufferSize, and must be at least as large as given by dtosStandardBufferSize
// or dtosVariableBufferSize, whichever is appropriate.
2000-02-23 01:51:44 +00:00
char *JS::doubleToStr(char *buffer, size_t DEBUG_ONLY(bufferSize), double value, DToStrMode mode, int precision)
2000-01-29 08:24:40 +00:00
{
2000-02-02 08:47:54 +00:00
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
2000-01-29 08:24:40 +00:00
// the sign and/or decimal point
2000-02-02 08:47:54 +00:00
char *numEnd; // Pointer past the digits returned by doubleToAscii
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
ASSERT(bufferSize >= (size_t)(mode <= dtosStandardExponential ? dtosStandardBufferSize : dtosVariableBufferSize(precision)));
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
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.
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
numEnd = doubleToAscii(value, doubleToAsciiModes[mode], mode >= dtosFixed, precision, &decPt, &negative, numBegin);
2000-01-29 08:24:40 +00:00
nDigits = numEnd - numBegin;
// If Infinity, -Infinity, or NaN, return the string regardless of the mode.
if (decPt != 9999) {
bool exponentialNotation = false;
int minNDigits = 0; // Minimum number of significand digits required by mode and precision
char *p;
char *q;
switch (mode) {
2000-02-02 08:47:54 +00:00
case dtosStandard:
if (decPt < -5 || decPt > 21)
exponentialNotation = true;
else
minNDigits = decPt;
break;
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
case dtosFixed:
if (precision >= 0)
minNDigits = decPt + precision;
else
minNDigits = decPt;
break;
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
case dtosExponential:
ASSERT(precision > 0);
minNDigits = precision;
// Fall through
case dtosStandardExponential:
exponentialNotation = true;
break;
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
case dtosPrecision:
ASSERT(precision > 0);
minNDigits = precision;
if (decPt < -5 || decPt > precision)
exponentialNotation = true;
break;
2000-01-29 08:24:40 +00:00
}
// If the number has fewer than minNDigits, pad it with zeros at the end
if (nDigits < minNDigits) {
p = numBegin + minNDigits;
nDigits = minNDigits;
do {
*numEnd++ = '0';
} while (numEnd != p);
*numEnd = '\0';
}
if (exponentialNotation) {
// Insert a decimal point if more than one significand digit
if (nDigits != 1) {
numBegin--;
numBegin[0] = numBegin[1];
numBegin[1] = '.';
}
2000-04-04 21:38:53 +00:00
sprintf(numEnd, "e%+d", decPt-1);
2000-01-29 08:24:40 +00:00
} else if (decPt != nDigits) {
// Some kind of a fraction in fixed notation
ASSERT(decPt <= nDigits);
if (decPt > 0) {
// dd...dd . dd...dd
p = --numBegin;
do {
*p = p[1];
p++;
} while (--decPt);
*p = '.';
} else {
// 0 . 00...00dd...dd
p = numEnd;
numEnd += 1 - decPt;
q = numEnd;
ASSERT(numEnd < buffer + bufferSize);
*numEnd = '\0';
while (p != numBegin)
*--q = *--p;
for (p = numBegin + 1; p != q; p++)
*p = '0';
*numBegin = '.';
*--numBegin = '0';
}
}
}
// If negative and neither -0.0 nor NaN, output a leading '-'.
if (negative &&
2000-02-02 08:47:54 +00:00
!(word0(value) == Sign_bit && word1(value) == 0) &&
!((word0(value) & Exp_mask) == Exp_mask &&
(word1(value) || (word0(value) & Frac_mask)))) {
2000-01-29 08:24:40 +00:00
*--numBegin = '-';
}
return numBegin;
}
inline char baseDigit(uint32 digit)
{
if (digit >= 10)
return char('a' - 10 + digit);
else
return char('0' + digit);
}
2000-02-02 08:47:54 +00:00
// Convert value to a string in the given base. The integral part of value will be printed exactly
2000-01-29 08:24:40 +00:00
// 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
2000-02-02 08:47:54 +00:00
// equal value (except for -0.0, which converts to "0", and NaN, which is not equal to itself).
2000-01-29 08:24:40 +00:00
//
2000-02-02 08:47:54 +00:00
// 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)
2000-01-29 08:24:40 +00:00
{
ASSERT(base >= 2 && base <= 36);
2000-02-02 08:47:54 +00:00
char *p = buffer; // Pointer to current position in the buffer
if (value < 0.0
2000-03-22 00:52:06 +00:00
#ifdef _WIN32
2000-02-02 08:47:54 +00:00
&& !((word0(value) & Exp_mask) == Exp_mask && ((word0(value) & Frac_mask) || word1(value))) // Visual C++ doesn't know how to compare against NaN
2000-01-29 08:24:40 +00:00
#endif
) {
*p++ = '-';
2000-02-02 08:47:54 +00:00
value = -value;
2000-01-29 08:24:40 +00:00
}
// Check for Infinity and NaN
2000-02-02 08:47:54 +00:00
if ((word0(value) & Exp_mask) == Exp_mask) {
2000-02-03 08:25:01 +00:00
strcpy(p, !word1(value) && !(word0(value) & Frac_mask) ? "Infinity" : "NaN");
return strlen(buffer);
2000-01-29 08:24:40 +00:00
}
2000-02-02 08:47:54 +00:00
// 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;
2000-01-29 08:24:40 +00:00
if (n)
do {
uint32 m = n / base;
digit = n - m*base;
n = m;
ASSERT(digit < base);
*p++ = baseDigit(digit);
} while (n);
else *p++ = '0';
} else {
int32 e;
2000-02-02 08:47:54 +00:00
int32 bits; // Number of significant bits in valueInt; not used.
2000-01-29 08:24:40 +00:00
BigInt b;
2000-02-02 08:47:54 +00:00
b.init(valueInt, e, bits);
2000-01-29 08:24:40 +00:00
b.pow2Mul(e);
do {
digit = b.divRem(base);
ASSERT(digit < base);
*p++ = baseDigit(digit);
} while (!b.isZero());
}
2000-02-02 08:47:54 +00:00
// Reverse the digits of the integer part of value.
char *q = p-1;
2000-01-29 08:24:40 +00:00
while (q > pInt) {
char ch = *pInt;
*pInt++ = *q;
*q-- = ch;
}
2000-02-02 08:47:54 +00:00
double valueFrac = value - valueInt; // The fractional part of value
if (valueFrac != 0.0) {
2000-01-29 08:24:40 +00:00
// We have a fraction.
*p++ = '.';
int32 e, bbits;
BigInt b;
2000-02-02 08:47:54 +00:00
b.init(valueFrac, e, bbits);
2000-01-29 08:24:40 +00:00
ASSERT(e < 0);
2000-02-02 08:47:54 +00:00
// At this point valueFrac = b * 2^e. e must be less than zero because 0 < valueFrac < 1.
2000-01-29 08:24:40 +00:00
2000-02-02 08:47:54 +00:00
int32 s2 = -int32(word0(value) >> Exp_shift1 & Exp_mask>>Exp_shift1);
2000-01-29 08:24:40 +00:00
#ifndef Sudden_Underflow
if (!s2)
s2 = -1;
#endif
s2 += Bias + P;
2000-02-02 08:47:54 +00:00
// 1/2^s2 = (nextDouble(value) - value)/2
2000-01-29 08:24:40 +00:00
ASSERT(-s2 < e);
BigInt mLow;
BigInt mHigh;
bool useMHigh = false; // If false, assume that mHigh == mLow
mLow.init(1);
2000-02-02 08:47:54 +00:00
if (!word1(value) && !(word0(value) & Bndry_mask)
2000-01-29 08:24:40 +00:00
#ifndef Sudden_Underflow
2000-02-02 08:47:54 +00:00
&& word0(value) & (Exp_mask & Exp_mask << 1)
2000-01-29 08:24:40 +00:00
#endif
) {
// The special case. Here we want to be within a quarter of the last input
2000-02-02 08:47:54 +00:00
// significant digit instead of one half of it when the output string's value is less than value.
2000-01-29 08:24:40 +00:00
s2 += Log2P;
useMHigh = true;
mHigh.init(1u<<Log2P);
}
b.pow2Mul(e + s2);
BigInt s;
s.init(1);
s.pow2Mul(s2);
// At this point we have the following:
// s = 2^s2;
2000-02-02 08:47:54 +00:00
// 1 > valueFrac = b/2^s2 > 0;
// (value - prevDouble(value))/2 = mLow/2^s2;
// (nextDouble(value) - value)/2 = mHigh/2^s2.
2000-01-29 08:24:40 +00:00
bool done = false;
do {
int32 j, j1;
b.mulAdd(base, 0);
digit = b.quoRem2(s2);
mLow.mulAdd(base, 0);
if (useMHigh)
mHigh.mulAdd(base, 0);
2000-02-02 08:47:54 +00:00
// Do we yet have the shortest string that will round to value?
2000-01-29 08:24:40 +00:00
j = b.cmp(mLow);
// j is b/2^s2 compared with mLow/2^s2.
{
BigInt delta;
delta.initDiff(s, useMHigh ? mHigh : mLow);
j1 = delta.negative ? 1 : b.cmp(delta);
}
// j1 is b/2^s2 compared with 1 - mHigh/2^s2.
#ifndef ROUND_BIASED
2000-02-02 08:47:54 +00:00
if (j1 == 0 && !(word1(value) & 1)) {
2000-01-29 08:24:40 +00:00
if (j > 0)
digit++;
done = true;
} else
#endif
if (j < 0 || (j == 0
#ifndef ROUND_BIASED
2000-02-02 08:47:54 +00:00
&& !(word1(value) & 1)
2000-01-29 08:24:40 +00:00
#endif
)) {
if (j1 > 0) {
// Either dig or dig+1 would work here as the least significant digit.
2000-02-02 08:47:54 +00:00
// Use whichever would produce an output value closer to value.
2000-01-29 08:24:40 +00:00
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
// such as 3.5 in base 3.
digit++;
}
done = true;
} else if (j1 > 0) {
digit++;
done = true;
}
ASSERT(digit < base);
*p++ = baseDigit(digit);
} while (!done);
}
2000-02-02 08:47:54 +00:00
ASSERT(p < buffer + dtobasesBufferSize);
2000-01-29 08:24:40 +00:00
*p = '\0';
2000-02-02 08:47:54 +00:00
return size_t(p - buffer);
}
// A version of doubleToStr that appends to the end of String dst.
2000-04-06 23:47:33 +00:00
// precision should not exceed 101.
void JS::appendDouble(String &dst, double value, DToStrMode mode, int precision)
2000-02-02 08:47:54 +00:00
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
dst += doubleToStr(buffer, sizeof buffer, value, mode, precision);
2000-01-29 08:24:40 +00:00
}
2000-04-06 23:47:33 +00:00
// A version of doubleToStr that prints to Formatter f.
// precision should not exceed 101.
void JS::printDouble(Formatter &f, double value, DToStrMode mode, int precision)
{
char buffer[dtosVariableBufferSize(101)];
ASSERT(uint(precision) <= 101);
f << doubleToStr(buffer, sizeof buffer, value, mode, precision);
}