您的位置:首页 > 编程语言 > C语言/C++

[C++]pseudo-random numbers(random库)

2016-04-23 20:53 417 查看

pseudo-random numbers(random库)

Description:

First you need to know is the idea of the method:

1. Linear-Congruential: (a * x + c) % m, a > 0, m > 0, m % a < m / a.

This formulus is a linear function to generate random numbers

a - multiplier | x - seed | c - increment | m - modulus

note: You may know that every random-number-engin generater need a seed.

2. calculation of (a * x + c) % m.

This formula need to avoid integer overflow, that means when x is

very big like 2147483646, it should still return the right answer.

The algorithm is very well-known and you should find by yourself.

Then, you should learn something about ‘mod’ and ‘linear_congruential_engine’

1. class mod is a model for linear_congruential_engine, which realize the

formula “(a * x + c) % m” in calc();

2. class linear_congruential_engine is a generater which sets seed and make

random-number with its public member ‘mod_temp’

———- mod_my ———-

int m, a, c; // This define the three parameters for the formula.

mod_my(int _m, int _a, int _c); // Constructer, initialize three params.

int calc(int x); // Caculator, take x as a seed to make number and return.

———- linear_congruential_engine ———-

int multiplier, increment, modulus; // Correspond to a, c, m

// Initialize to 16807, 1, 2147483647 as default.

unsigned int default_seed_my, seed_my; // Initialize to 1u as default.

mod_my mod_temp; // It is the model for this engin.

linear_congruential_engine_my(); // Default constructer.

linear_congruential_engine_my(int _m, int _a, int _c, int _s);

void seed(unsigned int); // Set seed.

int min(); // Return the least bound of the range

int max(); // Return the most bound of the range.

void discard(unsigned long long); // Discard the generator.

// Use its own seed to generate x random numbers (x is the input param).

int operator()(); // Overload the ‘()’

Answer:

#include <iostream>
#include "random_my.h"
using namespace std;
using namespace RAND_GEN;

void test_calc() {
mod_my mod_1(9223372036854775807, 16807, 1);
if (mod_1.calc(9223372036854775) != 7443261233741790514 ||
mod_1.calc(922337203685477580) != 6456360425798331301 ||
mod_1.calc(9223372036852222220) != 9223371993936639099 ||
mod_1.calc(922337203685473330) != 6456360425726901551 ||
mod_1.calc(9223372022254775806) != 9223126654654759001)
cout << "Your calc() is wrong.\n";
else cout << "Pass all tests for calc().\n";
}

void test_engin() {
linear_congruential_engine_my lce;
int count = 1000;
int num[1001] = {0};
while (count--) num[lce()%5]++;
if (num[0] != 216 || num[1] != 190 ||
num[2] != 203 || num[3] != 216 ||
num[4] != 175) {
cout << "Your engin class is wrong in generator.\n";
return;
} else if (lce.min() != (lce.increment == 0u ? 1u : 0u)) {
cout << "Your engin class is wrong in min().\n";
return;
} else if (lce.max() != (lce.modulus - 1u)) {
cout << "Your engin class is wrong in max().\n";
return;
}
else cout << "Pass all tests for class engin.\n";
}

void hard_test() {
long long m, a, c, n, num[5] = {0};
unsigned long long s;
unsigned long long discard_n;
cin >> m >> a >> c >> s;
mod_my mod_1(m, a, c);
for (int i = 0; i < 5; i++) {
cin >> n;
cout << "(MOD CALC) ";
cout << n << ": " << mod_1.calc(n) << endl;
}
linear_congruential_engine_my lce(m, a, c, s);
cin >> discard_n;
lce.discard(discard_n);
cin >> n;
while (n--) num[lce()%5]++;
for (int i = 0; i < 5; i++) {
cout << "(ENGIN) ";
cout << i << ": " << num[i] << endl;
}
}

int main() {
int t;
cin >> t;
if (t == 0) {
test_calc();
test_engin();
} else {
hard_test();
}
return 0;
}


#ifndef RANDOM_MY_H
#define RANDOM_MY_H

namespace RAND_GEN {
class mod_my {
public:
long long m, a, c;
mod_my(long long _m, long long _a, long long _c) : m(_m), a(_a), c(_c) {}

long long calc(long long x) {
if (a == 1) {
x %= m;
} else {
long long q = m / a;
long long r = m % a;
long long t1 = a * (x % q);
long long t2 = r * (x / q);
if (t1 >= t2) x = t1 - t2;
else x = m - t2 + t1;
}
if (c != 0) {
const long long d = m - x;
if (d > c) x += c;
else x = c - d;
}
return x;
}
};

class linear_congruential_engine_my {
public:
long long multiplier, increment, modulus;
unsigned long long default_seed_my, seed_my;
mod_my mod_temp;

linear_congruential_engine_my()
: multiplier(16807), increment(1), modulus(2147483647)
, default_seed_my(1u), mod_temp(modulus, multiplier, increment)
{ seed(default_seed_my); }

linear_congruential_engine_my(long long _m, long long _a,
long long _c, long long _s)
: multiplier(_a), increment(_c), modulus(_m)
, default_seed_my(_s), mod_temp(modulus, multiplier, increment)
{ seed(default_seed_my); }

void seed(unsigned long long s)
{ seed_my = s; }

long long min()
{ return  increment == 0u ? 1u : 0u; }

long long max()
{ return modulus - 1u; }

void discard(unsigned long long z)
{ for (; z != 0ULL; --z) (*this)(); }

long long operator()() {
seed_my = mod_temp.calc(seed_my);
return seed_my;
}
};

}  // namespace RAND_GEN

#endif


Schrage’s algorithm

//  General case for x = (ax + c) mod m -- use Schrage's algorithm
//  to avoid integer overflow.
//  (ax + c) mod m can be rewritten as:
//    a(x mod q) - r(x / q)  if >= 0
//    a(x mod q) - r(x / q)  otherwise
//  where: q = m / a , r = m mod a
//
//  Preconditions:  a > 0, m > 0.
//
//  Note: only works correctly for m % a < m / a.    long long calc(long long x) {
if (a == 1) {
x %= m;
} else {
long long q = m / a;
long long r = m % a;
long long t1 = a * (x % q);
long long t2 = r * (x / q);
if (t1 >= t2) x = t1 - t2;
else x = m - t2 + t1;
}
if (c != 0) {
const long long d = m - x;
if (d > c) x += c;
else x = c - d;
}
return x;
}


此处提供此算法的解析,见:

http://blog.csdn.net/linwh8/article/details/51248227#t2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: