我正在对一个问题进行数值模拟,我需要先生成N / 2 0和其他1的N个元素数组。随着每次迭代,数组被混洗,并且从先前的迭代中随机选择下一个数组元素,直到仅剩下0或1。我正在记录T次试验中的迭代次数。为了生成随机整数,我使用rand()
的discard-modulo方法(从here获得了想法)。
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <fstream>
#include <algorithm>
#include <array>
using namespace std;
//generate random integer between 0 and MAX
int randomn(int MAX);
int main()
{
const int N = 10000;
const int T = 100; //Number of trials
srand((unsigned)time(0));
ofstream writefile ("Observation.out");
for (int indexT = 0; indexT < T; indexT++) {
//initializing myArray
array<bool, N> myArray;
array<bool, N> newArray;
auto middle = myArray.begin() + myArray.size() / 2;
fill(myArray.begin(), middle, false);
fill(middle, myArray.end(), true);
int counterIt = 0; //desired Iteration number
for (;;) {
int counterF = 0;
int randompos = 0;
bool savedata = true;
//suffling myArray using Fisher–Yates shuffle
for (int indexN = N-1; indexN > 0; indexN--) {
randompos = randomn(indexN);
savedata = myArray[randompos];
myArray[randompos] = myArray[indexN] ;
myArray[indexN] = savedata;
}
//next Iteration
for (int indexN = 0; indexN < N; indexN++) {
randompos = randomn(N-1);
savedata = myArray[randompos];
newArray[indexN] = savedata;
if (savedata == false){
counterF += 1;
}
}
copy(begin(newArray), end(newArray), begin(myArray));
//updating Iteration number
counterIt += 1;
if ((counterF == 0)|| (counterF == N)) {
break;
}
}
writefile << indexT+1 <<"\t"<<counterIt <<endl;
}
writefile.close();
return 0;
}
int randomn (int MAX){
int temp;
for (;;){
temp = rand();
if ( temp < RAND_MAX - RAND_MAX%(MAX+1) )
return temp%(MAX+1);
}
}
输出非常有趣。输出中的前几个数字(每次试验的迭代次数)不同,但无论我运行多少次,它都会收敛到振荡。 以下是输出的两个示例:
1st run 2nd run
1 28278 1 13583
2 7754 2 7308
3 11308 3 22580
4 5093 4 6307 ** oscillation starts
5 4952 5 42060
6 5017 6 10485
7 10400 7 8525
8 6307 ** 8 31061
9 42060 9 6307 ** 1st period
10 10485 10 42060
11 8525 11 10485
12 31061 12 8525
13 6307 ** 13 31061
14 42060 14 6307 ** 2nd period
15 10485 15 42060
现在我知道rand()
不是这项工作的最佳功能(更好的选择是c ++ 11中的<rand>
库)。
但它是如何从任何初始随机数汇总到这个确切的时期
6307 - 42060 - 10485 - 8525 - 31061
?
观察:该程序在该周期中使用恰好2^31
个随机数,即随机数生成函数的周期。 但是如何?
答案 0 :(得分:1)
rand()
不应该用于任何严肃的事情。它的质量可能非常差。
例如,我用它进行了模拟,我知道确切的答案。使用rand()
时,模拟会收敛到与确切答案略有不同的数字。我用更好的东西替换了rand()
,并且:
一个常见的建议是使用mersenne twister代替。但是,即使MT有shortcomings,它也没有通过BigCrush测试。
然而,这个简单的随机生成器通过并且非常快(xorshift128+):
uint64_t s[2]; // seed this
uint64_t next(void) {
uint64_t s1 = s[0];
const uint64_t s0 = s[1];
const uint64_t result = s0 + s1;
s[0] = s0;
s1 ^= s1 << 23; // a
s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); // b, c
return result;
}