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

source code of boost/libs/charconv/src/to_chars.cpp