使用代码得出概率的近似值

Arriving at a close approximation of the probability using code

给我一道关于概率的数学题。它是这样的:

There are 1000 lotteries and each has 1000 tickets. You decide to buy 1 ticket per lottery. What is the probability that you win at least one lottery?

我能够在纸上用数学方法做到这一点(达到 1 - (999/1000)^1000),但我想到了在我的计算机上进行随机实验的大量迭代的想法。所以,我输入了一些代码——确切地说是两个版本,但都出现了故障。

代码 1:

#include<iostream>
#include <stdlib.h>

using namespace std;

int main() {
    int p2 = 0;
    int p1 = 0;
    srand(time(NULL));
    for (int i = 0; i<100000; i++){
        for(int j = 0; j<1000; j++){
            int s = 0;
            int x = rand()%1000;
            int y = rand()%1000;
            if(x == y)
                s = 1;
            p1 += s;
        }
        if(p1>0)
            p2++;
    }
    cout<<"The final probability is = "<< (p2/100000);
    return 0;
}

代码 2:

#include<iostream>

#include <stdlib.h>

using namespace std;

int main() {
    int p2 = 0;
    int p1 = 0;
    for (int i = 0; i<100000; i++){
        for(int j = 0; j<1000; j++){
            int s = 0;
            srand(time(NULL));
            int x = rand()%1000;
            srand(time(NULL));
            int y = rand()%1000;
            if(x == y)
                s = 1;
            p1 += s;
        }
        if(p1>0)
            p2++;
    }
    cout<<"The final probability is = "<< (p2/100000);
    return 0;
}

代码3(参考了一些进阶课文,但大部分都看不懂):

#include<iostream>

#include <random>

using namespace std;

int main() {
    int p2 = 0;
    int p1 = 0;
    random_device rd;
    mt19937 gen(rd());
    for (int i = 0; i<100000; i++){
        for(int j = 0; j<1000; j++){
            uniform_int_distribution<> dis(1, 1000);
            int s = 0;
            int x = dis(gen);
            int y = dis(gen);
            if(x == y)
                s = 1;
            p1 += s;
        }
        if(p1>0)
            p2++;
    }
    cout<<"The final probability is = "<< (p2/100000);
    return 0;
}

现在,所有这些代码都输出相同的文本:

The final probability is = 1
Process finished with exit code 0

似乎 rand() 函数在循环的所有 100000 次迭代中一直输出相同的值。我没能解决这个问题。

我也试过使用 randomize() 函数而不是 srand() 函数,但它似乎不起作用并且会出现奇怪的错误,例如:

error: ‘randomize’ was not declared in this scope
randomize();
           ^

我认为 randomize() 已在更高版本的 C++ 中停用。

我知道我在很多层面上都错了。如果您能耐心地解释我的错误并让我知道一些可能的更正,我将不胜感激。

仅在程序开始时通过 srand 为伪随机数生成器播种一次。当你一遍又一遍地播种时,你将伪随机数生成器重置为相同的初始状态。 time 默认以秒为单位。您很有可能在一秒钟内完成所有 1000 次迭代(或其中的大部分迭代)。

有关伪随机数生成器工作原理的一般说明,请参阅

这意味着您应该 在您的程序中创建一个 PRNG 实例 并且 播种一次。不要在循环内或在多次调用的函数内执行这些任务,除非你真的知道你在做什么并且正在尝试做一些复杂的事情,例如使用相关归纳策略,例如 common random numbers or antithetic variates to achieve "variance reduction” .

您应该在外循环开始时重置计数 (p1)。另外,请注意最后的 整数 除法 p2/100000,任何 p2 < 100000 的值都会导致 0.

查看您的代码的修改版本:

#include <iostream>
#include <random>

int main()
{
    const int number_of_tests = 100000;
    const int lotteries = 1000;
    const int tickets_per_lottery = 1000;

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> lottery(1, tickets_per_lottery);

    int winning_cases = 0;
    for (int i = 0; i < number_of_tests; ++i )
    {
        int wins = 0;                           // <- reset when each test start
        for(int j = 0; j < lotteries; ++j )
        {
            int my_ticket = lottery(gen);
            int winner = lottery(gen);
            if( my_ticket == winner )
                ++wins;
        }
        if ( wins > 0 )
            ++winning_cases;
    }
    // use the correct type to perform these calculations
    double expected = 1.0 - std::pow((lotteries - 1.0)/lotteries, lotteries);
    double probability = static_cast<double>(winning_cases) / number_of_tests;

    std::cout << "Expected: " << expected 
              << "\nCalculated: " << probability << '\n';

    return 0;
}

典型的 运行 会输出如下内容:

Expected: 0.632305
Calculated: 0.63125