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