无偏随机数发生器

时间:2011-11-16 19:15:55

标签: c++ random

我使用以下代码在域中生成随机数。当我绘制它们时,它们看起来分组在右边。我可以告诉你我的情节,但我不知道如何上传它。基本上我将一些数据值与相应的点相关联。你能告诉我怎样才能纠正它?我的完整代码是

#include <iostream>
#include <cmath>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <time.h>

using namespace std;
string int2string1( int l );
string int2string2( int m );
int main ()
{
    ofstream outFile;
    ofstream myimp;
    string filename;
    srand((unsigned)time(0));
    int nx = 400;
    int ny = 200;
    int i,j,ix,iy,xm,ym,nimp,nfam[nx][ny];
    float vo,rnd,rr,rad,sig,vimp[nx][ny];
    for (i=0; i<nx; i++)
    {
        for (j=0; j<ny; j++)
        {
            vimp[i][j] = 0.0;
        }
    }
    rad = 5.0;
    xm = 0;
    ym = 0;
    vo = 0.08;
    sig = 4.0;
    myimp.open("imp.dat");
    for(i=1; i<nx-1; i++)
    {
        for(j=1; j<ny-1; j++)
        {
            rnd = (random() %1000 + 1)*1.0/1000.0;
            if(rnd>0.99)
            {
                xm = random() % 398 + 1;              /***1 through 399 ***/
                ym = random() % 198 + 1;              /***1 through 199 ***/
                for(ix=xm-5; ix<=xm+5; ix++)
                {
                    for(iy=ym-5; iy<=ym+5; iy++)
                    {
                        rr = sqrt(pow(ix-xm,2.)+pow(iy-ym,2.));
                        if(rr<=rad)
                        {
                            vimp[ix][iy] = vo*1.6e-19;
                        }
                    }
                }
            }
            myimp<<i<<"\t\t"<<j<<"\t\t"<<xm<<"\t\t"<<ym<<"\t\t"<<nfam[i][j]<<"\t\t"<<vimp[i][j]*6.23e18<<"\n";
        }
    }
    myimp.close();
    return 0;
}

5 个答案:

答案 0 :(得分:11)

int r = rand() % N;

不会导致均匀分布 1

相反,我建议只使用C ++ TR1(或boost)随机:

#include <random>

std::mt19937 rng(seed);
std::uniform_int_distribution<int> gen(0, N); // uniform, unbiased

int r = gen(rng);

或者生成任何类型的浮点数:

std::uniform_real_distribution<double> gen(-2*PI, +2*PI); // uniform, unbiased
double r = gen(rng);

<子> 1 背景,例如:Using rand()

如果您真的坚持使用rand()和N 均匀划分 MAX_RAND,该页面会提供一些有关如何使用的提示使用其他公式实现稍微更好的整数分布。请注意,我会引导您转到André Caron's answer

答案 1 :(得分:7)

基本上,如果rand() % N不是RAND_MAX的倍数,则N表达会引入偏差。它将[0,RAND_MAX]中的数字以非均匀方式投射到范围[0,N]上。

假设RAND_MAX=4N=2。然后,有3个数字产生0024)和2个数字,产生11和{ {1}})。因此,您获得3的变化率为60%,获得0的几率为40%。

实现从1[0,RAND_MAX]的无偏投影的正确方法是重复调用[0,N],直到随机值处于所需的时间间隔内。请参阅Java中的documentation for Random.nextInt()(Oli Charlesworth的致谢链接)。

假设对于纯粹的执行速度,您希望避免多次调用rand(),那么生成最小偏差的方法是使用中间rand()数字,例如:

double

编辑:这是一个简单的类,它将double myrand () { return double(rand()) / double(RAND_MAX); } int myrand ( int max ) { return int(myrand() * double(max)); } 函数的输出投影到范围rand(),其偏差不小于[0,N]

rand()

警告:未经过测试或调试。

您可以像这样使用此生成器:

class BoundedRandom
{
    const int m_maximum;
    const int m_divisor;
public:
    BoundedRandom ( int maximum )
        : m_maximum(maximum),
          m_divisor(RAND_MAX/(maximum+1))
    {}

    int operator() ()
    {
        int result = rand() / m_divisor;
        while ( result > m_maximum ) {
            result = rand() / m_divisor;
        }
        return (result);
    }
};

答案 2 :(得分:3)

C ++ 11引入了随机数生成器,几乎肯定会比rand做得更好。以下是使用mersenne twister算法的示例,但根据您需要的特性,还有其他选择。

// [1, 399]
auto random_int = std::bind(std::uniform_int_distribution<int>(1,399),std::mt19937()); 

// [0, 1.0)
auto random_double = std::bind(std::uniform_real_distribution<double>(0.0,1.0),std::mt19937());

答案 3 :(得分:2)

rand() % 398 + 1; /*** 1 through 399 ***/将生成数字1到398,因为`rand() % 398将为0-397(398%398为0)。下一行也一样。

顺便说一句,请注意,使用pow和2的恒定功率可能比简单地写出乘法要多一个数量级的CPU,通常应该避免使用。

此外,由于您只使用rnd与常量0.99进行一次比较,因此您应该将其作为整数数学运算,因为浮点数的转换和比较将花费更多而不仅仅是整数比较。例如,两行(rnd =if)使用if((rand() % 100) == 0),而略微偏见应准确表明您的意图。

答案 4 :(得分:0)

我已经阅读了您的代码,找不到任何偏向右侧的内容。如果有的话,存在统计偏差(左边三分之二应该受到0.6%ish的青睐)。