Skip to content

Commit db330f4

Browse files
committed
add new numbers generator
- uniform: we can now selectively generate only in [0, 1] or among all possible floats - new centered/non-centered generators
1 parent 932b972 commit db330f4

File tree

1 file changed

+54
-21
lines changed

1 file changed

+54
-21
lines changed

benchmarks/random_generators.h

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define RANDOM_GENERATORS_H
33

44
#include <array>
5+
#include <bit>
56
#include <memory>
67
#include <random>
78
#include <iostream>
@@ -22,13 +23,42 @@ struct uniform_generator : float_number_generator<T> {
2223
explicit uniform_generator(T a = 0.0, T b = 1.0)
2324
: rd(), gen(rd()), dis(a, b) {}
2425
std::string describe() override {
25-
return std::string("generate random numbers uniformly in the interval [") +
26+
return "generate random numbers uniformly in the interval [" +
2627
std::to_string((dis.min)()) + std::string(",") +
2728
std::to_string((dis.max)()) + std::string("]");
2829
}
2930
T new_float() override { return dis(gen); }
3031
};
3132

33+
enum centering { centered, non_centered };
34+
template <std::floating_point T, centering C>
35+
struct centered_generator : float_number_generator<T> {
36+
constexpr static int MAN_BITS = sizeof(T) == 4 ? 23 : 52;
37+
constexpr static int EXP_BITS = sizeof(T) == 4 ? 8 : 11;
38+
std::random_device rd;
39+
std::mt19937_64 gen;
40+
std::uniform_int_distribution<uint32_t> dist_sign;
41+
std::uniform_int_distribution<uint32_t> dist_exp; // exclut 0=subnormal et max=inf/NaN
42+
std::uniform_int_distribution<uint64_t> dist_man; // mantisse, sauf le LSB
43+
explicit centered_generator()
44+
: rd(), gen(rd()), dist_sign(0, 1),
45+
dist_exp(1u << (EXP_BITS - 1), (1u << EXP_BITS) - 2),
46+
dist_man(1ull, (1ull << MAN_BITS) - 1) {}
47+
std::string describe() override {
48+
return "generate random "
49+
+ (C == centered ? std::string("centered") : std::string("non-centered"))
50+
+ " numbers uniformly among all normal floating-point numbers";
51+
}
52+
T new_float() override {
53+
using type_t = typename std::conditional_t< sizeof(T) == 4, uint32_t, uint64_t>;
54+
const type_t sign = dist_sign(gen);
55+
const type_t exp = dist_exp(gen);
56+
const type_t man = C == centered ? dist_man(gen) : 0u;
57+
const type_t bits = (sign << (EXP_BITS + MAN_BITS)) | (exp << MAN_BITS) | man;
58+
return std::bit_cast<T>(bits);
59+
}
60+
};
61+
3262
template <typename T>
3363
struct integer_uniform_generator : float_number_generator<T> {
3464
std::random_device rd;
@@ -37,8 +67,7 @@ struct integer_uniform_generator : float_number_generator<T> {
3767
explicit integer_uniform_generator(long a = LONG_MIN, long b = LONG_MAX)
3868
: rd(), gen(rd()), dis(a, b) {}
3969
std::string describe() override {
40-
return std::string(
41-
"generate random integers numbers uniformly in the interval [") +
70+
return "generate random integers numbers uniformly in the interval [" +
4271
std::to_string((dis.min)()) + std::string(",") +
4372
std::to_string((dis.max)()) + std::string("]");
4473
}
@@ -47,9 +76,8 @@ struct integer_uniform_generator : float_number_generator<T> {
4776

4877
template <typename T>
4978
struct simple_uniform : float_number_generator<T> {
50-
using gen_type = std::conditional_t<sizeof(T) == 4, std::mt19937, std::mt19937_64>;
5179
std::random_device rd;
52-
gen_type gen;
80+
std::mt19937_64 gen;
5381
explicit simple_uniform() : rd(), gen(rd()) {}
5482
std::string describe() override { return "rand() / 0xFFFFFFFF "; }
5583
T new_float() override {
@@ -60,7 +88,6 @@ struct simple_uniform : float_number_generator<T> {
6088

6189
template <typename T>
6290
struct simple_int : float_number_generator<T> {
63-
using gen_type = std::conditional_t<sizeof(T) == 4, std::mt19937, std::mt19937_64>;
6491
std::random_device rd;
6592
std::mt19937_64 gen;
6693
std::string describe() override { return "rand()"; }
@@ -70,9 +97,8 @@ struct simple_int : float_number_generator<T> {
7097

7198
template <typename T>
7299
struct one_over_rand : float_number_generator<T> {
73-
using gen_type = std::conditional_t<sizeof(T) == 4, std::mt19937, std::mt19937_64>;
74100
std::random_device rd;
75-
gen_type gen;
101+
std::mt19937_64 gen;
76102
explicit one_over_rand() : rd(), gen(rd()) {}
77103
std::string describe() override { return "1 / rand()"; }
78104
T new_float() override {
@@ -85,9 +111,10 @@ struct one_over_rand : float_number_generator<T> {
85111
}
86112
};
87113

88-
constexpr std::array<const char*, 5> model_names = {
89-
"uniform", "integer_uniform",
90-
"simple_uniform", "simple_int",
114+
constexpr std::array<const char*, 8> model_names = {
115+
"uniform_01" , "uniform_all" , "integer_uniform" ,
116+
"centered" , "non_centered" ,
117+
"simple_uniform" , "simple_int" ,
91118
"one_over_rand"
92119
};
93120

@@ -101,23 +128,29 @@ get_generator_by_name(std::string name) {
101128
std::cout << std::endl;
102129

103130
// This is naive, but also not very important.
104-
if (name == "uniform") {
131+
if (name == "uniform_01")
105132
return std::unique_ptr<float_number_generator<T>>(new uniform_generator<T>());
133+
if (name == "uniform_all") {
134+
return std::unique_ptr<float_number_generator<T>>(
135+
new uniform_generator<T>(std::numeric_limits<T>::lowest(),
136+
std::numeric_limits<T>::max())
137+
);
106138
}
107-
if (name == "integer_uniform") {
139+
if (name == "centered")
140+
return std::unique_ptr<float_number_generator<T>>(new centered_generator<T, centered>());
141+
if (name == "non_centered")
142+
return std::unique_ptr<float_number_generator<T>>(new centered_generator<T, non_centered>());
143+
if (name == "integer_uniform")
108144
return std::unique_ptr<float_number_generator<T>>(new integer_uniform_generator<T>());
109-
}
110-
if (name == "simple_uniform") {
145+
if (name == "simple_uniform")
111146
return std::unique_ptr<float_number_generator<T>>(new simple_uniform<T>());
112-
}
113-
if (name == "simple_int") {
147+
if (name == "simple_int")
114148
return std::unique_ptr<float_number_generator<T>>(new simple_int<T>());
115-
}
116-
if (name == "one_over_rand") {
149+
if (name == "one_over_rand")
117150
return std::unique_ptr<float_number_generator<T>>(new one_over_rand<T>());
118-
}
151+
119152
std::cerr << " I do not recognize " << name << std::endl;
120-
std::cerr << " Warning: falling back on uniform generator. " << std::endl;
153+
std::cerr << " Warning: falling back on uniform_01 generator. " << std::endl;
121154
return std::unique_ptr<float_number_generator<T>>(new uniform_generator<T>());
122155
}
123156

0 commit comments

Comments
 (0)