[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
相关文章推荐
- Android——C语言、JNI与低层调用
- C++ 11(二)
- C++第四次实验——项目二
- 那些关于C语言的一些事
- C语言逻辑运算短路(与运算、或运算)
- C++字符串类
- C++第四次实验——作业
- C++中cin、cin.get()、cin.getline()、getline()、gets()等函数的用法
- C语言之数据类型(第一天)
- 【C++】Geekband-专题四:traints的使用
- 用C语言实现简单的计算器(加、减、乘、除)
- 用C语言打印出杨辉三角
- C语言小游戏设计报告
- C++中的explicit关键字(转)
- 作业:C++作业4
- 用C语言做一个通讯录
- base64加密解密c++的简单实现
- 编程学习笔记之c++相关::vector学习心得
- C语言中,为什么字符串可以赋值给字符指针变量
- 字符串反转引发的char str[]="abc"和char *str="abc"思考