Dziwne wyniku przy losowaniu szóstek w lotto.

0

Witam postanowiłem zrobić program który symuluje grę w lotto. I problem jest taki że przy 1000 losach powinno minimum 10 losów trafić trójkę a u mnie przy dobrym farcie jest jedna osoba. Tak ma być czy prawdopodobieństwo w lotto na trójkę jes 1/57 czy nie?

#include <iostream>
#include <cstdlib>
#include <time.h>
#include <windows.h>

using namespace std;

int licznik, licznik2, licznik3, licznik4, licznik5, licznik6, a, i, i2, j, g, losuje, x, z, y, u, z2, o, piewsza, druga, trzecia, czwarta, suma, piota, szosta, siodma, k, trafienia, k2, licznik7, licznik8, k3, wyjdz, h;
string obywatel;
int tablica[9999999];
string tablica2[9999999];
int tab[30000000][6];
int tabtraf[30000000];
int tabwynik[6];
int trojki;
int czworki;
int piotki;
int szostki;

int main()
{
    obywatel = "Obywatel";
    srand(time(NULL));
    a = rand() % 1 + 1000;
    z = 6;
    z2 = 1;

    do // Losuje szczęśliwe numerki
    {
        do {
            tabwynik[0] = rand() % 49 + 1;
            piewsza = 1;
        } while (piewsza != 1);
        do {
            tabwynik[1] = rand() % 49 + 1;
            if (tabwynik[1] == tabwynik[0]) {

                cin.clear();
                cin.sync();
                continue;
            }
            else {
                druga = 1;
            }
        } while (druga != 1);
        do {
            tabwynik[2] = rand() % 49 + 1;
            if (tabwynik[2] == tabwynik[0] || tabwynik[2] == tabwynik[1]) {

                cin.clear();
                cin.sync();
                continue;
            }
            else {
                trzecia = 1;
            }
        } while (trzecia != 1);
        do {
            tabwynik[3] = rand() % 49 + 1;
            if (tabwynik[3] == tabwynik[0] || tabwynik[3] == tabwynik[1] || tabwynik[3] == tabwynik[2]) {

                cin.clear();
                cin.sync();
                continue;
            }
            else {
                czwarta = 1;
            }
        } while (czwarta != 1);
        do {
            tabwynik[4] = rand() % 49 + 1;
            if (tabwynik[4] == tabwynik[0] || tabwynik[4] == tabwynik[1] || tabwynik[4] == tabwynik[2] || tabwynik[4] == tabwynik[3]) {

                cin.clear();
                cin.sync();
                continue;
            }
            else {
                piota = 1;
            }
        } while (piota != 1);
        do {
            tabwynik[5] = rand() % 49 + 1;
            if (tabwynik[5] == tabwynik[0] || tabwynik[5] == tabwynik[1] || tabwynik[5] == tabwynik[2] || tabwynik[5] == tabwynik[3] || tabwynik[5] == tabwynik[4]) {

                cin.clear();
                cin.sync();
                continue;
            }
            else {
                szosta = 1;
            }
        } while (szosta != 1);

        siodma = 1;
    } while (siodma != 1);
    //Wypisuje szczęsliwe numerki
    cout << "Wylosowane szczesliwe numerki." << endl;
    cout << "Pierwsze: " << tabwynik[0] << "" << endl;
    cout << "Drugie: " << tabwynik[1] << "" << endl;
    cout << "Trzecie: " << tabwynik[2] << "" << endl;
    cout << "Czwarte: " << tabwynik[3] << "" << endl;
    cout << "Piote: " << tabwynik[4] << "" << endl;
    cout << "Szoste: " << tabwynik[5] << "" << endl;

    // Losuje szczęśliwe numerki uczestnikom
    for (i; i < a; i++) {

        cout << "" << obywatel << " nr. " << licznik << endl;

        for (g; g < z; g++) {
            tab[licznik4][licznik3] = rand() % 49 + 1;

            if (tab[licznik4][licznik3] == tab[licznik4][(licznik3)-1] || tab[licznik4][licznik3] == tab[licznik4][(licznik3)-2] || tab[licznik4][licznik3] == tab[licznik4][(licznik3)-3] || tab[licznik4][licznik3] == tab[licznik4][(licznik3)-4] || tab[licznik4][licznik3] == tab[licznik4][(licznik3)-5] || tab[licznik4][licznik3] == tab[licznik4][(licznik3)-6]) {
                // Kiedy losuje jeszcze raz
                cout << "" << tab[licznik4][licznik3] << " " << tab[licznik4][(licznik3)-1] << "Jeszcze raz." << i << " " << g << "" << endl;
                g--;

                cin.clear();
                cin.sync();

                continue;
            }
            licznik3++;
        }
        g = 0;
        licznik3 = 0;
        licznik4++;

        licznik++;

        cout << "" << endl;
    }
    licznik = 0;

    //Wypisuje wylosowane szóstki
    for (y; y < a; y++) {
        for (u; u < z2; u++) {
            cout << "Wylosowane szostki " << obywatel << " nr. " << licznik << ": ";
            for (o; o < z; o++) {
                cout << "" << tab[licznik5][licznik6] << "  ";
                licznik6++;
            }
            cout << "" << endl;
            o = 0;
            licznik++;
        }
        u = 0;
    }
    licznik = 0;
    licznik4 = 0;
    licznik3 = 0;

    //Sprawdza ile razy trafili
    for (k; k < a; k++) {
        for (k2; k2 < z2; k2++) {
            cout << "" << obywatel << " nr. " << licznik << " " << endl;
            for (h; h < z; h++) {
                cout << "" << tabwynik[licznik3] << " ? " << tab[licznik4][licznik3] << "" << endl;
                if (tabwynik[licznik3] == tab[licznik4][licznik3])
                    trafienia++;

                licznik3++;
            }
            if (trafienia == 3)
                trojki++;
            if (trafienia == 4)
                czworki++;
            if (trafienia == 5)
                piotki++;
            if (trafienia == 6)
                szostki++;

            h = 0;
            licznik3 = 0;
            tabtraf[licznik4] = tabtraf[licznik4] + trafienia;
            cout << " ilosc trafien: " << tabtraf[licznik4] << "" << endl;
            licznik++;
            trafienia = 0;
            licznik4++;
        }
        k2 = 0;
    }
    licznik3 = 0;
    licznik4 = 0;
    licznik = 0;

    cout << "Liczba uczestnikow:  " << a << "" << endl;
    cout << "Liczba szczesliwcow: " << endl;
    cout << "Szostki:             " << szostki << "" << endl;
    cout << "Piotki:              " << piotki << "" << endl;
    cout << "Czworki:             " << czworki << "" << endl;
    cout << "Trojki:              " << trojki << "" << endl;
    return 0;
}

3

Być może komuś się będzie chciało wejść głębiej w ten kod i napisać pełną odpowiedź, ale ja ograniczę się do kilku ogólnych rad:

  1. Formatuj zrozumiale kod
  2. Nie używaj zmiennych globalnych
  3. Dziel kod na małe funkcje o jednym zadaniu
  4. Nazywaj sensownie zmienne i funkcje (czyli inaczej niż zrobiłeś to tu)
  5. https://dsp.krzaq.cc/post/180/nie-uzywaj-rand-cxx-ma-random/
  6. https://dsp.krzaq.cc/post/1304/zwi-4-jak-wylosowac-elementy-bez-powtorzen/
0

Prawdopodobieństwo trafienia liczby 3 wynosi 1/49.
Nie zagłębiałem się w kod ale nie uwzględniasz kilku rzeczy.

  1. To jest prawdopodobieństwo. Nie oznacza to w cale że na 490 prób będziesz miał dokładnie 10 trójek.
  2. rand() zwraca liczby pseudolosowe, z prawdziwą losowością nie ma to zbyt wiele wspólnego
  3. 1000 prób to jest tyle co nic, sprawdź na 100k lub 1kk prób, wtedy wyniki powinny nieco zbliżyć się do oczekiwanych.
0
tomepaw napisał(a):

Prawdopodobieństwo trafienia liczby 3 wynosi 1/49.
Nie zagłębiałem się w kod ale nie uwzględniasz kilku rzeczy.

  1. To jest prawdopodobieństwo. Nie oznacza to w cale że na 490 prób będziesz miał dokładnie 10 trójek.
  2. rand() zwraca liczby pseudolosowe, z prawdziwą losowością nie ma to zbyt wiele wspólnego
  3. 1000 prób to jest tyle co nic, sprawdź na 100k lub 1kk prób, wtedy wyniki powinny nieco zbliżyć się do oczekiwanych.

Skoro rand() to liczby pseudolosowe to jak uzyskać efekt który chcę uzyskać?
Przy 100k prób jest ~18 trójek i czasami 1 czwórka
Przy 1kk prób jest ~170 trójek ~2 czwórki

0

Losowość polega właśnie na tym, że jest losowa, więc wszystkie wyliczenia to tylko teorie, które mogą znacząco odbiegać od rzeczywistości.

2

Wypróbuj różne generatory i sporządź statystyki, a zobaczysz, że rand() jest dość kiepski.
https://en.cppreference.com/w/cpp/header/random

#include <iostream>
#include <algorithm>
#include <set>
#include <array>
#include <random>
#include <numeric>

std::mt19937 gen{ std::random_device{}() };

std::set<int> RandomNums(int min, int max, std::size_t nElems) {
   std::uniform_int_distribution<> dist(min, max);
   std::set<int> nums;
   while (nums.size() < nElems) {
      nums.insert(dist(gen));
   }
   return nums;
}

template <typename C>
void PrintResult(const C& coll) {
   for (std::size_t i = 0; i < coll.size(); ++i) {
      std::cout << i << " trafionych w " << coll[i] << " losowaniach\n";
   }
}

int main() {
   std::array<int, 7> accuracy{};
   std::size_t nLoops = 1000;
   auto myNums = RandomNums(1, 49, 6);
   for (std::size_t i = 0; i < nLoops; ++i) {      
      auto currentRndNums = RandomNums(1, 49, 6);
      ++accuracy[std::count_if(myNums.cbegin(), myNums.cend(),
         [&](auto const& el) {return std::find(currentRndNums.cbegin(), currentRndNums.cend(), el) != currentRndNums.cend(); })];
   }
   PrintResult(accuracy);
}

https://wandbox.org/permlink/l53ayGiJZngYFmQp

0

Masz rację, powinno być na praktykę te co najmniej 10 trójek na tysiąc losowań; prawdopodobieństwo trójki to, tak jak Piszesz 1/57. Ale do rzeczy, oto kod (Python, bo najszybciej się pisze, podobny do pseudokodu, można łatwo coś tłumaczyć):

import math
def Newton(n,k):
    """Newton symbol: (n / k) """
    f = math.factorial
    return f(n) // (f(n - k) * f(k))

def p_bernoulli(n, k, p):
    """Bernoulli Scheme"""
    return Newton(n, k) * p ** k * (1 - p) ** (n - k) 

p_hit_three_lotto = (Newton(6, 3) * Newton(43, 3)) /  Newton(49, 6)
p_hit_three_lotto # -> 0.017650... = 1/57

def p_bernoulli_at_least(n, k, p):
    """Gives probability of at least k successes for 
    n probes."""
    return sum([p_bernoulli(n, x, p) for x in range(k, n + 1)])

p_bernoulli_at_least(1000, 10, 1/57) # -> 0.98113...

def p_hit_three(xs):
    """Is exactly three in Lotto?"""
    m_set = random.sample(range(1, 50), 6)
    a_list = [elem for elem in xs if elem in m_set]
    return True if len(a_list) == 3 else False

cnt = 0
for _ in range(1000):
    if p_hit_three(random.sample(range(1, 50), 6)):
        cnt += 1
cnt

Schemat Bernoulliego: http://matematyka.pisz.pl/strona/1025.html
Symbol Newtona: https://pl.wikipedia.org/wiki/Symbol_Newtona

Jak widać funkcja p_bernoulli_at_least daje ponad 98% pewności, że na 1000 losowań trafimy co najmniej 10 trójek. Można to potestować ostatnią pętlą, przeważnie wychodzi między 12 a 22. Funkcja def p_hit_three jest trochę cryptic, ale jest poprawna. Czyli, praktycznie na pewno Masz błąd w swoim spaghetti, bo nawet jak liczby nie są porządnie losowe, to aż takiej różnicy nie powinno być.

1 użytkowników online, w tym zalogowanych: 0, gości: 1