Korttipakka todennäköisyyksiä

Seuraa 
Viestejä45973
Liittynyt3.9.2015

Tilastot & todennäköisyys kurssikokeen vikana tehtävänä oli tämä: Pakkaan lisätään 2 jokeria. Pakasta otetaan umpimähkään 5 korttia. Millä todennäköisyydellä saadaan viisi samaa ts. viitoset?

Itse lähdin tätä laskemaan seuraavasti.
2 suotuisaa alkeistapausta:

3 saman arvoista korttia + 2 jokeria
4 saman arvoista korttia + 1 jokeri

Laskin kummankin tapauksen todennäköisyyden ja plussasin yhteen, tuloksena P(5 samaa) = 2,6E-07

Ei mitään hajua menikö edes sinne päin. Jos täällä voisikin nyt joku vähän antaa neuvoa että miten se menee? Veikkaisin, että osuin johonkin ansaan/laskin todennäköisyydet väärin.

Kommentit (10)

Vierailija

Ed: Paitsi että simulaattori laski täyttä sontaa, koska kädestä pitää ensin plarata vertailukortiksi se, joka ei ole jokeri. Sitten se tarkempi todennäköisyys on:

2.1e-06

Näyttäisi suppenevan todennäköisyyteen:

1.6e-05 <=> väärin, kun tapauksia on tutkittu 200000000

Näin ollen laskit ilmeisesti väärin. Mutta eihän opiskelijoilta voi vaatia mitään niin monimutkaista, että joutuisi tutkimaan asiaa konkreettisella simulaattorilla, että miten asian laita on noin empiirisesti. (Kun oikea vastaus on tiedossa, on helpompi sisäistää siihen liittyvä matemaattinen perusta.) Plaah. Ohessa vielä tuo koodinpaskakin, jos siitä on apua C-opintojen edistyessä.

[code:3s90o67y]#include

int rnd(unsigned max)
{
static unsigned long R16A=1L;
static unsigned long R16B=2L;
R16A -= 0x012357bfL;
R16B += 0xfedca201L;
R16A += (R16A>>16)^(R16B<<16);
R16B -= (R16A<<16)^(R16B>>16);
return (R16A^R16B)%max;
}

void main(void)
{
int kortit[52+2];

// korttipakan luonti jokereineen
for (int i=0; i<52; i++)
{
kortit[i]=i%13;
kortit[52]=100;
kortit[53]=100;
}

// empiirinen tutkimus ja tilastointi

double eria=0.0;
double samoja=0.0;
double tapauksia=0.0;

for (int loop=1; ; loop++)
{
int kasi[5];
int apu, i, n;
int kortteja=54;

for (i=0; i<5; i++)
{
n=rnd(kortteja);
kasi[i]=kortit[n];
apu=kortit[n];
kortit[n]=kortit[kortteja-1];
kortit[kortteja-1]=apu;
kortteja-=1;
}

for (int n=0; n<5; n++) // pitää olla vertailukorttina
if (kasi[n]!=100) break; // joku muu kuin jokeri.

for (i=0; i<5; i++)
if (kasi[i]!=kasi[n])
{
if (kasi[i]!=100) break;
}

if (i==5)
samoja+=1.0;
else eria+=1.0;
tapauksia+=(int)1;

if (!(loop%100000))
{
printf("todennakoisyys = %e (tapauksia = %0.0f)\n",
samoja/tapauksia, tapauksia);
}
}
}[/code:3s90o67y]

Vierailija

No, kieltämättä ilmeisesti aika vaikea lasku, koska vasta 4000000000 tapauksessa pystyy persetuntumalla sanomaan, että todennäköisyys on likimain:

1.9e-06

Saattaa tuo laskusi olla ihan oikeinkin, jos tuon simulaattorin optimoisi, ja tutkisi tähtitieteellisen määrän tapauksia. Piru tietää, vaikka se lopulta suppenisikin arvoon 2.6e-07? Ei se tietokonekkaan kaikkivoipa ole. Kannattaa siis laskea, niin ei jää mitään epäselväksi!

Vierailija

Lähdetään liikkeelle siitä, että viidestä samasta ensimmäinen kortti ei ole jokeri(tapahtuma A). Tällöin

P(A)=(52*5*4*3*2)/(54*53*52*51*50)=0,00001644263576

Olkoon B tapaus, missä viidestä samasta ensimmäinen on jokeri, mutta toinen ei. Tällöin

P(B)=(2*52*4*3*2)/(54*53*52*51*50)=0,0000065770543

Olkoon C tapaus, missä viidestä samasta kaksi ensimmäistä on jokereita. Tällöin

P(C)=(2*1*52*3*2)/(54*53*52*51*50)=0,00000164426358

Nyt siis

P(viisi samaa) = P(A)+P(B)+P(C) = 0,00002466395364

Eli pyöreästi 0,0025 %. Luulisin, että laskin oikein, mutta tod.näk. kurssista on niin pitkä aika etten vanno varmaksi.

Vierailija

No voi herran pieksut. Eihän tuossa koodissa:

[code:2mgxsqos]for (int n=0; n<5; n++) // pitää olla vertailukorttina
if (kasi[n]!=100) break; // joku muu kuin jokeri.[/code:2mgxsqos]

voi luoda silmukaan uutta sisäistä n-muuttujaa, koska vertailukortti on silloin sanalla sanoen lehmän perseessä.

Huomasin tämän, kun tein optimoidun version, joka rupesi antamaan erilaisia tuloksia. Piti sitten debugata puoli päivää, että missä perkeleessä oikein nyt heittää härän persettä. int-määrittely tuosta luupista helvettiin, niin n alkaa osoittamaan oikeaan vertailukorttiin.

Ja sitten lopulta tuolla optimoidulla versiolla todennäköisyydeksi saa likimain:

2.5e-05

Eli tuo Imperatorin kalkyylli antaa saman tuloksen simulaation kanssa. No, tuossa tuo paskakoodi vielä optimoituna ja oikeellisena:

[code:2mgxsqos]#include

unsigned long R16A=1L;
unsigned long R16B=2L;

inline int rnd(unsigned max)
{
R16A -= 0x012357bfL;
R16B += 0xfedca201L;
R16A += (R16A>>16)^(R16B<<16);
R16B -= (R16A<<16)^(R16B>>16);
return (R16A^R16B)%max;
}

void main(void)
{
int kortit[52+2];

// korttipakan luonti jokereineen
for (int i=0; i<52; i++)
{
kortit[i]=i%13;
kortit[52]=100;
kortit[53]=100;
}

// empiirinen tutkimus ja tilastointi

double eria=0.0;
double samoja=0.0;
double tapauksia=0.0;

for (int loop=1; ; loop++)
{
int kortteja=54;
int kortti, i, n;
int lippu=1, ref=-1;

for (i=0; i<5 && lippu; i++)
{
n=rnd(kortteja);
kortti=kortit[n];
kortteja-=1;

kortit[n]=kortit[kortteja];
kortit[kortteja]=kortti;

if (lippu)
{
if (ref==-1)
{
if (kortti!=100) ref=kortti;
}

if (kortti!=ref)
{
if (kortti!=100) lippu=0;
}
}
}

if (lippu)
samoja+=1.0;
else eria+=1.0;
tapauksia+=(int)1;

if (!(loop&0xffffff))
{
printf("todennakoisyys = %0.1e (tapauksia = %0.0f)\n",
samoja/tapauksia, tapauksia);
}
}
}[/code:2mgxsqos]

Vierailija

En nyt käsitä miksi se pitää laskea noin vaikeasti kuin _jone_ teki, mutta Imperator on oikeassa. Sitten jos käytetään vielä kombinatoriikkaa hyödyksi, niin saadaan kaavan avulla helpommin sovelletteva ja mukavamman näköinen ratkaisu. Kaava löytyy esimerkiksi Pitkä matematiikka -oppikirjasta.

Täällä on asiasta myös jotain:

http://www.it.lut.fi/mat/virtuaali/isom ... odnakl.pdf

Kannattaa lukea erityisesti siis kohta "Esimerkkejä kombinatorisesta todennäköisyyslaskennasta".

Vierailija

Nettiä kaivellessani löysin suhteellisen uskottavan oloisen pokeritodennäköisyyssivuston:
Durango Bill's Poker Probabilities

Durango Bill

5 card poker probabilities if two Jokers are added to the deck [...] 5 of a kind [...] 0.00002466



Lontoota taitavalle sivulla on aika perusteelliset selitykset noille laskuille, mutta tämän tapauksen voin käsitellä tässä lyhyesti:
Sivustolla olevassa taulukossa, missä tuo todennäköisyys luki, oli mainittu 78 erilaista kättä. Lyhyellä miettimisellä tajuaa, että noista 13 on käsiä joissa on yksi jokeri ja 13 joissa on se toinen. Loput 52 tulee siitä, että joikaiset kahden jokerin lisäksi olevat kolmoset voidaan muodostaa neljällä tavalla (eli se kortti joka kolmosista puuttuu on yksi neljästä), näitä käsiä on siten 13 x 4.
Ja kun tämä suotuisten käsien määrä jaetaan kaikkien mahdollisten käsien määrällä (54 yli 5:n) saadaan tuo aiemmin mainittu todennäköisyys (0.00002466).

[size=70:31qt54bd]edit. selvensin vähän kirjoitusasua[/size:31qt54bd]

Vierailija

No terveisiä perseestä... Lasku siis oikein mutta ilmeisesti olen pyöristänyt jonkin välivaiheen liian ankarasti.... : (
Kiitos

EDIT: Mullahan onkin iha väärä vastaus.. No se siitä

Vierailija

"En nyt käsitä miksi se pitää laskea noin vaikeasti kuin _jone_ teki, mutta Imperator on oikeassa."

No kyllä tuollaisista empiirisistä simulaattoreista on hyötyä varsinkin monimutkaisempia todennäköisyyksiä tutkittaessa. Kuten sanottu, oikea suuntaa antava tulos saattaa olla elintärkeä, kun johonkin sovellukseen alkaa vääntämään lopullista kaavaa.

Ainahan noissa todennäköisyyksissä voi kuitenkin myös luottaa puhtaasti siihen syyhyyn, joka kenenkin perseessä sattuu hyvältä tuntumaan. mutta varmemmalla pohjalla on silloin, kun kaksi toisistaan riippumatonta metodia puhuu saman tuloksen puolesta. mene ja tiedä. Piru tietää, muttei kerro.

abskissa
Seuraa 
Viestejä3654
Liittynyt9.10.2008

Erilaisia vitosia yhdellä jokerilla:

2pa, 2he, 2ri, 2ru, j1
2pa, 2he, 2ri, 2ru, j2
3pa, 3he, 3ri, 3ru, j1
3pa, 3he, 3ri, 3ru, j2
...
Apa, Ahe, Ari, Aru, j1
Apa, Ahe, Ari, Aru, j2

Yhteensä 2 * 13 = 26

Erilaisia vitosia kahdella jokerilla:

2pa, 2he, 2ri, j1, j2
2pa, 2he, 2ru, j1, j2
2pa, 2ri, 2ru, j1, j2
2he, 2ri, 2ru, j1, j2

3pa, 3he, 3ri, j1, j2
3pa, 3he, 3ru, j1, j2
3pa, 3ri, 3ru, j1, j2
3he, 3ri, 3ru, j1, j2

...

Apa, Ahe, Ari, j1, j2
Apa, Ahe, Aru, j1, j2
Apa, Ari, Aru, j1, j2
Ahe, Ari, Aru, j1, j2

Yhteensä 4*13 = 52

Erilaisia vitosia kaikkiaan: 78

Erilaisia käsiä kaikkiaan: 54 * 53 * 52 * 51 * 50 / 5! = 3162510

Vitosten todennäköisyys: 78 / 3162510 ~= 0,000024664

Ja jonen tyyliin simulointia ja Java-opetusta . Käydään brutella vaan kaikki mahdolliset kädet läpi. En nyt kuitenkaan viitsi pistää noita Combinations ja Card -luokkia tähän, ideahan välittyy tästäkin.

[code:2369ujo1]
package vitoset;

import java.util.Arrays;
import java.util.Collection;

import poker.Card;
import util.Combinations;

public class Vitoset {

public static void main(String[] args) {
// otetaan aikaa
long time = System.currentTimeMillis();

// lasketaan kädet ja vitoset
int handCount = 0;
int fivesCount = 0;

// varataan taulukko jaukaumalle
int[] dev = new int[14];

// luodaan pakka 2:lla jokerilla
Card[] deck = Card.createDeckArray(2);

// käsitellään viiden kortin kombinaatiot
Combinations hands =
new Combinations(deck, 5);

// käydään kaikki kombinaatiot läpi
for (Collection hand: hands) {

// käydään käsi läpi
// viitosia ei ole, jos esiintyy kahta eri arvoista korttia

int foundVal = -1;
boolean fives = true;

for (Card c: hand) {
int val = c.getValue();
if (val == Card.VALUE_JOKER) continue;
if (foundVal == -1) foundVal = val;
else if (foundVal != val) {
fives = false;
break;
}
}

if (fives) fivesCount++;

// merkitään läpikäydyt kädet
handCount++;
}

// otetaan ylös kulunut aika
time = System.currentTimeMillis() - time;

// ulostellaan
System.out.println("Käsiä: " + handCount);
System.out.println("Vitosia: " + fivesCount);
System.out.println("Aikaa kului: " + time + " millisekuntia");
}

}
[/code:2369ujo1]

Tulokseksi tulee

Käsiä: 3162510
Vitosia: 78
Aikaa kului: 1739 millisekuntia

EDIT: yksinkertaistin vähän tuota ohjelmaa

We're all mad here.

Uusimmat

Suosituimmat