Newsgroup: it.comp.lang.c++
Titolo: Simulazione scelta random - contenuto 2 scatole

Salve.
Ho trovato su un blog di matematica il seguente quesito:
- Il Capo ha comprato due scatole di svedesi da 40 fiammiferi
ciascuna. Le ha tenute nella stessa tasca, usando indifferentemente
l’una o l’altra. Ad un certo punto ne trova una vuota, che aveva
evidentemente rimesso in tasca senza notarlo. Dall’altra scatola tira
fuori un fiammifero e ci chiede: «Quanti fiammiferi mi sarei dovuto
aspettare di trovare, nella scatola non ancora vuota?»
Premetto che non so niente di matematica (non chiedetemi come ho fatto
a capitare nel blog).
Questo è l'indirizzo del blog:
http://rudimatematici-lescienze.blogautore.espresso.repubblica.it/2009/04/29/il-problema-di-aprile-488-limitrofe-conifere/#comments
La risposta data sul blog è:
distribuzione di probabilità --> valore medio --> = 7
Mi sono ricordato che 5 anni fa sapevo ancora scrivere qualche riga di
codice, ho scaricato wxDev-C++, ed ho provato a buttar giù una
simulazione del problema (ovviamente, con numeri pseoudorandom).
Il problema è che il mio programmino mi indica come numero più
frequente 2, a dispetto di ben 100.000.000 di loop, invece che sette.
Visto che in questi 5 anni dalla mia mente sembra essere scappato
tutto quello che sapevo sul C, ho pensato di chiedere aiuto su questo
forum per scoprire dov'è che sbaglio.
Ecco il codice che ho scritto:
*********************
#include <cstdlib>
#include <iostream>
#include <fstream.h>
using namespace std;
int main(int argc, char *argv[])
{
    int ris[41]; //Risultato finale
    srand((unsigned)time(NULL));
    for(int n=1;n<=40;n++)
        ris[n]=0;
    for(int n=1;n<=100000000;n++)
    {
        int a=40, b=40;
        while(a && b) // if a or b is not 0, result value is not 0
        {
            switch (rand()%2 + 1)
            {
                case 1:
                    if((--a)==0) ris[b]++;
                    break;
                case 2:
                    if((--b)==0) ris[a]++;
                    break;
                default:
                    cerr << "Error: random number out of range 1-2";
                    system("PAUSE");
                    abort();
                    break;
            }
        }
    }
    ofstream out("Risultati.txt",ios::app);
    for(int n=1;n<=40;n++)
    {
        out << n << " --> \t" << ris[n] << "\n";
    }
    out << "\n";
    out.close();
    //system("PAUSE");
    return EXIT_SUCCESS;
}
*********************
Grazie di ogni aiuto!
P.s. la risposta mi interessa, ma per motivi "tecnici" posso
collegarmi solo ad intervalli. Mi scuso se non sono in grado di
leggere subito i vostri post.

 
il programmino va bene cosï¿½
la soluzione ï¿½ il valore medio della distribuzione
non il numero piï¿½ frequente

 non il numero più frequente
Beh, capisco che sia decisamente OT, ma mi sapresti spiegare come mai
il valore atteso non è quello che esce più di frequente?
Forse sono io che non ho proprio speranze con la matematica.
Grazie mille comunque di averci speso tempo.

 Forse sono io che non ho proprio speranze con la matematica.
Si tratta del calcolo delle probabilita' che e' uno specifico settore 
della matematica, e se non si ha mai studiato non e' detto che non si 
abbiano speranze.
Penso che l'unica risposta corretta alla domanda �Quanti fiammiferi mi 
sarei dovuto aspettare di trovare, nella scatola non ancora vuota?� 
abbia la forma della seguente.
Una probabilita' P1 di trovare un solo fiammifero.
Una probabilita' P2 di trovare due fiammiferi.
Una probabilita' P3 di trovare tre fiammiferi.
...
Una probabilita' P40 di trovare quaranta fiammiferi.
Ovviamente P1 + P2 + P3 + ... + P40 = 1, dato che abbiamo la certezza 
che ci sia un numero intero di fiammiferi compreso tra 1 e 40.
Data questa distribuzione, possiamo calcolare varie statistiche, cioe' 
funzioni della distribuzione. tra le statistiche piu' famose ci sono la 
media aritmetica, la moda, la mediana, la varianza, la deviazione standard.
Tu hai calcolato giustamente che la moda e' 2, mentre asserisci 
erroneamente che la media e' 7. Non ho fatto i conti, ma dal sito citato 
risulta che la media di tale distribuzione e' circa 7,11423.
La media aritmetica e' purtroppo normalmente chiamata dagli statistici 
"valore atteso", sebbene non sia affatto il valore che ci si attende.
per esempio, lanciando in aria una moneta perfetta che ha scritto su una 
faccia il numero 0 e sull'altra il numero 1, che valore ci si attende?
La risposta e': al 50% il valore 0 e al 50% il valore 1. tuttavia il 
cosiddetto valore atteso (in inglese "expectation") e' 0,5, anche se 
nessuno si aspetta che esca un faccia con sopra scritto il numero 0,5.
Nel caso della moneta perfetta, la distribuzione e' bimodale, in quanto 
i casi possibili sono equiprobabili, cioe' non c'e' una sola moda, ma ce 
ne sono due, 0 e 1.
-- 
Carlo Milanesi
http://digilander.libero.it/carlmila

 Tu hai calcolato giustamente che la moda e' 2.
Ma, simulazione a parte, come mai la moda sarebbe 2?
Perché le scatole di fiammiferi sono 2 e ogni volta la probabilità di 
estrarre dalla scatola A o dalla B è 1/2?
Ma in tal caso, la moda non dovrebbe essere 1? Intuitivamente (almeno 
secondo il mio intuito :) il tipo di estrazione a cui si tende e quella 
in cui si estrae un fiammifero alternativamente da ogni scatola, per cui 
nel momento in cui la A è vuota, nella B ce ne sarà 1.

Luigi ha scritto:

Chiedo scusa dell'errore. La moda e' proprio 1, l'intuizione non ti inganna.
Questo dimostra quanto sia scadente il generatore di numeri 
pseudocasuali "rand", almeno sulle cifre meno significative. Infatti nel 
lo standard C++0x sara' introdotto un nuovo generatore di numeri 
pseudocasuali.


 abbia la forma della seguente.
...
Ok, ti ringrazio dell'impegno che ci metti a cercare di farmi capire.
Indubbiamente, se non ci arrivo, il problema è solo mio.
Ma non esiste un modo semplice per spiegarmi come mai, se la domanda è
(semplificando all'estremo):
"Quanti fiammiferi mi dovrei aspettare di trovare?"
La risposta *non* è:
"Il numero che capita più spesso" ?
Perché dovrei aspettarmi un numero diverso da quello che
'sperimentalmente' è il più frequente?
E' solo un problema di generatore pseudorandom?
Nel qual caso, mi arrendo, perché ho sentito parlare di schede da
installare nel computer che sfruttano fenomeni quantistici per creare
numeri realmente casuali, e di servizi online che permettono di
scaricare flussi di numeri casuali, ma non credo che mi getterò
nell'impresa.

 nell'impresa.
Una scheda che sfrutta fenomeni quantistici su un comune pc?
Prova a riscrivere quel programma in pascal, fino ad ora ho sempre notato 
che quel generatore di numeri casuali non è male, soprattutto se 
paragonato a srand (notoriamente poco imprevedibile).

 pseudocasuali "rand", almeno sulle cifre meno significative.
Per ovviare a questo problema si puo' ricorrere a questo (indicato
nelle FAQ):
al posto di
  rand() % N
quando N e' un valore piccolo e' meglio usare
  (int)((double)rand() / ((double)RAND_MAX + 1) * N)
ciao
Giacomo

   (int)((double)rand() / ((double)RAND_MAX + 1) * N)
Con switch ((int)((double)rand() / ((double)RAND_MAX + 1) * 2) % 2 + 1)
La moda viene 1.

 Prova a riscrivere quel programma in pascal
Sicuramente è una buona idea.
Ma c'è un problema...
Ti sarebbe di molto incomodo, a questo punto, insegnarmi il pascal? :-
D

 non ancora vuota?»
Ciao,
Ti pongo un quesito sperando che ti illumini:
Se ho 8 partecipanti ad una gara, P1 vince al 30%, mentre gli altri
P2..P8 vincono al 10% ciascuno;
P1 è sicuramente la moda, ma credi che vincerà la prossima gara ?
Ha piu speranze di vincere di tutti gli altri (presi singolarmente),
ma probabilmente perderà.
Tornando al tuo problema (ristretto a 4): se
1 esce 100 volte,
2 esce 90 volte,
3 esce 60 volte,
4 esce 50 volte;
Allora per 1/3 uscirà 1, mentre per 2/3 uscirà un valore tra 2 e 4.
Ovvero, mediamente, non uscirà 1 (ma un valore piu alto), anche se 1 è
la moda
Ciao
Gg

 Ti sarebbe di molto incomodo, a questo punto, insegnarmi il pascal? :-
Eheh, addirittura insegnare un linguaggio ;-)
Scrivo il sorgente, come sarebbe in pascal (vado un po' a memoria, ma
credo sia corretto). Poi procurati un compilatore (Turbo Pascal) e
prova il sorgente:
program fiammiferi;
uses crt;
var
    ris : array[1..40] of integer;
    n, a, b, s : integer;
    f : text;
begin
    for n := 1 to 40 do
        ris[n] := 0;
    for n := 1 to 100000000 do
        begin
            a := 40;
            b := 40;
            while (a > 0 and b > 0 ) do
                begin
                    randomize;
                    s = random(2) + 1;
                    case s of
		        1 :
			begin
                            a := a - 1;
                            if (a = 0) then
                               ris[b] := ris[b] + 1;
	                end;
                        2 :
			begin
                            b := b - 1;
                            if (b = 0) then
                               ris[a] := ris[a] + 1;
	                end;
		end;
            end;
    assign(f, 'Risultati.txt');
    rewrite(f);
    for n := 1 to 40 do
        begin
            write(f, n);
            write(f, '  ->  ');
            writeln(f, ris[n]);
	end;
    close (f);
end.

 s = random(2) + 1;
sarebbe
s := random(2) + 1;
gli assegnamenti che in C++ sono indicati con = in pascal sono indicati 
con :=
mentre l'uguaglianza invece di == è =
Comunque siamo molto OT, puoi anche chiedere su it.comp.lang.pascal :-D