Задать вопрос
@historydev
Редактирую файлы с непонятными расширениями

Как проверить збч на примере игральной кости, не ожидая миллиона лет?

Закон больших чисел

Наверно самый популярный пример, это подбрасывание монеты:
let mut coins = vec![];
    
    for _ in 0..1e6 as u32 {
        let mut rng = thread_rng();
        coins.push(rng.gen_range(0..=1));
    }
    
    let len_of_zero = coins.iter().filter(|&&c| c == 0).collect::<Vec<_>>().len() as f32;
    let len_of_one = coins.iter().filter(|&&c| c == 1).collect::<Vec<_>>().len() as f32;
    
    println!("Percent of 0: {}, Percent of 1: {}", 100. * (len_of_zero / coins.len() as f32), 100. * (len_of_one / coins.len() as f32));


100 монет - 10 тестов
Percent of 0: 44.00, Percent of 1: 56.00
Percent of 0: 51.00, Percent of 1: 49.00
Percent of 0: 41.00, Percent of 1: 59.00
Percent of 0: 53.00, Percent of 1: 47.00
Percent of 0: 46.00, Percent of 1: 54.00
Percent of 0: 48.00, Percent of 1: 52.00
Percent of 0: 41.00, Percent of 1: 59.00
Percent of 0: 50.00, Percent of 1: 50.00
Percent of 0: 47.00, Percent of 1: 53.00
Percent of 0: 53.00, Percent of 1: 47.00

1000 монет - 10 тестов
Percent of 0: 48.20, Percent of 1: 51.80
Percent of 0: 50.90, Percent of 1: 49.10
Percent of 0: 48.30, Percent of 1: 51.70
Percent of 0: 50.60, Percent of 1: 49.40
Percent of 0: 50.00, Percent of 1: 50.00
Percent of 0: 50.20, Percent of 1: 49.80
Percent of 0: 48.20, Percent of 1: 51.80
Percent of 0: 47.90, Percent of 1: 52.10
Percent of 0: 48.60, Percent of 1: 51.40
Percent of 0: 48.60, Percent of 1: 51.40

10_000 монет - 10 тестов
Percent of 0: 49.36, Percent of 1: 50.64
Percent of 0: 50.08, Percent of 1: 49.92
Percent of 0: 49.95, Percent of 1: 50.05
Percent of 0: 49.47, Percent of 1: 50.53
Percent of 0: 50.18, Percent of 1: 49.82
Percent of 0: 49.51, Percent of 1: 50.49
Percent of 0: 49.62, Percent of 1: 50.38
Percent of 0: 49.62, Percent of 1: 50.38
Percent of 0: 49.31, Percent of 1: 50.69
Percent of 0: 49.91, Percent of 1: 50.09

100_000 монет - 10 тестов
Percent of 0: 49.90, Percent of 1: 50.10
Percent of 0: 49.94, Percent of 1: 50.06
Percent of 0: 49.58, Percent of 1: 50.42
Percent of 0: 49.91, Percent of 1: 50.09
Percent of 0: 49.95, Percent of 1: 50.05
Percent of 0: 50.13, Percent of 1: 49.87
Percent of 0: 49.95, Percent of 1: 50.05
Percent of 0: 50.06, Percent of 1: 49.94
Percent of 0: 49.96, Percent of 1: 50.04
Percent of 0: 49.88, Percent of 1: 50.12

1_000_000 монет - 10 тестов
Percent of 0: 49.92, Percent of 1: 50.08
Percent of 0: 49.98, Percent of 1: 50.02
Percent of 0: 50.05, Percent of 1: 49.95
Percent of 0: 50.10, Percent of 1: 49.90
Percent of 0: 49.98, Percent of 1: 50.02
Percent of 0: 49.99, Percent of 1: 50.01
Percent of 0: 50.05, Percent of 1: 49.95
Percent of 0: 49.92, Percent of 1: 50.08
Percent of 0: 50.02, Percent of 1: 49.98
Percent of 0: 49.98, Percent of 1: 50.02


Здесь всё очень наглядно, понятно и очевидно.
Однако с игральной костью у меня не удалось при миллионе бросков выйти за 3-4% значений в диапазоне (3.4 - 3.6). - Почему?

Udp: Не учёл float разброс, генерировал f32 значения для костей и отсюда столь маленький шанс был, однако переведя всё в целые числа, я получаю ~16% - это безумно мало.

Полный код
fn coins() -> (f32, f32) {
    let mut coins = vec![];

    for _ in 0..1e7 as u32 {
        let mut rng = thread_rng();
        coins.push(rng.gen_range(0..=1));
    }

    let len_of_zero = coins.iter().filter(|&&c| c == 0).collect::<Vec<_>>().len() as f32;
    let len_of_one = coins.iter().filter(|&&c| c == 1).collect::<Vec<_>>().len() as f32;

    (len_of_zero / coins.len() as f32, len_of_one / coins.len() as f32)
}

fn bones() -> f32 {
    let mut bones = vec![];

    for _ in 0..1e6 as u32 {
        let mut rng = thread_rng();
        bones.push(rng.gen_range(1..=6));
    }

    bones.iter().filter(|&&b| (3..4).contains(&b)).collect::<Vec<_>>().len() as f32 / bones.len() as f32
}

fn main() {
    println!("Coins:");
    for _ in 0..10 {
        let (len_of_zero, len_of_one) = coins();
        println!("Percent of 0: {:.2}, Percent of 1: {:.2}", 100. * len_of_zero, 100. * len_of_one);
    }

    println!("Bones:");
    for _ in 0..10 {
        println!("Percent of 3.5: {}", 100. * bones());
    }
    
}


Вывод:
Coins:
Percent of 0: 50.00, Percent of 1: 50.00
Percent of 0: 50.00, Percent of 1: 50.00
Percent of 0: 50.00, Percent of 1: 50.00
Percent of 0: 50.02, Percent of 1: 49.98
Percent of 0: 49.98, Percent of 1: 50.02
Percent of 0: 49.97, Percent of 1: 50.03
Percent of 0: 50.01, Percent of 1: 49.99
Percent of 0: 50.01, Percent of 1: 49.99
Percent of 0: 49.98, Percent of 1: 50.02
Percent of 0: 49.99, Percent of 1: 50.01
Bones:
Percent of 3.5: 16.6519
Percent of 3.5: 16.6561
Percent of 3.5: 16.735401
Percent of 3.5: 16.694
Percent of 3.5: 16.64
Percent of 3.5: 16.6974
Percent of 3.5: 16.682001
Percent of 3.5: 16.7197
Percent of 3.5: 16.702799
Percent of 3.5: 16.6759


UDP2: Изменил логику, перечитал закон, необходимо работать со средним значением и всё стало как нужно.
Полный код 2
fn coins() -> f32 {
    let mut coins = vec![];
    let mut rng = thread_rng();

    for _ in 0..1e6 as u32 {
        let whole_part = 0.0;
        let fractional_part = rng.gen_range(0..=10);
        let random_number = whole_part as f32 + fractional_part as f32 / 10.0;

        coins.push(random_number);
    }

    coins.iter().sum::<f32>() / coins.len() as f32 / 100.
}

fn bones() -> f32 {
    let mut bones = vec![];
    let mut rng = thread_rng();

    for _ in 0..1e6 as u32 {
        let whole_part = rng.gen_range(1..=5);
        let fractional_part = rng.gen_range(0..=10);
        let random_number = whole_part as f32 + fractional_part as f32 / 10.0;

        bones.push(random_number);
    }

    bones.iter().sum::<f32>() / bones.len() as f32 / 100.
}


fn main() {
    println!("Coins:");
    for _ in 0..10 {
        println!("Percent of coins: {:.4}", 100. * coins());
    }

    println!("Bones:");
    for _ in 0..10 {
        println!("Percent of 3.5: {:.4}", 100. * bones());
    }
}


Вывод на 1_000_000 бросков:
Coins:
Percent of coins: 0.4998
Percent of coins: 0.5003
Percent of coins: 0.4998
Percent of coins: 0.4999
Percent of coins: 0.5001
Percent of coins: 0.5002
Percent of coins: 0.4997
Percent of coins: 0.5003
Percent of coins: 0.5003
Percent of coins: 0.5001
Bones:
Percent of 3.5: 3.4969
Percent of 3.5: 3.4983
Percent of 3.5: 3.5003
Percent of 3.5: 3.5030
Percent of 3.5: 3.4997
Percent of 3.5: 3.5016
Percent of 3.5: 3.4987
Percent of 3.5: 3.4993
Percent of 3.5: 3.4963
Percent of 3.5: 3.4977
  • Вопрос задан
  • 152 просмотра
Подписаться 1 Простой 6 комментариев
Решения вопроса 2
vabka
@vabka Куратор тега Rust
1. всё-таки не bones, а dice
2. (3..4).contains(&b)
Это то же самое, что и 3==b
16% - это как раз почти 1/6, так что всё сходится

UPD: оказывается, dice - это и есть множественное число, так что dices - это тоже неправильно
Ответ написан
@historydev Автор вопроса
Редактирую файлы с непонятными расширениями
Ошибка была в коде, вот конечная функция для любых диапазонов:
// law of large numbers
pub fn lln(min: u32, max: u32, attempts: u32) -> f32 {
    let mut sum = 0;
    let mut rng = thread_rng();

    for _ in 0..attempts { sum += rng.gen_range(min..=max); }

    sum as f32 / attempts as f32
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы