/src/boost/libs/charconv/src/to_chars.cpp
Line | Count | Source |
1 | | // Copyright 2020-2023 Junekey Jeon |
2 | | // Copyright 2022 Peter Dimov |
3 | | // Copyright 2023 Matt Borland |
4 | | // Distributed under the Boost Software License, Version 1.0. |
5 | | // https://www.boost.org/LICENSE_1_0.txt |
6 | | |
7 | | #include "float128_impl.hpp" |
8 | | #include "to_chars_float_impl.hpp" |
9 | | #include <boost/charconv/to_chars.hpp> |
10 | | #include <boost/charconv/chars_format.hpp> |
11 | | #include <limits> |
12 | | #include <cstring> |
13 | | #include <cstdio> |
14 | | #include <cstdint> |
15 | | #include <cmath> |
16 | | |
17 | | namespace boost { namespace charconv { namespace detail { namespace to_chars_detail { |
18 | | |
19 | | #ifdef BOOST_MSVC |
20 | | # pragma warning(push) |
21 | | # pragma warning(disable: 4127) // Conditional expression is constant (e.g. BOOST_IF_CONSTEXPR statements) |
22 | | #endif |
23 | | |
24 | | // These "//"'s are to prevent clang-format to ruin this nice alignment. |
25 | | // Thanks to reddit user u/mcmcc: |
26 | | // https://www.reddit.com/r/cpp/comments/so3wx9/dragonbox_110_is_released_a_fast_floattostring/hw8z26r/?context=3 |
27 | | static constexpr char radix_100_head_table[] = { |
28 | | '0', '.', '1', '.', '2', '.', '3', '.', '4', '.', // |
29 | | '5', '.', '6', '.', '7', '.', '8', '.', '9', '.', // |
30 | | '1', '.', '1', '.', '1', '.', '1', '.', '1', '.', // |
31 | | '1', '.', '1', '.', '1', '.', '1', '.', '1', '.', // |
32 | | '2', '.', '2', '.', '2', '.', '2', '.', '2', '.', // |
33 | | '2', '.', '2', '.', '2', '.', '2', '.', '2', '.', // |
34 | | '3', '.', '3', '.', '3', '.', '3', '.', '3', '.', // |
35 | | '3', '.', '3', '.', '3', '.', '3', '.', '3', '.', // |
36 | | '4', '.', '4', '.', '4', '.', '4', '.', '4', '.', // |
37 | | '4', '.', '4', '.', '4', '.', '4', '.', '4', '.', // |
38 | | '5', '.', '5', '.', '5', '.', '5', '.', '5', '.', // |
39 | | '5', '.', '5', '.', '5', '.', '5', '.', '5', '.', // |
40 | | '6', '.', '6', '.', '6', '.', '6', '.', '6', '.', // |
41 | | '6', '.', '6', '.', '6', '.', '6', '.', '6', '.', // |
42 | | '7', '.', '7', '.', '7', '.', '7', '.', '7', '.', // |
43 | | '7', '.', '7', '.', '7', '.', '7', '.', '7', '.', // |
44 | | '8', '.', '8', '.', '8', '.', '8', '.', '8', '.', // |
45 | | '8', '.', '8', '.', '8', '.', '8', '.', '8', '.', // |
46 | | '9', '.', '9', '.', '9', '.', '9', '.', '9', '.', // |
47 | | '9', '.', '9', '.', '9', '.', '9', '.', '9', '.' // |
48 | | }; |
49 | | |
50 | | static void print_1_digit(std::uint32_t n, char* buffer) noexcept |
51 | 3.95k | { |
52 | 3.95k | *buffer = char('0' + n); |
53 | 3.95k | } |
54 | | |
55 | | static void print_2_digits(std::uint32_t n, char* buffer) noexcept |
56 | 35.9M | { |
57 | 35.9M | std::memcpy(buffer, radix_table + n * 2, 2); |
58 | 35.9M | } |
59 | | |
60 | | // These digit generation routines are inspired by James Anhalt's itoa algorithm: |
61 | | // https://github.com/jeaiii/itoa |
62 | | // The main idea is for given n, find y such that floor(10^k * y / 2^32) = n holds, |
63 | | // where k is an appropriate integer depending on the length of n. |
64 | | // For example, if n = 1234567, we set k = 6. In this case, we have |
65 | | // floor(y / 2^32) = 1, |
66 | | // floor(10^2 * ((10^0 * y) mod 2^32) / 2^32) = 23, |
67 | | // floor(10^2 * ((10^2 * y) mod 2^32) / 2^32) = 45, and |
68 | | // floor(10^2 * ((10^4 * y) mod 2^32) / 2^32) = 67. |
69 | | // See https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ for more explanation. |
70 | | |
71 | | BOOST_FORCEINLINE static void print_9_digits(std::uint32_t s32, int& exponent, |
72 | | char*& buffer) noexcept |
73 | 348k | { |
74 | | // -- IEEE-754 binary32 |
75 | | // Since we do not cut trailing zeros in advance, s32 must be of 6~9 digits |
76 | | // unless the original input was subnormal. |
77 | | // In particular, when it is of 9 digits it shouldn't have any trailing zeros. |
78 | | // -- IEEE-754 binary64 |
79 | | // In this case, s32 must be of 7~9 digits unless the input is subnormal, |
80 | | // and it shouldn't have any trailing zeros if it is of 9 digits. |
81 | 348k | if (s32 >= 100000000) |
82 | 0 | { |
83 | | // 9 digits. |
84 | | // 1441151882 = ceil(2^57 / 1'0000'0000) + 1 |
85 | 0 | auto prod = s32 * std::uint64_t(1441151882); |
86 | 0 | prod >>= 25; |
87 | 0 | std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2, 2); |
88 | |
|
89 | 0 | prod = std::uint32_t(prod) * std::uint64_t(100); |
90 | 0 | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
91 | 0 | prod = std::uint32_t(prod) * std::uint64_t(100); |
92 | 0 | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
93 | 0 | prod = std::uint32_t(prod) * std::uint64_t(100); |
94 | 0 | print_2_digits(std::uint32_t(prod >> 32), buffer + 6); |
95 | 0 | prod = std::uint32_t(prod) * std::uint64_t(100); |
96 | 0 | print_2_digits(std::uint32_t(prod >> 32), buffer + 8); |
97 | |
|
98 | 0 | exponent += 8; |
99 | 0 | buffer += 10; |
100 | 0 | } |
101 | 348k | else if (s32 >= 1000000) |
102 | 5.90k | { |
103 | | // 7 or 8 digits. |
104 | | // 281474978 = ceil(2^48 / 100'0000) + 1 |
105 | 5.90k | auto prod = s32 * std::uint64_t(281474978); |
106 | 5.90k | prod >>= 16; |
107 | 5.90k | const auto head_digits = std::uint32_t(prod >> 32); |
108 | | // If s32 is of 8 digits, increase the exponent by 7. |
109 | | // Otherwise, increase it by 6. |
110 | 5.90k | exponent += static_cast<int>(6 + unsigned(head_digits >= 10)); |
111 | | |
112 | | // Write the first digit and the decimal point. |
113 | 5.90k | std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2); |
114 | | // This third character may be overwritten later, but we don't care. |
115 | 5.90k | buffer[2] = radix_table[head_digits * 2 + 1]; |
116 | | |
117 | | // Remaining 6 digits are all zero? |
118 | 5.90k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 1000000)) |
119 | 0 | { |
120 | | // The number of characters actually need to be written is: |
121 | | // 1, if only the first digit is nonzero, which means that either s32 is of 7 |
122 | | // digits or it is of 8 digits but the second digit is zero, or |
123 | | // 3, otherwise. |
124 | | // Note that buffer[2] is never '0' if s32 is of 7 digits, because the input is |
125 | | // never zero. |
126 | 0 | buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2); |
127 | 0 | } |
128 | 5.90k | else |
129 | 5.90k | { |
130 | | // At least one of the remaining 6 digits are nonzero. |
131 | | // After this adjustment, now the first destination becomes buffer + 2. |
132 | 5.90k | buffer += unsigned(head_digits >= 10); |
133 | | |
134 | | // Obtain the next two digits. |
135 | 5.90k | prod = std::uint32_t(prod) * std::uint64_t(100); |
136 | 5.90k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
137 | | |
138 | | // Remaining 4 digits are all zero? |
139 | 5.90k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000)) |
140 | 0 | { |
141 | 0 | buffer += (3 + unsigned(buffer[3] > '0')); |
142 | 0 | } |
143 | 5.90k | else |
144 | 5.90k | { |
145 | | // At least one of the remaining 4 digits are nonzero. |
146 | | |
147 | | // Obtain the next two digits. |
148 | 5.90k | prod = std::uint32_t(prod) * std::uint64_t(100); |
149 | 5.90k | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
150 | | |
151 | | // Remaining 2 digits are all zero? |
152 | 5.90k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100)) |
153 | 0 | { |
154 | 0 | buffer += (5 + unsigned(buffer[5] > '0')); |
155 | 0 | } |
156 | 5.90k | else |
157 | 5.90k | { |
158 | | // Obtain the last two digits. |
159 | 5.90k | prod = std::uint32_t(prod) * std::uint64_t(100); |
160 | 5.90k | print_2_digits(std::uint32_t(prod >> 32), buffer + 6); |
161 | | |
162 | 5.90k | buffer += (7 + unsigned(buffer[7] > '0')); |
163 | 5.90k | } |
164 | 5.90k | } |
165 | 5.90k | } |
166 | 5.90k | } |
167 | 342k | else if (s32 >= 10000) |
168 | 5.80k | { |
169 | | // 5 or 6 digits. |
170 | | // 429497 = ceil(2^32 / 1'0000) |
171 | 5.80k | auto prod = s32 * std::uint64_t(429497); |
172 | 5.80k | const auto head_digits = std::uint32_t(prod >> 32); |
173 | | |
174 | | // If s32 is of 6 digits, increase the exponent by 5. |
175 | | // Otherwise, increase it by 4. |
176 | 5.80k | exponent += static_cast<int>(4 + unsigned(head_digits >= 10)); |
177 | | |
178 | | // Write the first digit and the decimal point. |
179 | 5.80k | std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2); |
180 | | // This third character may be overwritten later but we don't care. |
181 | 5.80k | buffer[2] = radix_table[head_digits * 2 + 1]; |
182 | | |
183 | | // Remaining 4 digits are all zero? |
184 | 5.80k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000)) |
185 | 0 | { |
186 | | // The number of characters actually written is 1 or 3, similarly to the case of |
187 | | // 7 or 8 digits. |
188 | 0 | buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2); |
189 | 0 | } |
190 | 5.80k | else |
191 | 5.80k | { |
192 | | // At least one of the remaining 4 digits are nonzero. |
193 | | // After this adjustment, now the first destination becomes buffer + 2. |
194 | 5.80k | buffer += unsigned(head_digits >= 10); |
195 | | |
196 | | // Obtain the next two digits. |
197 | 5.80k | prod = std::uint32_t(prod) * std::uint64_t(100); |
198 | 5.80k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
199 | | |
200 | | // Remaining 2 digits are all zero? |
201 | 5.80k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100)) |
202 | 0 | { |
203 | 0 | buffer += (3 + unsigned(buffer[3] > '0')); |
204 | 0 | } |
205 | 5.80k | else |
206 | 5.80k | { |
207 | | // Obtain the last two digits. |
208 | 5.80k | prod = std::uint32_t(prod) * std::uint64_t(100); |
209 | 5.80k | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
210 | | |
211 | 5.80k | buffer += (5 + unsigned(buffer[5] > '0')); |
212 | 5.80k | } |
213 | 5.80k | } |
214 | 5.80k | } |
215 | 337k | else if (s32 >= 100) |
216 | 6.00k | { |
217 | | // 3 or 4 digits. |
218 | | // 42949673 = ceil(2^32 / 100) |
219 | 6.00k | auto prod = s32 * std::uint64_t(42949673); |
220 | 6.00k | const auto head_digits = std::uint32_t(prod >> 32); |
221 | | |
222 | | // If s32 is of 4 digits, increase the exponent by 3. |
223 | | // Otherwise, increase it by 2. |
224 | 6.00k | exponent += (2 + int(head_digits >= 10)); |
225 | | |
226 | | // Write the first digit and the decimal point. |
227 | 6.00k | std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2); |
228 | | // This third character may be overwritten later but we don't care. |
229 | 6.00k | buffer[2] = radix_table[head_digits * 2 + 1]; |
230 | | |
231 | | // Remaining 2 digits are all zero? |
232 | 6.00k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100)) |
233 | 0 | { |
234 | | // The number of characters actually written is 1 or 3, similarly to the case of |
235 | | // 7 or 8 digits. |
236 | 0 | buffer += (1 + (unsigned(head_digits >= 10) & unsigned(buffer[2] > '0')) * 2); |
237 | 0 | } |
238 | 6.00k | else |
239 | 6.00k | { |
240 | | // At least one of the remaining 2 digits are nonzero. |
241 | | // After this adjustment, now the first destination becomes buffer + 2. |
242 | 6.00k | buffer += unsigned(head_digits >= 10); |
243 | | |
244 | | // Obtain the last two digits. |
245 | 6.00k | prod = std::uint32_t(prod) * std::uint64_t(100); |
246 | 6.00k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
247 | | |
248 | 6.00k | buffer += (3 + unsigned(buffer[3] > '0')); |
249 | 6.00k | } |
250 | 6.00k | } |
251 | 331k | else |
252 | 331k | { |
253 | | // 1 or 2 digits. |
254 | | // If s32 is of 2 digits, increase the exponent by 1. |
255 | 331k | exponent += int(s32 >= 10); |
256 | | |
257 | | // Write the first digit and the decimal point. |
258 | 331k | std::memcpy(buffer, radix_100_head_table + s32 * 2, 2); |
259 | | // This third character may be overwritten later but we don't care. |
260 | 331k | buffer[2] = radix_table[s32 * 2 + 1]; |
261 | | |
262 | | // The number of characters actually written is 1 or 3, similarly to the case of |
263 | | // 7 or 8 digits. |
264 | 331k | buffer += (1 + (unsigned(s32 >= 10) & unsigned(buffer[2] > '0')) * 2); |
265 | 331k | } |
266 | 348k | } |
267 | | |
268 | | template <> |
269 | | to_chars_result dragon_box_print_chars<float, dragonbox_float_traits<float>>(std::uint32_t s32, int exponent, char* first, char* last, chars_format fmt) noexcept |
270 | 0 | { |
271 | 0 | auto buffer = first; |
272 | |
|
273 | 0 | const std::ptrdiff_t total_length = total_buffer_length(9, exponent, false); |
274 | 0 | if (total_length > (last - first)) |
275 | 0 | { |
276 | 0 | return {last, std::errc::value_too_large}; |
277 | 0 | } |
278 | | |
279 | | // Print significand. |
280 | 0 | print_9_digits(s32, exponent, buffer); |
281 | | |
282 | | // Print exponent and return |
283 | 0 | if (exponent < 0) |
284 | 0 | { |
285 | 0 | std::memcpy(buffer, "e-", 2); |
286 | 0 | buffer += 2; |
287 | 0 | exponent = -exponent; |
288 | 0 | } |
289 | 0 | else if (exponent == 0) |
290 | 0 | { |
291 | 0 | if (fmt == chars_format::scientific) |
292 | 0 | { |
293 | 0 | std::memcpy(buffer, "e+00", 4); |
294 | 0 | buffer += 4; |
295 | 0 | } |
296 | |
|
297 | 0 | return {buffer, std::errc()}; |
298 | 0 | } |
299 | 0 | else |
300 | 0 | { |
301 | 0 | std::memcpy(buffer, "e+", 2); |
302 | 0 | buffer += 2; |
303 | 0 | } |
304 | | |
305 | 0 | print_2_digits(std::uint32_t(exponent), buffer); |
306 | 0 | buffer += 2; |
307 | |
|
308 | 0 | return {buffer, std::errc()}; |
309 | 0 | } |
310 | | |
311 | | template <> |
312 | | to_chars_result dragon_box_print_chars<double, dragonbox_float_traits<double>>(const std::uint64_t significand, int exponent, char* first, char* last, chars_format fmt) noexcept |
313 | 4.30M | { |
314 | 4.30M | auto buffer = first; |
315 | | |
316 | | // Print significand by decomposing it into a 9-digit block and a 8-digit block. |
317 | 4.30M | std::uint32_t first_block; |
318 | 4.30M | std::uint32_t second_block {}; |
319 | 4.30M | bool no_second_block; |
320 | | |
321 | 4.30M | if (significand >= 100000000) |
322 | 3.95M | { |
323 | 3.95M | first_block = std::uint32_t(significand / 100000000); |
324 | 3.95M | second_block = std::uint32_t(significand) - first_block * 100000000; |
325 | 3.95M | exponent += 8; |
326 | 3.95M | no_second_block = (second_block == 0); |
327 | 3.95M | } |
328 | 348k | else |
329 | 348k | { |
330 | 348k | first_block = std::uint32_t(significand); |
331 | 348k | no_second_block = true; |
332 | 348k | } |
333 | | |
334 | 4.30M | const std::ptrdiff_t total_length = total_buffer_length(no_second_block ? 9 : 17, exponent, false);; |
335 | 4.30M | if (total_length > (last - first)) |
336 | 0 | { |
337 | 0 | return {last, std::errc::value_too_large}; |
338 | 0 | } |
339 | | |
340 | 4.30M | if (no_second_block) |
341 | 348k | { |
342 | 348k | print_9_digits(first_block, exponent, buffer); |
343 | 348k | } |
344 | 3.95M | else |
345 | 3.95M | { |
346 | | // We proceed similarly to print_9_digits(), but since we do not need to remove |
347 | | // trailing zeros, the procedure is a bit simpler. |
348 | 3.95M | if (first_block >= 100000000) |
349 | 3.89M | { |
350 | | // The input is of 17 digits, thus there should be no trailing zero at all. |
351 | | // The first block is of 9 digits. |
352 | | // 1441151882 = ceil(2^57 / 1'0000'0000) + 1 |
353 | 3.89M | auto prod = first_block * std::uint64_t(1441151882); |
354 | 3.89M | prod >>= 25; |
355 | 3.89M | std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2, 2); |
356 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
357 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
358 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
359 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
360 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
361 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 6); |
362 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
363 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 8); |
364 | | |
365 | | // The second block is of 8 digits. |
366 | | // 281474978 = ceil(2^48 / 100'0000) + 1 |
367 | 3.89M | prod = second_block * std::uint64_t(281474978); |
368 | 3.89M | prod >>= 16; |
369 | 3.89M | prod += 1; |
370 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 10); |
371 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
372 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 12); |
373 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
374 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 14); |
375 | 3.89M | prod = std::uint32_t(prod) * std::uint64_t(100); |
376 | 3.89M | print_2_digits(std::uint32_t(prod >> 32), buffer + 16); |
377 | | |
378 | 3.89M | exponent += 8; |
379 | 3.89M | buffer += 18; |
380 | 3.89M | } |
381 | 59.2k | else |
382 | 59.2k | { |
383 | 59.2k | if (first_block >= 1000000) |
384 | 49.0k | { |
385 | | // 7 or 8 digits. |
386 | | // 281474978 = ceil(2^48 / 100'0000) + 1 |
387 | 49.0k | auto prod = first_block * std::uint64_t(281474978); |
388 | 49.0k | prod >>= 16; |
389 | 49.0k | const auto head_digits = std::uint32_t(prod >> 32); |
390 | | |
391 | 49.0k | std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2); |
392 | 49.0k | buffer[2] = radix_table[head_digits * 2 + 1]; |
393 | | |
394 | 49.0k | exponent += static_cast<int>(6 + unsigned(head_digits >= 10)); |
395 | 49.0k | buffer += unsigned(head_digits >= 10); |
396 | | |
397 | | // Print remaining 6 digits. |
398 | 49.0k | prod = std::uint32_t(prod) * std::uint64_t(100); |
399 | 49.0k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
400 | 49.0k | prod = std::uint32_t(prod) * std::uint64_t(100); |
401 | 49.0k | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
402 | 49.0k | prod = std::uint32_t(prod) * std::uint64_t(100); |
403 | 49.0k | print_2_digits(std::uint32_t(prod >> 32), buffer + 6); |
404 | | |
405 | 49.0k | buffer += 8; |
406 | 49.0k | } |
407 | 10.1k | else if (first_block >= 10000) |
408 | 5.69k | { |
409 | | // 5 or 6 digits. |
410 | | // 429497 = ceil(2^32 / 1'0000) |
411 | 5.69k | auto prod = first_block * std::uint64_t(429497); |
412 | 5.69k | const auto head_digits = std::uint32_t(prod >> 32); |
413 | | |
414 | 5.69k | std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2); |
415 | 5.69k | buffer[2] = radix_table[head_digits * 2 + 1]; |
416 | | |
417 | 5.69k | exponent += static_cast<int>(4 + unsigned(head_digits >= 10)); |
418 | 5.69k | buffer += unsigned(head_digits >= 10); |
419 | | |
420 | | // Print remaining 4 digits. |
421 | 5.69k | prod = std::uint32_t(prod) * std::uint64_t(100); |
422 | 5.69k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
423 | 5.69k | prod = std::uint32_t(prod) * std::uint64_t(100); |
424 | 5.69k | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
425 | | |
426 | 5.69k | buffer += 6; |
427 | 5.69k | } |
428 | 4.47k | else if (first_block >= 100) |
429 | 3.31k | { |
430 | | // 3 or 4 digits. |
431 | | // 42949673 = ceil(2^32 / 100) |
432 | 3.31k | auto prod = first_block * std::uint64_t(42949673); |
433 | 3.31k | const auto head_digits = std::uint32_t(prod >> 32); |
434 | | |
435 | 3.31k | std::memcpy(buffer, radix_100_head_table + head_digits * 2, 2); |
436 | 3.31k | buffer[2] = radix_table[head_digits * 2 + 1]; |
437 | | |
438 | 3.31k | exponent += static_cast<int>(2 + unsigned(head_digits >= 10)); |
439 | 3.31k | buffer += unsigned(head_digits >= 10); |
440 | | |
441 | | // Print remaining 2 digits. |
442 | 3.31k | prod = std::uint32_t(prod) * std::uint64_t(100); |
443 | 3.31k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
444 | | |
445 | 3.31k | buffer += 4; |
446 | 3.31k | } |
447 | 1.16k | else |
448 | 1.16k | { |
449 | | // 1 or 2 digits. |
450 | 1.16k | std::memcpy(buffer, radix_100_head_table + first_block * 2, 2); |
451 | 1.16k | buffer[2] = radix_table[first_block * 2 + 1]; |
452 | | |
453 | 1.16k | exponent += (first_block >= 10); |
454 | 1.16k | buffer += (2 + unsigned(first_block >= 10)); |
455 | 1.16k | } |
456 | | |
457 | | // Next, print the second block. |
458 | | // The second block is of 8 digits, but we may have trailing zeros. |
459 | | // 281474978 = ceil(2^48 / 100'0000) + 1 |
460 | 59.2k | auto prod = second_block * std::uint64_t(281474978); |
461 | 59.2k | prod >>= 16; |
462 | 59.2k | prod += 1; |
463 | 59.2k | print_2_digits(std::uint32_t(prod >> 32), buffer); |
464 | | |
465 | | // Remaining 6 digits are all zero? |
466 | 59.2k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 1000000)) |
467 | 0 | { |
468 | 0 | buffer += (1 + unsigned(buffer[1] > '0')); |
469 | 0 | } |
470 | 59.2k | else |
471 | 59.2k | { |
472 | | // Obtain the next two digits. |
473 | 59.2k | prod = std::uint32_t(prod) * std::uint64_t(100); |
474 | 59.2k | print_2_digits(std::uint32_t(prod >> 32), buffer + 2); |
475 | | |
476 | | // Remaining 4 digits are all zero? |
477 | 59.2k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 10000)) |
478 | 0 | { |
479 | 0 | buffer += (3 + unsigned(buffer[3] > '0')); |
480 | 0 | } |
481 | 59.2k | else |
482 | 59.2k | { |
483 | | // Obtain the next two digits. |
484 | 59.2k | prod = std::uint32_t(prod) * std::uint64_t(100); |
485 | 59.2k | print_2_digits(std::uint32_t(prod >> 32), buffer + 4); |
486 | | |
487 | | // Remaining 2 digits are all zero? |
488 | 59.2k | if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100)) |
489 | 0 | { |
490 | 0 | buffer += (5 + unsigned(buffer[5] > '0')); |
491 | 0 | } |
492 | 59.2k | else |
493 | 59.2k | { |
494 | | // Obtain the last two digits. |
495 | 59.2k | prod = std::uint32_t(prod) * std::uint64_t(100); |
496 | 59.2k | print_2_digits(std::uint32_t(prod >> 32), buffer + 6); |
497 | 59.2k | buffer += (7 + unsigned(buffer[7] > '0')); |
498 | 59.2k | } |
499 | 59.2k | } |
500 | 59.2k | } |
501 | 59.2k | } |
502 | 3.95M | } |
503 | 4.30M | if (exponent < 0) |
504 | 61.7k | { |
505 | 61.7k | std::memcpy(buffer, "e-", 2); |
506 | 61.7k | buffer += 2; |
507 | 61.7k | exponent = -exponent; |
508 | 61.7k | } |
509 | 4.24M | else if (exponent == 0) |
510 | 6.14k | { |
511 | 6.14k | if (fmt == chars_format::scientific) |
512 | 6.14k | { |
513 | 6.14k | std::memcpy(buffer, "e+00", 4); |
514 | 6.14k | buffer += 4; |
515 | 6.14k | } |
516 | | |
517 | 6.14k | return {buffer, std::errc()}; |
518 | 6.14k | } |
519 | 4.23M | else |
520 | 4.23M | { |
521 | 4.23M | std::memcpy(buffer, "e+", 2); |
522 | 4.23M | buffer += 2; |
523 | 4.23M | } |
524 | | |
525 | 4.29M | if (exponent >= 100) |
526 | 3.95k | { |
527 | | // d1 = exponent / 10; d2 = exponent % 10; |
528 | | // 6554 = ceil(2^16 / 10) |
529 | 3.95k | auto prod = std::uint32_t(exponent) * std::uint32_t(6554); |
530 | 3.95k | auto d1 = prod >> 16; |
531 | 3.95k | prod = std::uint16_t(prod) * std::uint32_t(5); // * 10 |
532 | 3.95k | auto d2 = prod >> 15; // >> 16 |
533 | 3.95k | print_2_digits(d1, buffer); |
534 | 3.95k | print_1_digit(d2, buffer + 2); |
535 | 3.95k | buffer += 3; |
536 | 3.95k | } |
537 | 4.29M | else |
538 | 4.29M | { |
539 | 4.29M | print_2_digits(static_cast<std::uint32_t>(exponent), buffer); |
540 | 4.29M | buffer += 2; |
541 | 4.29M | } |
542 | | |
543 | 4.29M | return {buffer, std::errc()}; |
544 | 4.30M | } |
545 | | |
546 | | #ifdef BOOST_MSVC |
547 | | # pragma warning(pop) |
548 | | #endif |
549 | | |
550 | | }}}} // Namespaces |
551 | | |
552 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, float value, |
553 | | boost::charconv::chars_format fmt) noexcept |
554 | 0 | { |
555 | 0 | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1); |
556 | 0 | } |
557 | | |
558 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, float value, |
559 | | boost::charconv::chars_format fmt, int precision) noexcept |
560 | 0 | { |
561 | 0 | if (precision < 0) |
562 | 0 | { |
563 | 0 | precision = 6; |
564 | 0 | } |
565 | |
|
566 | 0 | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision); |
567 | 0 | } |
568 | | |
569 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, double value, |
570 | | boost::charconv::chars_format fmt) noexcept |
571 | 4.30M | { |
572 | 4.30M | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1); |
573 | 4.30M | } |
574 | | |
575 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, double value, |
576 | | boost::charconv::chars_format fmt, int precision) noexcept |
577 | 0 | { |
578 | 0 | if (precision < 0) |
579 | 0 | { |
580 | 0 | precision = 6; |
581 | 0 | } |
582 | |
|
583 | 0 | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision); |
584 | 0 | } |
585 | | |
586 | | #if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC) |
587 | | |
588 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value, |
589 | | boost::charconv::chars_format fmt) noexcept |
590 | | { |
591 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, -1); |
592 | | } |
593 | | |
594 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value, |
595 | | boost::charconv::chars_format fmt, int precision) noexcept |
596 | | { |
597 | | if (precision < 0) |
598 | | { |
599 | | precision = 6; |
600 | | } |
601 | | |
602 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision); |
603 | | } |
604 | | |
605 | | #elif !defined(BOOST_CHARCONV_UNSUPPORTED_LONG_DOUBLE) && !defined(BOOST_CHARCONV_LDBL_IS_FLOAT128) |
606 | | |
607 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value, |
608 | | boost::charconv::chars_format fmt) noexcept |
609 | 0 | { |
610 | 0 | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1); |
611 | 0 | } |
612 | | |
613 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value, |
614 | | boost::charconv::chars_format fmt, int precision) noexcept |
615 | 0 | { |
616 | 0 | if (precision < 0) |
617 | 0 | { |
618 | 0 | precision = 6; |
619 | 0 | } |
620 | |
|
621 | 0 | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision); |
622 | 0 | } |
623 | | |
624 | | #endif |
625 | | |
626 | | #ifdef BOOST_CHARCONV_HAS_QUADMATH |
627 | | |
628 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt) noexcept |
629 | | { |
630 | | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1); |
631 | | } |
632 | | |
633 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt, int precision) noexcept |
634 | | { |
635 | | if (precision < 0) |
636 | | { |
637 | | precision = 6; |
638 | | } |
639 | | |
640 | | return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision); |
641 | | } |
642 | | |
643 | | #endif |
644 | | |
645 | | #ifdef BOOST_CHARCONV_HAS_FLOAT16 |
646 | | |
647 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float16_t value, |
648 | | boost::charconv::chars_format fmt) noexcept |
649 | | { |
650 | | return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, -1); |
651 | | } |
652 | | |
653 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float16_t value, |
654 | | boost::charconv::chars_format fmt, int precision) noexcept |
655 | | { |
656 | | if (precision < 0) |
657 | | { |
658 | | precision = 6; |
659 | | return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, precision); |
660 | | } |
661 | | |
662 | | // If the precision is specified it is better to use our exisiting methods for float |
663 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision); |
664 | | } |
665 | | #endif |
666 | | |
667 | | #ifdef BOOST_CHARCONV_HAS_FLOAT32 |
668 | | |
669 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float32_t value, |
670 | | boost::charconv::chars_format fmt) noexcept |
671 | | { |
672 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, -1); |
673 | | } |
674 | | |
675 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float32_t value, |
676 | | boost::charconv::chars_format fmt, int precision) noexcept |
677 | | { |
678 | | static_assert(std::numeric_limits<std::float32_t>::digits == FLT_MANT_DIG && |
679 | | std::numeric_limits<std::float32_t>::min_exponent == FLT_MIN_EXP, |
680 | | "float and std::float32_t are not the same layout like they should be"); |
681 | | |
682 | | if (precision < 0) |
683 | | { |
684 | | precision = 6; |
685 | | } |
686 | | |
687 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision); |
688 | | } |
689 | | #endif |
690 | | |
691 | | #ifdef BOOST_CHARCONV_HAS_FLOAT64 |
692 | | |
693 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float64_t value, |
694 | | boost::charconv::chars_format fmt) noexcept |
695 | | { |
696 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, -1); |
697 | | } |
698 | | |
699 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float64_t value, |
700 | | boost::charconv::chars_format fmt, int precision) noexcept |
701 | | { |
702 | | static_assert(std::numeric_limits<std::float64_t>::digits == DBL_MANT_DIG && |
703 | | std::numeric_limits<std::float64_t>::min_exponent == DBL_MIN_EXP, |
704 | | "double and std::float64_t are not the same layout like they should be"); |
705 | | |
706 | | if (precision < 0) |
707 | | { |
708 | | precision = 6; |
709 | | } |
710 | | |
711 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision); |
712 | | } |
713 | | #endif |
714 | | |
715 | | #if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_QUADMATH) |
716 | | |
717 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float128_t value, |
718 | | boost::charconv::chars_format fmt) noexcept |
719 | | { |
720 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<__float128>(value), fmt, -1); |
721 | | } |
722 | | |
723 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float128_t value, |
724 | | boost::charconv::chars_format fmt, int precision) noexcept |
725 | | { |
726 | | if (precision < 0) |
727 | | { |
728 | | precision = 6; |
729 | | } |
730 | | |
731 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<__float128>(value), fmt, precision); |
732 | | } |
733 | | #endif |
734 | | |
735 | | #ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16 |
736 | | |
737 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::bfloat16_t value, |
738 | | boost::charconv::chars_format fmt) noexcept |
739 | | { |
740 | | return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, -1); |
741 | | } |
742 | | |
743 | | boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::bfloat16_t value, |
744 | | boost::charconv::chars_format fmt, int precision) noexcept |
745 | | { |
746 | | if (precision < 0) |
747 | | { |
748 | | precision = 6; |
749 | | return boost::charconv::detail::to_chars_16_bit_float_impl(first, last, value, fmt, precision); |
750 | | } |
751 | | |
752 | | // If the precision is specified it is better to use our existing methods for float |
753 | | return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision); |
754 | | } |
755 | | #endif |