1// Copyright 2022, 2023 Peter Dimov
2// Copyright 2023 Matt Borland
3// Distributed under the Boost Software License, Version 1.0.
4// https://www.boost.org/LICENSE_1_0.txt
5
6#include <boost/charconv.hpp>
7#include <boost/core/lightweight_test.hpp>
8#include <boost/core/detail/splitmix64.hpp>
9#include <system_error>
10#include <string>
11#include <sstream>
12#include <iomanip>
13#include <iostream>
14#include <limits>
15#include <cstdint>
16#include <cfloat>
17#include <cmath>
18
19int const N = 1024;
20
21static boost::detail::splitmix64 rng;
22
23//
24
25char const* fmt_from_type( int )
26{
27 return "%d";
28}
29
30char const* fmt_from_type( unsigned )
31{
32 return "%u";
33}
34
35char const* fmt_from_type( long )
36{
37 return "%ld";
38}
39
40char const* fmt_from_type( unsigned long )
41{
42 return "%lu";
43}
44
45char const* fmt_from_type( long long )
46{
47 return "%lld";
48}
49
50char const* fmt_from_type( unsigned long long )
51{
52 return "%llu";
53}
54
55char const* fmt_from_type( float )
56{
57 return "%.9g";
58}
59
60char const* fmt_from_type_scientific( float )
61{
62 return "%.9e";
63}
64
65char const* fmt_from_type_fixed( float )
66{
67 return "%.9f";
68}
69
70char const* fmt_from_type( double )
71{
72 return "%g";
73}
74
75char const* fmt_from_type_scientific( double )
76{
77 return "%.17e";
78}
79
80char const* fmt_from_type_fixed( double )
81{
82 return "%.17f";
83}
84
85char const* fmt_from_type( long double )
86{
87 return "%Lg";
88}
89
90char const* fmt_from_type_fixed( long double )
91{
92 return "%.0Lf";
93}
94
95#if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC)
96
97
98char const* fmt_from_type_scientific( long double )
99{
100 return "%.17e";
101}
102
103#elif BOOST_CHARCONV_LDBL_BITS == 80
104
105char const* fmt_from_type_scientific( long double )
106{
107 return "%.20Le";
108}
109
110#else
111
112char const* fmt_from_type_scientific( long double )
113{
114 return "%.35Le";
115}
116
117#endif
118
119template<class T> void test_sprintf( T value )
120{
121 char buffer[ 256 ];
122
123 auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value );
124
125 BOOST_TEST( r.ec == std::errc() );
126
127 char buffer2[ 256 ];
128 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type( value ), value );
129
130 BOOST_TEST_EQ( std::string( buffer, r.ptr ), std::string( buffer2 ) );
131}
132
133#ifdef BOOST_MSVC
134# pragma warning(push)
135# pragma warning(disable: 4127) // Conditional expression is constant (e.g. BOOST_IF_CONSTEXPR statements)
136#endif
137
138template<class T> void test_sprintf_float( T value, boost::charconv::chars_format fmt )
139{
140 char buffer[ 256 ];
141
142
143 boost::charconv::to_chars_result r;
144 if (fmt != boost::charconv::chars_format::scientific)
145 {
146 r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, fmt );
147 }
148 else
149 {
150 // Sprintf uses 9 / 17 digits of precision
151 r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, fmt, std::numeric_limits<T>::max_digits10);
152 }
153
154 BOOST_TEST( r.ec == std::errc() );
155
156 char buffer2[ 256 ];
157
158 T max_value;
159 BOOST_IF_CONSTEXPR (std::is_same<T, float>::value)
160 {
161 max_value = static_cast<T>((std::numeric_limits<std::uint32_t>::max)());
162 }
163 else BOOST_IF_CONSTEXPR(std::is_same<T, double>::value
164 #if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC)
165 || std::is_same<T, long double>::value
166 #endif
167 )
168 {
169 max_value = static_cast<T>(1e16);
170 }
171 else
172 {
173 max_value = static_cast<T>((std::numeric_limits<std::uint64_t>::max)());
174 }
175
176 if (fmt == boost::charconv::chars_format::general)
177 {
178 // See https://godbolt.org/z/dd33nM6ax
179 if (value >= 1 && value < max_value)
180 {
181 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type_fixed( value ), value );
182 }
183 else
184 {
185 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type( value ), value );
186 }
187 }
188 else if (fmt == boost::charconv::chars_format::scientific)
189 {
190 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type_scientific( value ), value );
191 }
192 else if (fmt == boost::charconv::chars_format::hex)
193 {
194 // GCC 4.X does not support std:::hexfloat
195 // GCC and Clang on Windows both diverge slightly from what they should be doing
196 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && !defined(_MSC_VER))
197
198 std::stringstream ss;
199 ss << std::hexfloat << value;
200 std::string hex_value = ss.str();
201 hex_value = hex_value.substr(pos: 2); // Remove the 0x
202 std::memcpy(dest: buffer2, src: hex_value.c_str(), n: hex_value.size() + 1);
203
204 #endif
205 }
206 else if (fmt == boost::charconv::chars_format::fixed)
207 {
208 if (value >= 1 && value < max_value)
209 {
210 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type_fixed( value ), value );
211 }
212 else
213 {
214 return;
215 }
216 }
217
218 // Remove ranges where sprintf does not perform like it should under general formatting:
219 // See to_chars_float_STL_comp.cpp
220 //
221 // Value: 3.78882532780079974e+18
222 // To chars: 3.7888253278007997e+18
223 // Snprintf: 3.78883e+18
224 //
225 // Value: 2.25907093342864926e-289
226 // To chars: 2.2590709334286493e-289
227 // Snprintf: 2.25907e-289
228 //
229 // Value: 2.98808092305723294e+289
230 // To chars: 2.988080923057233e+289
231 // Snprintf: 2.98808e+289
232
233 BOOST_IF_CONSTEXPR(std::is_same<T, double>::value
234 #if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC)
235 || std::is_same<T, long double>::value
236 #endif
237 )
238 {
239 if ( !(((value > 1e16 && value < 1e20) || (value < 1e-288 && value > 0) || (value > 1e288) ) && fmt == boost::charconv::chars_format::general))
240 {
241 if(!BOOST_TEST_EQ( std::string( buffer, r.ptr ), std::string( buffer2 ) ))
242 {
243 // Set precision for integer part + decimal digits
244 // See: https://en.cppreference.com/w/cpp/io/manip/setprecision
245 // LCOV_EXCL_START
246 std::cerr << std::setprecision(std::numeric_limits<T>::max_digits10 + 1)
247 << " Value: " << value
248 << "\nTo chars: " << std::string( buffer, r.ptr )
249 << "\nSnprintf: " << std::string( buffer2 ) << std::endl;
250 // LCOV_EXCL_STOP
251 }
252 }
253 }
254 else
255 {
256 if ( !(((value > 1e15 && value < 1e23) || (value < 1e-18 && value > 0) ) && fmt == boost::charconv::chars_format::general))
257 {
258 if(!BOOST_TEST_EQ( std::string( buffer, r.ptr ), std::string( buffer2 ) ))
259 {
260 // Set precision for integer part + decimal digits
261 // See: https://en.cppreference.com/w/cpp/io/manip/setprecision
262 // LCOV_EXCL_START
263 std::cerr << std::setprecision(std::numeric_limits<T>::max_digits10 + 1)
264 << " Value: " << value
265 << "\nTo chars: " << std::string( buffer, r.ptr )
266 << "\nSnprintf: " << std::string( buffer2 ) << std::endl;
267 // LCOV_EXCL_STOP
268 }
269 }
270 }
271}
272
273#if BOOST_CHARCONV_LDBL_BITS > 64
274template<> void test_sprintf_float( long double value, boost::charconv::chars_format fmt )
275{
276 char buffer[ 256 ];
277 char buffer2 [ 256 ];
278
279 if (fmt == boost::charconv::chars_format::fixed && (value > 1e100 || value < 1e-100))
280 {
281 // Avoid failures from overflow
282 return;
283 }
284
285 const auto r = boost::charconv::to_chars(first: buffer, last: buffer + sizeof(buffer), value, fmt);
286
287 if (!BOOST_TEST( r.ec == std::errc() ))
288 {
289 // LCOV_EXCL_START
290 const char* error_format {};
291 switch (fmt)
292 {
293 case boost::charconv::chars_format::general:
294 error_format = "General";
295 break;
296 case boost::charconv::chars_format::scientific:
297 error_format = "Scientific";
298 break;
299 case boost::charconv::chars_format::fixed:
300 error_format = "Fixed";
301 break;
302 case boost::charconv::chars_format::hex:
303 error_format = "Hex";
304 break;
305 }
306
307 std::cerr << "Failure: " << static_cast<int>(r.ec)
308 << "\nValue: " << value
309 << "\nFormat: " << error_format << std::endl;
310 // LCOV_EXCL_STOP
311 }
312
313 if (fmt == boost::charconv::chars_format::general)
314 {
315 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type( value ), value );
316 }
317 else if (fmt == boost::charconv::chars_format::scientific)
318 {
319 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type_scientific( value ), value );
320 }
321 else if (fmt == boost::charconv::chars_format::hex)
322 {
323 // GCC 4.X does not support std:::hexfloat
324 // GCC and Clang on Windows both diverge slightly from what they should be doing
325 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && !defined(_MSC_VER))
326
327 std::stringstream ss;
328 ss << std::hexfloat << value;
329 std::string hex_value = ss.str();
330 hex_value = hex_value.substr(pos: 2); // Remove the 0x
331 std::memcpy(dest: buffer2, src: hex_value.c_str(), n: hex_value.size() + 1);
332
333 #endif
334 }
335 else if (fmt == boost::charconv::chars_format::fixed)
336 {
337 std::snprintf( s: buffer2, maxlen: sizeof( buffer2 ), format: fmt_from_type_fixed( value ), value );
338 }
339
340 // Remove trailing zeros from printf
341 // Ryu only supports shortest representation
342 std::string printf_string {buffer2};
343
344 #ifndef __i686__
345 if (fmt == boost::charconv::chars_format::scientific)
346 {
347 std::size_t found_trailing_0 = printf_string.find_first_of(c: 'e');
348 if (found_trailing_0 != std::string::npos)
349 {
350 --found_trailing_0;
351 while (printf_string[found_trailing_0] == '0')
352 {
353 printf_string.erase(pos: found_trailing_0, n: 1);
354 --found_trailing_0;
355 }
356 }
357 }
358 #endif
359
360 // printf weirdness as above
361 //
362 // Value: 17766898683978543104
363 // To chars: 1.7766898683978543104e+19
364 // Snprintf: 1.77669e+19
365 //
366 // Value: 5.65459196790898857701e-4913
367 //To chars: 5.654591967908988577e-4913
368 //Snprintf: 5.65459e-4913
369 if ((value > 1e16L && value < 1e20L) ||
370 (value > 1e4912L || value < 1e-4912L) ||
371 (value > 1e-115L && value < 2e-109L))
372 {
373 return;
374 }
375
376
377 if(!BOOST_TEST_EQ( std::string( buffer, r.ptr ), printf_string ))
378 {
379 // Set precision for integer part + decimal digits
380 // See: https://en.cppreference.com/w/cpp/io/manip/setprecision
381 // LCOV_EXCL_START
382 std::cerr << std::setprecision(std::numeric_limits<long double>::max_digits10 + 1)
383 << " Value: " << value
384 << "\nTo chars: " << std::string( buffer, r.ptr )
385 << "\nSnprintf: " << printf_string << std::endl;
386 // LCOV_EXCL_STOP
387 }
388}
389#endif
390
391#ifdef BOOST_MSVC
392# pragma warning(pop)
393#endif
394
395// integral types, random values
396
397template<class T> void test_sprintf_int8()
398{
399 for( int i = -256; i <= 255; ++i )
400 {
401 test_sprintf( static_cast<T>( i ) );
402 }
403}
404
405template<class T> void test_sprintf_uint8()
406{
407 for( int i = 0; i <= 256; ++i )
408 {
409 test_sprintf( static_cast<T>( i ) );
410 }
411}
412
413template<class T> void test_sprintf_int16()
414{
415 test_sprintf_int8<T>();
416
417 for( int i = 0; i < N; ++i )
418 {
419 std::int16_t w = static_cast<std::int16_t>( rng() );
420 test_sprintf( static_cast<T>( w ) );
421 }
422}
423
424template<class T> void test_sprintf_uint16()
425{
426 test_sprintf_uint8<T>();
427
428 for( int i = 0; i < N; ++i )
429 {
430 std::uint16_t w = static_cast<std::uint16_t>( rng() );
431 test_sprintf( static_cast<T>( w ) );
432 }
433}
434
435template<class T> void test_sprintf_int32()
436{
437 test_sprintf_int16<T>();
438
439 for( int i = 0; i < N; ++i )
440 {
441 std::int32_t w = static_cast<std::int32_t>( rng() );
442 test_sprintf( static_cast<T>( w ) );
443 }
444}
445
446template<class T> void test_sprintf_uint32()
447{
448 test_sprintf_uint16<T>();
449
450 for( int i = 0; i < N; ++i )
451 {
452 std::uint32_t w = static_cast<std::uint32_t>( rng() );
453 test_sprintf( static_cast<T>( w ) );
454 }
455}
456
457template<class T> void test_sprintf_int64()
458{
459 test_sprintf_int32<T>();
460
461 for( int i = 0; i < N; ++i )
462 {
463 std::int64_t w = static_cast<std::int64_t>( rng() );
464 test_sprintf( static_cast<T>( w ) );
465 }
466}
467
468template<class T> void test_sprintf_uint64()
469{
470 test_sprintf_uint32<T>();
471
472 for( int i = 0; i < N; ++i )
473 {
474 std::uint64_t w = static_cast<std::uint64_t>( rng() );
475 test_sprintf( static_cast<T>( w ) );
476 }
477}
478
479// integral types, boundary values
480
481template<class T> void test_sprintf_bv()
482{
483 test_sprintf( std::numeric_limits<T>::min() );
484 test_sprintf( std::numeric_limits<T>::max() );
485}
486
487// floating point types, boundary values
488
489template<class T> void test_sprintf_bv_fp()
490{
491 test_sprintf_float( std::numeric_limits<T>::min(), boost::charconv::chars_format::scientific );
492 test_sprintf_float( -std::numeric_limits<T>::min(), boost::charconv::chars_format::scientific );
493 test_sprintf_float( std::numeric_limits<T>::max(), boost::charconv::chars_format::scientific );
494 test_sprintf_float( -std::numeric_limits<T>::max(), boost::charconv::chars_format::scientific );
495}
496
497#if BOOST_CHARCONV_LDBL_BITS > 64
498template<> void test_sprintf_bv_fp<long double>()
499{
500 test_sprintf_float( LDBL_MIN, fmt: boost::charconv::chars_format::scientific );
501 test_sprintf_float( value: -LDBL_MIN, fmt: boost::charconv::chars_format::scientific );
502 test_sprintf_float( LDBL_MAX, fmt: boost::charconv::chars_format::scientific );
503 test_sprintf_float( value: -LDBL_MAX, fmt: boost::charconv::chars_format::scientific );
504}
505#endif
506
507//
508
509int main()
510{
511 // integral types, random values
512
513 test_sprintf_int8<std::int8_t>();
514 test_sprintf_uint8<std::uint8_t>();
515
516 test_sprintf_int16<std::int16_t>();
517 test_sprintf_uint16<std::uint16_t>();
518
519 test_sprintf_int32<std::int32_t>();
520 test_sprintf_uint32<std::uint32_t>();
521
522 test_sprintf_int64<std::int64_t>();
523 test_sprintf_uint64<std::uint64_t>();
524
525 test_sprintf_bv<char>();
526 test_sprintf_bv<signed char>();
527 test_sprintf_bv<unsigned char>();
528
529 test_sprintf_bv<short>();
530 test_sprintf_bv<unsigned short>();
531
532 test_sprintf_bv<int>();
533 test_sprintf_bv<unsigned int>();
534
535 test_sprintf_bv<long>();
536 test_sprintf_bv<unsigned long>();
537
538 test_sprintf_bv<long long>();
539 test_sprintf_bv<unsigned long long>();
540
541 // float
542
543 double const q = std::pow( x: 1.0, y: -64 );
544
545 {
546 for( int i = 0; i < N; ++i )
547 {
548 float w0 = static_cast<float>( rng() ); // 0 .. 2^64
549 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::general );
550 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::scientific );
551 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::fixed );
552 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
553 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::hex );
554 #endif
555
556 float w1 = static_cast<float>( static_cast<double>(rng()) * q ); // 0.0 .. 1.0
557 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::general );
558 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::scientific );
559 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::fixed );
560 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
561 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::hex );
562 #endif
563
564
565 float w2 = FLT_MAX / static_cast<float>( rng() ); // large values
566 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::general );
567 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::scientific );
568 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::fixed );
569 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
570 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::hex );
571 #endif
572
573
574 float w3 = FLT_MIN * static_cast<float>( rng() ); // small values
575 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::general );
576 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::scientific );
577 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::fixed );
578 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
579 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::hex );
580 #endif
581
582 }
583
584 test_sprintf_bv_fp<float>();
585 }
586
587 // double
588
589 {
590 for( int i = 0; i < N; ++i )
591 {
592 double w0 = static_cast<double>(rng()) * 1.0; // 0 .. 2^64
593 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::general );
594 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::scientific );
595 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::fixed );
596 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
597 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::hex );
598 #endif
599
600 double w1 = static_cast<double>(rng()) * q; // 0.0 .. 1.0
601 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::general );
602 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::scientific );
603 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::fixed );
604 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
605 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::hex );
606 #endif
607
608 double w2 = DBL_MAX / static_cast<double>(rng()); // large values
609 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::general );
610 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::scientific );
611 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::fixed );
612 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
613 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::hex );
614 #endif
615
616 double w3 = DBL_MIN * static_cast<double>(rng()); // small values
617 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::general );
618 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::scientific );
619 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::fixed );
620 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
621 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::hex );
622 #endif
623 }
624
625 test_sprintf_bv_fp<double>();
626 }
627
628 // long double
629
630 {
631 for( int i = 0; i < N; ++i )
632 {
633 long double w0 = static_cast<long double>(rng()) * 1.0L; // 0 .. 2^64
634 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::general );
635 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::scientific );
636 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::fixed );
637 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
638 test_sprintf_float( value: w0, fmt: boost::charconv::chars_format::hex );
639 #endif
640
641 long double w1 = static_cast<long double>(rng()) * static_cast<long double>(q); // 0.0 .. 1.0
642 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::general );
643 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::scientific );
644 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::fixed );
645 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
646 test_sprintf_float( value: w1, fmt: boost::charconv::chars_format::hex );
647 #endif
648
649 long double w2 = LDBL_MAX / static_cast<long double>(rng()); // large values
650 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::general );
651 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::scientific );
652 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::fixed );
653 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
654 test_sprintf_float( value: w2, fmt: boost::charconv::chars_format::hex );
655 #endif
656
657 long double w3 = LDBL_MIN * static_cast<long double>(rng()); // small values
658 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::general );
659 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::scientific );
660 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::fixed );
661 #if ((defined(__GNUC__) && __GNUC__ > 4) || defined(__clang__)) && !(defined(BOOST_WINDOWS) && (defined(__clang__) || defined(__GNUC__)))
662 test_sprintf_float( value: w3, fmt: boost::charconv::chars_format::hex );
663 #endif
664 }
665
666 test_sprintf_bv_fp<long double>();
667 }
668
669 return boost::report_errors();
670}
671

source code of boost/libs/charconv/test/to_chars_sprintf.cpp