Закон больших чисел
Наверно самый популярный пример, это подбрасывание монеты:
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: Изменил логику, перечитал закон, необходимо работать со средним значением и всё стало как нужно.
Полный код 2fn 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