C++ 概率规划

C++ 概率规划,c++,algorithm,math,random,probability,C++,Algorithm,Math,Random,Probability,在我们需要生成概率的情况下,例如,一个有75%的头部和25%的尾部摆动的偏向硬币。按照惯例,我会这样做: #include <cstdlib> #include <iostream> #include <ctime> using namespace std; int main() { int heads=0, tails=0; srand(time(NULL)); number = rand() % 100 + 1; //Gener

在我们需要生成概率的情况下,例如,一个有75%的头部和25%的尾部摆动的偏向硬币。按照惯例,我会这样做:

#include <cstdlib>
#include <iostream>
#include <ctime>
using namespace std;

int main()
{
    int heads=0, tails=0;
    srand(time(NULL));
    number = rand() % 100 + 1;  //Generate random number 1 to 100
          if (number <= 75) //75% chance
                heads++; //This is head
          else
                tails++; //This is tail
}
#包括
#包括
#包括
使用名称空间std;
int main()
{
int头=0,尾=0;
srand(时间(空));
number=rand()%100+1;//生成随机数1到100
如果(数字)
上述代码是否可用于创建模拟
概率?或者这些代码中是否存在任何会影响
模拟结果的准确性如何

如果这是“可接受的”,这取决于您对可接受的定义。这肯定是不正确的,因为运算符%会使您的概率发生偏差,因为RAND_MAX是
RAND()的最大值
不能等于k*100+99,这导致如果您想象0-RAND_MAX字符串的100个长度部分,那么您可以看到最后一部分可能不会生成完整的0-99范围,因此您有更多的数字生成0,1,2…,x,但不需要x+1…,98,99(0,1,2,…,x中的每个数字多出现1次)。这种方法的不准确度随着除数的增大而增加,除数不能均匀地划分范围

如果上述代码有缺陷,正确的解决方法是什么 实现概率模拟

您可以使用boost,或者如果您可以运行C++11,那么您可以使用标准库。

使用
rand()%100+1
的工作方式与“生成100个随机数时,正好75个数将小于75”的工作方式不同


换句话说,它不能保证在100个随机生成的数字中,75个数字将小于75!

由于数字的有限性,您总是会得到有偏差的结果(增加随机数生成器的结果数将提高准确性)

在您的样本中,您可能对什么是75%有更好的定义:

int main()
{
    int heads=0, tails=0;
    srand(time(NULL));
    const std::size_t Samples = 10000000;
    for(std::size_t i = 0; i < Samples; ++i) {
        int head_limit = RAND_MAX * 0.75;
        int number = rand();
        if (number <= head_limit) heads++;
        else tails++;
    }
    // heads: 7498728 [0.749873%]
    // tails: 2501272 [0.250127%]
    std::cout 
        << "heads: " << heads << " [" << double(heads) / Samples << "%]\n"
        << "tails: " << tails << " [" << double(tails) / Samples << "%]\n";
}
intmain()
{
int头=0,尾=0;
srand(时间(空));
const std::size\u t Samples=10000000;
对于(标准::尺寸\u t i=0;i
我不知道您对“可接受”的定义。但是,我会避免使用
rand()
,请参见示例

如果上面的代码有缺陷,那么实现模拟的正确方法是什么 概率

我会使用。它质量高、速度快(根据Stephan T.Lavavej的介绍)而且标准

顺便说一下,
std::bernoulli_分布的示例代码给出了时间的“真”1/4和“假”3/4;

std::rand()

假设
RAND_MAX
被定义为32767,将
RAND()%100
生成平面分布?否。从0到32699,0到99的每个值将显示327次。但是从32700到32767,0到67的值显示一次,68-99的值显示0次。因此,您的分布有328次00-67,327次68-99

此外,除非您以某种方式指定RAND_MAX是什么,或者在代码中使用它,否则编译器实现对RAND_MAX使用的任何东西都将影响您,并且您的分布将以某种未知的方式发生倾斜

如果你想要一枚硬币在四分之三的时间里出现,考虑这样的事情:

if((double)std::rand()/3.0 > (double)RAND_MAX/4.0)
bool trial (int randList[], const int SIZE, int trialCount)
{
    return (randList[trialCount % SIZE] < 75); // Head = True = 75%
}
(如果a>3/4*b,那么a/3>b/4)。这几乎是公平的;RAND_MAX不太可能整齐地划分为4。但这比原始代码中的1/327偏差要好


但更好的是,使用更好的随机数生成器,您可以在其中设置限制。

为了确保1到100或0到99之间的每个数字都有一个概率p=1/100,以确保您有准确的概率排序

然后,不是使用随机生成的数字,而是使用1000个1-100个均匀分布的列表,然后每次需要重复使用它们时,使用相同的随机数生成器将它们洗牌

因此,首先我们要建立一个列表:

const int SIZE = 1000;
srand(time(NULL));
int randList [SIZE];
void shuffle (int randList[], const int SIZE)
{
    for (int i=0; i<SIZE; i++)
        swap(randList,i,(rand() % SIZE));
}

void swap (int randList[], int a, int b)
{
    int t = randList[a];
    randList[a] = randList[b];
    randList[b] = t;
}
然后我们填写:

void init (int randList[], const int SIZE)
{
    for (int i=0; i<SIZE; i++)
        randList[i] = i % 100;
}

“因为随机函数生成正态分布”-不,它不生成正态分布。它生成一个均匀分布,
%
运算符使分布倾斜。@MitchWheat是的,我的意思是均匀分布,我将对此进行编辑。谢谢:-)Bethsheba对您链接的问题的回答充分解释了为什么不赞成使用%的原因。rand()与模数结合使用有已知缺陷,不要用于任何重要的东西,例如证明。使用10000000个样本(至少,使用动态内存)只需加上它,
(MAX\u INT%100)
不是零,(我不确定
rand()
的分布情况如何,但考虑到它是0到MAX_INT的统一分布,您只需使用
rand()%4
并检查是否小于4(您希望以2的幂进行修改)。
void test (bool * resultList, const int resultSize)
{
    const int SIZE = 1000;
    srand(time(NULL));
    int randList [SIZE];

    init(randList,SIZE);

    for (int i=0; i<resultSize; i++)
    {
        if (i%SIZE == 0)
            shuffle(randList,SIZE);

        resultList[i] = trial(randList,SIZE,i);
    }
}
int main ()
{
    const int resultSize = 2000000; // 2 Million

    bool * resultList = new bool[resultSize];

    test(resultList,resultSize);

    // check sequence of outcomes

    return 0;
}