Dziwne wyniku przy losowaniu szóstek w lotto.

Odpowiedz Nowy wątek
2018-10-14 18:51

Rejestracja: 1 rok temu

Ostatnio: 1 rok temu

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;
}
edytowany 1x, ostatnio: kq, 2018-10-14 19:08

Pozostało 580 znaków

kq
2018-10-14 19:10
kq
Moderator C/C++

Rejestracja: 6 lat temu

Ostatnio: 1 minuta temu

Lokalizacja: Szczecin

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/130[...]sowac-elementy-bez-powtorzen/

Pozostało 580 znaków

2018-10-14 19:12

Rejestracja: 9 lat temu

Ostatnio: 2 miesiące temu

Lokalizacja: Lublin

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.
edytowany 2x, ostatnio: tomepaw, 2018-10-14 19:15
Moim zdaniem przy 1000 próbach powinny już być w miarę poprawne wyniki. Podejrzewam błąd w kodzie. - enedil 2018-10-14 19:16

Pozostało 580 znaków

2018-10-14 19:29

Rejestracja: 1 rok temu

Ostatnio: 1 rok temu

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

Pozostało 580 znaków

GN
2018-10-14 19:37
GN

Rejestracja: 3 lata temu

Ostatnio: 2 dni temu

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.


“Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter.” ~ Eric S. Raymond

Pozostało 580 znaków

2018-10-14 19:39

Rejestracja: 2 lata temu

Ostatnio: 4 miesiące temu

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


Nie pisz na priv. Zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: YooSy, 2018-10-14 19:40

Pozostało 580 znaków

2018-10-14 22:19

Rejestracja: 3 lata temu

Ostatnio: 56 sekund temu

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ć.


edytowany 1x, ostatnio: lion137, 2018-10-15 01:17

Pozostało 580 znaków

Odpowiedz

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