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.
47 #include "jsutil.h" /* Added by JSIFY */
51 #include "jslibmath.h"
57 #ifdef IS_LITTLE_ENDIAN
77 #define ULlong JSUint64
82 static PRLock
*dtoalock
;
83 static JSBool _dtoainited
= JS_FALSE
;
85 #define LOCK_DTOA() PR_Lock(dtoalock);
86 #define UNLOCK_DTOA() PR_Unlock(dtoalock)
98 dtoalock
= PR_NewLock();
100 _dtoainited
= JS_TRUE
;
103 return (dtoalock
!= 0);
114 PR_DestroyLock(dtoalock
);
116 _dtoainited
= JS_FALSE
;
121 /* Mapping of JSDToStrMode -> js_dtoa mode */
122 static const uint8 dtoaModes
[] = {
123 0, /* DTOSTR_STANDARD */
124 0, /* DTOSTR_STANDARD_EXPONENTIAL, */
125 3, /* DTOSTR_FIXED, */
126 2, /* DTOSTR_EXPONENTIAL, */
127 2}; /* DTOSTR_PRECISION */
129 JS_FRIEND_API(double)
130 JS_strtod(const char *s00
, char **se
, int *err
)
136 retval
= _strtod(s00
, se
);
141 JS_FRIEND_API(char *)
142 JS_dtostr(char *buffer
, size_t bufferSize
, JSDToStrMode mode
, int precision
, double dinput
)
145 int decPt
; /* Offset of decimal point from first digit */
146 int sign
; /* Nonzero if the sign bit was set in d */
147 int nDigits
; /* Number of significand digits returned by js_dtoa */
148 char *numBegin
; /* Pointer to the digits returned by js_dtoa */
149 char *numEnd
= 0; /* Pointer past the digits returned by js_dtoa */
151 JS_ASSERT(bufferSize
>= (size_t)(mode
<= DTOSTR_STANDARD_EXPONENTIAL
152 ? DTOSTR_STANDARD_BUFFER_SIZE
153 : DTOSTR_VARIABLE_BUFFER_SIZE(precision
)));
156 * Change mode here rather than below because the buffer may not be large
157 * enough to hold a large integer.
159 if (mode
== DTOSTR_FIXED
&& (dinput
>= 1e21
|| dinput
<= -1e21
))
160 mode
= DTOSTR_STANDARD
;
164 numBegin
= dtoa(d
, dtoaModes
[mode
], precision
, &decPt
, &sign
, &numEnd
);
170 nDigits
= numEnd
- numBegin
;
171 JS_ASSERT((size_t) nDigits
<= bufferSize
- 2);
172 if ((size_t) nDigits
> bufferSize
- 2) {
177 memcpy(buffer
+ 2, numBegin
, nDigits
);
180 numBegin
= buffer
+ 2; /* +2 leaves space for sign and/or decimal point */
181 numEnd
= numBegin
+ nDigits
;
184 /* If Infinity, -Infinity, or NaN, return the string regardless of mode. */
186 JSBool exponentialNotation
= JS_FALSE
;
187 int minNDigits
= 0; /* Min number of significant digits required */
192 case DTOSTR_STANDARD
:
193 if (decPt
< -5 || decPt
> 21)
194 exponentialNotation
= JS_TRUE
;
201 minNDigits
= decPt
+ precision
;
206 case DTOSTR_EXPONENTIAL
:
207 JS_ASSERT(precision
> 0);
208 minNDigits
= precision
;
210 case DTOSTR_STANDARD_EXPONENTIAL
:
211 exponentialNotation
= JS_TRUE
;
214 case DTOSTR_PRECISION
:
215 JS_ASSERT(precision
> 0);
216 minNDigits
= precision
;
217 if (decPt
< -5 || decPt
> precision
)
218 exponentialNotation
= JS_TRUE
;
222 /* If the number has fewer than minNDigits, end-pad it with zeros. */
223 if (nDigits
< minNDigits
) {
224 p
= numBegin
+ minNDigits
;
225 nDigits
= minNDigits
;
228 } while (numEnd
!= p
);
232 if (exponentialNotation
) {
233 /* Insert a decimal point if more than one significand digit */
236 numBegin
[0] = numBegin
[1];
239 JS_snprintf(numEnd
, bufferSize
- (numEnd
- buffer
), "e%+d", decPt
-1);
240 } else if (decPt
!= nDigits
) {
241 /* Some kind of a fraction in fixed notation */
242 JS_ASSERT(decPt
<= nDigits
);
244 /* dd...dd . dd...dd */
252 /* 0 . 00...00dd...dd */
256 JS_ASSERT(numEnd
< buffer
+ bufferSize
);
258 while (p
!= numBegin
)
260 for (p
= numBegin
+ 1; p
!= q
; p
++)
268 /* If negative and neither -0.0 nor NaN, output a leading '-'. */
270 !(word0(d
) == Sign_bit
&& word1(d
) == 0) &&
271 !((word0(d
) & Exp_mask
) == Exp_mask
&&
272 (word1(d
) || (word0(d
) & Frac_mask
)))) {
279 /* Let b = floor(b / divisor), and return the remainder. b must be nonnegative.
280 * divisor must be between 1 and 65536.
281 * This function cannot run out of memory. */
283 divrem(Bigint
*b
, uint32 divisor
)
286 uint32 remainder
= 0;
290 JS_ASSERT(divisor
> 0 && divisor
<= 65536);
293 return 0; /* b is zero */
298 ULong dividend
= remainder
<< 16 | a
>> 16;
299 ULong quotientHi
= dividend
/ divisor
;
302 remainder
= dividend
- quotientHi
*divisor
;
303 JS_ASSERT(quotientHi
<= 0xFFFF && remainder
< divisor
);
304 dividend
= remainder
<< 16 | (a
& 0xFFFF);
305 quotientLo
= dividend
/ divisor
;
306 remainder
= dividend
- quotientLo
*divisor
;
307 JS_ASSERT(quotientLo
<= 0xFFFF && remainder
< divisor
);
308 *bp
= quotientHi
<< 16 | quotientLo
;
310 /* Decrease the size of the number if its most significant word is now zero. */
316 /* Return floor(b/2^k) and set b to be the remainder. The returned quotient must be less than 2^32. */
317 static uint32
quorem2(Bigint
*b
, int32 k
)
336 JS_ASSERT(!(bxe
[1] & ~mask
));
338 result
|= bxe
[1] << (32 - k
);
341 while (!*bxe
&& bxe
!= bx
) {
350 /* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string that we could produce,
351 * which occurs when printing -5e-324 in binary. We could compute a better estimate of the size of
352 * the output string and malloc fewer bytes depending on d and base, but why bother? */
353 #define DTOBASESTR_BUFFER_SIZE 1078
354 #define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
356 JS_FRIEND_API(char *)
357 JS_dtobasestr(int base
, double dinput
)
360 char *buffer
; /* The output string */
361 char *p
; /* Pointer to current position in the buffer */
362 char *pInt
; /* Pointer to the beginning of the integer part of the string */
365 U di
; /* d truncated to an integer */
366 U df
; /* The fractional part of d */
368 JS_ASSERT(base
>= 2 && base
<= 36);
371 buffer
= (char*) js_malloc(DTOBASESTR_BUFFER_SIZE
);
375 #if defined(XP_WIN) || defined(XP_OS2)
376 && !((word0(d
) & Exp_mask
) == Exp_mask
&& ((word0(d
) & Frac_mask
) || word1(d
))) /* Visual C++ doesn't know how to compare against NaN */
383 /* Check for Infinity and NaN */
384 if ((word0(d
) & Exp_mask
) == Exp_mask
) {
385 strcpy(p
, !word1(d
) && !(word0(d
) & Frac_mask
) ? "Infinity" : "NaN");
390 /* Output the integer part of d with the digits in reverse order. */
392 dval(di
) = floor(dval(d
));
393 if (dval(di
) <= 4294967295.0) {
394 uint32 n
= (uint32
)dval(di
);
400 JS_ASSERT(digit
< (uint32
)base
);
401 *p
++ = BASEDIGIT(digit
);
406 int bits
; /* Number of significant bits in di; not used. */
407 Bigint
*b
= d2b(di
, &e
, &bits
);
419 digit
= divrem(b
, base
);
420 JS_ASSERT(digit
< (uint32
)base
);
421 *p
++ = BASEDIGIT(digit
);
425 /* Reverse the digits of the integer part of d. */
433 dval(df
) = dval(d
) - dval(di
);
434 if (dval(df
) != 0.0) {
435 /* We have a fraction. */
438 Bigint
*b
, *s
, *mlo
, *mhi
;
440 b
= s
= mlo
= mhi
= NULL
;
443 b
= d2b(df
, &e
, &bbits
);
456 /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */
458 s2
= -(int32
)(word0(d
) >> Exp_shift1
& Exp_mask
>>Exp_shift1
);
459 #ifndef Sudden_Underflow
464 /* 1/2^s2 = (nextDouble(d) - d)/2 */
470 if (!word1(d
) && !(word0(d
) & Bndry_mask
)
471 #ifndef Sudden_Underflow
472 && word0(d
) & (Exp_mask
& Exp_mask
<< 1)
475 /* The special case. Here we want to be within a quarter of the last input
476 significant digit instead of one half of it when the output string's value is less than d. */
482 b
= lshift(b
, e
+ s2
);
491 /* At this point we have the following:
493 * 1 > df = b/2^s2 > 0;
494 * (d - prevDouble(d))/2 = mlo/2^s2;
495 * (nextDouble(d) - d)/2 = mhi/2^s2. */
502 b
= multadd(b
, base
, 0);
505 digit
= quorem2(b
, s2
);
507 mlo
= mhi
= multadd(mlo
, base
, 0);
512 mlo
= multadd(mlo
, base
, 0);
515 mhi
= multadd(mhi
, base
, 0);
520 /* Do we yet have the shortest string that will round to d? */
522 /* j is b/2^s2 compared with mlo/2^s2. */
523 delta
= diff(s
, mhi
);
526 j1
= delta
->sign
? 1 : cmp(b
, delta
);
528 /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
531 if (j1
== 0 && !(word1(d
) & 1)) {
543 /* Either dig or dig+1 would work here as the least significant digit.
544 Use whichever would produce an output value closer to d. */
549 if (j1
> 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output
550 * such as 3.5 in base 3. */
558 JS_ASSERT(digit
< (uint32
)base
);
559 *p
++ = BASEDIGIT(digit
);
567 JS_ASSERT(p
< buffer
+ DTOBASESTR_BUFFER_SIZE
);