js/src/jsdtoa.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * Portable double to alphanumeric string and back converters.
michael@0 9 */
michael@0 10
michael@0 11 #include "jsdtoa.h"
michael@0 12
michael@0 13 #include "jsprf.h"
michael@0 14 #include "jstypes.h"
michael@0 15 #include "jsutil.h"
michael@0 16
michael@0 17 using namespace js;
michael@0 18
michael@0 19 #ifdef IS_LITTLE_ENDIAN
michael@0 20 #define IEEE_8087
michael@0 21 #else
michael@0 22 #define IEEE_MC68k
michael@0 23 #endif
michael@0 24
michael@0 25 #ifndef Long
michael@0 26 #define Long int32_t
michael@0 27 #endif
michael@0 28
michael@0 29 #ifndef ULong
michael@0 30 #define ULong uint32_t
michael@0 31 #endif
michael@0 32
michael@0 33 /*
michael@0 34 #ifndef Llong
michael@0 35 #define Llong int64_t
michael@0 36 #endif
michael@0 37
michael@0 38 #ifndef ULlong
michael@0 39 #define ULlong uint64_t
michael@0 40 #endif
michael@0 41 */
michael@0 42
michael@0 43 /*
michael@0 44 * MALLOC gets declared external, and that doesn't work for class members, so
michael@0 45 * wrap.
michael@0 46 */
michael@0 47 static inline void* dtoa_malloc(size_t size) { return js_malloc(size); }
michael@0 48 static inline void dtoa_free(void* p) { return js_free(p); }
michael@0 49
michael@0 50 #define NO_GLOBAL_STATE
michael@0 51 #define NO_ERRNO
michael@0 52 #define MALLOC dtoa_malloc
michael@0 53 #define FREE dtoa_free
michael@0 54 #include "dtoa.c"
michael@0 55
michael@0 56 /* Mapping of JSDToStrMode -> js_dtoa mode */
michael@0 57 static const uint8_t dtoaModes[] = {
michael@0 58 0, /* DTOSTR_STANDARD */
michael@0 59 0, /* DTOSTR_STANDARD_EXPONENTIAL, */
michael@0 60 3, /* DTOSTR_FIXED, */
michael@0 61 2, /* DTOSTR_EXPONENTIAL, */
michael@0 62 2}; /* DTOSTR_PRECISION */
michael@0 63
michael@0 64 double
michael@0 65 js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err)
michael@0 66 {
michael@0 67 double retval;
michael@0 68 if (err)
michael@0 69 *err = 0;
michael@0 70 retval = _strtod(state, s00, se);
michael@0 71 return retval;
michael@0 72 }
michael@0 73
michael@0 74 char *
michael@0 75 js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision,
michael@0 76 double dinput)
michael@0 77 {
michael@0 78 U d;
michael@0 79 int decPt; /* Offset of decimal point from first digit */
michael@0 80 int sign; /* Nonzero if the sign bit was set in d */
michael@0 81 int nDigits; /* Number of significand digits returned by js_dtoa */
michael@0 82 char *numBegin; /* Pointer to the digits returned by js_dtoa */
michael@0 83 char *numEnd = 0; /* Pointer past the digits returned by js_dtoa */
michael@0 84
michael@0 85 JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL
michael@0 86 ? DTOSTR_STANDARD_BUFFER_SIZE
michael@0 87 : DTOSTR_VARIABLE_BUFFER_SIZE(precision)));
michael@0 88
michael@0 89 /*
michael@0 90 * Change mode here rather than below because the buffer may not be large
michael@0 91 * enough to hold a large integer.
michael@0 92 */
michael@0 93 if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21))
michael@0 94 mode = DTOSTR_STANDARD;
michael@0 95
michael@0 96 dval(d) = dinput;
michael@0 97 numBegin = dtoa(PASS_STATE d, dtoaModes[mode], precision, &decPt, &sign, &numEnd);
michael@0 98 if (!numBegin) {
michael@0 99 return nullptr;
michael@0 100 }
michael@0 101
michael@0 102 nDigits = numEnd - numBegin;
michael@0 103 JS_ASSERT((size_t) nDigits <= bufferSize - 2);
michael@0 104 if ((size_t) nDigits > bufferSize - 2) {
michael@0 105 return nullptr;
michael@0 106 }
michael@0 107
michael@0 108 js_memcpy(buffer + 2, numBegin, nDigits);
michael@0 109 freedtoa(PASS_STATE numBegin);
michael@0 110 numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */
michael@0 111 numEnd = numBegin + nDigits;
michael@0 112 *numEnd = '\0';
michael@0 113
michael@0 114 /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */
michael@0 115 if (decPt != 9999) {
michael@0 116 bool exponentialNotation = false;
michael@0 117 int minNDigits = 0; /* Min number of significant digits required */
michael@0 118 char *p;
michael@0 119 char *q;
michael@0 120
michael@0 121 switch (mode) {
michael@0 122 case DTOSTR_STANDARD:
michael@0 123 if (decPt < -5 || decPt > 21)
michael@0 124 exponentialNotation = true;
michael@0 125 else
michael@0 126 minNDigits = decPt;
michael@0 127 break;
michael@0 128
michael@0 129 case DTOSTR_FIXED:
michael@0 130 if (precision >= 0)
michael@0 131 minNDigits = decPt + precision;
michael@0 132 else
michael@0 133 minNDigits = decPt;
michael@0 134 break;
michael@0 135
michael@0 136 case DTOSTR_EXPONENTIAL:
michael@0 137 JS_ASSERT(precision > 0);
michael@0 138 minNDigits = precision;
michael@0 139 /* Fall through */
michael@0 140 case DTOSTR_STANDARD_EXPONENTIAL:
michael@0 141 exponentialNotation = true;
michael@0 142 break;
michael@0 143
michael@0 144 case DTOSTR_PRECISION:
michael@0 145 JS_ASSERT(precision > 0);
michael@0 146 minNDigits = precision;
michael@0 147 if (decPt < -5 || decPt > precision)
michael@0 148 exponentialNotation = true;
michael@0 149 break;
michael@0 150 }
michael@0 151
michael@0 152 /* If the number has fewer than minNDigits, end-pad it with zeros. */
michael@0 153 if (nDigits < minNDigits) {
michael@0 154 p = numBegin + minNDigits;
michael@0 155 nDigits = minNDigits;
michael@0 156 do {
michael@0 157 *numEnd++ = '0';
michael@0 158 } while (numEnd != p);
michael@0 159 *numEnd = '\0';
michael@0 160 }
michael@0 161
michael@0 162 if (exponentialNotation) {
michael@0 163 /* Insert a decimal point if more than one significand digit */
michael@0 164 if (nDigits != 1) {
michael@0 165 numBegin--;
michael@0 166 numBegin[0] = numBegin[1];
michael@0 167 numBegin[1] = '.';
michael@0 168 }
michael@0 169 JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1);
michael@0 170 } else if (decPt != nDigits) {
michael@0 171 /* Some kind of a fraction in fixed notation */
michael@0 172 JS_ASSERT(decPt <= nDigits);
michael@0 173 if (decPt > 0) {
michael@0 174 /* dd...dd . dd...dd */
michael@0 175 p = --numBegin;
michael@0 176 do {
michael@0 177 *p = p[1];
michael@0 178 p++;
michael@0 179 } while (--decPt);
michael@0 180 *p = '.';
michael@0 181 } else {
michael@0 182 /* 0 . 00...00dd...dd */
michael@0 183 p = numEnd;
michael@0 184 numEnd += 1 - decPt;
michael@0 185 q = numEnd;
michael@0 186 JS_ASSERT(numEnd < buffer + bufferSize);
michael@0 187 *numEnd = '\0';
michael@0 188 while (p != numBegin)
michael@0 189 *--q = *--p;
michael@0 190 for (p = numBegin + 1; p != q; p++)
michael@0 191 *p = '0';
michael@0 192 *numBegin = '.';
michael@0 193 *--numBegin = '0';
michael@0 194 }
michael@0 195 }
michael@0 196 }
michael@0 197
michael@0 198 /* If negative and neither -0.0 nor NaN, output a leading '-'. */
michael@0 199 if (sign &&
michael@0 200 !(word0(d) == Sign_bit && word1(d) == 0) &&
michael@0 201 !((word0(d) & Exp_mask) == Exp_mask &&
michael@0 202 (word1(d) || (word0(d) & Frac_mask)))) {
michael@0 203 *--numBegin = '-';
michael@0 204 }
michael@0 205 return numBegin;
michael@0 206 }
michael@0 207
michael@0 208
michael@0 209 /* Let b = floor(b / divisor), and return the remainder. b must be nonnegative.
michael@0 210 * divisor must be between 1 and 65536.
michael@0 211 * This function cannot run out of memory. */
michael@0 212 static uint32_t
michael@0 213 divrem(Bigint *b, uint32_t divisor)
michael@0 214 {
michael@0 215 int32_t n = b->wds;
michael@0 216 uint32_t remainder = 0;
michael@0 217 ULong *bx;
michael@0 218 ULong *bp;
michael@0 219
michael@0 220 JS_ASSERT(divisor > 0 && divisor <= 65536);
michael@0 221
michael@0 222 if (!n)
michael@0 223 return 0; /* b is zero */
michael@0 224 bx = b->x;
michael@0 225 bp = bx + n;
michael@0 226 do {
michael@0 227 ULong a = *--bp;
michael@0 228 ULong dividend = remainder << 16 | a >> 16;
michael@0 229 ULong quotientHi = dividend / divisor;
michael@0 230 ULong quotientLo;
michael@0 231
michael@0 232 remainder = dividend - quotientHi*divisor;
michael@0 233 JS_ASSERT(quotientHi <= 0xFFFF && remainder < divisor);
michael@0 234 dividend = remainder << 16 | (a & 0xFFFF);
michael@0 235 quotientLo = dividend / divisor;
michael@0 236 remainder = dividend - quotientLo*divisor;
michael@0 237 JS_ASSERT(quotientLo <= 0xFFFF && remainder < divisor);
michael@0 238 *bp = quotientHi << 16 | quotientLo;
michael@0 239 } while (bp != bx);
michael@0 240 /* Decrease the size of the number if its most significant word is now zero. */
michael@0 241 if (bx[n-1] == 0)
michael@0 242 b->wds--;
michael@0 243 return remainder;
michael@0 244 }
michael@0 245
michael@0 246 /* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */
michael@0 247 static uint32_t quorem2(Bigint *b, int32_t k)
michael@0 248 {
michael@0 249 ULong mask;
michael@0 250 ULong result;
michael@0 251 ULong *bx, *bxe;
michael@0 252 int32_t w;
michael@0 253 int32_t n = k >> 5;
michael@0 254 k &= 0x1F;
michael@0 255 mask = (1<<k) - 1;
michael@0 256
michael@0 257 w = b->wds - n;
michael@0 258 if (w <= 0)
michael@0 259 return 0;
michael@0 260 JS_ASSERT(w <= 2);
michael@0 261 bx = b->x;
michael@0 262 bxe = bx + n;
michael@0 263 result = *bxe >> k;
michael@0 264 *bxe &= mask;
michael@0 265 if (w == 2) {
michael@0 266 JS_ASSERT(!(bxe[1] & ~mask));
michael@0 267 if (k)
michael@0 268 result |= bxe[1] << (32 - k);
michael@0 269 }
michael@0 270 n++;
michael@0 271 while (!*bxe && bxe != bx) {
michael@0 272 n--;
michael@0 273 bxe--;
michael@0 274 }
michael@0 275 b->wds = n;
michael@0 276 return result;
michael@0 277 }
michael@0 278
michael@0 279
michael@0 280 /* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
michael@0 281 * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
michael@0 282 * the output string and malloc fewer bytes depending on d and base, but why bother? */
michael@0 283 #define DTOBASESTR_BUFFER_SIZE 1078
michael@0 284 #define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
michael@0 285
michael@0 286 char *
michael@0 287 js_dtobasestr(DtoaState *state, int base, double dinput)
michael@0 288 {
michael@0 289 U d;
michael@0 290 char *buffer; /* The output string */
michael@0 291 char *p; /* Pointer to current position in the buffer */
michael@0 292 char *pInt; /* Pointer to the beginning of the integer part of the string */
michael@0 293 char *q;
michael@0 294 uint32_t digit;
michael@0 295 U di; /* d truncated to an integer */
michael@0 296 U df; /* The fractional part of d */
michael@0 297
michael@0 298 JS_ASSERT(base >= 2 && base <= 36);
michael@0 299
michael@0 300 dval(d) = dinput;
michael@0 301 buffer = (char*) js_malloc(DTOBASESTR_BUFFER_SIZE);
michael@0 302 if (!buffer)
michael@0 303 return nullptr;
michael@0 304 p = buffer;
michael@0 305
michael@0 306 if (dval(d) < 0.0
michael@0 307 #if defined(XP_WIN)
michael@0 308 && !((word0(d) & Exp_mask) == Exp_mask && ((word0(d) & Frac_mask) || word1(d))) /* Visual C++ doesn't know how to compare against NaN */
michael@0 309 #endif
michael@0 310 ) {
michael@0 311 *p++ = '-';
michael@0 312 dval(d) = -dval(d);
michael@0 313 }
michael@0 314
michael@0 315 /* Check for Infinity and NaN */
michael@0 316 if ((word0(d) & Exp_mask) == Exp_mask) {
michael@0 317 strcpy(p, !word1(d) && !(word0(d) & Frac_mask) ? "Infinity" : "NaN");
michael@0 318 return buffer;
michael@0 319 }
michael@0 320
michael@0 321 /* Output the integer part of d with the digits in reverse order. */
michael@0 322 pInt = p;
michael@0 323 dval(di) = floor(dval(d));
michael@0 324 if (dval(di) <= 4294967295.0) {
michael@0 325 uint32_t n = (uint32_t)dval(di);
michael@0 326 if (n)
michael@0 327 do {
michael@0 328 uint32_t m = n / base;
michael@0 329 digit = n - m*base;
michael@0 330 n = m;
michael@0 331 JS_ASSERT(digit < (uint32_t)base);
michael@0 332 *p++ = BASEDIGIT(digit);
michael@0 333 } while (n);
michael@0 334 else *p++ = '0';
michael@0 335 } else {
michael@0 336 int e;
michael@0 337 int bits; /* Number of significant bits in di; not used. */
michael@0 338 Bigint *b = d2b(PASS_STATE di, &e, &bits);
michael@0 339 if (!b)
michael@0 340 goto nomem1;
michael@0 341 b = lshift(PASS_STATE b, e);
michael@0 342 if (!b) {
michael@0 343 nomem1:
michael@0 344 Bfree(PASS_STATE b);
michael@0 345 js_free(buffer);
michael@0 346 return nullptr;
michael@0 347 }
michael@0 348 do {
michael@0 349 digit = divrem(b, base);
michael@0 350 JS_ASSERT(digit < (uint32_t)base);
michael@0 351 *p++ = BASEDIGIT(digit);
michael@0 352 } while (b->wds);
michael@0 353 Bfree(PASS_STATE b);
michael@0 354 }
michael@0 355 /* Reverse the digits of the integer part of d. */
michael@0 356 q = p-1;
michael@0 357 while (q > pInt) {
michael@0 358 char ch = *pInt;
michael@0 359 *pInt++ = *q;
michael@0 360 *q-- = ch;
michael@0 361 }
michael@0 362
michael@0 363 dval(df) = dval(d) - dval(di);
michael@0 364 if (dval(df) != 0.0) {
michael@0 365 /* We have a fraction. */
michael@0 366 int e, bbits;
michael@0 367 int32_t s2, done;
michael@0 368 Bigint *b, *s, *mlo, *mhi;
michael@0 369
michael@0 370 b = s = mlo = mhi = nullptr;
michael@0 371
michael@0 372 *p++ = '.';
michael@0 373 b = d2b(PASS_STATE df, &e, &bbits);
michael@0 374 if (!b) {
michael@0 375 nomem2:
michael@0 376 Bfree(PASS_STATE b);
michael@0 377 Bfree(PASS_STATE s);
michael@0 378 if (mlo != mhi)
michael@0 379 Bfree(PASS_STATE mlo);
michael@0 380 Bfree(PASS_STATE mhi);
michael@0 381 js_free(buffer);
michael@0 382 return nullptr;
michael@0 383 }
michael@0 384 JS_ASSERT(e < 0);
michael@0 385 /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */
michael@0 386
michael@0 387 s2 = -(int32_t)(word0(d) >> Exp_shift1 & Exp_mask>>Exp_shift1);
michael@0 388 #ifndef Sudden_Underflow
michael@0 389 if (!s2)
michael@0 390 s2 = -1;
michael@0 391 #endif
michael@0 392 s2 += Bias + P;
michael@0 393 /* 1/2^s2 = (nextDouble(d) - d)/2 */
michael@0 394 JS_ASSERT(-s2 < e);
michael@0 395 mlo = i2b(PASS_STATE 1);
michael@0 396 if (!mlo)
michael@0 397 goto nomem2;
michael@0 398 mhi = mlo;
michael@0 399 if (!word1(d) && !(word0(d) & Bndry_mask)
michael@0 400 #ifndef Sudden_Underflow
michael@0 401 && word0(d) & (Exp_mask & Exp_mask << 1)
michael@0 402 #endif
michael@0 403 ) {
michael@0 404 /* The special case. Here we want to be within a quarter of the last input
michael@0 405 significant digit instead of one half of it when the output string's value is less than d. */
michael@0 406 s2 += Log2P;
michael@0 407 mhi = i2b(PASS_STATE 1<<Log2P);
michael@0 408 if (!mhi)
michael@0 409 goto nomem2;
michael@0 410 }
michael@0 411 b = lshift(PASS_STATE b, e + s2);
michael@0 412 if (!b)
michael@0 413 goto nomem2;
michael@0 414 s = i2b(PASS_STATE 1);
michael@0 415 if (!s)
michael@0 416 goto nomem2;
michael@0 417 s = lshift(PASS_STATE s, s2);
michael@0 418 if (!s)
michael@0 419 goto nomem2;
michael@0 420 /* At this point we have the following:
michael@0 421 * s = 2^s2;
michael@0 422 * 1 > df = b/2^s2 > 0;
michael@0 423 * (d - prevDouble(d))/2 = mlo/2^s2;
michael@0 424 * (nextDouble(d) - d)/2 = mhi/2^s2. */
michael@0 425
michael@0 426 done = false;
michael@0 427 do {
michael@0 428 int32_t j, j1;
michael@0 429 Bigint *delta;
michael@0 430
michael@0 431 b = multadd(PASS_STATE b, base, 0);
michael@0 432 if (!b)
michael@0 433 goto nomem2;
michael@0 434 digit = quorem2(b, s2);
michael@0 435 if (mlo == mhi) {
michael@0 436 mlo = mhi = multadd(PASS_STATE mlo, base, 0);
michael@0 437 if (!mhi)
michael@0 438 goto nomem2;
michael@0 439 }
michael@0 440 else {
michael@0 441 mlo = multadd(PASS_STATE mlo, base, 0);
michael@0 442 if (!mlo)
michael@0 443 goto nomem2;
michael@0 444 mhi = multadd(PASS_STATE mhi, base, 0);
michael@0 445 if (!mhi)
michael@0 446 goto nomem2;
michael@0 447 }
michael@0 448
michael@0 449 /* Do we yet have the shortest string that will round to d? */
michael@0 450 j = cmp(b, mlo);
michael@0 451 /* j is b/2^s2 compared with mlo/2^s2. */
michael@0 452 delta = diff(PASS_STATE s, mhi);
michael@0 453 if (!delta)
michael@0 454 goto nomem2;
michael@0 455 j1 = delta->sign ? 1 : cmp(b, delta);
michael@0 456 Bfree(PASS_STATE delta);
michael@0 457 /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
michael@0 458
michael@0 459 #ifndef ROUND_BIASED
michael@0 460 if (j1 == 0 && !(word1(d) & 1)) {
michael@0 461 if (j > 0)
michael@0 462 digit++;
michael@0 463 done = true;
michael@0 464 } else
michael@0 465 #endif
michael@0 466 if (j < 0 || (j == 0
michael@0 467 #ifndef ROUND_BIASED
michael@0 468 && !(word1(d) & 1)
michael@0 469 #endif
michael@0 470 )) {
michael@0 471 if (j1 > 0) {
michael@0 472 /* Either dig or dig+1 would work here as the least significant digit.
michael@0 473 Use whichever would produce an output value closer to d. */
michael@0 474 b = lshift(PASS_STATE b, 1);
michael@0 475 if (!b)
michael@0 476 goto nomem2;
michael@0 477 j1 = cmp(b, s);
michael@0 478 if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
michael@0 479 * such as 3.5 in base 3. */
michael@0 480 digit++;
michael@0 481 }
michael@0 482 done = true;
michael@0 483 } else if (j1 > 0) {
michael@0 484 digit++;
michael@0 485 done = true;
michael@0 486 }
michael@0 487 JS_ASSERT(digit < (uint32_t)base);
michael@0 488 *p++ = BASEDIGIT(digit);
michael@0 489 } while (!done);
michael@0 490 Bfree(PASS_STATE b);
michael@0 491 Bfree(PASS_STATE s);
michael@0 492 if (mlo != mhi)
michael@0 493 Bfree(PASS_STATE mlo);
michael@0 494 Bfree(PASS_STATE mhi);
michael@0 495 }
michael@0 496 JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE);
michael@0 497 *p = '\0';
michael@0 498 return buffer;
michael@0 499 }
michael@0 500
michael@0 501 DtoaState *
michael@0 502 js_NewDtoaState()
michael@0 503 {
michael@0 504 return newdtoa();
michael@0 505 }
michael@0 506
michael@0 507 void
michael@0 508 js_DestroyDtoaState(DtoaState *state)
michael@0 509 {
michael@0 510 destroydtoa(state);
michael@0 511 }

mercurial