Problema con questo programmino...:(

di il
17 risposte

Problema con questo programmino...:(

Salve a tutti, se qualcuno vuole provare ad aiutarmi gliene sarei grato...ho scritto un programma di c++ che calcola le probabilità di un gioco di "fortuna" tipo poker chiamato Perudo, un gioco in cui si usano quasi solo i dadi.
Allora io volevo calcolare la probabilità che lanciando n dadi vengano fuori x dadi di valore y(y può essere da 1 a 6, utilizzo dadi a sei facce).
Il metodo di risoluzione del problema consiste, visto che è impossibile arrivarci con un metodo matematico, xkè i numeri, sarebbero troppo elevati per qualunque macchina, conviene usare un metodo di simulazione, praticamente, simulo col c++ il lancio di n dadi, poi lo ripeto per 1 milione di volte(o anche di più) con un ciclo for, poi con svariati if raggruppo in quanti lanci si è verificato che ci sono stati x dadi y (quelli richiesti all'inizio) e poi calcolo la mia percentuale (la formula casi favorevoli diviso casi totali)

ecco il testo del programma:

#include <iostream>
#include <conio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
using namespace std;

int n;//numero di dadi totali;
int x;//quantità di y;
int y;//facce del dado richieste;
int h;
double cf=0;//casi favorevoli(parte da zero);
double p;//probabilità;
double pp;//probabilità percentuale;

int main()
{cout<<"Quanti dadi si lanciano???"<<endl;
cin>>n;
if(n>25||n<2) //al massimo si usano 25 dadi in perudo;
goto fine;
else
;
cout<<"Ora calcolero' la probabilita' che ci siano x dadi di valore y.\n Scrivi x e poi y:"<<endl;
cin>>x>>y; //aquisisco da tastiera i dati x e y;
srand(time(NULL)); //chiamo la funzione per i numeri casuali;

for(int h=0;h<1000000;h++) /*entro nel loop che mi fa fare 1 milione di volte la simulazione di
un lancio;*/
{ int g=0;



do{ //simulazione di un lancio(di n dadi);
{int xx;
int r;//contatore;
xx = rand() % 6+1; //esito lancio;
g++; /*incrementa la variabile g, appena raggiunge il numero di dadi esce dal ciclo
per poi rifarlo, finchè non termina il for(1 milione di volte);*/

if(xx==y||xx==1) //se il lancio di un dado da il numero cercato allora aumenta la variabile risultato di 1;
r++;

}while(r!=n);
if(r==x)
cf++;


}
;




p=cf/1000000; //calcolo la probabilità;
pp=p*100; //calcolo la probabilità percentuale;

cout<<"la probabilita' che ci siano"<<' 'x' '<<"numeri"<<' 'y' '<<"e' del"<<pp<<"%"<<endl;

fine:


_getch();
}

17 Risposte

  • Re: Problema con questo programmino...:(

    Ciao!
    Invece di tute quelle complicate forumle io utilizzere la generazione di numeri pseudocasuali del C.
    Sostanzialmente viene generato un numero partendo da un numero "seme" impostando un valore masismo ed un valore minimo che comprenda il risultato.
    Se tu come numero seme utilizzi il numero dei secondi da cui l'orologio dei sistemi calcola il "secondo 0" utilizzando la libreria time.h, ottieni un numero che varia ogni volta che il programma viene lanciato e che può essere ritenuto "pseudocasuale"

    Adesso non mi ricordo esattamente i codici.
    In ogni caso puoi googlare qualcosa come: numeri pseudocasuali C

    Ed eventualmente aspettare l'intervento di chi, magari avendoli usati recentemente, può stenderti velocmente qualche codice di esempio.

    In ogni caso spero di averti aiutato,
    a presto
  • Re: Problema con questo programmino...:(

    Ananke Melior ha scritto:


    Ciao!
    Invece di tute quelle complicate forumle io utilizzere la generazione di numeri pseudocasuali del C.[..]
    Mi sembra che lui già faccia quel che dici.

    Se il problema è la generazione di un numero che sia abbastanza casuale su sistemi linux è possibile leggere N byte ( in questo caso ne basterebbe solo 1 ) da /dev/random
  • Re: Problema con questo programmino...:(

    Ananke Melior ha scritto:


    Ciao!
    Invece di tute quelle complicate forumle io utilizzere la generazione di numeri pseudocasuali del C.
    Sostanzialmente viene generato un numero partendo da un numero "seme" impostando un valore masismo ed un valore minimo che comprenda il risultato.
    Se tu come numero seme utilizzi il numero dei secondi da cui l'orologio dei sistemi calcola il "secondo 0" utilizzando la libreria time.h, ottieni un numero che varia ogni volta che il programma viene lanciato e che può essere ritenuto "pseudocasuale"

    Adesso non mi ricordo esattamente i codici.
    In ogni caso puoi googlare qualcosa come: numeri pseudocasuali C

    Ed eventualmente aspettare l'intervento di chi, magari avendoli usati recentemente, può stenderti velocmente qualche codice di esempio.

    In ogni caso spero di averti aiutato,
    a presto

    Bene, adesso che abbiamo una chiara visione dell'ovvio, potresti darmi la soluzione?
  • Re: Problema con questo programmino...:(

    Ciao miky9757,
    se vuoi puoi considerare un altro approccio, in numeri in gioco diventano troppo grandi perchè hai a che fare coi fattoriali, pero nella formula della binomiale c' è spazio per semplificare, tanto che potresti facilmente fare il calcolo con carta e penna.

    Se devi calcolare la divisione tra due fattoriali A! / B! basta moltiplicare i numeri va vanno da B+1 ad A.
  • Re: Problema con questo programmino...:(

    Bene, adesso che abbiamo una chiara visione dell'ovvio, potresti darmi la soluzione?
    In effetti ho letto male il codice, in ogni caso cercavo solo di aiutare, non c'è bisogno di fare gli "splendidi" eh.
  • Re: Problema con questo programmino...:(

    Scusa, stavo scherzando, volevo citare Sherlock Holmes
  • Re: Problema con questo programmino...:(

    Ok ok nessun problema
  • Re: Problema con questo programmino...:(

    Ciao Holmes, guarda che simpatica questa funzione, ti calcola senza problemi il binomiale di 25 su 24 (perchè provvede a semplificare i termini), dovrebbe fare al caso tuo.
    
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include <limits.h>
    #include <iostream>
    using namespace std;
    
    long Binomial(long n, long k)
    {
    	long result = 1;
    	long a = n - k;
     
    	if (a > k) // prende il minore tra k and n - k
    	{ 
    		k = a; 
    		a = n - k; 
    	}
     
    	while (n > k) 
    	{
    		if (result >= UINT_MAX / n)
    			return 0; // overflow
    	
    		result *= n--;
    
    		// dividendo per (n - k)! può evitare l' overflow 
    		while (a > 1 && !(result % a)) 
    			result /= a--;
    	}
    
    	return result;
    }
     
    int main()
    {
        int n = 25;
        int k = 5;
    		
        double p = 1.0 / 6.0;
        cout << Binomial(n, k) * pow(p, k) * pow(1 - p, n - k) << endl;
    
        return 0;
    }
    
    Ovviamente il funzionamento è elementare.
  • Re: Problema con questo programmino...:(

    Ottima deduzione Watson, ma io cercavo di risolvere questo esercizio senza uso di funzioni diverse da srand (quella che ho usato)...
  • Re: Problema con questo programmino...:(

    Ciao miky9757,
    il fatto è che non ho capito (o non hai spiegato) quello che vuoi. Cosa c' è nel tuo programma che non va?
  • Re: Problema con questo programmino...:(

    Prova a fare copia incolla sul tuo programma di c++, verranno fuori degli errori xkè il programma non riesce nel processo di aumentare le variabili r e cf, perchè credo le consideri variabili locali, e finito il ciclo dopo le cancella...bo, non ho capito nemmeno io xkè non va! Per questo ho chiesto qui
  • Re: Problema con questo programmino...:(

    Prova a portare la dichiarazione delle due variabili xx ed r fuori dal ciclo, e poi noto che r non è inizializzata quindi aumenti un valore che non sai qual è ( in C\C++ le variabili non vengono automaticamente inizializzate al valore 0 ).
  • Re: Problema con questo programmino...:(

    Ciao miky9757,
    tutto sommato il problema è interessante, cioè capire come una simulazione del genere possa essere precisa. Ti posto una soluzione, che contiene sia il calcolo esatto, sia il calcolo simulato come serve a te.
    
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include <limits.h>
    #include <conio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <math.h>
    
    #include <iostream>
    using namespace std;
    
    // -----------------------------------------------------------------------------------------
    // Calcolo esatto
    
    long Binomial(long n, long k)
    {
    	long a = n - k;
    	if (a > k) 
    	{ 
    		k = a; 
    		a = n - k; 
    	}
    
    	long result = 1;
    	while (n > k) 
    	{
    		if (result >= UINT_MAX / n)
    		{
    			cout << "Overflow" << endl;
    			return 0; 
    		}
    
    		result *= n--;
    		while (a > 1 && !(result % a)) 
    			result /= a--;
    	}
    
    	return result;
    }
    
    void CalcolaPerudo(int numeroDadi, int facceRichieste)
    {
        const double p = 1.0 / 6.0;
        double probabilita = Binomial(numeroDadi, facceRichieste) * pow(p, facceRichieste) * 
                 pow(1 - p, numeroDadi - facceRichieste);
        cout << "Valore esatto: " << probabilita * 100 << endl;
    }
    
    // ---------------------------------------------------------------------------------------
    
    // Simulazione
    
    void SimulaPerudo(int numeroDadi, int facceRichieste, int valoreRichiesto)
    {
    	double casiFavorevoli = 0;
    	srand(time(NULL));
    
    	for(int i = 0; i < 1000000; i++)
    	{	
    		int tot = 0;
    		for(int j = 0; j < numeroDadi; ++j) // simulazione di un lancio di n dadi
    		{	 
    			int valoreDado = rand() % 6 + 1;
    			if( valoreDado == valoreRichiesto )	
    				tot++;
    		}
    
    		if(tot == facceRichieste)
    			++casiFavorevoli;
    	};	
    
    	double probabilita = casiFavorevoli / 1000000;	 
    	double probabilitaPercentuale = probabilita * 100;	 
    
    	cout << "la probabilita' che ci siano " << facceRichieste << " numeri " << valoreRichiesto 
                  << " e' del " << probabilitaPercentuale << "%" << endl;
    }
    
    int main()
    {
    	int numeroDadi;
    	cout << "Quanti dadi si lanciano??? (da 2 a 25)" << endl;
    	cin >> numeroDadi;
    	if( numeroDadi > 25 || numeroDadi < 2) //al massimo si usano 25 dadi in perudo;
    	{
    		cout << "i valori validi sono da 2 a 25" << endl;
    		return 0;
    	}
    
        int facceRichieste;
    	int valoreRichiesto;
    	cout << "Ora calcolero' la probabilita' che ci siano x dadi di valore y." << endl 
                 << "Scrivi x e poi y:" << endl;
    	cin >> facceRichieste >> valoreRichiesto;	 
    
    	SimulaPerudo(numeroDadi, facceRichieste, valoreRichiesto);
    	CalcolaPerudo(numeroDadi, facceRichieste);
    
    	_getch();
    	return 0;
    }
    
    Come vedrai i risultati forniti dalla simulazione sono piuttosto buoni, ad esempio con 25 dati e 5 facce uguali si ha 17.86% (simulato) contro 17.82% (esatto). Chiaramente più la probalibità diminuisce più il simulatore è impreciso.

    La soluzione simulata ricalca quelle scritta da te, confrontandole potrai vedere cosa non andava.
    Saluti dal tuo affezionato Professor Moriarty
    (e mi racommando non usare mai più i goto).
  • Re: Problema con questo programmino...:(

    barba59 ha scritto:


    Ciao miky9757,
    tutto sommato il problema è interessante, cioè capire come una simulazione del genere possa essere precisa. Ti posto una soluzione, che contiene sia il calcolo esatto, sia il calcolo simulato come serve a te.
    
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include <limits.h>
    #include <conio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <math.h>
    
    #include <iostream>
    using namespace std;
    
    // -----------------------------------------------------------------------------------------
    // Calcolo esatto
    
    long Binomial(long n, long k)
    {
    	long a = n - k;
    	if (a > k) 
    	{ 
    		k = a; 
    		a = n - k; 
    	}
    
    	long result = 1;
    	while (n > k) 
    	{
    		if (result >= UINT_MAX / n)
    		{
    			cout << "Overflow" << endl;
    			return 0; 
    		}
    
    		result *= n--;
    		while (a > 1 && !(result % a)) 
    			result /= a--;
    	}
    
    	return result;
    }
    
    void CalcolaPerudo(int numeroDadi, int facceRichieste)
    {
        const double p = 1.0 / 6.0;
        double probabilita = Binomial(numeroDadi, facceRichieste) * pow(p, facceRichieste) * 
                 pow(1 - p, numeroDadi - facceRichieste);
        cout << "Valore esatto: " << probabilita * 100 << endl;
    }
    
    // ---------------------------------------------------------------------------------------
    
    // Simulazione
    
    void SimulaPerudo(int numeroDadi, int facceRichieste, int valoreRichiesto)
    {
    	double casiFavorevoli = 0;
    	srand(time(NULL));
    
    	for(int i = 0; i < 1000000; i++)
    	{	
    		int tot = 0;
    		for(int j = 0; j < numeroDadi; ++j) // simulazione di un lancio di n dadi
    		{	 
    			int valoreDado = rand() % 6 + 1;
    			if( valoreDado == valoreRichiesto )	
    				tot++;
    		}
    
    		if(tot == facceRichieste)
    			++casiFavorevoli;
    	};	
    
    	double probabilita = casiFavorevoli / 1000000;	 
    	double probabilitaPercentuale = probabilita * 100;	 
    
    	cout << "la probabilita' che ci siano " << facceRichieste << " numeri " << valoreRichiesto 
                  << " e' del " << probabilitaPercentuale << "%" << endl;
    }
    
    int main()
    {
    	int numeroDadi;
    	cout << "Quanti dadi si lanciano??? (da 2 a 25)" << endl;
    	cin >> numeroDadi;
    	if( numeroDadi > 25 || numeroDadi < 2) //al massimo si usano 25 dadi in perudo;
    	{
    		cout << "i valori validi sono da 2 a 25" << endl;
    		return 0;
    	}
    
        int facceRichieste;
    	int valoreRichiesto;
    	cout << "Ora calcolero' la probabilita' che ci siano x dadi di valore y." << endl 
                 << "Scrivi x e poi y:" << endl;
    	cin >> facceRichieste >> valoreRichiesto;	 
    
    	SimulaPerudo(numeroDadi, facceRichieste, valoreRichiesto);
    	CalcolaPerudo(numeroDadi, facceRichieste);
    
    	_getch();
    	return 0;
    }
    
    Come vedrai i risultati forniti dalla simulazione sono piuttosto buoni, ad esempio con 25 dati e 5 facce uguali si ha 17.86% (simulato) contro 17.82% (esatto). Chiaramente più la probalibità diminuisce più il simulatore è impreciso.

    La soluzione simulata ricalca quelle scritta da te, confrontandole potrai vedere cosa non andava.
    Saluti dal tuo affezionato Professor Moriarty
    (e mi racommando non usare mai più i goto).

    Grazie mille signor Moriarti, sono un allievo del c++ alle prime armi, un principiante, grazie mille per il programma, è esattamente quello che volevo fare io...ora non mi resta che studiarlo e capirlo, ma l'ho già provato, e funziona perfettamente, grazie. Una cosa, ma perchè non devo mai usarlo il goto? Che problemi può dare?? Secondo me è comodo per uscire da cicli o altro...
Devi accedere o registrarti per scrivere nel forum
17 risposte