OpenFPGA/libs/libvtrutil/src/vtr_random.cpp

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