mt19937生成的重复值

时间:2013-04-15 13:29:27

标签: c++ random prng mersenne-twister

我正在使用C ++ 11的random库,我有一个小程序,它在单位半径的圆上生成坐标对x,y。这是简单的多线程程序

#include <iostream>
#include <fstream>
#include <random>

using namespace std;



int main()
{
    const double PI = 3.1415;



    double angle, radius, X, Y;
    int i;
    vector<double> finalPositionX, finalPositionY;

    #pragma omp parallel
    {
        vector <double> positionX, positionY;

        mt19937 engine(0);
        uniform_real_distribution<> uniform(0, 1);
        normal_distribution<double> normal(0, 1);



        #pragma omp for private(angle, radius, X, Y)
        for(i=0; i<1000000; ++i)
        {
            angle  = uniform(engine)*2.0*PI;
            radius = sqrt(uniform(engine));
            X      = radius*cos(angle);
            Y      = radius*sin(angle);

            positionX.push_back(X);
            positionY.push_back(Y);
        }
        #pragma omp barrier

        #pragma omp critical
        finalPositionX.insert(finalPositionX.end(), positionX.begin(), positionX.end());
        finalPositionY.insert(finalPositionY.end(), positionY.begin(), positionY.end());
    }


    ofstream output_data("positions.txt", ios::out);
    output_data.precision(9);
    for(unsigned long long temp_var=0; temp_var<(unsigned long long)finalPositionX.size(); temp_var++)
    {
        output_data << finalPositionX[temp_var]
                    << "\t\t\t\t"
                    << finalPositionY[temp_var]
                    << "\n";
    }
    output_data.close();
    return 0;
}

问题:许多x坐标出现两次(与y坐标相同)。我不明白这一点,因为mt19937的时间远远超过1.000.000。有没有人知道这里有什么问题?

注意:当我没有多线程处理应用程序时,我得到相同的行为,因此问题与错误的多线程无关。

编辑正如其中一个答案所指出的那样,我不应该为两个线程使用相同的种子 - 但这是我在制定这个问题时所犯的错误,在我的真实程序中我似乎线程不同。

3 个答案:

答案 0 :(得分:1)

正如this article(以及Stack Overflow主持人的later article)所述,真正的随机性并不能完美分配。

良好的随机性:

enter image description here

随机性差:

enter image description here

我真的建议阅读这篇文章,但总结一下:RNG必须是不可预测的,这意味着调用它100次不一定能完全填满10x10网格。

答案 1 :(得分:1)

使用代码的核心部分,我编写了这个不完美的测试,但从我可以看到的分布是非常统一的:

#include <iostream>
#include <fstream>
#include <random>
#include <map>
#include <iomanip>

using namespace std;

int main()
{
    int i;
    vector<double> finalPositionX, finalPositionY; 
    std::map<int, int> hist;


    vector <double> positionX, positionY;

    mt19937 engine(0);
    uniform_real_distribution<> uniform(0, 1);
    //normal_distribution<double> normal(0, 1);
    for(i=0; i<1000000; ++i)
    {
        double rnum = uniform(engine);            

       ++hist[std::round(1000*rnum)];

    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }

    return 0;
}

正如其他人已经说过,重复看到一些价值并不出人意料。对于normal发布,我对rnumhist使用了以下修改来测试它,它看起来也很好:

double rnum = normal(engine);                  
++hist[std::round(10*rnum)];

答案 2 :(得分:0)

首先 - 只是因为你得到两次相同的数字并不意味着它不是随机的。如果你掷骰子六次,你会期待六种不同的结果吗?看生日悖论。话虽这么说 - 你是对的,你不应该在这种特殊情况下看到太多的重复。

我不熟悉“#pragma omp parallel”,但我的猜测是你产生了多个线程,所有线程都使用相同的种子(0)播种mt19937。你应该为所有线程使用不同的种子 - 例如线程ID。