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+
3262template <typename T>
3363struct 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
4877template <typename T>
4978struct 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
6189template <typename T>
6290struct 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
7198template <typename T>
7299struct 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