[ C ++] Compilazione di un semplice programma matematico

daniele912
Ciao a tutti!
Ho appena iniziato a studiare qualcosa del linguaggio C++ in quanto devo realizzare un piccolo programma per la risoluzione di problemi matematici da portare all'appello orale di un esame. Siccome la parte di programmazione è ridotta all'osso (non costituisce, infatti, la parte centrale dell'esame) e siccome il prof. ha richiesto una conoscenza davvero minima del linguaggio, vorrei realizzare un programma non troppo complicato ma, comunque, non banale. Che tipo di programma potrei realizzare secondo voi? Avete qualche idea? Inoltre, sarebbe davvero gradita una mano nella compilazione del programma e nella correzione degli errori...
Grazie a tutti :)

Risposte
daniele912
Avevo aggiunto proprio quel codice. Il problema è che, dopo aver ripetuto il ciclo per due volte, mi ripete per due volte di fila il messaggio "Vuoi ripetere il programma?"...

daniele912
Infatti, se immetto il numero 2 alla richiesta "Vuoi ripetere l'operazione?", devo ripetere due volte la digitazione altrimenti non si chiude. Da cosa dipende? Pensavo di aver commesso qualche errore io...

hamming_burst
"daniele91":
Infatti, se immetto il numero 2 alla richiesta "Vuoi ripetere l'operazione?", devo ripetere due volte la digitazione altrimenti non si chiude. Da cosa dipende? Pensavo di aver commesso qualche errore io...

sicuro di aver inserito l'operazione che ho scritto sopra, perchè deve essere un AND tra le due condizioni.

Io lo ho compilato ora, funziona tutto normalmente...

daniele912
Si sicuro! Come è possibile? '_'

Ecco guarda:


E questo è il codice:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

int main ()
{
int n;
int f[6], i, faccia, risp;

   srand ((unsigned)time(NULL));
   cout << "SIMULATORE DI LANCIO DEL DADO" << endl;

   do{
      for (i=0; i<6; i++){

         f[i]=0;
      }
      cout << " " << endl;
      cout << "Inserisci il numero di ripetizione del lancio" << endl;
      cin >> n;
      for (i=0; i<n; i++){
         faccia=rand()%6;
         f[faccia]++;
      }

      for (i=0; i<6; i++){
         cout << "Faccia" << i+1 <<  "Frequenza > " << f[i] << endl;
      }

      cout << "Vuoi ripetere l'operazione? Si=1, No=2" << endl;
      cin >> risp;
 }
   while (risp==1);
   
do {
    cout << "Vuoi ripetere l'operazione? Si=1, No=2" << endl;
    cin >> risp; 
}
   while (risp!=1&&risp!=2);

   return 0;
}

hamming_burst
bhe semola :-D
se nel codice lo chiedi te DUE volte, ovvio che lo stampa DUE volte (o infinite) :D

questo il tuo codice:
      cout << "Vuoi ripetere l'operazione? Si=1, No=2" << endl;
      cin >> risp;
 }
   while (risp==1);
   
do {
    cout << "Vuoi ripetere l'operazione? Si=1, No=2" << endl;
    cin >> risp; 
}
   while (risp!=1&&risp!=2);

codice corretto, se rileggi ciò che scrissi nel post sopra, ho parlato di circondare non aggiungere:
		do{
			cout << "Vuoi ripetere l'operazione? Si=1, No=2" << endl;
			cin >> risp;
		}while(risp!=1&&risp!=2);

	}while (risp==1);

daniele912
Adesso finalmente ho capito! Solo che dovrò aggiungere un bel pò di commenti al codice altrimenti non ricorderò niente perchè non ho capito fino in fondo le istruzioni ed i vari cicli. Comunque, adesso vorrei implementare nel programma un test del chi quadro ma non ho la più pallida idea di come iniziare a fare. In seguito, dovrei realizzare un secondo programma simile a questo (magari con un altro tipo di "gioco" di cui si può calcolare la frequenza) sempre con un test del chi quadro.
Il problema è che non so mai da dove iniziare. Infine, ho scaricato Code::blocks ma non capisco per quale motivo mi da errore sulle librerie nonostante abbia fatto il copia e incolla del codice da Dev C++. Sbaglio a impostare qualcosa? Grazie!

hamming_burst
"daniele91":
Adesso finalmente ho capito! Solo che dovrò aggiungere un bel pò di commenti al codice altrimenti non ricorderò niente perchè non ho capito fino in fondo le istruzioni ed i vari cicli.

queste condizioni di uscita si possono scrivere anche non utilizzando due cicli annidati, se ti sembra più facile comprendere la questione, utilizza degli if.

Per Code::blocks, non so aiutarti, non lo ho quasi mai utilizzato (uso altro). Penso sia dovuto a come hai configurato le librerie nella tua cartella di lavoro....

daniele912
Mentre per il testo del chi quadro potresti darmi una mano?

daniele912
Nessun'altro può aiutarmi?

daniele912
Up!

vict85
Comincia con il riportare qui la formula per il caso in questione... Noi ti aiuteremo a capire come si traduce in C++...

Ma devi comunque essere tu a scrivere il codice, il sito non può fare il lavoro al posto tuo.

P.S: te la faccio scrivere per fartici ragionare sopra.

daniele912
Il chi quadro, nel mio caso, si calcola in questo modo:

$\chi ^2 = sum_(i=1)^(n) ((e_1 - o_i)^2)/(e_i)$

con $e_i$ = dato atteso e $o_1$ = dato osservato, ovvero le frequenze fornite dal programma.

Ora, io non so come definire la formula all'interno del programma e non ho la più pallida idea di come proseguire. Ecco per quale motivo non ho scritto il mio codice...mi servirebbe una bella dritta. Come si implementano formule matematiche in programmi scritti con il C++?

vict85
"daniele91":
Il chi quadro, nel mio caso, si calcola in questo modo:

$\chi ^2 = sum_(i=1)^(n) ((e_1 - o_i)^2)/(e_i)$

con $e_i$ = dato atteso e $o_1$ = dato osservato, ovvero le frequenze fornite dal programma.

Ora, io non so come definire la formula all'interno del programma e non ho la più pallida idea di come proseguire. Ecco per quale motivo non ho scritto il mio codice...mi servirebbe una bella dritta. Come si implementano formule matematiche in programmi scritti con il C++?


Io intendevo proprio nel tuo caso. Siccome hai usato n per il numero di classi scrivo il numero di lanci del dado come tiri_dadi

\(\displaystyle n = 6 \)
\(\displaystyle e_i = \text{tiri_dadi}/6 \) per ogni \(\displaystyle i \)
\(\displaystyle o_i = \text{f[i-1]} \) (dubbi su questo?)

Quindi ricavi la formula:

\(\displaystyle \chi^2 = \sum_{i=0}^5 \frac{(\text{tiri_dadi} - 6\text{f})^2}{6\text{tiri_dadi}} \)

oppure come è scritto in wiki (l'uguaglianza si dimostra semplicemente calcolando il quadrato e semplificando)

\(\displaystyle \chi^2 = \sum_{i=0}^5 \frac{6(\text{f})^2}{\text{tiri_dadi}} - \text{tiri_dadi} = \frac{6}{\text{tiri_dadi}}\sum_{i=0}^5 (\text{f})^2 - \text{tiri_dadi} \)

Fin qui ci sei?

Io userei l'ultima formula perché il tutto è divisibile in operazione molto elementari.

Vediamo come si può dividere in operazioni più semplici.

\(\displaystyle \text{sum} = \sum_{i=0}^5 (\text{f})^2 \)
\(\displaystyle \text{scaled_sum} = \frac{\text{sum}}{\text{tiri_dadi}} \times 6 \)
\(\displaystyle \chi^2 = \text{scaled_sum} - \text{tiri_dadi} \)

Dopo di che devi confrontarlo con la tabella. La variabile è \(\displaystyle \chi^2_5 \) e penso sia opportuno usare come regione critica \(\displaystyle \chi^2 > \chi^2_{0,05\ 5} = 10,070 \)

Ora veniamo a questione di implementazione.

Per prima cosa non ho bisogno di tutte quelle variabili. Mettendo da parte la correttezza matematica posso infatti riscrivere come:
\(\displaystyle \chi^2 = \sum_{i=0}^5 (\text{f})^2 \)
\(\displaystyle \chi^2 = \frac{\chi^2}{\text{tiri_dadi}} \times 6 \)
\(\displaystyle \chi^2 = \chi^2 - \text{tiri_dadi} \)

Tenendo conto che nel tuo codice tiri_dadi è la variabile n ed ignorando il primo step, che poi vediamo come farlo, gli ultimi passaggi diventano, in C++:
chi_q /= n;
chi_q *= 6;
chi_q -= n;

Ho deciso di dividere apposta in passaggi elementari. Avrei ovviamente potuto scriverli tutti in una sola riga oppure riunendo i primi due.

Ora veniamo alla prima parte, cioè:
\(\displaystyle \chi^2 = \sum_{i=0}^5 (\text{f})^2 \)

Questo è equivalente a:
\(\displaystyle \displaystyle \chi^2 = (\text{f[0]})^2 + (\text{f[1]})^2 + (\text{f[2]})^2 + (\text{f[3]})^2 + (\text{f[4]})^2 + (\text{f[5]})^2 \)

Seguendo il modo in cui lo calcoleresti a mano, e ignorando la correttezza matematica, lo posso riscrivere anche come:
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f[0]})^2\)
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f[1]})^2\)
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f[2]})^2\)
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f[3]})^2\)
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f[4]})^2\)
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f[5]})^2\)
che come si può vedere è la ripetizione per i che va da 0 a 5 di
\(\displaystyle \displaystyle \chi^2 = \chi^2 + (\text{f})^2\)
Quindi questo va scritto come un ciclo for.

for(int i = 0; i<6; i++)
{
  const double temp = f[i]*f[i];
  chi_q += temp;
}


Ovviamente devi definire chi_q e porla uguale a 0 prima di tutto questo. Inoltre devi fare il test finale per controllare se \(\displaystyle \chi^2 > 10,070 \) (ricorda che in C++ devi mettere il punto e non la virgola).

È conveniente inoltre controllare che \(\displaystyle n>60 \) (magari anche 100) al fine da assicurarti che il test sia sufficientemente attendibile. Volendo per evitare sorprese di calcolo potresti anche porre un limite superiore.

daniele912
Quando hai scitto $o_i= f[i-1]$, quello che c'è nelle parentesi quadre si riferisce al fatto che l'array "parte" da 0 piuttosto che da 1? Oppure ho tralasciato qualcosa? Inoltre, ho consultato una tabella sulla disribuzione del chi quadro su internet e ho constatato che il valore è di 11,07 piuttosto di 10,07. Vorrei chiarire questi aspetti prima di procedere con la compilazione del programma.
Grazie!

vict85
Per il valore... Possibile. Riguardo alla prima cosa si, intendevo che partiva da 0.

daniele912
Riprendo questo post per evitare di scriverne un altro. Ho modificato il codice inserendo il test del chi quadro ma, facendo una verifica dei calcoli, il calcolo del valore del chi è sempre sballato e non riesco a trovare l'errore. Ecco il codice:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

int main ()
{
int n;

double X[6], risultato_chi_quadro;

int f[6], i, faccia, risp;


   srand ((unsigned)time(NULL));
   cout << "SIMULATORE DI LANCIO DEL DADO" << endl;

   do{
      for (i=0; i<6; i++){

         f[i]=0;
      }
      cout << " " << endl;
      cout << "Inserisci il numero di ripetizione del lancio" << endl;
      cin >> n;
      for (i=0; i<n; i++){
         faccia=rand()%6;
         f[faccia]++;
      }

      for (i=0; i<6; i++){
         cout << "Faccia" << i+1 <<  "Frequenza > " << f[i] << endl;
      }
      
      
               for(i=0; i<6; i++){
X[i] = ((f[i] - (n / 6))*(f[i] - (n / 6)) / (n / 6));

 risultato_chi_quadro = X[0] + X[1] + X[2] + X[3] + X[4] + X[5];
}


cout << "Chi quadro   " << risultato_chi_quadro << endl;


do {
      cout << "Vuoi ripetere l'operazione? Si=1, No=2" << endl;
      cin >> risp;
      }while(risp!=1&&risp!=2);

 }
   while (risp==1);
   
   return 0;
}


Spero che qualcuno possa aiutarmi! Grazie :)

daniele912
Qualcuno può aiutarmi, please?

hamming_burst
               for(i=0; i<6; i++){
X[i] = ((f[i] - (n / 6))*(f[i] - (n / 6)) / (n / 6));

 risultato_chi_quadro = X[0] + X[1] + X[2] + X[3] + X[4] + X[5];
}


cout << "Chi quadro   " << risultato_chi_quadro << endl;


qualcosa che non ha molto senso mi pare questo, oltre il significato del codice che non ho guardato.

               for(i=0; i<6; i++){
                        X[i] = ((f[i] - (n / 6))*(f[i] - (n / 6)) / (n / 6));
               }
               risultato_chi_quadro = X[0] + X[1] + X[2] + X[3] + X[4] + X[5];

               cout << "Chi quadro   " << risultato_chi_quadro << endl;


Mi pare più corretto, perchè non fai nulla cpn risultato_chi_quadro oltre che sovrascriverlo ad ogni iterazione.
oppure scritto meglio, a patto di inizializzare sempre risultato_chi_quadro:

               risultato_chi_quadro = 0;
               for(i=0; i<6; i++){
                        X[i] = ((f[i] - (n / 6))*(f[i] - (n / 6)) / (n / 6));
                        risultato_chi_quadro = risultato_chi_quadro + X[i];
               }
             
               cout << "Chi quadro   " << risultato_chi_quadro << endl;

daniele912
Ho apportato quelle modifiche al programma ma rimane il fatto che il risultato fornito dal programma non è attendibile...

daniele912
Ho trovato l'errore nel codice e ora sembra che i risultati forniti dal programma siano corretti. A parte questo, in risposta al post di Vict85, mi chiedevo se ha senso inserire il test finale verificando che $\chi^2 > 11,070$.
Infatti, se il $\chi^2$ è minore di quel valore critico dimostro che i risultati sono frutto di fluttuazioni statistiche. Se invece il valore è maggiore, allora il valore del $\chi^2$ è più verosimilmente frutto di altre cause non dovute alle fluttuazioni. Siccome il programma realizzato è una simulazione di dadi non truccati in quanto le frequenze risultanti sono del tutto casuali, qual'è il senso della verifica finale? Cosa dimostro se il $\chi^2$ è maggiore o minore del valore critico?

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.