77#include < cstring>
88#include < iostream>
99#include < string_view>
10+ #include < charconv>
1011
1112#include " algorithms.h"
1213#include " cxxopts.hpp"
@@ -37,24 +38,25 @@ size_t count_significant_digits(std::string_view num_str) {
3738}
3839
3940std::string float_to_hex (float f) {
40- if (std::isnan (f) || std::isinf (f)) {
41- return fmt::format (" {}" , f); // Handle special cases
42- }
43-
44- uint32_t bits = std::bit_cast<uint32_t >(f);
45- int exponent;
46- float mantissa = std::frexp (f, &exponent); // Get mantissa and exponent
47- uint32_t mantissa_bits = bits & 0x7FFFFF ; // 23-bit mantissa
48- int exp_bits = (bits >> 23 ) & 0xFF ; // 8-bit exponent
49- bool sign = bits >> 31 ; // Sign bit
50-
51- // Adjust for IEEE 754 representation
52- if (exp_bits == 0 && mantissa_bits == 0 ) {
53- return " 0x0p+0" ; // Zero case
54- }
41+ std::ostringstream oss;
42+ oss << std::hexfloat << f;
43+ return oss.str ();
44+ }
5545
56- // Convert to hex format
57- return fmt::format (" 0x1.{:06x}p{:+d}" , mantissa_bits, exponent - 23 );
46+ std::optional<float > parse_float (std::string_view sv) {
47+ float result;
48+ const char * begin = sv.data ();
49+ const char * end = sv.data () + sv.size ();
50+
51+ auto [ptr, ec] = std::from_chars (begin, end, result);
52+
53+ // Check if parsing succeeded and consumed the entire string
54+ if (ec == std::errc{} && ptr == end) {
55+ return result;
56+ }
57+
58+ // Return nullopt if parsing failed or didn't consume all input
59+ return std::nullopt ;
5860}
5961
6062void run_exhaustive32 (bool errol) {
@@ -66,7 +68,11 @@ void run_exhaustive32(bool errol) {
6668
6769 for (const auto &algo : args) {
6870 if (!algo.used ) {
69- std::cout << " # skipping " << algo.name << std::endl;
71+ fmt::print (" # skipping {}\n " , algo.name );
72+ continue ;
73+ }
74+ if (algo.func == Benchmarks::dragonbox<float >) {
75+ fmt::print (" # skipping {} because it is the reference.\n " , algo.name );
7076 continue ;
7177 }
7278 bool incorrect = false ;
@@ -85,15 +91,42 @@ void run_exhaustive32(bool errol) {
8591 std::memcpy (&d, &i32 , sizeof (float ));
8692 if (std::isnan (d) || std::isinf (d))
8793 continue ;
88- // Reference output
89- const size_t vRef = Benchmarks::std_to_chars (d, bufRef);
94+ // Reference output, we cannot use std::to_chars here, because it produces
95+ // the shortest representation, which is not necessarily the same as the
96+ // as the representation using the fewest significant digits.
97+ // So we use dragonbox, which serves as the reference implementation.
98+ const size_t vRef = Benchmarks::dragonbox (d, bufRef);
9099 const size_t vAlgo = algo.func (d, bufAlgo);
91100
92101 std::string_view svRef{bufRef.data (), vRef};
93102 std::string_view svAlgo{bufAlgo.data (), vAlgo};
94103
95104 auto countRef = count_significant_digits (svRef);
96105 auto countAlgo = count_significant_digits (svAlgo);
106+ auto backRef = parse_float (svRef);
107+ auto backAlgo = parse_float (svAlgo);
108+ if (!backRef || !backAlgo) {
109+ incorrect = true ;
110+ fmt::print (" parse error: d = {}, bufRef = {}, bufAlgo = {}" , float_to_hex (d),
111+ svRef, svAlgo);
112+ fflush (stdout);
113+ break ;
114+ }
115+ if (*backRef != d || *backAlgo != d) {
116+ fmt::println (" \n # Error: parsing the output with std::from_chars does not bring back the input." );
117+ }
118+ if (*backRef != d) {
119+ incorrect = true ;
120+ fmt::print (" ref mismatch: d = {}, backRef = {}" , d, *backRef);
121+ fflush (stdout);
122+ break ;
123+ }
124+ if (*backAlgo != d) {
125+ incorrect = true ;
126+ fmt::print (" algo mismatch: d = {}, backAlgo = {}, parsing the output with std::from_chars does not recover the original" , d, *backAlgo);
127+ fflush (stdout);
128+ break ;
129+ }
97130 if (countRef != countAlgo) {
98131 incorrect = true ;
99132 fmt::print (" mismatch: d = {}, bufRef = {}, bufAlgo = {}" , float_to_hex (d),
@@ -121,12 +154,12 @@ int main(int argc, char **argv) {
121154 const auto result = options.parse (argc, argv);
122155
123156 if (result[" help" ].as <bool >()) {
124- std::cout << options.help () << std::endl ;
157+ fmt::print ( " {} \n " , options.help ()) ;
125158 return EXIT_SUCCESS;
126159 }
127160 run_exhaustive32 (result[" errol" ].as <bool >());
128161 } catch (const std::exception &e) {
129- std::cout << " error parsing options: " << e.what () << std::endl ;
162+ fmt::print ( " error parsing options: {} \n " , e.what ()) ;
130163 return EXIT_FAILURE;
131164 }
132165}
0 commit comments