3

我在使用 rand_r 时遇到问题。我有一个生成数百万随机数的模拟。我注意到在某个时间点,这些数字不再统一。可能是什么问题呢?

我做什么:我创建一个生成器的实例并给它自己的种子。

mainRGen= new nativeRandRUni(idumSeed_g);

这是类/对象定义:

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();

}    
4

2 回答 2

1

鉴于随机数是模拟的关键,您应该实现自己的生成器。我不知道 rand_r 使用的是什么算法,但它可能是非常糟糕的东西,比如线性全等生成器。

我会考虑在您了解底层算法的情况下快速实现具有良好品质的东西。我会从实现 Mersenne Twister 开始:

http://en.wikipedia.org/wiki/Mersenne_twister

它易于实现且速度非常快 - 无需分隔。

于 2012-08-08T17:37:16.310 回答
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;
};

我不再遇到问题了......虽然它解决了它,但我对不理解它是什么感到很不舒服。我认为 Rafael 是对的,我不应该相信 rand_r 这么密集的几代人

现在,这比以前慢,所以我可能会寻找优化它的方法。 问题:Mersenne Twister 的实现原则上会更快吗?

谢谢大家!

于 2012-08-08T22:45:51.323 回答