Java: Birthday paradox

1.3k Views Asked by At

I'm trying to make a program that represents the birthday paradox. I understand the paradox and I'm pretty sure my code is wrong but I'm not sure where I went wrong. I've looked through related posts, but I haven't found anything that's helpful. I wrote the code when I was younger, so sorry if it's a bit messy. I know there are other ways to do it, and I understand why those work. I just want to know why my code doesn't work. Thanks!

EDIT: Sorry, it's late. Forgot to put what my actual problem was. I run it how it is and expect to get about 50.5%, which is the theoretical value. But, instead, I get about 21.1%.

public class Main {
    static int trialsSucceeded = 0; // Stores number of successful trials
    static final int TRIALS = 1000000; // 1,000,000 is a good number :) Biggest I've tried: 2,147,483,647, which is Integer.MAX_VALUE
    static int numberOfPeople = 23; // The 'n' value for the birthday paradox

public static void main(String[] args) {
    ArrayList<Integer> birthdays = new ArrayList<Integer>(); // Stores people's birthdays

    // Runs until desired trials are completed
    for (int trialNumber = 0; trialNumber < TRIALS; trialNumber++) {
        // Provides progress updates to user
        if (trialNumber % 1000 == 0)
            System.out.printf("%.1f%% complete\n", (double) trialNumber * 100 / TRIALS);

        // Populates the birthdays array
        for (int personNumber = 0; personNumber < numberOfPeople; personNumber++) {
            birthdays.add(getRandInt(1, 365));
        }

        // Used later to see if current trial should end
        int prevTrialsSucceeded = trialsSucceeded;

        // Checks each person's birthday against everyone else's
        for (int i = 0; i < birthdays.size(); i++) {
            for (int j = i + 1; j < birthdays.size(); j++) {
                // If birthdays match, marks trial as a success jumps to next trail
                if ((birthdays.get(i) == birthdays.get(j))) {
                    trialsSucceeded += 1;
                    break;
                }
            }
            // Jumps to next trial if this one has already succeeded
            if (prevTrialsSucceeded != trialsSucceeded) {
                break;
            }
        }
        // Clears list of birthdays to get ready for next trial
        birthdays.clear();
    }
    // Tells user ratio of successful trials to total trials
    System.out.println(((double) trialsSucceeded / TRIALS * 100) + "% of trials succeeded");
}

private static int getRandInt(int lowerBound, int upperBound) {
    // Returns random integer between lowerBound and upperBound
    Random random = new Random();
    return random.nextInt(upperBound - lowerBound + 1) + lowerBound;
}

}

2

There are 2 best solutions below

2
GhostCat On

As others have figured correctly your problem is rooted in comparing references... But even when fixing that problem the solution here is neither efficient nor easy to grasp.

There is a simpler way to check this: just use a Set to store the random number birthdays instead of a list. But before adding the next number you use Set.contains() to check if that number is already in the set. If so you found a match... and you can stop right there!

2
clstrfsck On

The underlying issue is this line:

if ((birthdays.get(i) == birthdays.get(j))) {

This is comparing Integer objects for identity equality. What you need to do here is compare for value equality:

if ((birthdays.get(i).equals(birthdays.get(j)))) {

This should give you the right result, slightly above 50%.