自强不息，有容乃大

posts - 139, comments - 80, trackbacks - 0, articles - 0
::  ::  ::  ::

Linear Congruential Generator (LCG) represents one of the oldest and best-known pseudorandomnumbergenerator algorithms.

The generator is defined by the recurrencerelation:

$X_{n+1} \equiv \left( a X_n + c \right)~~\pmod{m}$

where $X$ is the sequence of pseudorandom values, and

$m,\, 0 — the "modulus"
$a,\,0 < a < m$ — the "multiplier"
$c,\,0 \le c < m$ — the "increment"
$X_0,\,0 \le X_0 < m$ — the "seed" or "start value"

are integer constants that specify the generator. If c = 0, the generator is often called a multiplicative congruential method, or LehmerRNG. If c ≠ 0, the generator is called a mixed congruential method.

The period of a general LCG is at most m, and for some choices of a much less than that. Provided that c is nonzero, the LCG will have a full period for all seed values if and only if:

1. $\,c$ and $\,m$ are relatively prime,
2. $\,a - 1$ is divisible by all prime factors of $\,m$,
3. $\,a - 1$ is a multiple of 4 if $\,m$ is a multiple of 4.

These three requirements are referred to as the Hull-Dobell Theorem. While LCGs are capable of producing decent pseudorandom numbers, this is extremely sensitive to the choice of the parameters cm, and a.

Historically, poor choices had led to ineffective implementations of LCGs. A particularly illustrative example of this is RANDU which was widely used in the early 1970s and led to many results which are currently being questioned because of the use of this poor LCG.

The most efficient LCGs have an m equal to a power of 2, most often m = 232 or m = 264, because this allows the modulus operation to be computed by merely truncating all but the rightmost 32 or 64 bits.

static unsigned int mySeed = 1;

void mySrand(unsigned int seed) {
mySeed = seed;
}

unsigned int myRand(){
mySeed = mySeed * 214013 + 2531011;
return (unsigned int)((mySeed >> 16) & 0x7fff);
}

mySrand传入的参数即为初始种子，每次调用myRand会取得一个随机数，且调用myRand产生的随机数取决于之前的mySeed值，mySeed一直在变，故随机数也随之改变。

#include <map>
#include <iostream>
class Randint { // 均匀分布，假定32位long
unsigned long randx;
public:
Randint(long s = 0) { randx = s; }
void seed(long s) { randx = s; }

// 魔幻数选用32位long中的31位
long abs(long x) { return x&0x7fffffff; }
static double max() { return 2147483648.0; } // 注意：double
long draw() { return randx = randx * 1103515245; }
double  fdraw() { return abs(draw()) / max(); } // 在区间[0, 1]
long operator() () { return abs(draw()); } // 在区间[0, pow(2, 31)]
};

class Urand : public Randint { // 均匀分布，区间[0:n]
long n;
public:
Urand(long nn) { n = nn; }
long operator() () { long r = n * fdraw(); return (r == n) ? n-1 : r; }
};

class Erand : public Randint { // 指数分布随机数生成器
long mean;
public:
Erand(long m) { mean = m; }
long operator() () { return -mean * long( (max() - draw()) / max() + .5); }
};

int main () {
const int count = 10;
Urand temp(count);
temp.seed(time(NULL));
std::map<int, int>bucket;
for (int i = 0; i < 1000000; ++i) {
bucket[temp()]++;
}
for (int i = 0; i < count; ++i) {
std::cout << bucket[i] << '\n';
}
}