1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * Portable double to alphanumeric string and back converters.
11 #include "util/DoubleToString.h"
13 #include "mozilla/EndianUtils.h"
15 #include "js/Utility.h"
19 #if MOZ_LITTLE_ENDIAN()
30 # define ULong uint32_t
39 #define ULlong uint64_t
43 // dtoa.c requires that MALLOC be infallible. Furthermore, its allocations are
44 // few and small. So AutoEnterOOMUnsafeRegion is appropriate here.
45 static inline void* dtoa_malloc(size_t size
) {
46 AutoEnterOOMUnsafeRegion oomUnsafe
;
47 void* p
= js_malloc(size
);
48 if (!p
) oomUnsafe
.crash("dtoa_malloc");
53 static inline void dtoa_free(void* p
) { return js_free(p
); }
55 #define NO_GLOBAL_STATE
57 #define Omit_Private_Memory // This saves memory for the workloads we see.
58 #define MALLOC dtoa_malloc
59 #define FREE dtoa_free
62 /* Let b = floor(b / divisor), and return the remainder. b must be nonnegative.
63 * divisor must be between 1 and 65536.
64 * This function cannot run out of memory. */
65 static uint32_t divrem(Bigint
* b
, uint32_t divisor
) {
67 uint32_t remainder
= 0;
71 MOZ_ASSERT(divisor
> 0 && divisor
<= 65536);
73 if (!n
) return 0; /* b is zero */
78 ULong dividend
= remainder
<< 16 | a
>> 16;
79 ULong quotientHi
= dividend
/ divisor
;
82 remainder
= dividend
- quotientHi
* divisor
;
83 MOZ_ASSERT(quotientHi
<= 0xFFFF && remainder
< divisor
);
84 dividend
= remainder
<< 16 | (a
& 0xFFFF);
85 quotientLo
= dividend
/ divisor
;
86 remainder
= dividend
- quotientLo
* divisor
;
87 MOZ_ASSERT(quotientLo
<= 0xFFFF && remainder
< divisor
);
88 *bp
= quotientHi
<< 16 | quotientLo
;
90 /* Decrease the size of the number if its most significant word is now zero.
92 if (bx
[n
- 1] == 0) b
->wds
--;
96 /* Return floor(b/2^k) and set b to be the remainder. The returned quotient
97 * must be less than 2^32. */
98 static uint32_t quorem2(Bigint
* b
, int32_t k
) {
106 mask
= (ULong(1) << k
) - 1;
109 if (w
<= 0) return 0;
116 MOZ_ASSERT(!(bxe
[1] & ~mask
));
117 if (k
) result
|= bxe
[1] << (32 - k
);
120 while (!*bxe
&& bxe
!= bx
) {
128 /* "-0.0000...(1073 zeros after decimal point)...0001\0" is the longest string
129 * that we could produce, which occurs when printing -5e-324 in binary. We
130 * could compute a better estimate of the size of the output string and malloc
131 * fewer bytes depending on d and base, but why bother? */
132 #define DTOBASESTR_BUFFER_SIZE 1078
133 #define BASEDIGIT(digit) \
134 ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
136 char* js_dtobasestr(DtoaState
* state
, int base
, double dinput
) {
138 char* buffer
; /* The output string */
139 char* p
; /* Pointer to current position in the buffer */
140 char* pInt
; /* Pointer to the beginning of the integer part of the string */
143 U di
; /* d truncated to an integer */
144 U df
; /* The fractional part of d */
146 MOZ_ASSERT(base
>= 2 && base
<= 36);
149 buffer
= js_pod_malloc
<char>(DTOBASESTR_BUFFER_SIZE
);
150 if (!buffer
) return nullptr;
158 /* Check for Infinity and NaN */
159 if ((word0(d
) & Exp_mask
) == Exp_mask
) {
160 strcpy(p
, !word1(d
) && !(word0(d
) & Frac_mask
) ? "Infinity" : "NaN");
164 /* Output the integer part of d with the digits in reverse order. */
166 dval(di
) = floor(dval(d
));
167 if (dval(di
) <= 4294967295.0) {
168 uint32_t n
= (uint32_t)dval(di
);
170 uint32_t m
= n
/ base
;
171 digit
= n
- m
* base
;
173 MOZ_ASSERT(digit
< (uint32_t)base
);
174 *p
++ = BASEDIGIT(digit
);
180 int bits
; /* Number of significant bits in di; not used. */
181 Bigint
* b
= d2b(PASS_STATE di
, &e
, &bits
);
183 b
= lshift(PASS_STATE b
, e
);
191 digit
= divrem(b
, base
);
192 MOZ_ASSERT(digit
< (uint32_t)base
);
193 *p
++ = BASEDIGIT(digit
);
197 /* Reverse the digits of the integer part of d. */
205 dval(df
) = dval(d
) - dval(di
);
206 if (dval(df
) != 0.0) {
207 /* We have a fraction. */
212 Bigint
* mlo
= nullptr;
213 Bigint
* mhi
= nullptr;
216 b
= d2b(PASS_STATE df
, &e
, &bbits
);
221 if (mlo
!= mhi
) Bfree(PASS_STATE mlo
);
222 Bfree(PASS_STATE mhi
);
227 /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1.
230 s2
= -(int32_t)(word0(d
) >> Exp_shift1
& Exp_mask
>> Exp_shift1
);
231 #ifndef Sudden_Underflow
235 /* 1/2^s2 = (nextDouble(d) - d)/2 */
237 mlo
= i2b(PASS_STATE
1);
238 if (!mlo
) goto nomem2
;
240 if (!word1(d
) && !(word0(d
) & Bndry_mask
)
241 #ifndef Sudden_Underflow
242 && word0(d
) & (Exp_mask
& Exp_mask
<< 1)
245 /* The special case. Here we want to be within a quarter of the last
246 input significant digit instead of one half of it when the output
247 string's value is less than d. */
249 mhi
= i2b(PASS_STATE
1 << Log2P
);
250 if (!mhi
) goto nomem2
;
252 b
= lshift(PASS_STATE b
, e
+ s2
);
254 s
= i2b(PASS_STATE
1);
256 s
= lshift(PASS_STATE s
, s2
);
258 /* At this point we have the following:
260 * 1 > df = b/2^s2 > 0;
261 * (d - prevDouble(d))/2 = mlo/2^s2;
262 * (nextDouble(d) - d)/2 = mhi/2^s2. */
269 b
= multadd(PASS_STATE b
, base
, 0);
271 digit
= quorem2(b
, s2
);
273 mlo
= mhi
= multadd(PASS_STATE mlo
, base
, 0);
274 if (!mhi
) goto nomem2
;
276 mlo
= multadd(PASS_STATE mlo
, base
, 0);
277 if (!mlo
) goto nomem2
;
278 mhi
= multadd(PASS_STATE mhi
, base
, 0);
279 if (!mhi
) goto nomem2
;
282 /* Do we yet have the shortest string that will round to d? */
284 /* j is b/2^s2 compared with mlo/2^s2. */
285 delta
= diff(PASS_STATE s
, mhi
);
286 if (!delta
) goto nomem2
;
287 j1
= delta
->sign
? 1 : cmp(b
, delta
);
288 Bfree(PASS_STATE delta
);
289 /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
292 if (j1
== 0 && !(word1(d
) & 1)) {
303 /* Either dig or dig+1 would work here as the least significant digit.
304 Use whichever would produce an output value closer to d. */
305 b
= lshift(PASS_STATE b
, 1);
308 if (j1
> 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here
309 * because it messes up odd base output such as 3.5 in
318 MOZ_ASSERT(digit
< (uint32_t)base
);
319 *p
++ = BASEDIGIT(digit
);
323 if (mlo
!= mhi
) Bfree(PASS_STATE mlo
);
324 Bfree(PASS_STATE mhi
);
326 MOZ_ASSERT(p
< buffer
+ DTOBASESTR_BUFFER_SIZE
);
331 DtoaState
* js::NewDtoaState() { return newdtoa(); }
333 void js::DestroyDtoaState(DtoaState
* state
) { destroydtoa(state
); }
335 /* Cleanup pollution from dtoa.c */