我在使用rand_r时遇到了麻烦。我有一个生成数百万随机数的模拟。我注意到,在某个时间点,这些数字不再是统一的。可能是什么问题?
我做什么:我创建一个生成器的实例,并给它自己的种子。
mainRGen= new nativeRandRUni(idumSeed_g);
这是类/对象def:
class nativeRandRUni {
public:
unsigned seed;
nativeRandRUni(unsigned sd){ seed= sd; }
float genP() { return (rand_r(&seed))/float(RAND_MAX); } // [0,1]
int genI(int R) { return (rand_r(&seed) % R); } // [0,R-1]
};
数字简单地由以下方式生成:
newIntNumber= mainRGen->genI(desired_max);
newFloatNumber= mainRGen->genP();
模拟具有上述问题。我知道这种情况正在发生,因为我已经检查了结果中显示签名的时间点之后生成的数字的分布(参见本顶部图片,http://ubuntuone.com/0tbfidZaXfGNTfiVr3x7DR)
另外,如果我在t-1和t打印种子,是签名的时间点,我可以看到种子从值263069042到1069048066变化一个数量级
如果我使用不同的种子运行代码,问题总是存在,但在不同的时间点
此外,如果我使用rand()而不是我的对象,一切顺利...我需要对象原因有时我使用线程。上面的例子没有线程。
我真的迷失在这里,有任何线索吗?
编辑 - 编辑
它可以通过循环足够多次来重现,问题是,就像我说的那样,需要数百万次迭代才能出现问题。对于种子-158342163,我在世代t = 134065568得到它。可以检查之前(均匀)和之后(不均匀)生成的数字。如果我在给定的t上手动更改种子,我会遇到同样的问题,请参阅代码中的(*)。我也不希望发生什么?
#include <tr1/random>
#include <fstream>
#include <sstream>
#include <iostream>
using std::ofstream;
using std::cout;
using std::endl;
class nativeRandRUni {
public:
unsigned seed;
long count;
nativeRandRUni(unsigned sd){ seed= sd; count=0; }
float genP() { count++; return (rand_r(&seed))/float(RAND_MAX); } // [0,1]
int genI(int R) { count++; return (rand_r(&seed) % R); } // [0,R-1]
};
int main(int argc, char *argv[]){
long timePointOfProblem= 134065568;
nativeRandRUni* mainRGen= new nativeRandRUni(-158342163);
int rr;
//ofstream* fout_metaAux= new ofstream();
//fout_metaAux->open("random.numbers");
for(int i=0; i< timePointOfProblem; i++){
rr= mainRGen->genI(1009200);
//(*fout_metaAux) << rr << endl;
//if(i%1000==0) mainRGen->seed= 111111; //(*) FORCE
}
//fout_metaAux->close();
}
答案 0 :(得分:1)
鉴于随机数是模拟的关键,您应该实现自己的生成器。我不知道rand_r正在使用什么算法,但它可能像线性全等生成器一样非常糟糕。
我会考虑快速实现一些具有良好品质的东西,你知道底层算法。我首先考虑实施Mersenne Twister:
http://en.wikipedia.org/wiki/Mersenne_twister
它易于实现且速度非常快 - 不需要分割。
答案 1 :(得分:1)
最终尝试使用boost的简单解决方案,将生成器更改为:
class nativeRandRUni {
public:
typedef mt19937 EngineType;
typedef uniform_real<> DistributionType;
typedef variate_generator<EngineType, DistributionType> VariateGeneratorType;
nativeRandRUni(long s, float min, float max) : gen(EngineType(s), DistributionType(min, max)) {}
VariateGeneratorType gen;
};
我不再解决问题了......它解决了它,我不觉得不明白它是什么感觉很舒服。我认为拉斐尔是对的,我不应该信任rand_r这一代人的密集数量
现在,这比以前慢,所以我可能会寻找优化它的方法。 问题:原则上Mersenne Twister的实施会更快吗?
感谢大家!