2828using Benchmarks::BenchArgs;
2929
3030template <arithmetic_float T>
31- void evaluateProperties (const std::vector<T > &lines,
31+ void evaluateProperties (const std::vector<TestCase<T> > &lines,
3232 const std::array<BenchArgs<T>, Benchmarks::COUNT> &args,
3333 const std::vector<std::string> &algo_filter) {
34- fmt::println (" {:20} {:20}" , " Algorithm" , " Valid round-trip" );
35-
36- for (const auto &algo : args) {
37- if (!algo.used ) {
38- fmt::println (" # skipping {}" , algo.name );
39- continue ;
40- }
41- if (algo_filtered_out (algo.name , algo_filter)) {
42- fmt::println (" # filtered out {}" , algo.name );
43- continue ;
44- }
45-
46- char buf1[100 ], buf2[100 ];
47- std::span<char > bufRef (buf1, sizeof (buf1)), bufAlgo (buf2, sizeof (buf2));
48- int incorrect = 0 ;
49- for (const auto d : lines) {
50- // Reference output
51- const int vRef = Benchmarks::std_to_chars (d, bufRef);
52- bufRef[vRef] = ' \0 ' ;
53- T dRef;
54- // We prefer fast_float::from_chars over std::from_chars because it is more
55- // likely to be available.
56- auto [ptr, ec] = fast_float::from_chars (bufRef.data (), bufRef.data () + vRef, dRef);
57- assert (ptr == bufRef.data () + vRef);
58- assert (ec == std::errc ());
59- assert (d == dRef);
60- // Tested algorithm output
61- const int vAlgo = algo.func (d, bufAlgo);
62- bufAlgo[vAlgo] = ' \0 ' ;
63- T dAlgo;
64- auto [ptrAlgo, ecAlgo] = fast_float::from_chars (bufAlgo.data (), bufAlgo.data () + vAlgo, dAlgo);
65- assert (ptrAlgo == bufAlgo.data () + vAlgo);
66- assert (ecAlgo == std::errc ());
67- if ((incorrect += (d != dAlgo)) == 1 )
68- fmt::println (" #\t {:20} mismatch: d = {:.17f}, bufRef = {}, bufAlgo = {}, dAlgo = {:.17f}" ,
69- algo.name , d, bufRef.data (), bufAlgo.data (), dAlgo);
70- }
71- fmt::println (" {:20} {:20}" , algo.name , incorrect == 0 ? " yes" : " no" );
72- }
34+ evaluate_properties_helper<T>(lines, algo_filter, args);
7335}
7436
7537struct diy_float_t {
@@ -81,23 +43,23 @@ struct diy_float_t {
8143};
8244
8345template <arithmetic_float T>
84- void process (const std::vector<T > &lines,
46+ void process (const std::vector<TestCase<T> > &lines,
8547 const std::array<BenchArgs<T>, Benchmarks::COUNT> &args,
8648 const std::vector<std::string> &algo_filter) {
8749 // We have a special algorithm for the string generation:
8850 if (const std::string just_string = " just_string" ;
8951 !algo_filtered_out (just_string, algo_filter)) {
9052 std::vector<diy_float_t > parsed;
91- for (auto d : lines) {
92- auto v = jkj::grisu_exact (d);
53+ for (const auto d : lines) {
54+ const auto v = jkj::grisu_exact (d. value );
9355 parsed.emplace_back (v.significand , v.exponent , v.is_negative );
9456 }
9557 pretty_print (parsed, just_string, [](const std::vector<diy_float_t >& parsed) -> int {
9658 int volume = 0 ;
9759 char buf[100 ];
9860 std::span<char > bufspan (buf, sizeof (buf));
9961 for (const auto v : parsed)
100- volume += to_chars (v.significand , v.exponent , v.is_negative , bufspan.data ());
62+ volume += to_chars (v.significand , v.exponent , v.is_negative , bufspan.data ());
10163 return volume;
10264 }, 100 );
10365 } else {
@@ -114,31 +76,30 @@ void process(const std::vector<T> &lines,
11476 continue ;
11577 }
11678
117- pretty_print (lines, algo.name , [&algo](const std::vector<T > &lines) -> int {
79+ pretty_print (lines, algo.name , [&algo](const std::vector<TestCase<T> > &lines) -> int {
11880 int volume = 0 ;
11981 char buf[100 ];
12082 std::span<char > bufspan (buf, sizeof (buf));
12183 for (const auto d : lines)
122- volume += algo.func (d, bufspan);
84+ volume += algo.func (d. value , bufspan);
12385 return volume;
12486 }, algo.testRepeat );
12587 }
12688}
12789
128- template <typename T>
129- std::vector<T > fileload (const std::string &filename) {
90+ template <arithmetic_float T>
91+ std::vector<TestCase<T> > fileload (const std::string &filename) {
13092 std::ifstream inputfile (filename);
13193 if (!inputfile) {
13294 fmt::println (stderr, " can't open {}" , filename);
13395 return {};
13496 }
13597
136- std::vector<T > lines;
98+ std::vector<TestCase<T> > lines;
13799 lines.reserve (10000 ); // let us reserve plenty of memory.
138100 for (std::string line; getline (inputfile, line);) {
139101 try {
140- lines.push_back (std::is_same_v<T, float > ? std::stof (line)
141- : std::stod (line));
102+ lines.emplace_back (std::is_same_v<T, float > ? std::stof (line) : std::stod (line), line);
142103 } catch (...) {
143104 fmt::println (stderr, " problem with {}\n We expect floating-point numbers (one per line)." , line);
144105 std::abort ();
@@ -148,17 +109,17 @@ std::vector<T> fileload(const std::string &filename) {
148109 return lines;
149110}
150111
151- template <typename T>
152- std::vector<T > get_random_numbers (size_t howmany,
153- const std::string &random_model) {
112+ template <arithmetic_float T>
113+ std::vector<TestCase<T> > get_random_numbers (size_t howmany,
114+ const std::string &random_model) {
154115 fmt::println (" # parsing random numbers" );
155- std::vector<T > lines;
116+ std::vector<TestCase<T> > lines;
156117 auto g = get_generator_by_name<T>(random_model);
157118 fmt::println (" model: {}\n volume: {} floats" , g->describe (), howmany);
158119 lines.reserve (howmany); // let us reserve plenty of memory.
159120 for (size_t i = 0 ; i < howmany; i++) {
160121 const T line = g->new_float ();
161- lines.push_back (line);
122+ lines.emplace_back (line, std:: nullopt );
162123 }
163124 return lines;
164125}
@@ -183,7 +144,7 @@ int main(int argc, char **argv) {
183144 (" e,errol" , " Enable errol3 (current impl. returns invalid values, e.g., for 0)." ,
184145 cxxopts::value<bool >()->default_value (" false" ))
185146 (" a,algo-filter" , " Filter algorithms by name substring: you can use multiple filters separated by commas." ,
186- cxxopts::value<std::vector<std::string>>()-> default_value ( " " ) )
147+ cxxopts::value<std::vector<std::string>>())
187148 (" r,repeat" , " Force a number of repetitions." ,
188149 cxxopts::value<size_t >()->default_value (" 0" ))
189150 (" h,help" , " Print usage." );
@@ -195,10 +156,13 @@ int main(int argc, char **argv) {
195156 }
196157 const size_t repeat = result[" repeat" ].as <size_t >();
197158 const bool single = result[" single" ].as <bool >();
198- std::vector<std::string> filter = result[" algo-filter" ].as <std::vector<std::string>>();
159+ const auto filter = result.count (" algo-filter" )
160+ ? result[" algo-filter" ].as <std::vector<std::string>>()
161+ : std::vector<std::string>{};
199162 fmt::println (" number type: binary{}" , (single ? " 32 (float)" : " 64 (double)" ));
200163
201- std::variant<std::vector<float >, std::vector<double >> numbers;
164+ std::variant<std::vector<TestCase<float >>,
165+ std::vector<TestCase<double >>> numbers;
202166 const auto filename = result[" file" ].as <std::string>();
203167 if (filename.empty ()) {
204168 const auto volume = result[" volume" ].as <size_t >();
@@ -207,7 +171,7 @@ int main(int argc, char **argv) {
207171 numbers = get_random_numbers<float >(volume, model);
208172 else
209173 numbers = get_random_numbers<double >(volume, model);
210- fmt::println (" # You can also provide a filename (with the -f flag):"
174+ fmt::println (" # You can also provide a filename (with the -f flag): "
211175 " it should contain one string per line corresponding to a number" );
212176 }
213177 else {
@@ -234,8 +198,8 @@ int main(int argc, char **argv) {
234198 }
235199
236200 const bool test = result[" test" ].as <bool >();
237- std::visit ([test,&filter](const auto &lines, const auto &args) {
238- using T1 = typename std::decay_t <decltype (lines)>::value_type;
201+ std::visit ([test, &filter](const auto &lines, const auto &args) {
202+ using T1 = typename std::decay_t <decltype (lines)>::value_type::Type ;
239203 using T2 = typename std::decay_t <decltype (args)>::value_type::Type;
240204 if constexpr (std::is_same_v<T1, T2>) {
241205 if (test)
0 commit comments