Skip to content

Commit 7a2cf8d

Browse files
authored
Merge pull request #2793 from verilog-to-routing/temp_rand_remove_static
Random number generation classes
2 parents 30b4927 + b83c603 commit 7a2cf8d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+705
-502
lines changed

libs/libvtrutil/src/specrand.cpp

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,15 @@
5252

5353
#include "specrand.h"
5454

55-
/* Period parameters */
56-
#define N 624
57-
#define M 397
58-
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
59-
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
60-
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
61-
62-
static unsigned long mt[N]; /* the array for the state vector */
63-
static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
64-
65-
void spec_srand(int seed) {
66-
spec_init_genrand((unsigned long)seed);
55+
double SpecRandomNumberGenerator::spec_rand_() {
56+
return spec_genrand_int32_() * (1.0 / 4294967296.0);
6757
}
6858

69-
/* Just a copy of spec_genrand_real2() */
70-
double spec_rand() {
71-
return spec_genrand_int32() * (1.0 / 4294967296.0);
59+
long SpecRandomNumberGenerator::spec_lrand48_() {
60+
return (long)(spec_genrand_int32_() >> 1);
7261
}
7362

74-
/* Just a copy of spec_genrand_int31() */
75-
long spec_lrand48() {
76-
return (long)(spec_genrand_int32() >> 1);
77-
}
78-
79-
/* initializes mt[N] with a seed */
80-
void spec_init_genrand(unsigned long s) {
63+
void SpecRandomNumberGenerator::spec_init_genrand_(unsigned long s) {
8164
mt[0] = s & 0xffffffffUL;
8265
for (mti = 1; mti < N; mti++) {
8366
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
@@ -90,16 +73,11 @@ void spec_init_genrand(unsigned long s) {
9073
}
9174
}
9275

93-
/* initialize by an array with array-length */
94-
/* init_key is the array for initializing keys */
95-
/* key_length is its length */
96-
/* slight change for C++, 2004/2/26 */
97-
void spec_init_by_array(unsigned long init_key[], int key_length) {
98-
int i, j, k;
99-
spec_init_genrand(19650218UL);
100-
i = 1;
101-
j = 0;
102-
k = (N > key_length ? N : key_length);
76+
void SpecRandomNumberGenerator::spec_init_by_array_(const unsigned long init_key[], size_t key_length) {
77+
spec_init_genrand_(19650218UL);
78+
size_t i = 1;
79+
size_t j = 0;
80+
size_t k = (N > key_length ? N : key_length);
10381
for (; k; k--) {
10482
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL))
10583
+ init_key[j] + j; /* non linear */
@@ -127,22 +105,21 @@ void spec_init_by_array(unsigned long init_key[], int key_length) {
127105
}
128106

129107
/* generates a random number on [0,0xffffffff]-interval */
130-
unsigned long spec_genrand_int32() {
108+
unsigned long SpecRandomNumberGenerator::spec_genrand_int32_() {
131109
unsigned long y;
132110
static unsigned long mag01[2] = {0x0UL, MATRIX_A};
133111
/* mag01[x] = x * MATRIX_A for x=0,1 */
134112

135113
if (mti >= N) { /* generate N words at one time */
136-
int kk;
137114

138115
if (mti == N + 1) /* if init_genrand() has not been called, */
139-
spec_init_genrand(5489UL); /* a default initial seed is used */
116+
spec_init_genrand_(5489UL); /* a default initial seed is used */
140117

141-
for (kk = 0; kk < N - M; kk++) {
118+
for (size_t kk = 0; kk < N - M; kk++) {
142119
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
143120
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
144121
}
145-
for (; kk < N - 1; kk++) {
122+
for (size_t kk; kk < N - 1; kk++) {
146123
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
147124
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
148125
}
@@ -163,32 +140,45 @@ unsigned long spec_genrand_int32() {
163140
return y;
164141
}
165142

166-
/* generates a random number on [0,0x7fffffff]-interval */
167-
long spec_genrand_int31() {
168-
return (long)(spec_genrand_int32() >> 1);
143+
long SpecRandomNumberGenerator::spec_genrand_int31_() {
144+
return (long)(spec_genrand_int32_() >> 1);
169145
}
170146

171-
/* generates a random number on [0,1]-real-interval */
172-
double spec_genrand_real1() {
173-
return spec_genrand_int32() * (1.0 / 4294967295.0);
147+
double SpecRandomNumberGenerator::spec_genrand_real1_() {
148+
return spec_genrand_int32_() * (1.0 / 4294967295.0);
174149
/* divided by 2^32-1 */
175150
}
176151

177-
/* generates a random number on [0,1)-real-interval */
178-
double spec_genrand_real2() {
179-
return spec_genrand_int32() * (1.0 / 4294967296.0);
152+
double SpecRandomNumberGenerator::spec_genrand_real2_() {
153+
return spec_genrand_int32_() * (1.0 / 4294967296.0);
180154
/* divided by 2^32 */
181155
}
182156

183-
/* generates a random number on (0,1)-real-interval */
184-
double spec_genrand_real3() {
185-
return (((double)spec_genrand_int32()) + 0.5) * (1.0 / 4294967296.0);
157+
double SpecRandomNumberGenerator::spec_genrand_real3_() {
158+
return (((double)spec_genrand_int32_()) + 0.5) * (1.0 / 4294967296.0);
186159
/* divided by 2^32 */
187160
}
188161

189-
/* generates a random number on [0,1) with 53-bit resolution*/
190-
double spec_genrand_res53() {
191-
unsigned long a = spec_genrand_int32() >> 5, b = spec_genrand_int32() >> 6;
162+
double SpecRandomNumberGenerator::spec_genrand_res53_() {
163+
unsigned long a = spec_genrand_int32_() >> 5, b = spec_genrand_int32_() >> 6;
192164
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
193165
}
194-
/* These real versions are due to Isaku Wada, 2002/01/09 added */
166+
167+
void SpecRandomNumberGenerator::srandom(int seed) {
168+
spec_init_genrand_((unsigned long)seed);
169+
}
170+
171+
int SpecRandomNumberGenerator::irand(int imax) {
172+
return (int)(spec_genrand_int31_() % (imax + 1));
173+
}
174+
175+
float SpecRandomNumberGenerator::frand() {
176+
return (float)spec_genrand_real2_();
177+
}
178+
179+
SpecRandomNumberGenerator::SpecRandomNumberGenerator(int seed) {
180+
spec_init_genrand_((unsigned long)seed);
181+
}
182+
183+
SpecRandomNumberGenerator::SpecRandomNumberGenerator()
184+
: SpecRandomNumberGenerator(0) {}

libs/libvtrutil/src/specrand.h

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,35 +52,69 @@
5252
/* Slightly modified for use in SPEC CPU by Cloyce D. Spradling (5 Nov 2009)
5353
*/
5454

55-
void spec_srand(int seed);
56-
double spec_rand();
57-
long spec_lrand48();
55+
#include "vtr_random.h"
5856

59-
/* initializes mt[N] with a seed */
60-
void spec_init_genrand(unsigned long s);
57+
class SpecRandomNumberGenerator : public vtr::RandomNumberGeneratorInterface {
58+
public:
59+
SpecRandomNumberGenerator(const SpecRandomNumberGenerator&) = delete;
60+
SpecRandomNumberGenerator& operator=(SpecRandomNumberGenerator& other) = delete;
6161

62-
/* initialize by an array with array-length */
63-
/* init_key is the array for initializing keys */
64-
/* key_length is its length */
65-
/* slight change for C++, 2004/2/26 */
66-
void spec_init_by_array(unsigned long init_key[], int key_length);
62+
SpecRandomNumberGenerator();
63+
explicit SpecRandomNumberGenerator(int seed);
6764

68-
/* generates a random number on [0,0xffffffff]-interval */
69-
unsigned long spec_genrand_int32();
65+
virtual void srandom(int seed) override;
66+
virtual int irand(int imax) override;
67+
virtual float frand() override;
7068

71-
/* generates a random number on [0,0x7fffffff]-interval */
72-
long spec_genrand_int31();
69+
private:
70+
/// @brief initializes mt[N] with a seed
71+
void spec_init_genrand_(unsigned long s);
7372

74-
/* generates a random number on [0,1]-real-interval */
75-
double spec_genrand_real1();
73+
/**
74+
* @brief initialize by an array with array-length
75+
* @param init_key the array for initializing keys
76+
* @param key_length the length of array
77+
*/
78+
void spec_init_by_array_(const unsigned long init_key[], size_t key_length);
7679

77-
/* generates a random number on [0,1)-real-interval */
78-
double spec_genrand_real2();
80+
/// @brief generates a random number on [0,0xffffffff]-interval
81+
unsigned long spec_genrand_int32_();
7982

80-
/* generates a random number on (0,1)-real-interval */
81-
double spec_genrand_real3();
83+
/// @brief Just a copy of spec_genrand_real2()
84+
double spec_rand_();
85+
/// @brief Just a copy of spec_genrand_int31()
86+
long spec_lrand48_();
8287

83-
/* generates a random number on [0,1) with 53-bit resolution*/
84-
double spec_genrand_res53();
88+
/// @brief generates a random number on [0,0x7fffffff]-interval */
89+
long spec_genrand_int31_();
90+
91+
/// @brief generates a random number on [0,1]-real-interval
92+
double spec_genrand_real1_();
93+
94+
/// @brief generates a random number on [0,1)-real-interval
95+
double spec_genrand_real2_();
96+
97+
/// @brief generates a random number on (0,1)-real-interval
98+
double spec_genrand_real3_();
99+
100+
/// @brief generates a random number on [0,1) with 53-bit resolution
101+
double spec_genrand_res53_();
102+
103+
private:
104+
/// Period parameters
105+
static constexpr size_t M = 397;
106+
static constexpr size_t N = 624;
107+
/// constant vector a
108+
static constexpr unsigned long MATRIX_A = 0x9908b0dfUL;
109+
/// most significant w-r bits
110+
static constexpr unsigned long UPPER_MASK = 0x80000000UL;
111+
/// least significant r bits
112+
static constexpr unsigned long LOWER_MASK = 0x7fffffffUL;
113+
/// mti==N+1 means mt[N] is not initialized
114+
size_t mti = N + 1;
115+
/// the array for the state vector
116+
unsigned long mt[N];
117+
118+
};
85119

86120
#endif

libs/libvtrutil/src/vtr_random.cpp

Lines changed: 39 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,67 @@
1-
#include <cstddef>
21

32
#include "vtr_random.h"
3+
#include "specrand.h"
44
#include "vtr_util.h"
55
#include "vtr_error.h"
6-
#include "specrand.h"
7-
8-
#define CHECK_RAND
96

107
namespace vtr {
11-
/* Portable random number generator defined below. Taken from ANSI C by *
12-
* K & R. Not a great generator, but fast, and good enough for my needs. */
138

14-
constexpr size_t IA = 1103515245u;
15-
constexpr size_t IC = 12345u;
16-
constexpr size_t IM = 2147483648u;
17-
18-
static RandState random_state = 0;
19-
20-
/**
21-
* @brief The pseudo-random number generator is initialized using the argument passed as seed.
22-
*/
23-
void srandom(int seed) {
24-
random_state = (unsigned int)seed;
25-
#ifdef SPEC_CPU
26-
/* SPEC CPU requires a different random number generator */
27-
spec_init_genrand((unsigned long)seed);
28-
#endif
9+
RandomNumberGenerator::RandomNumberGenerator(int seed) {
10+
random_state_ = (unsigned int)seed;
2911
}
3012

31-
/* returns the random_state value */
32-
RandState get_random_state() {
33-
return random_state;
13+
RandomNumberGenerator::RandomNumberGenerator()
14+
: RandomNumberGenerator(0) {}
15+
16+
void RandomNumberGenerator::srandom(int seed) {
17+
random_state_ = (unsigned int)seed;
3418
}
3519

36-
int irand(int imax, RandState& state) {
37-
#ifdef SPEC_CPU
38-
/* SPEC CPU requires a different random number generator */
39-
return (int)(spec_genrand_int31() % (imax + 1));
40-
#else
41-
/* Creates a random integer between 0 and imax, inclusive. i.e. [0..imax] */
20+
int RandomNumberGenerator::irand(int imax) {
21+
// Creates a random integer between 0 and imax, inclusive. i.e. [0..imax]
4222
int ival;
4323

44-
/* state = (state * IA + IC) % IM; */
45-
state = state * IA + IC; /* Use overflow to wrap */
46-
ival = state & (IM - 1); /* Modulus */
24+
// state = (state * IA + IC) % IM;
25+
random_state_ = random_state_ * IA + IC; // Use overflow to wrap
26+
ival = random_state_ & (IM - 1); // Modulus
4727
ival = (int)((float)ival * (float)(imax + 0.999) / (float)IM);
4828

49-
# ifdef CHECK_RAND
50-
if ((ival < 0) || (ival > imax)) {
51-
if (ival == imax + 1) {
52-
/* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */
53-
ival = imax;
54-
} else {
55-
throw VtrError(string_fmt("Bad value in my_irand, imax = %d ival = %d", imax, ival), __FILE__, __LINE__);
29+
if constexpr (CHECK_RAND_CONSTEXPR) {
30+
if ((ival < 0) || (ival > imax)) {
31+
if (ival == imax + 1) {
32+
// Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1
33+
ival = imax;
34+
} else {
35+
throw VtrError(string_fmt("Bad value in my_irand, imax = %d ival = %d", imax, ival), __FILE__, __LINE__);
36+
}
5637
}
5738
}
58-
# endif
5939

6040
return ival;
61-
#endif
6241
}
6342

64-
int irand(int imax) {
65-
return irand(imax, random_state);
66-
}
43+
float RandomNumberGenerator::frand() {
44+
random_state_ = random_state_ * IA + IC; /* Use overflow to wrap */
45+
int ival = random_state_ & (IM - 1); /* Modulus */
46+
float fval = (float)ival / (float)IM;
6747

68-
float frand() {
69-
/* Creates a random float between 0 and 1. i.e. [0..1). */
70-
#ifdef SPEC_CPU
71-
/* SPEC CPU requires a different random number generator */
72-
return (float)spec_genrand_real2();
73-
#else
74-
float fval;
75-
int ival;
48+
if constexpr (CHECK_RAND_CONSTEXPR) {
49+
if (fval < 0 || fval > 1.) {
50+
throw VtrError(string_fmt("Bad value in my_frand, fval = %g", fval), __FILE__, __LINE__);
51+
}
52+
}
7653

77-
random_state = random_state * IA + IC; /* Use overflow to wrap */
78-
ival = random_state & (IM - 1); /* Modulus */
79-
fval = (float)ival / (float)IM;
54+
return fval;
55+
}
8056

81-
# ifdef CHECK_RAND
82-
if ((fval < 0) || (fval > 1.)) {
83-
throw VtrError(string_fmt("Bad value in my_frand, fval = %g", fval), __FILE__, __LINE__);
57+
RngContainer::RngContainer(int seed) {
58+
if constexpr (SPEC_CPU_CONSTEXPR) {
59+
rng_ = std::make_unique<SpecRandomNumberGenerator>(seed);
60+
} else {
61+
rng_ = std::make_unique<vtr::RandomNumberGenerator>(seed);
8462
}
85-
# endif
86-
87-
return (fval);
88-
#endif
8963
}
9064

65+
RngContainer::RngContainer()
66+
: RngContainer(0) {}
9167
} // namespace vtr

0 commit comments

Comments
 (0)