java 生日派对的概率为零,也不知道如何使用模拟

rryofs0p  于 2023-11-15  发布在  Java
关注(0)|答案(2)|浏览(104)

我一直在尝试创建一个程序,它计算的概率2人的生日是相同的,考虑到有23人在房间里
我做过逻辑,但概率总是为零,应该在0.5以上,这是我的第一堂计算机科学课,所以我对Java和编码不是很熟悉。
我在网上看到一些程序有多个模拟,但我不能理解它。

import java.util.Random;

public class Main {

    public static int rand_bd() {
        Random rand = new Random();
        int x = rand.nextInt(365);
        return x;
    }

    public static void main(String[] args) {
        System.out.println("Hello world!");
        
        int h = 0;
        double count = 0.0;
        int g = rand_bd();

        for(int i = 0;i  <= 23;i++) {
            h = rand_bd();
            if(g == h)
                count++;
        }
        System.out.println(count);
        System.out.println(count/23.0);
        System.out.println(rand_bd());
    }
}

字符串

exdqitrt

exdqitrt1#

初步说明:

你似乎是在为每个随机值使用一个Random生成器对象(在你的rand_bd方法中)。但这不是伪随机数生成的工作方式,所以你处于未经测试的环境中。
库设计者唯一要测试的是 * 单个 * Random对象生成的序列是否具有正确的统计属性。因此,您应该修改代码以确保在整个模拟过程中使用单个Random对象,通常通过将单个生成器对象(的地址)传递给rand_bd

主要问题:

你似乎是在测试每个新的随机值是否与第一个随机值相等,但是,正如评论中提到的,这不是Birthday Paradox应该如何工作的。
每个新的伪随机值都必须测试是否与所有先前值相等。
为了测试所有先前的值,而不是编写低级Java代码,我们可以只维护和使用一个HashSet<Integer>对象,该对象包含所有先前找到的伪随机值。
这可以用下面的代码来实现:

import java.util.*; 
import java.util.Random;

public class SO_q77456187  {

    public static int rand_bd(Random rand) {
        int x = rand.nextInt(365);
        return x;
    }

    public static void main(String[] args) {
        System.out.println("Hello world!");

        Random rand      = new Random();
        Set<Integer> set = new HashSet<Integer>();

        int h = 0;
        int classSize = 23;
        double count = 0.0;

        for (int i = 0; i  < classSize; i++) {
            h = new Integer(rand_bd(rand));
            if (set.contains(h))
                count++;  // collision found !
            else
                set.add(h);
        }
        if (count > 0)
            System.out.println("collision");
        System.out.println(count);
        System.out.println(count / Double.valueOf(classSize));
        System.out.println(rand_bd(rand));
    }
}

字符串
正如预期的那样,由上述代码生成的类文件在大约50%的时间内发现一个或多个冲突。

gcxthw6b

gcxthw6b2#

首先,让我重申jpmarinier的评论,你应该只创建一个Random对象。为每个要生成的值示例化一个新对象是昂贵的,它否定了PRNG创建者为确保值序列正确地模仿独立均匀分布的值所做的所有努力。
接下来,我想你错过了生日问题的本质。它问的是在一个包含一定数量的人的集合中,有一个 * 或多个 * 重复生日的概率是多少。这是一个布尔选择,要么有重复的,要么没有。一旦你找到一个重复的,你可以缩短检查过程,因为目标不是计算发生了多少次。这很容易使用Set对象来完成,它不允许重复。
最后,您忽略了Monte Carlo simulation的本质,即您需要重复随机实验。(重复/无重复),你可以通过运行大量的实验来更好地估计该事件的概率。很多很多。此外,由于重新运行随机实验会得到不同的结果,知道你所估计的任何东西的“误差幅度”是很好的。这以所谓的置信区间半宽的形式出现。
下面的代码将这些部分组合在一起:

import java.util.HashSet; 
import java.util.Random;

public class BdayMonteCarlo {
    // only create one instance of Random per program!
    private static Random rng = new Random();

    /*
     * Each experiment places classSize students in the room, checking
     * to see if there are any collisions on the birth dates.
     */
    public static int experiment(int classSize) {
        // each experiment starts with an empty set of birthdays
        HashSet<Integer> set = new HashSet<Integer>();

        // for each student, generate a birthday and try adding it to set
        // if add fails, short circuit and signal a collision
        for (int i = 0; i  < classSize; i++) {
            if(!set.add(rng.nextInt(365)))
                return 1;
        }
        return 0;   // if all people in class missed collisions, signal no collision
    }

    public static void main(String[] args) {
        int classSize = 23;
        int numberOfExptsWithCollisions = 0;
        int numberOfExperiments = 100_000;

        // Monte Carlo replication of the experiment, tallying results
        for (int i = 0; i < numberOfExperiments; ++i) {
            numberOfExptsWithCollisions += experiment(classSize);
        }

        // probabilities are estimated using proportions of outcomes
        // that yielded a "success"
        System.out.print("Probability of one or more duplicate birthdays ");
        System.out.println("with classSize = " + classSize + " is:");
        Double prob = Double.valueOf(numberOfExptsWithCollisions) / numberOfExperiments;
        // confidence interval half-width for the estimate of a proportion/probability
        Double halfWidth = 1.96 * Math.sqrt(prob * (1.0 - prob) / numberOfExperiments);
        System.out.println(prob + " ± " + halfWidth);
    }
}

字符串
并产生如下结果:

me@mymachine % java BdayMonteCarlo      
Probability of one or more duplicate birthdays with classSize = 23 is:
0.5085 ± 0.0030985842644665968
me@mymachine % java BdayMonteCarlo
Probability of one or more duplicate birthdays with classSize = 23 is:
0.50936 ± 0.003098489049457235


你可以清楚地看到,至少有一个重复生日的实验比例在23人中超过0.5。

相关问题