Task: Birthday problem


C++: #include <iostream>
#include <random>
#include <vector>

double equalBirthdays(int nSharers, int groupSize, int nRepetitions) {
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(0, 364);
    std::vector<int> group(365);

    int eq = 0;
    for (int i = 0; i < nRepetitions; i++) {
        std::fill(group.begin(), group.end(), 0);
        for (int j = 0; j < groupSize; j++) {
            int day = distribution(generator);
            group[day]++;
        }
        if (std::any_of(group.cbegin(), group.cend(), [nSharers](int c) { return c >= nSharers; })) {
            eq++;
        }
    }

    return (100.0 * eq) / nRepetitions;
}

int main() {
    int groupEst = 2;

    for (int sharers = 2; sharers < 6; sharers++) {
        
        int groupSize = groupEst + 1;
        while (equalBirthdays(sharers, groupSize, 100) < 50.0) {
            groupSize++;
        }

        
        int inf = (int)(groupSize - (groupSize - groupEst) / 4.0f);
        for (int gs = inf; gs < groupSize + 999; gs++) {
            double eq = equalBirthdays(sharers, groupSize, 250);
            if (eq > 50.0) {
                groupSize = gs;
                break;
            }
        }

        
        for (int gs = groupSize - 1; gs < groupSize + 999; gs++) {
            double eq = equalBirthdays(sharers, gs, 50000);
            if (eq > 50.0) {
                groupEst = gs;
                printf("%d independant people in a group of %d share a common birthday. (%5.1f)\n", sharers, gs, eq);
                break;
            }
        }
    }

    return 0;
}



Go: package main

import (
    "fmt"
    "math"
    "math/rand"
    "time"
)

const (
    DEBUG   = 0
    DAYS    = 365
    n_sigmas = 5.
    WORKERS = 16   
    RUNS    = 1000 
)

func simulate1(p, n int, r *rand.Rand) int {
    var days [DAYS]int
    for i := 0; i < p; i++ {
        days[r.Intn(DAYS)]++
    }
    for _, d := range days {
        if d >= n {
            return 1
        }
    }
    return 0
}


func work(p, n int, ych chan int, cancel chan bool) {
    r := rand.New(rand.NewSource(time.Now().Unix() + rand.Int63()))
    for {
        select {
        case <-cancel:
            return
        default:
        }
        y := 0
        for i := 0; i < RUNS; i++ {
            y += simulate1(p, n, r)
        }
        ych <- y
    }
}

func prob(np, n int) (p, d float64) {
    ych := make(chan int, WORKERS)
    cancel := make(chan bool)
    for i := 0; i < WORKERS; i++ {
        go work(np, n, ych, cancel)
    }
    var runs, yes int
    for {
        yes += <-ych
        runs += RUNS
        fr := float64(runs)
        p = float64(yes) / fr
        d = math.Sqrt(p * (1 - p) / fr)
        if DEBUG > 1 {
            fmt.Println("\t\t", np, yes, runs, p, d)
        }
        
        if !(math.Abs(p-.5) < n_sigmas*d) {
            close(cancel)
            break
        }
    }
    if DEBUG > 1 {
        fmt.Println()
    }
    return
}

func find_half_chance(n int) (mid int, p, dev float64) {
reset:
    lo := 0
    hi := DAYS*(n-1) + 1
    for {
        mid = (hi + lo) / 2
        p, dev = prob(mid, n)

        if DEBUG > 0 {
            fmt.Println("\t", lo, mid, hi, p, dev)
        }
        if p < .5 {
            lo = mid + 1
        } else {
            hi = mid
        }
        if hi < lo {
            if DEBUG > 0 {
                fmt.Println("\tMade a mess, will redo.")
            }
            goto reset
        }
        if !(lo < mid || p < .5) {
            break
        }
    }
    return
}

func main() {
    for n := 2; n <= 5; n++ {
        np, p, d := find_half_chance(n)
        fmt.Printf("%d collision: %d people, P = %.4f ± %.4f\n",
            n, np, p, d)
    }
}