@@ -141,13 +141,113 @@ cxxopts::Options
141141 options (" benchmark" ,
142142 " Compute the parsing speed of different number parsers." );
143143
144+
145+ // Checks if a floating-point number is exactly representable as the specified integer type
146+ template <std::integral int_type, std::floating_point float_type>
147+ bool is_exact_integer (float_type x) {
148+ if (!std::isfinite (x)) {
149+ return false ;
150+ }
151+ int_type i = static_cast <int_type>(x);
152+ return static_cast <float_type>(i) == x;
153+ }
154+
155+ // Nouvelle version template de describe
156+ template <typename T>
157+ void describe (const std::variant<std::vector<TestCase<float >>, std::vector<TestCase<double >>> &numbers,
158+ const std::vector<BenchArgs<T>> &args,
159+ const std::vector<std::string> &algo_filter) {
160+ std::visit ([&args, &algo_filter](const auto &lines) {
161+ size_t integers64 = 0 ;
162+ size_t integers32 = 0 ;
163+ for (const auto &d : lines) {
164+ integers64 += is_exact_integer<int64_t >(d.value ) ? 1 : 0 ;
165+ integers32 += is_exact_integer<int32_t >(d.value ) ? 1 : 0 ;
166+ }
167+ std::vector<size_t > sizes (lines.size (), std::numeric_limits<size_t >::max ());
168+ std::vector<std::string> shortest (lines.size ());
169+ std::vector<std::tuple<std::string, size_t , double , bool >> results;
170+ size_t min_size = std::numeric_limits<size_t >::max ();
171+ for (const auto &algo : args) {
172+ if (!algo.used ) continue ;
173+ if (algo_filtered_out (algo.name , algo_filter)) continue ;
174+ size_t total_size = 0 ;
175+ std::vector<char > buffer (100 );
176+ std::span<char > bufspan (buffer);
177+ bool precise = true ;
178+ for (size_t i = 0 ; i < lines.size (); ++i) {
179+ const auto &d = lines[i];
180+ int len = algo.func (d.value , bufspan);
181+ if (sizes[i] > len) {
182+ sizes[i] = len;
183+ shortest[i].assign (bufspan.data (), len);
184+ }
185+ total_size += len;
186+ std::string_view sv (buffer.data (), len);
187+ auto parsed = parse_float<T>(sv);
188+ if (!parsed.has_value () || parsed.value () != d.value ) {
189+ precise = false ;
190+ break ;
191+ }
192+ }
193+ double avg = total_size / double (lines.size ());
194+ results.emplace_back (algo.name , total_size, avg, precise);
195+ if (precise && total_size < min_size) min_size = total_size;
196+ }
197+ constexpr size_t warning_max = 1 ;
198+ for (const auto &algo : args) {
199+ if (!algo.used ) continue ;
200+ if (algo_filtered_out (algo.name , algo_filter)) continue ;
201+ size_t howmany = 0 ;
202+ std::vector<char > buffer (100 );
203+ std::span<char > bufspan (buffer);
204+ size_t worse_than_shortest = 0 ;
205+ for (size_t i = 0 ; i < lines.size (); ++i) {
206+ const auto &d = lines[i];
207+ int len = algo.func (d.value , bufspan);
208+ if (sizes[i] < len) {
209+ howmany++;
210+ bool new_record = (len > worse_than_shortest + sizes[i]);
211+ worse_than_shortest = (std::max)(worse_than_shortest, len - sizes[i]);
212+ if (new_record || howmany <= warning_max) {
213+ fmt::print (stderr, " Warning: algorithm {} produced a longer string ({}) than the shortest ({}) for value {}\n " ,
214+ algo.name , len, sizes[i], d.value );
215+ fmt::print (stderr, " Shortest: '{}'\n " , shortest[i]);
216+ std::string_view this_answer (bufspan.data (), len);
217+ fmt::print (stderr, " Produced: '{}'\n " , this_answer);
218+ auto parsed_ref = parse_float<T>(shortest[i]);
219+ auto parsed_this = parse_float<T>(this_answer);
220+ if (!parsed_ref.has_value () || !parsed_this.has_value ()) {
221+ fmt::print (stderr, " BUG! Parsing failed for one of the strings.\n " );
222+ } else if (parsed_ref.value () != parsed_this.value ()) {
223+ fmt::print (stderr, " BUG! Parsed values differ: {} vs {}\n " ,
224+ parsed_ref.value (), parsed_this.value ());
225+ }
226+
227+ }
228+ }
229+ }
230+ if (howmany > warning_max) {
231+ fmt::print (stderr, " Warning: algorithm {} produced longer strings than the shortest for {} values, worst gap is {} characters\n " ,
232+ algo.name , howmany, worse_than_shortest);
233+ }
234+ }
235+ for (const auto &[name, total_size, avg, precise] : results) {
236+ bool is_min = (precise && total_size == min_size);
237+ fmt::print (" {:<18} {:>12} ({:>5.3f} chars/f){}{}\n " , name, total_size, avg, is_min ? " [minimal]" : " " , precise ? " [precise]" : " [imprecise]" );
238+ }
239+ fmt::println (" count: {}, 32-bit ints: {}, 64-bit ints: {}" , lines.size (), integers32, integers64);
240+ }, numbers);
241+ }
242+
144243int main (int argc, char **argv) {
145244 try {
146245 options.add_options ()
147246 (" f,file" , " File name." ,
148247 cxxopts::value<std::string>()->default_value (" " ))
149248 (" F,fixed" , " Fixed-point representation." ,
150249 cxxopts::value<size_t >()->default_value (" 0" ))
250+ (" D,data" , " Description of the data." )
151251 (" v,volume" , " Volume (number of floats generated)." ,
152252 cxxopts::value<size_t >()->default_value (" 100000" ))
153253 (" m,model" , " Random Model." ,
@@ -205,7 +305,13 @@ int main(int argc, char **argv) {
205305 algorithms = initArgs<float >(errol, repeat, fixed_size);
206306 else
207307 algorithms = initArgs<double >(errol, repeat, fixed_size);
208-
308+ if (result[" data" ].as <bool >()) {
309+ if (single)
310+ describe<float >(numbers, std::get<std::vector<BenchArgs<float >>>(algorithms), filter);
311+ else
312+ describe<double >(numbers, std::get<std::vector<BenchArgs<double >>>(algorithms), filter);
313+ return EXIT_SUCCESS;
314+ }
209315 const bool test = result[" test" ].as <bool >();
210316 const bool string_eval = result[" string-eval" ].as <bool >();
211317 std::visit ([test, string_eval, &filter](const auto &lines, const auto &args) {
0 commit comments