我正在使用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。有没有人知道这里有什么问题?
注意:当我没有多线程处理应用程序时,我得到相同的行为,因此问题与错误的多线程无关。
编辑正如其中一个答案所指出的那样,我不应该为两个线程使用相同的种子 - 但这是我在制定这个问题时所犯的错误,在我的真实程序中我似乎线程不同。
答案 0 :(得分:1)
正如this article(以及Stack Overflow主持人的later article)所述,真正的随机性并不能完美分配。
良好的随机性:
随机性差:
我真的建议阅读这篇文章,但总结一下: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
发布,我对rnum
和hist
使用了以下修改来测试它,它看起来也很好:
double rnum = normal(engine);
++hist[std::round(10*rnum)];
答案 2 :(得分:0)
首先 - 只是因为你得到两次相同的数字并不意味着它不是随机的。如果你掷骰子六次,你会期待六种不同的结果吗?看生日悖论。话虽这么说 - 你是对的,你不应该在这种特殊情况下看到太多的重复。
我不熟悉“#pragma omp parallel”,但我的猜测是你产生了多个线程,所有线程都使用相同的种子(0)播种mt19937。你应该为所有线程使用不同的种子 - 例如线程ID。