rand():奇怪的行为

时间:2017-07-02 23:04:15

标签: c++ random

我正在对一个问题进行数值模拟,我需要先生成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个随机数,即随机数生成函数的周期。 但是如何?

1 个答案:

答案 0 :(得分:1)

rand()不应该用于任何严肃的事情。它的质量可能非常差。

例如,我用它进行了模拟,我知道确切的答案。使用rand()时,模拟会收敛到与确切答案略有不同的数字。我用更好的东西替换了rand(),并且:

  • 模拟速度提高了3倍
  • 模拟融合到确切的解决方案。

一个常见的建议是使用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; 
}

查看http://xoroshiro.di.unimi.it/及其最新的生成器xoroshiro128+

相关问题