
--------------------------------------------------------------------------
    Il tema conduttore di questa prova è la distribuzione binomiale,
ovvero quella descrive le probabilità di x successi in n prove,
se si ritiene che la probabilità (p) di successo in ciascuna prova
sia costante e non dipenda dagli esiti ottenuti nelle altre prove.
    Indicando con X la variabile "numero di successi in n prove",
essa può assumere valori (indicati con x) che vanno 
da 0 (nessun successo) a n (tutti successi).
    Si ricorda inoltre la formula che dà la probabilità
    di ciascun valore di x:
    
       P(X=x|n,p) = f(x|n,p) = n! / ( x! * (n-x!) ) * p^x * (1-p)^(n-x)
   
---------------------------------------------------------------------

1. Scrivere in C la funzione 'factorial' la quale ritorni in
   un 'double' il fattoriale di un intero ricevuto come argomento.
   La funzione va quindi chiamata da un 'main' il quale prende
   l'intero di cui calcolare il fattoriale da riga di comando
   (e se non trova niente protesta, con messaggio informativo) ,
   chiama la funzione factorial e stampa il risultato in notazione
   scientifica (anche per valori ragionevolmente piccoli,
   per i quali si potrebbe stampare il valore intero esatto).
   
   [ nome del programma: factorial.c ]
   [ comando di esecuzione (ad es. per 4!): ./factorial 4 ]

   Ovviamente si verifichi con R, facendo uso della sua funzione
   factorial(), la correttezza del risultato. 

   NOTE (VALIDE IN GENERALE):
     - si raccomanda di cominciare a scrivere il programma a partire
       da un main 'minimalista' e di provarlo, mediante
       compilazione/esecuzione a ogni passo;
     - nel file del programma va scritto possibilmente prima il main
       e poi la/e funzione/i (se si fa il contrario si perdono
       punticini), separando le funzioni da un commento
       contenente una sequenza di trattini in modo da migliorare
       la leggibilità dell'insieme.


2. Scrivere ora la funzione 'dbinom' la quale riceve
   x (intero), n (intero) e p (float) e calcola la probabilità
   che X assuma il valore x (vedi sopra). 
   Scrivere inoltre la funzione 'pbinom' la quale, mediante
   un numero opportuno di chiamate a 'dbinom' calcola la probabilità
   cumulativa, indicata comunemente in letteratura con F(x),
   ovvero 
       F(x|n,p) = P(X<=x|n,p) 
   [quindi, ad esempio, per la binomiale F(0|n,p)=f(0|n,p) e F(N|n,p)=1
    -> questi posssono essere utili check]

   Le funzioni vanno quindi chiamate dal main il quale legge,
   nell'ordine, x, n e p da riga di comando e stampa i valori ottenuti
   in notazione scientifica.
   
   [ nome del programma: binomiale.c ]
   [ esempio di comando di esecuzione: ./binomiale 4 10 0.5 ]

   Si raccomanda di controllare la correttezza dei risultati
   facendo uso di R, calcolando le stesse probabilità mediante
   le sue funzioni dbinom() e pbinom().


3. Modifichiamo quindi il programma per calcolare la media ('valore atteso')
   e la deviazione standard della distribuzione. In questo caso
   il main legge da riga di comando n e p, effettua n+1 chiamate a
   dbinom e si calcola valore atteso ('media') e deviazione standard
   di X tramite opportune medie pesate 
       m   = Sum_x x*f(x)
       m2  = Sum_x (x^2)*f(x)
       var = m2 - m^2
       std = sqrt(var)
   e stampa i risultati.

   [ nome del programma: binomialeMS.c ]
   [ esempio di comando di esecuzione: ./binomialeMS 10 0.5 ]


4. Facciamo ora un generatore di numeri (pseudo-)casuali alquanto
   rudimentale (ovvero poco efficiente) ma ugualmente istruttivo.
   Si scriva la funzione 'SimulaProve' la quale riceve come argomenti
   il numero di prove (n) da effettuare e la probabilità p di successo
   in ciascuna prova, simula le prove e 'ritorna' il numero (intero)
   di successi ottenuti.
   La simulazione è effettuata estraendo un numero random uniforme fra 0 e 1
   e definendo 'successo' quando esso è minore o uguale a p
   (=> se p=0 non si avranno mai successi;
       se p=1 si avranno sempre successi;
       etc. ). 
   La funzione va quindi chiamata dal main il quale legge, nell'ordine,
   n e p da riga di comando, chiama 'SimulaProve' e stampa il numero di
   successi ottenuti.
   Per quanto riguarda l'inizializzazione del generatore di numeri casuali,
   in questo caso conviene usare l'orologio interno del computer,
   al fine di ottenere numeri diversi ad ogni chiamata del programma.
   Viene fornita  direttamente la funzione nel file inizializza_random.c,
   la quale va inserita nel file che stiamo scrivendo, insieme agli header
   necessari.

   [ nome del programma: rbinom1.c ]
   [ comando di esecuzione: ./rbinom1 10 0.5 ]

   Si raccomanda di controllare i risultati con R facendo uso della
   funzione rbinom() richiedendo di generare un solo valore.
   (Ovviamente trattandosi di numeri casali non verranno le stesse sequenze,
   ma ci aspettiamo che i valori 'tipici' e la 'variabilità sia la simile.)
   

5. Il motivo per cui il programma precedente è stato chiamato rbinom1.c
   è che a ogni chiamata ritorna un solo numero casuale associato
   al numero di successi ottenuti nelle n prove. La funzione di R rbinom()
   può invece ritornare un vettore di occorrenze del numero di successi
   in una sequenza lunga N di n prove (ovvero si ripetono N volte le n prove).
   Vogliamo fare qualcosa di analogo in C.
   
   Questa volta il main legge da riga di comando la lunghezza N del 'vettore'
   (di interi) in cui mettere i risultati, il numero n di prove di effettuare
   ciascuna volta e la probabilità p. Chiama quindi la funzione void 'rbinom'
   la quale chiama N volte la funzione 'SimulaProve'
   e ritorna 'in qualche modo' al main nel vettore 'vs'
   la sequenza dei numeri casuali ottenuti.
   Il vettore 'vs' è dichiarato nel main avente lunghezza NMAX,
   definito opportunamente all'inizio del file, ma
   di esso verranno usate le prime N locazioni.
   
   Dopo la chiamata a 'rbinom' 
   - calcolare la media e la deviazione standard dei valori della sequenza,
     ricordando che la deviazione standard ('campionaria')
     si ottiene facendo la radice quadrata della varianza ('campionaria')
     la quale si calcola a sua volta facendo la "media dei quadrati dei valori
     meno il quadrato della media dei valori" (e senza preoccuparsi
     del famigerato "n-1" di cui qualcuno potrebbe aver sentito parlare!);
   - mostra sullo schermo media e deviazione standard ottenuti;
   - scrive su un file testo (ovvero rileggibile da un normale editor)
     la sequenza ottenuta, mettendo un numero per riga.

  Per quanto riguarda l'inizializzazione dei numeri casuali,
  in questo caso conviene
  - nella fase di debug, effettuata con N piccoli, usare
    l'orologio interno del computer, in modo da avere
    un'idea che il programma dia risultati sensati;
  - alla fine usare il proprio numero di matricola, in modo
    che ciascuno produca una serie ripetibile. 

   [ nome del programma: simulabinom.c ]
   [ esempio di comando di esecuzione: ./simulabinom 100 10 0.5 ] 
   [ comando di esecuzione(*) PER SCRIVERE IL FILE: ./simulabinom 10000 20 0.6 ]
   [ nome del file dei dati: sequenza_successi.txt ]

   (*) Il comando per scrivere il file finale deve essere
       lo stesso, in modo da avere risultati confrontabili
       (anche alla luce del prossimo punto)

6. Terminiamo rileggendo da uno script R il file sequenza_successi.txt
   ed effettuando ulteriori analisi.
   - Innanzitutto importare il contenuto in modo opportuno i numeri
     contenuti nel file.
   - Si calcolino, facendo uso delle funzioni di R, media e deviazione
     standard dei numeri di successi. 
   - Facendo uso della funzione table() si calcolino le occorrenze di
     ciascun possibile numero di successo.
   - Utilizzando quanto ottenuto nel punto precedente si visualizzi
     il risultato mediante un plot a barre.

     [ nome dello script: analizza_successi.R ]

     Nota: chi avesse avuto problemi nel punto precedente può
           usare il file sequenza_successi_bkp.txt che si
	   trova in questa directory



	   
