/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsdtoa.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs · C++ · 572 lines · 433 code · 49 blank · 90 comment · 113 complexity · 904d503b58acd9cbb384d6c6dd923168 MD5 · raw file

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