75 lines
1.9 KiB
C++
75 lines
1.9 KiB
C++
#include <cstddef>
|
|
|
|
#include "vtr_random.h"
|
|
#include "vtr_util.h"
|
|
#include "vtr_error.h"
|
|
|
|
#define CHECK_RAND
|
|
|
|
namespace vtr {
|
|
/* Portable random number generator defined below. Taken from ANSI C by *
|
|
* K & R. Not a great generator, but fast, and good enough for my needs. */
|
|
|
|
constexpr size_t IA = 1103515245u;
|
|
constexpr size_t IC = 12345u;
|
|
constexpr size_t IM = 2147483648u;
|
|
|
|
static RandState random_state = 0;
|
|
|
|
void srandom(int seed) {
|
|
random_state = (unsigned int)seed;
|
|
}
|
|
|
|
/* returns the random_state value */
|
|
RandState get_random_state() {
|
|
return random_state;
|
|
}
|
|
|
|
int irand(int imax, RandState& state) {
|
|
/* Creates a random integer between 0 and imax, inclusive. i.e. [0..imax] */
|
|
int ival;
|
|
|
|
/* state = (state * IA + IC) % IM; */
|
|
state = state * IA + IC; /* Use overflow to wrap */
|
|
ival = state & (IM - 1); /* Modulus */
|
|
ival = (int)((float)ival * (float)(imax + 0.999) / (float)IM);
|
|
|
|
#ifdef CHECK_RAND
|
|
if ((ival < 0) || (ival > imax)) {
|
|
if (ival == imax + 1) {
|
|
/* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */
|
|
ival = imax;
|
|
} else {
|
|
throw VtrError(string_fmt("Bad value in my_irand, imax = %d ival = %d", imax, ival), __FILE__, __LINE__);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return ival;
|
|
}
|
|
|
|
int irand(int imax) {
|
|
return irand(imax, random_state);
|
|
}
|
|
|
|
float frand() {
|
|
/* Creates a random float between 0 and 1. i.e. [0..1). */
|
|
|
|
float fval;
|
|
int ival;
|
|
|
|
random_state = random_state * IA + IC; /* Use overflow to wrap */
|
|
ival = random_state & (IM - 1); /* Modulus */
|
|
fval = (float)ival / (float)IM;
|
|
|
|
#ifdef CHECK_RAND
|
|
if ((fval < 0) || (fval > 1.)) {
|
|
throw VtrError(string_fmt("Bad value in my_frand, fval = %g", fval), __FILE__, __LINE__);
|
|
}
|
|
#endif
|
|
|
|
return (fval);
|
|
}
|
|
|
|
} // namespace vtr
|