Skip to content

Commit f09853a

Browse files
committed
add a mode to evaluate algorithms properties
- For now, only checks internal round-trip validity - std::to_string can't be configured to output with enough precision - All other algorithms seem to respect the property.
1 parent 6c15ce7 commit f09853a

File tree

1 file changed

+62
-18
lines changed

1 file changed

+62
-18
lines changed

benchmarks/benchmark.cpp

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "cxxopts.hpp"
1414
#include "random_generators.h"
1515

16+
#include <cassert>
1617
#include <climits>
1718
#include <cmath>
1819
#include <cstdio>
@@ -24,27 +25,63 @@
2425
using Benchmarks::arithmetic_float;
2526
using Benchmarks::BenchArgs;
2627

28+
template <arithmetic_float T>
29+
void evaluateProperties(const std::vector<T> &lines,
30+
const std::array<BenchArgs<T>, Benchmarks::COUNT> &args) {
31+
constexpr auto precision = std::numeric_limits<T>::digits10;
32+
fmt::println("{:20} {:20}", "Algorithm", "Valid round-trip");
33+
34+
for (const auto &algo : args) {
35+
if (!algo.used) {
36+
std::cout << "# skipping " << algo.name << std::endl;
37+
continue;
38+
}
39+
40+
char buf1[100], buf2[100];
41+
std::span<char> bufRef(buf1, sizeof(buf1)), bufAlgo(buf2, sizeof(buf2));
42+
int incorrect = 0;
43+
for (const auto d : lines) {
44+
// Reference output
45+
const int vRef = Benchmarks::std_to_chars(d, bufRef);
46+
bufRef[vRef] = '\0';
47+
T dRef;
48+
auto [ptr, ec] = std::from_chars(bufRef.data(), bufRef.data() + vRef, dRef);
49+
assert(ptr == bufRef.data() + vRef);
50+
assert(ec == std::errc());
51+
assert(d == dRef);
52+
53+
// Tested algorithm output
54+
const int vAlgo = algo.func(d, bufAlgo);
55+
bufAlgo[vAlgo] = '\0';
56+
T dAlgo;
57+
auto [ptrAlgo, ecAlgo] = std::from_chars(bufAlgo.data(), bufAlgo.data() + vAlgo, dAlgo);
58+
assert(ptrAlgo == bufAlgo.data() + vAlgo);
59+
assert(ecAlgo == std::errc());
60+
if ((incorrect += (d != dAlgo)) == 1)
61+
fmt::println("\t{:20} mismatch: d = {:.17f}, bufRef = {}, bufAlgo = {}, dAlgo = {:.17f}",
62+
algo.name, d, bufRef.data(), bufAlgo.data(), dAlgo);
63+
}
64+
fmt::println("{:20} {:20}", algo.name, incorrect == 0 ? "yes" : "no");
65+
}
66+
}
67+
2768
template <arithmetic_float T>
2869
void process(const std::vector<T> &lines,
2970
const std::array<BenchArgs<T>, Benchmarks::COUNT> &args) {
30-
auto testWrapper = [](const std::vector<T> &lines, const std::string &name,
31-
int (*func)(T, std::span<char> &), int repeat = 1) {
32-
pretty_print(lines, name, [func, repeat](const std::vector<T> &lines) -> int {
33-
int volume = 0;
34-
char buf[100];
35-
std::span<char> bufspan(buf, sizeof(buf));
36-
for (const auto d : lines)
37-
volume += func(d, bufspan);
38-
return volume;
39-
}, repeat);
40-
};
41-
4271
for (const auto &algo : args) {
4372
if (!algo.used) {
4473
std::cout << "# skipping " << algo.name << std::endl;
4574
continue;
4675
}
47-
testWrapper(lines, algo.name, algo.func, algo.testRepeat);
76+
77+
pretty_print(lines, algo.name, [&algo](const std::vector<T> &lines) -> int {
78+
int volume = 0;
79+
char buf[100];
80+
std::span<char> bufspan(buf, sizeof(buf));
81+
for (const auto d : lines)
82+
volume += algo.func(d, bufspan);
83+
return volume;
84+
}, algo.testRepeat);
4885
}
4986
}
5087

@@ -103,9 +140,11 @@ int main(int argc, char **argv) {
103140
cxxopts::value<std::string>()->default_value("uniform"))(
104141
"s,single", "Use single precision instead of double.",
105142
cxxopts::value<bool>()->default_value("false"))(
106-
"d,dragon", "Enable dragon4 (current impl. triggers some asserts)",
143+
"t,test", "Test the algorithms and find their properties.",
144+
cxxopts::value<bool>()->default_value("false"))(
145+
"d,dragon", "Enable dragon4 (current impl. triggers some asserts).",
107146
cxxopts::value<bool>()->default_value("false"))(
108-
"e,errol", "Enable errol3 (current impl. returns invalid values, e.g., for 0)",
147+
"e,errol", "Enable errol3 (current impl. returns invalid values, e.g., for 0).",
109148
cxxopts::value<bool>()->default_value("false"))(
110149
"h,help", "Print usage.");
111150
const auto result = options.parse(argc, argv);
@@ -167,11 +206,16 @@ int main(int argc, char **argv) {
167206
else
168207
algorithms = initArgs(double{});
169208

170-
std::visit([](const auto &lines, const auto &args) {
209+
const bool test = result["test"].as<bool>();
210+
std::visit([test](const auto &lines, const auto &args) {
171211
using T1 = typename std::decay_t<decltype(lines)>::value_type;
172212
using T2 = typename std::decay_t<decltype(args)>::value_type::Type;
173-
if constexpr (std::is_same_v<T1, T2>)
174-
process(lines, args);
213+
if constexpr (std::is_same_v<T1, T2>) {
214+
if (test)
215+
evaluateProperties(lines, args);
216+
else
217+
process(lines, args);
218+
}
175219
}, numbers, algorithms);
176220
} catch (const std::exception &e) {
177221
std::cout << "error parsing options: " << e.what() << std::endl;

0 commit comments

Comments
 (0)