/src/open62541/deps/dtoa.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2013, Andreas Samoljuk |
2 | | // Copyright 2023, Julius Pfrommer |
3 | | // |
4 | | // Boost Software License - Version 1.0 - August 17th, 2003 |
5 | | // |
6 | | // Permission is hereby granted, free of charge, to any person or organization |
7 | | // obtaining a copy of the software and accompanying documentation covered by |
8 | | // this license (the "Software") to use, reproduce, display, distribute, |
9 | | // execute, and transmit the Software, and to prepare derivative works of the |
10 | | // Software, and to permit third-parties to whom the Software is furnished to |
11 | | // do so, all subject to the following: |
12 | | // |
13 | | // The copyright notices in the Software and this entire statement, including |
14 | | // the above license grant, this restriction and the following disclaimer, |
15 | | // must be included in all copies of the Software, in whole or in part, and |
16 | | // all derivative works of the Software, unless such copies or derivative |
17 | | // works are solely in the form of machine-executable object code generated by |
18 | | // a source language processor. |
19 | | // |
20 | | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
21 | | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | | // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT |
23 | | // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE |
24 | | // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, |
25 | | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
26 | | // DEALINGS IN THE SOFTWARE. |
27 | | |
28 | | #include "dtoa.h" |
29 | | #include <stdint.h> |
30 | | #include <stdbool.h> |
31 | | #include <string.h> |
32 | | |
33 | 0 | #define mantissa_bits 52 |
34 | 0 | #define exponent_bits 11 |
35 | 0 | #define fracmask 0x000FFFFFFFFFFFFFU |
36 | 0 | #define expmask 0x7FF0000000000000U |
37 | 0 | #define hiddenbit 0x0010000000000000U |
38 | | #define signmask 0x8000000000000000U |
39 | 0 | #define expbias (1023 + 52) |
40 | | |
41 | 0 | #define absv(n) ((n) < 0 ? -(n) : (n)) |
42 | 0 | #define minv(a, b) ((a) < (b) ? (a) : (b)) |
43 | | |
44 | | static uint64_t tens[] = { |
45 | | 10000000000000000000U, 1000000000000000000U, 100000000000000000U, |
46 | | 10000000000000000U, 1000000000000000U, 100000000000000U, |
47 | | 10000000000000U, 1000000000000U, 100000000000U, |
48 | | 10000000000U, 1000000000U, 100000000U, |
49 | | 10000000U, 1000000U, 100000U, |
50 | | 10000U, 1000U, 100U, |
51 | | 10U, 1U |
52 | | }; |
53 | | |
54 | 0 | #define npowers 87 |
55 | 0 | #define steppowers 8 |
56 | 0 | #define firstpower -348 /* 10 ^ -348 */ |
57 | 0 | #define expmax -32 |
58 | 0 | #define expmin -60 |
59 | | |
60 | | typedef struct Fp { |
61 | | uint64_t frac; |
62 | | int exp; |
63 | | } Fp; |
64 | | |
65 | | static Fp powers_ten[] = { |
66 | | { 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 }, |
67 | | { 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 }, |
68 | | { 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 }, |
69 | | { 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 }, |
70 | | { 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 }, |
71 | | { 15227053142812498563U, -954 }, { 11345038669416679861U, -927 }, |
72 | | { 16905424996341287883U, -901 }, { 12595523146049147757U, -874 }, |
73 | | { 9384396036005875287U, -847 }, { 13983839803942852151U, -821 }, |
74 | | { 10418772551374772303U, -794 }, { 15525180923007089351U, -768 }, |
75 | | { 11567161174868858868U, -741 }, { 17236413322193710309U, -715 }, |
76 | | { 12842128665889583758U, -688 }, { 9568131466127621947U, -661 }, |
77 | | { 14257626930069360058U, -635 }, { 10622759856335341974U, -608 }, |
78 | | { 15829145694278690180U, -582 }, { 11793632577567316726U, -555 }, |
79 | | { 17573882009934360870U, -529 }, { 13093562431584567480U, -502 }, |
80 | | { 9755464219737475723U, -475 }, { 14536774485912137811U, -449 }, |
81 | | { 10830740992659433045U, -422 }, { 16139061738043178685U, -396 }, |
82 | | { 12024538023802026127U, -369 }, { 17917957937422433684U, -343 }, |
83 | | { 13349918974505688015U, -316 }, { 9946464728195732843U, -289 }, |
84 | | { 14821387422376473014U, -263 }, { 11042794154864902060U, -236 }, |
85 | | { 16455045573212060422U, -210 }, { 12259964326927110867U, -183 }, |
86 | | { 18268770466636286478U, -157 }, { 13611294676837538539U, -130 }, |
87 | | { 10141204801825835212U, -103 }, { 15111572745182864684U, -77 }, |
88 | | { 11258999068426240000U, -50 }, { 16777216000000000000U, -24 }, |
89 | | { 12500000000000000000U, 3 }, { 9313225746154785156U, 30 }, |
90 | | { 13877787807814456755U, 56 }, { 10339757656912845936U, 83 }, |
91 | | { 15407439555097886824U, 109 }, { 11479437019748901445U, 136 }, |
92 | | { 17105694144590052135U, 162 }, { 12744735289059618216U, 189 }, |
93 | | { 9495567745759798747U, 216 }, { 14149498560666738074U, 242 }, |
94 | | { 10542197943230523224U, 269 }, { 15709099088952724970U, 295 }, |
95 | | { 11704190886730495818U, 322 }, { 17440603504673385349U, 348 }, |
96 | | { 12994262207056124023U, 375 }, { 9681479787123295682U, 402 }, |
97 | | { 14426529090290212157U, 428 }, { 10748601772107342003U, 455 }, |
98 | | { 16016664761464807395U, 481 }, { 11933345169920330789U, 508 }, |
99 | | { 17782069995880619868U, 534 }, { 13248674568444952270U, 561 }, |
100 | | { 9871031767461413346U, 588 }, { 14708983551653345445U, 614 }, |
101 | | { 10959046745042015199U, 641 }, { 16330252207878254650U, 667 }, |
102 | | { 12166986024289022870U, 694 }, { 18130221999122236476U, 720 }, |
103 | | { 13508068024458167312U, 747 }, { 10064294952495520794U, 774 }, |
104 | | { 14996968138956309548U, 800 }, { 11173611982879273257U, 827 }, |
105 | | { 16649979327439178909U, 853 }, { 12405201291620119593U, 880 }, |
106 | | { 9242595204427927429U, 907 }, { 13772540099066387757U, 933 }, |
107 | | { 10261342003245940623U, 960 }, { 15290591125556738113U, 986 }, |
108 | | { 11392378155556871081U, 1013 }, { 16975966327722178521U, 1039 }, |
109 | | { 12648080533535911531U, 1066 } |
110 | | }; |
111 | | |
112 | | static Fp |
113 | 0 | find_cachedpow10(int exp, int* k) { |
114 | 0 | const double one_log_ten = 0.30102999566398114; |
115 | 0 | int approx = (int)(-(exp + npowers) * one_log_ten); |
116 | 0 | int idx = (approx - firstpower) / steppowers; |
117 | 0 | while(1) { |
118 | 0 | int current = exp + powers_ten[idx].exp + 64; |
119 | 0 | if(current < expmin) { |
120 | 0 | idx++; |
121 | 0 | continue; |
122 | 0 | } |
123 | 0 | if(current > expmax) { |
124 | 0 | idx--; |
125 | 0 | continue; |
126 | 0 | } |
127 | 0 | *k = (firstpower + idx * steppowers); |
128 | 0 | return powers_ten[idx]; |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | 0 | static Fp build_fp(uint64_t bits) { |
133 | 0 | Fp fp; |
134 | 0 | fp.frac = bits & fracmask; |
135 | 0 | fp.exp = (bits & expmask) >> 52; |
136 | 0 | if(fp.exp) { |
137 | 0 | fp.frac += hiddenbit; |
138 | 0 | fp.exp -= expbias; |
139 | 0 | } else { |
140 | 0 | fp.exp = -expbias + 1; |
141 | 0 | } |
142 | 0 | return fp; |
143 | 0 | } |
144 | | |
145 | 0 | static void normalize(Fp* fp) { |
146 | 0 | while((fp->frac & hiddenbit) == 0) { |
147 | 0 | fp->frac <<= 1; |
148 | 0 | fp->exp--; |
149 | 0 | } |
150 | 0 | int shift = 64 - 52 - 1; |
151 | 0 | fp->frac <<= shift; |
152 | 0 | fp->exp -= shift; |
153 | 0 | } |
154 | | |
155 | 0 | static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) { |
156 | 0 | upper->frac = (fp->frac << 1) + 1; |
157 | 0 | upper->exp = fp->exp - 1; |
158 | 0 | while ((upper->frac & (hiddenbit << 1)) == 0) { |
159 | 0 | upper->frac <<= 1; |
160 | 0 | upper->exp--; |
161 | 0 | } |
162 | |
|
163 | 0 | int u_shift = 64 - 52 - 2; |
164 | 0 | upper->frac <<= u_shift; |
165 | 0 | upper->exp = upper->exp - u_shift; |
166 | |
|
167 | 0 | int l_shift = fp->frac == hiddenbit ? 2 : 1; |
168 | 0 | lower->frac = (fp->frac << l_shift) - 1; |
169 | 0 | lower->exp = fp->exp - l_shift; |
170 | 0 | lower->frac <<= lower->exp - upper->exp; |
171 | 0 | lower->exp = upper->exp; |
172 | 0 | } |
173 | | |
174 | 0 | static Fp multiply(Fp* a, Fp* b) { |
175 | 0 | const uint64_t lomask = 0x00000000FFFFFFFF; |
176 | 0 | uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask); |
177 | 0 | uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32); |
178 | 0 | uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask); |
179 | 0 | uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32); |
180 | 0 | uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32); |
181 | | /* round up */ |
182 | 0 | tmp += 1U << 31; |
183 | 0 | Fp fp; |
184 | 0 | fp.frac = ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32); |
185 | 0 | fp.exp = a->exp + b->exp + 64; |
186 | 0 | return fp; |
187 | 0 | } |
188 | | |
189 | | static void round_digit(char* digits, unsigned ndigits, uint64_t delta, |
190 | 0 | uint64_t rem, uint64_t kappa, uint64_t frac) { |
191 | 0 | while(rem < frac && delta - rem >= kappa && |
192 | 0 | (rem + kappa < frac || frac - rem > rem + kappa - frac)) { |
193 | 0 | digits[ndigits - 1]--; |
194 | 0 | rem += kappa; |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | 0 | static unsigned generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) { |
199 | 0 | uint64_t wfrac = upper->frac - fp->frac; |
200 | 0 | uint64_t delta = upper->frac - lower->frac; |
201 | |
|
202 | 0 | Fp one; |
203 | 0 | one.frac = 1ULL << -upper->exp; |
204 | 0 | one.exp = upper->exp; |
205 | |
|
206 | 0 | uint64_t part1 = upper->frac >> -one.exp; |
207 | 0 | uint64_t part2 = upper->frac & (one.frac - 1); |
208 | |
|
209 | 0 | unsigned idx = 0; |
210 | 0 | int kappa = 10; |
211 | 0 | uint64_t* divp; |
212 | | |
213 | | /* 1000000000 */ |
214 | 0 | for(divp = tens + 10; kappa > 0; divp++) { |
215 | 0 | uint64_t div = *divp; |
216 | 0 | uint64_t digit = part1 / div; |
217 | 0 | if(digit || idx) { |
218 | 0 | digits[idx++] = (char)(digit + '0'); |
219 | 0 | } |
220 | |
|
221 | 0 | part1 -= digit * div; |
222 | 0 | kappa--; |
223 | |
|
224 | 0 | uint64_t tmp = (part1 <<-one.exp) + part2; |
225 | 0 | if(tmp <= delta) { |
226 | 0 | *K += kappa; |
227 | 0 | round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac); |
228 | 0 | return idx; |
229 | 0 | } |
230 | 0 | } |
231 | | |
232 | | /* 10 */ |
233 | 0 | uint64_t* unit = tens + 18; |
234 | 0 | while(true) { |
235 | 0 | part2 *= 10; |
236 | 0 | delta *= 10; |
237 | 0 | kappa--; |
238 | |
|
239 | 0 | uint64_t digit = part2 >> -one.exp; |
240 | 0 | if(digit || idx) { |
241 | 0 | digits[idx++] = (char)(digit + '0'); |
242 | 0 | } |
243 | |
|
244 | 0 | part2 &= one.frac - 1; |
245 | 0 | if(part2 < delta) { |
246 | 0 | *K += kappa; |
247 | 0 | round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit); |
248 | 0 | break; |
249 | 0 | } |
250 | 0 | unit--; |
251 | 0 | } |
252 | 0 | return idx; |
253 | 0 | } |
254 | | |
255 | 0 | static unsigned grisu2(uint64_t bits, char* digits, int* K) { |
256 | 0 | Fp w = build_fp(bits); |
257 | 0 | Fp lower, upper; |
258 | 0 | get_normalized_boundaries(&w, &lower, &upper); |
259 | 0 | normalize(&w); |
260 | 0 | int k; |
261 | 0 | Fp cp = find_cachedpow10(upper.exp, &k); |
262 | 0 | w = multiply(&w, &cp); |
263 | 0 | upper = multiply(&upper, &cp); |
264 | 0 | lower = multiply(&lower, &cp); |
265 | 0 | lower.frac++; |
266 | 0 | upper.frac--; |
267 | 0 | *K = -k; |
268 | 0 | return generate_digits(&w, &upper, &lower, digits, K); |
269 | 0 | } |
270 | | |
271 | | static unsigned |
272 | 0 | emit_digits(char* digits, unsigned ndigits, char* dest, int K, bool neg) { |
273 | 0 | int exp = absv(K + (int)ndigits - 1); |
274 | | |
275 | | /* write plain integer */ |
276 | 0 | if(K >= 0 && (exp < (int)ndigits + 7)) { |
277 | 0 | memcpy(dest, digits, ndigits); |
278 | 0 | memset(dest + ndigits, '0', (unsigned)K); |
279 | 0 | memcpy(dest + ndigits + (unsigned)K, ".0", 2); /* always append .0 for naked integers */ |
280 | 0 | return (unsigned)(ndigits + (unsigned)K + 2); |
281 | 0 | } |
282 | | |
283 | | /* write decimal w/o scientific notation */ |
284 | 0 | if(K < 0 && (K > -7 || exp < 4)) { |
285 | 0 | int offset = (int)ndigits - absv(K); |
286 | 0 | if(offset <= 0) { |
287 | | /* fp < 1.0 -> write leading zero */ |
288 | 0 | offset = -offset; |
289 | 0 | dest[0] = '0'; |
290 | 0 | dest[1] = '.'; |
291 | 0 | memset(dest + 2, '0', (size_t)offset); |
292 | 0 | memcpy(dest + offset + 2, digits, ndigits); |
293 | 0 | return ndigits + 2 + (unsigned)offset; |
294 | 0 | } else { |
295 | | /* fp > 1.0 */ |
296 | 0 | memcpy(dest, digits, (size_t)offset); |
297 | 0 | dest[offset] = '.'; |
298 | 0 | memcpy(dest + offset + 1, digits + offset, ndigits - (unsigned)offset); |
299 | 0 | return ndigits + 1; |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | | /* write decimal w/ scientific notation */ |
304 | 0 | ndigits = minv(ndigits, (unsigned)(18 - neg)); |
305 | 0 | unsigned idx = 0; |
306 | 0 | dest[idx++] = digits[0]; |
307 | 0 | if(ndigits > 1) { |
308 | 0 | dest[idx++] = '.'; |
309 | 0 | memcpy(dest + idx, digits + 1, ndigits - 1); |
310 | 0 | idx += ndigits - 1; |
311 | 0 | } |
312 | |
|
313 | 0 | dest[idx++] = 'e'; |
314 | |
|
315 | 0 | char sign = K + (int)ndigits - 1 < 0 ? '-' : '+'; |
316 | 0 | dest[idx++] = sign; |
317 | |
|
318 | 0 | int cent = 0; |
319 | 0 | if(exp > 99) { |
320 | 0 | cent = exp / 100; |
321 | 0 | dest[idx++] = (char)(cent + '0'); |
322 | 0 | exp -= cent * 100; |
323 | 0 | } |
324 | 0 | if(exp > 9) { |
325 | 0 | int dec = exp / 10; |
326 | 0 | dest[idx++] = (char)(dec + '0'); |
327 | 0 | exp -= dec * 10; |
328 | |
|
329 | 0 | } else if(cent) { |
330 | 0 | dest[idx++] = '0'; |
331 | 0 | } |
332 | 0 | dest[idx++] = (char)(exp % 10 + '0'); |
333 | 0 | return idx; |
334 | 0 | } |
335 | | |
336 | 0 | unsigned dtoa(double d, char* buffer) { |
337 | 0 | uint64_t bits = 0; |
338 | 0 | memcpy(&bits, &d, sizeof(double)); |
339 | |
|
340 | 0 | uint64_t mantissa = bits & ((1ull << mantissa_bits) - 1); |
341 | 0 | uint32_t exponent = (uint32_t) |
342 | 0 | ((bits >> mantissa_bits) & ((1u << exponent_bits) - 1)); |
343 | |
|
344 | 0 | if(exponent == 0 && mantissa == 0) { |
345 | 0 | memcpy(buffer, "0.0", 3); |
346 | 0 | return 3; |
347 | 0 | } |
348 | | |
349 | 0 | bool sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0; |
350 | 0 | unsigned pos = 0; |
351 | 0 | if(sign) { |
352 | 0 | buffer[0] = '-'; |
353 | 0 | pos++; |
354 | 0 | buffer++; |
355 | 0 | } |
356 | |
|
357 | 0 | if(exponent == ((1u << exponent_bits) - 1u)) { |
358 | 0 | if(mantissa != 0) { |
359 | 0 | memcpy(buffer, "nan", 3); |
360 | 0 | return 3; |
361 | 0 | } else { |
362 | 0 | memcpy(&buffer[pos], "inf", 3); |
363 | 0 | return pos + 3; |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | 0 | int K = 0; |
368 | 0 | char digits[18]; |
369 | 0 | memset(digits, 0, 18); |
370 | 0 | unsigned ndigits = grisu2(bits, digits, &K); |
371 | 0 | return pos + emit_digits(digits, ndigits, buffer, K, sign); |
372 | 0 | } |