1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16 * The Original Code is Mozilla Communicator client code, released
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.
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.
38 * ***** END LICENSE BLOCK ***** */
41 * Portable double to alphanumeric string and back converters.
51 #include "jslibmath.h"
54 #include "jsobjinlines.h"
56 #ifdef IS_LITTLE_ENDIAN
76 #define ULlong JSUint64
80 #define NO_GLOBAL_STATE
81 #define MALLOC js_malloc
85 /* Mapping of JSDToStrMode -> js_dtoa mode */
86 static const uint8 dtoaModes
[] = {
87 0, /* DTOSTR_STANDARD */
88 0, /* DTOSTR_STANDARD_EXPONENTIAL, */
89 3, /* DTOSTR_FIXED, */
90 2, /* DTOSTR_EXPONENTIAL, */
91 2}; /* DTOSTR_PRECISION */
94 js_strtod_harder(DtoaState
*state
, const char *s00
, char **se
, int *err
)
99 retval
= _strtod(state
, s00
, se
);
104 js_dtostr(DtoaState
*state
, char *buffer
, size_t bufferSize
, JSDToStrMode mode
, int precision
,
108 int decPt
; /* Offset of decimal point from first digit */
109 int sign
; /* Nonzero if the sign bit was set in d */
110 int nDigits
; /* Number of significand digits returned by js_dtoa */
111 char *numBegin
; /* Pointer to the digits returned by js_dtoa */
112 char *numEnd
= 0; /* Pointer past the digits returned by js_dtoa */
114 JS_ASSERT(bufferSize
>= (size_t)(mode
<= DTOSTR_STANDARD_EXPONENTIAL
115 ? DTOSTR_STANDARD_BUFFER_SIZE
116 : DTOSTR_VARIABLE_BUFFER_SIZE(precision
)));
119 * Change mode here rather than below because the buffer may not be large
120 * enough to hold a large integer.
122 if (mode
== DTOSTR_FIXED
&& (dinput
>= 1e21
|| dinput
<= -1e21
))
123 mode
= DTOSTR_STANDARD
;
126 numBegin
= dtoa(PASS_STATE d
, dtoaModes
[mode
], precision
, &decPt
, &sign
, &numEnd
);
131 nDigits
= numEnd
- numBegin
;
132 JS_ASSERT((size_t) nDigits
<= bufferSize
- 2);
133 if ((size_t) nDigits
> bufferSize
- 2) {
137 memcpy(buffer
+ 2, numBegin
, nDigits
);
138 freedtoa(PASS_STATE numBegin
);
139 numBegin
= buffer
+ 2; /* +2 leaves space for sign and/or decimal point */
140 numEnd
= numBegin
+ nDigits
;
143 /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */
145 JSBool exponentialNotation
= JS_FALSE
;
146 int minNDigits
= 0; /* Min number of significant digits required */
151 case DTOSTR_STANDARD
:
152 if (decPt
< -5 || decPt
> 21)
153 exponentialNotation
= JS_TRUE
;
160 minNDigits
= decPt
+ precision
;
165 case DTOSTR_EXPONENTIAL
:
166 JS_ASSERT(precision
> 0);
167 minNDigits
= precision
;
169 case DTOSTR_STANDARD_EXPONENTIAL
:
170 exponentialNotation
= JS_TRUE
;
173 case DTOSTR_PRECISION
:
174 JS_ASSERT(precision
> 0);
175 minNDigits
= precision
;
176 if (decPt
< -5 || decPt
> precision
)
177 exponentialNotation
= JS_TRUE
;
181 /* If the number has fewer than minNDigits, end-pad it with zeros. */
182 if (nDigits
< minNDigits
) {
183 p
= numBegin
+ minNDigits
;
184 nDigits
= minNDigits
;
187 } while (numEnd
!= p
);
191 if (exponentialNotation
) {
192 /* Insert a decimal point if more than one significand digit */
195 numBegin
[0] = numBegin
[1];
198 JS_snprintf(numEnd
, bufferSize
- (numEnd
- buffer
), "e%+d", decPt
-1);
199 } else if (decPt
!= nDigits
) {
200 /* Some kind of a fraction in fixed notation */
201 JS_ASSERT(decPt
<= nDigits
);
203 /* dd...dd . dd...dd */
211 /* 0 . 00...00dd...dd */
215 JS_ASSERT(numEnd
< buffer
+ bufferSize
);
217 while (p
!= numBegin
)
219 for (p
= numBegin
+ 1; p
!= q
; p
++)
227 /* If negative and neither -0.0 nor NaN, output a leading '-'. */
229 !(word0(d
) == Sign_bit
&& word1(d
) == 0) &&
230 !((word0(d
) & Exp_mask
) == Exp_mask
&&
231 (word1(d
) || (word0(d
) & Frac_mask
)))) {
238 /* Let b = floor(b / divisor), and return the remainder. b must be nonnegative.
239 * divisor must be between 1 and 65536.
240 * This function cannot run out of memory. */
242 divrem(Bigint
*b
, uint32 divisor
)
245 uint32 remainder
= 0;
249 JS_ASSERT(divisor
> 0 && divisor
<= 65536);
252 return 0; /* b is zero */
257 ULong dividend
= remainder
<< 16 | a
>> 16;
258 ULong quotientHi
= dividend
/ divisor
;
261 remainder
= dividend
- quotientHi
*divisor
;
262 JS_ASSERT(quotientHi
<= 0xFFFF && remainder
< divisor
);
263 dividend
= remainder
<< 16 | (a
& 0xFFFF);
264 quotientLo
= dividend
/ divisor
;
265 remainder
= dividend
- quotientLo
*divisor
;
266 JS_ASSERT(quotientLo
<= 0xFFFF && remainder
< divisor
);
267 *bp
= quotientHi
<< 16 | quotientLo
;
269 /* Decrease the size of the number if its most significant word is now zero. */
275 /* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */
276 static uint32
quorem2(Bigint
*b
, int32 k
)
295 JS_ASSERT(!(bxe
[1] & ~mask
));
297 result
|= bxe
[1] << (32 - k
);
300 while (!*bxe
&& bxe
!= bx
) {
309 /* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
310 * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
311 * the output string and malloc fewer bytes depending on d and base, but why bother? */
312 #define DTOBASESTR_BUFFER_SIZE 1078
313 #define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
316 js_dtobasestr(DtoaState
*state
, int base
, double dinput
)
319 char *buffer
; /* The output string */
320 char *p
; /* Pointer to current position in the buffer */
321 char *pInt
; /* Pointer to the beginning of the integer part of the string */
324 U di
; /* d truncated to an integer */
325 U df
; /* The fractional part of d */
327 JS_ASSERT(base
>= 2 && base
<= 36);
330 buffer
= (char*) js_malloc(DTOBASESTR_BUFFER_SIZE
);
336 #if defined(XP_WIN) || defined(XP_OS2)
337 && !((word0(d
) & Exp_mask
) == Exp_mask
&& ((word0(d
) & Frac_mask
) || word1(d
))) /* Visual C++ doesn't know how to compare against NaN */
344 /* Check for Infinity and NaN */
345 if ((word0(d
) & Exp_mask
) == Exp_mask
) {
346 strcpy(p
, !word1(d
) && !(word0(d
) & Frac_mask
) ? "Infinity" : "NaN");
350 /* Output the integer part of d with the digits in reverse order. */
352 dval(di
) = floor(dval(d
));
353 if (dval(di
) <= 4294967295.0) {
354 uint32 n
= (uint32
)dval(di
);
360 JS_ASSERT(digit
< (uint32
)base
);
361 *p
++ = BASEDIGIT(digit
);
366 int bits
; /* Number of significant bits in di; not used. */
367 Bigint
*b
= d2b(PASS_STATE di
, &e
, &bits
);
370 b
= lshift(PASS_STATE b
, e
);
378 digit
= divrem(b
, base
);
379 JS_ASSERT(digit
< (uint32
)base
);
380 *p
++ = BASEDIGIT(digit
);
384 /* Reverse the digits of the integer part of d. */
392 dval(df
) = dval(d
) - dval(di
);
393 if (dval(df
) != 0.0) {
394 /* We have a fraction. */
397 Bigint
*b
, *s
, *mlo
, *mhi
;
399 b
= s
= mlo
= mhi
= NULL
;
402 b
= d2b(PASS_STATE df
, &e
, &bbits
);
408 Bfree(PASS_STATE mlo
);
409 Bfree(PASS_STATE mhi
);
414 /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */
416 s2
= -(int32
)(word0(d
) >> Exp_shift1
& Exp_mask
>>Exp_shift1
);
417 #ifndef Sudden_Underflow
422 /* 1/2^s2 = (nextDouble(d) - d)/2 */
424 mlo
= i2b(PASS_STATE
1);
428 if (!word1(d
) && !(word0(d
) & Bndry_mask
)
429 #ifndef Sudden_Underflow
430 && word0(d
) & (Exp_mask
& Exp_mask
<< 1)
433 /* The special case. Here we want to be within a quarter of the last input
434 significant digit instead of one half of it when the output string's value is less than d. */
436 mhi
= i2b(PASS_STATE
1<<Log2P
);
440 b
= lshift(PASS_STATE b
, e
+ s2
);
443 s
= i2b(PASS_STATE
1);
446 s
= lshift(PASS_STATE s
, s2
);
449 /* At this point we have the following:
451 * 1 > df = b/2^s2 > 0;
452 * (d - prevDouble(d))/2 = mlo/2^s2;
453 * (nextDouble(d) - d)/2 = mhi/2^s2. */
460 b
= multadd(PASS_STATE b
, base
, 0);
463 digit
= quorem2(b
, s2
);
465 mlo
= mhi
= multadd(PASS_STATE mlo
, base
, 0);
470 mlo
= multadd(PASS_STATE mlo
, base
, 0);
473 mhi
= multadd(PASS_STATE mhi
, base
, 0);
478 /* Do we yet have the shortest string that will round to d? */
480 /* j is b/2^s2 compared with mlo/2^s2. */
481 delta
= diff(PASS_STATE s
, mhi
);
484 j1
= delta
->sign
? 1 : cmp(b
, delta
);
485 Bfree(PASS_STATE delta
);
486 /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
489 if (j1
== 0 && !(word1(d
) & 1)) {
501 /* Either dig or dig+1 would work here as the least significant digit.
502 Use whichever would produce an output value closer to d. */
503 b
= lshift(PASS_STATE b
, 1);
507 if (j1
> 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
508 * such as 3.5 in base 3. */
516 JS_ASSERT(digit
< (uint32
)base
);
517 *p
++ = BASEDIGIT(digit
);
522 Bfree(PASS_STATE mlo
);
523 Bfree(PASS_STATE mhi
);
525 JS_ASSERT(p
< buffer
+ DTOBASESTR_BUFFER_SIZE
);
537 js_DestroyDtoaState(DtoaState
*state
)