Skip to content

Commit 0eaca2f

Browse files
committed
generalize random numbers generators
1 parent b99466e commit 0eaca2f

File tree

2 files changed

+91
-73
lines changed

2 files changed

+91
-73
lines changed

benchmarks/benchmark.cpp

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void process(const std::vector<T> &lines) {
6666
pretty_print(lines, "dragon4", [](const std::vector<T> &lines) -> int {
6767
int volume = 0;
6868
for (const auto d : lines) {
69-
MantissaType dmantissa;
69+
uint64_t dmantissa;
7070
int dexp;
7171
const IEEE754Type fields = decode_ieee754(d);
7272
dragon4::Dragon4(dmantissa, dexp, fields.mantissa, fields.exponent,
@@ -260,21 +260,23 @@ void process(const std::vector<T> &lines) {
260260
#endif
261261
}
262262

263-
void fileload(const char *filename) {
263+
template <typename T>
264+
void fileload(const std::string &filename) {
264265
std::ifstream inputfile(filename);
265266
if (!inputfile) {
266267
std::cerr << "can't open " << filename << std::endl;
267268
return;
268269
}
269270

270-
std::vector<double> lines;
271+
std::vector<T> lines;
271272
lines.reserve(10000); // let us reserve plenty of memory.
272273
for (std::string line; getline(inputfile, line);) {
273274
try {
274-
lines.push_back(std::stod(line));
275+
lines.push_back(std::is_same_v<T, float> ? std::stof(line)
276+
: std::stod(line));
275277
} catch (...) {
276-
std::cerr << "problem with " << line << std::endl;
277-
std::cerr << "We expect floating-point numbers (one per line)."
278+
std::cerr << "problem with " << line << "\n"
279+
<< "We expect floating-point numbers (one per line)."
278280
<< std::endl;
279281
std::abort();
280282
}
@@ -283,15 +285,16 @@ void fileload(const char *filename) {
283285
process(lines);
284286
}
285287

286-
void parse_random_numbers(size_t howmany, std::string random_model) {
288+
template <typename T>
289+
void parse_random_numbers(size_t howmany, const std::string &random_model) {
287290
std::cout << "# parsing random numbers" << std::endl;
288-
std::vector<double> lines;
289-
auto g = get_generator_by_name(random_model);
290-
std::cout << "model: " << g->describe() << std::endl;
291-
std::cout << "volume: " << howmany << " floats" << std::endl;
291+
std::vector<T> lines;
292+
auto g = get_generator_by_name<T>(random_model);
293+
std::cout << "model: " << g->describe() << "\n"
294+
<< "volume: " << howmany << " floats" << std::endl;
292295
lines.reserve(howmany); // let us reserve plenty of memory.
293296
for (size_t i = 0; i < howmany; i++) {
294-
double line = g->new_float();
297+
const T line = g->new_float();
295298
lines.push_back(line);
296299
}
297300
process(lines);
@@ -313,21 +316,33 @@ int main(int argc, char **argv) {
313316
cxxopts::value<bool>()->default_value("false"))(
314317
"h,help", "Print usage.");
315318
const auto result = options.parse(argc, argv);
319+
316320
if (result["help"].as<bool>()) {
317321
std::cout << options.help() << std::endl;
318322
return EXIT_SUCCESS;
319323
}
324+
320325
const bool single = result["single"].as<bool>();
326+
std::cout << "number type: " << (single ? "binary32 (float)" : "binary64 (double)") << std::endl;
327+
321328
const auto filename = result["file"].as<std::string>();
322329
if (filename.empty()) {
323-
parse_random_numbers(result["volume"].as<size_t>(),
324-
result["model"].as<std::string>());
325-
std::cout << "# You can also provide a filename (with the -f flag): it "
326-
"should contain one "
327-
"string per line corresponding to a number"
330+
if(single) {
331+
parse_random_numbers<float>(result["volume"].as<size_t>(),
332+
result["model"].as<std::string>());
333+
} else {
334+
parse_random_numbers<double>(result["volume"].as<size_t>(),
335+
result["model"].as<std::string>());
336+
}
337+
std::cout << "# You can also provide a filename (with the -f flag):"
338+
"it should contain one string per line corresponding to a number"
328339
<< std::endl;
329-
} else {
330-
fileload(filename.c_str());
340+
}
341+
else {
342+
if(single)
343+
fileload<float>(filename);
344+
else
345+
fileload<double>(filename);
331346
}
332347
} catch (const std::exception &e) {
333348
std::cout << "error parsing options: " << e.what() << std::endl;

benchmarks/random_generators.h

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,91 +5,94 @@
55
#include <memory>
66
#include <random>
77
#include <iostream>
8+
#include <type_traits>
89

10+
template <typename T>
911
struct float_number_generator {
10-
virtual double new_float() = 0;
12+
virtual T new_float() = 0;
1113
virtual std::string describe() = 0;
1214
virtual ~float_number_generator() = default;
1315
};
1416

15-
struct uniform_generator : float_number_generator {
17+
template <typename T>
18+
struct uniform_generator : float_number_generator<T> {
1619
std::random_device rd;
17-
std::mt19937 gen;
18-
std::uniform_real_distribution<double> dis;
19-
explicit uniform_generator(double a = 0, double b = 1)
20+
std::mt19937_64 gen;
21+
std::uniform_real_distribution<T> dis;
22+
explicit uniform_generator(T a = 0.0, T b = 1.0)
2023
: rd(), gen(rd()), dis(a, b) {}
2124
std::string describe() override {
2225
return std::string("generate random numbers uniformly in the interval [") +
2326
std::to_string((dis.min)()) + std::string(",") +
2427
std::to_string((dis.max)()) + std::string("]");
2528
}
26-
double new_float() override { return dis(gen); }
29+
T new_float() override { return dis(gen); }
2730
};
2831

29-
struct integer_uniform_generator : float_number_generator {
32+
template <typename T>
33+
struct integer_uniform_generator : float_number_generator<T> {
3034
std::random_device rd;
31-
std::mt19937 gen;
35+
std::mt19937_64 gen;
3236
std::uniform_int_distribution<uint64_t> dis;
3337
explicit integer_uniform_generator(uint64_t a = 0, uint64_t b = 1)
3438
: rd(), gen(rd()), dis(a, b) {}
3539
std::string describe() override {
3640
return std::string(
37-
"generate random untegers numbers uniformly in the interval [") +
41+
"generate random integers numbers uniformly in the interval [") +
3842
std::to_string((dis.min)()) + std::string(",") +
3943
std::to_string((dis.max)()) + std::string("]");
4044
}
41-
double new_float() override { return dis(gen); }
45+
T new_float() override { return dis(gen); }
4246
};
4347

44-
struct one_over_rand32 : float_number_generator {
48+
template <typename T>
49+
struct simple_uniform : float_number_generator<T> {
50+
using gen_type = std::conditional_t<sizeof(T) == 4, std::mt19937, std::mt19937_64>;
4551
std::random_device rd;
46-
std::mt19937 gen;
47-
explicit one_over_rand32() : rd(), gen(rd()) {}
48-
std::string describe() override { return "1 / rand()"; }
49-
double new_float() override {
50-
auto g = gen();
51-
while (g == 0) {
52-
g = gen();
53-
}
54-
double x = 1.0 / double(g);
55-
return x;
56-
}
57-
};
58-
59-
struct simple_uniform32 : float_number_generator {
60-
std::random_device rd;
61-
std::mt19937 gen;
62-
explicit simple_uniform32() : rd(), gen(rd()) {}
52+
gen_type gen;
53+
explicit simple_uniform() : rd(), gen(rd()) {}
6354
std::string describe() override { return "rand() / 0xFFFFFFFF "; }
64-
double new_float() override {
65-
double x = double(gen()) / double((std::mt19937::max)());
55+
T new_float() override {
56+
const T x = T(gen()) / gen.max();
6657
return x;
6758
}
6859
};
6960

70-
struct simple_int32 : float_number_generator {
61+
template <typename T>
62+
struct simple_int : float_number_generator<T> {
63+
using gen_type = std::conditional_t<sizeof(T) == 4, std::mt19937, std::mt19937_64>;
7164
std::random_device rd;
72-
std::mt19937 gen;
73-
explicit simple_int32() : rd(), gen(rd()) {}
65+
std::mt19937_64 gen;
7466
std::string describe() override { return "rand()"; }
75-
double new_float() override { return gen(); }
67+
explicit simple_int() : rd(), gen(rd()) {}
68+
T new_float() override { return gen(); }
7669
};
7770

78-
struct simple_int64 : float_number_generator {
71+
template <typename T>
72+
struct one_over_rand : float_number_generator<T> {
73+
using gen_type = std::conditional_t<sizeof(T) == 4, std::mt19937, std::mt19937_64>;
7974
std::random_device rd;
80-
std::mt19937_64 gen;
81-
std::string describe() override { return "rand64()"; }
82-
explicit simple_int64() : rd(), gen(rd()) {}
83-
double new_float() override { return gen(); }
75+
gen_type gen;
76+
explicit one_over_rand() : rd(), gen(rd()) {}
77+
std::string describe() override { return "1 / rand()"; }
78+
T new_float() override {
79+
auto g = gen();
80+
while (g == 0) {
81+
g = gen();
82+
}
83+
const T x = T(1.0) / T(g);
84+
return x;
85+
}
8486
};
8587

86-
constexpr std::array<const char*, 6> model_names = {
87-
"uniform", "one_over_rand32",
88-
"simple_uniform32", "simple_int32",
89-
"int_e_int", "simple_int64"
88+
constexpr std::array<const char*, 5> model_names = {
89+
"uniform", "integer_uniform",
90+
"simple_uniform", "simple_int",
91+
"one_over_rand"
9092
};
9193

92-
inline std::unique_ptr<float_number_generator>
94+
template <typename T>
95+
inline std::unique_ptr<float_number_generator<T>>
9396
get_generator_by_name(std::string name) {
9497
std::cout << "available models (-m): ";
9598
for (std::string name : model_names) {
@@ -99,23 +102,23 @@ get_generator_by_name(std::string name) {
99102

100103
// This is naive, but also not very important.
101104
if (name == "uniform") {
102-
return std::unique_ptr<float_number_generator>(new uniform_generator());
105+
return std::unique_ptr<float_number_generator<T>>(new uniform_generator<T>());
103106
}
104-
if (name == "one_over_rand32") {
105-
return std::unique_ptr<float_number_generator>(new one_over_rand32());
107+
if (name == "integer_uniform") {
108+
return std::unique_ptr<float_number_generator<T>>(new integer_uniform_generator<T>());
106109
}
107-
if (name == "simple_uniform32") {
108-
return std::unique_ptr<float_number_generator>(new simple_uniform32());
110+
if (name == "simple_uniform") {
111+
return std::unique_ptr<float_number_generator<T>>(new simple_uniform<T>());
109112
}
110-
if (name == "simple_int32") {
111-
return std::unique_ptr<float_number_generator>(new simple_int32());
113+
if (name == "simple_int") {
114+
return std::unique_ptr<float_number_generator<T>>(new simple_int<T>());
112115
}
113-
if (name == "simple_int64") {
114-
return std::unique_ptr<float_number_generator>(new simple_int64());
116+
if (name == "one_over_rand") {
117+
return std::unique_ptr<float_number_generator<T>>(new one_over_rand<T>());
115118
}
116119
std::cerr << " I do not recognize " << name << std::endl;
117120
std::cerr << " Warning: falling back on uniform generator. " << std::endl;
118-
return std::unique_ptr<float_number_generator>(new uniform_generator());
121+
return std::unique_ptr<float_number_generator<T>>(new uniform_generator<T>());
119122
}
120123

121124
#endif

0 commit comments

Comments
 (0)