
1. Un programma elementare è quello di sommare i primi N interi.
   Si richiede di scrivere un programma in C che svolga tale compito,
   con le sequenti condizioni:
   - N deve essere letto da tastiera su 'invito' del programma stesso,
     dopo che il programma è stato lanciato in esecuzione;
   - la somma deve essere eseguire in due modi:
     - prima con un semplice loop;
     - poi facendo uso di una apposita funzione ricorsiva.
   (E naturalmente ci devono essere apposite stampe del numero N
    ricevuto e dei due risultati, che ovviamente devono coincidere.)
    
  [ nome del programma: somma_1N.c  ]


2. Uno studente di statistica vuole testare la bontà del generatore
   di numeri casuali simulando dieci milioni ('N') di volte il lancio
   di un dado, mettendo il risultato in un vettore di interi
   di tale lunghezza e contando l'occorrenza delle diverse
   facce (in realtà non ci sarebbe bisogno di immagazzinare
   i risultati in un vettore, e anche l'uso di variabili
   'int' è uno spreco di memoria, ma tant'è...).
   Non potendo definire in C un vettore di tale dimensione è costretto ad
   effettuare una allocazione dinamica della memoria mediante malloc().
   Scrivere tale programma il quale,
   - effettua una allocazione dinamica di memoria di N*sizeof(int) bytes;
   - effettua le N estrazioni del dado, ovvero di numeri da 1 a 6
     "con la stessa probabilità", stampando, per controllo,
     soltanto l'esito delle prime 30 estrazioni;
   - conta quante volte è uscito ciascun numero e stampa i
     sei numeri alla fine. 

   Note: - ci si ricordi di RILASCIARE la memoria allocata mediante free()!
         - per la seed della random si usi il proprio numero di matricola.

   [ nome del programma: test_dadi.c  ]


3. A scuola abbiamo imparato a calcolare il Massimo Comune Divisore (MCD)
   fra due numeri naturali con la regoletta dei fattori comuni, presi
   con il minimo esponente. Ma la regoletta funziona solo con
   numeri 'facili', e applicarla per calcolare, ad esempio,
   MCD(544849, 82367647) diventa proibitiva.
   Possiamo allora usare il 'metodo di Euclide', basato sull'osservazione
   che se a e b non sono primi allora il MCD(a,b) è il massimo
   numero ('M') che "li misura entrambi", secondo l'espressione di Euclide,
   nel senso che a è pari ad na volte M e b è pari ad nb volte M.
   Ne risulta quindi che, definiti a e b interi, con 0<a<b, 
   - anche la differenza, b-a, sarà 'misurata' da M;
   - così pure vale per b-2*a, se 2*a è minore di b;
     e così via per b-3*a, b-4*a, etc., sempre con analoga condizione;
   - quindi anche il resto di b/a, che indicheremo con r
     sarà 'misurato' da M, ovvero M sarà anche il MCD fra r e a
     (si noti come r debba essere minore di a);
   - segue quindi  MCD(r,a) = MCD(a,b), etc. etc., iterando il ragionamento
     (si noti l'ordine cresente dei due argomenti di MCD!)
     finché il resto non è nullo, segno che siamo arrivati a M. 
   Queste osservazioni ci portano a costruire un algoritmo mediante il quale,
   - si calcola il resto di b/a  -> r;
   - si calcola il resto di a/r  -> r';
   - si calcola il resto di r'/r -> r'',
     etc.
   - la prima volta che un resto è nullo vuol dire che il
     resto ottenuto nel passo precedente era il MCD cercato.
     
   Dopo questa premessa, si richiede di implementare l'algoritmo
   di Euclide in C, e più precisamente:
   - scrivere la funzione MCD() che implementi l'algoritmo,
     stampando anche a, b e r ad ogni passo per avere un'idea
     della rapidità dell'algoritmo.
   - si scriva il main che
     - riceva a e b da riga di comando (ovvero mediante 'argv') e
       controlli che siano entrambi positivi (altrimenti termina, con messaggio)
       e nell'ordine giusto (in caso contrario li scambia);
     - chiami MCD() e stampi il risultato;
   - si provi il programma con numeri facili, ad esempio MCD(14,35)
     e MCD(18,84);
   - si calcoli finalmente MCD(544849, 82367647), e si scriva
     il risultato come commento dopo il main.
     
     [ nome del programma: MCD_Euclide.c  ]


4. È stata eseguita la simulazione numerica della caduta
   di un grave in aria, mediante un programma in C nel quale:
   - tempo e posizione erano immagazzinati in un vettore di strutture di tipo
       struct Posizione {
         float t;
         float x;
       };
   - la scrittura è stata effettuata, mediante fwrite(), su un file binario. 
      caduta_in_aria_t-x.bin
   Siccome si vuole graficare l'andamento ed effettuare ulteriori
   analisi, si richiede di scrivere un programma in C che
   - legga il vettore di strutture dal file binario;
   - riscriva i dati in un file csv mettendo in ogni riga il tempo t
     e la posizione x corrispondente, mettendo anche l'header opportuno.
   Il file finale avrà quindi due lunghe colonne e sarà rileggibile
   da un qualsiasi editor di testo, oltre che da R (vedi punto seguente).

    [ nome del programma: converti.c ]
    [ nome del file binario di input: caduta_in_aria_t-x.bin] 
    [ nome del file csv di output:    caduta_in_aria_t-x.csv ]


5. Si scriva uno script R che
   - rilegga il file 
   - grafichi la posizione in funzione di t
   - dalle variazioni di posizione calcoli la velocità,
     e la grafichi in funzione del tempo;
   - dalle variazione di velocità calcoli l'accelerazione. 
     e la grafichi in funzione del tempo.

    (NOTA per chi NON fosse riuscito a completare il punto precedente:
     usare come input il file caduta_in_aria_t-x_bkp.txt)

   [ nome dello script: analizza_caduta.R ]

6. Un classico giochino è quello di indovinare un numero (intero)
   compreso fra 1 e N che uno dei giocatori (il 'pensatore')  ha pensato.   
   Se non si indovina, il 'pensatore' dice soltanto se il numero vero
   è maggiore o minore di quello proposto. (Una variante è
   quella di provare a indovinare una parola, e se non si indovina
   il 'pensatore' dice se quella vera è dopo o prima di quella
   proposta nell'ordine alfabetico.)

   Ci si può convincere facilmente che, date le informazioni che fornisce
   il 'pensatore', la strategia ottimale consiste nel cominciare con n=N/2
   (opportunamente arrotondato, in quanto si possono proporre solo interi!)
   e
   - se il numero vero è maggiore di n, allora si ritenta nel range [n+1,N];
   - se il numero vero è minore di , allora si ritenta nel range [1,n-1].
   Quindi l'algoritmo si ripete nell'intervallo rimanente. 
   Siccome ogni volta si dimezza l'intervallo di ricerca, questa
   strategia di ricerca va sotto il nome di "ricerca binaria"
   e il numero massimo di tentativi per indovinare sarà circa log2(N).

   Dopo questa premessa, si costruisca un programma in cui
   main() gioca contro la function pensatore(). 

   In particolare, per quello che riguarda la function,
   - la prima volta che è chiamata, la function estrae a caso un intero
     compreso fra 1 e nmax (ricevuto come argomento) e lo immagazzina
     nella variabile statica nv che inizialmente valeva 0
     (così possiamo sapere se la funzione era già stata chiamata
      precedentemente per non riestrarre il numero);
   - ogni volta che viene chiamata (anche la prima volta) la function
     confronta n (secondo argomento) con nv e
     - se i due numeri sono uguali 'ritorna' 0;
     - se nv è maggiore di n 'ritorna' +1;
     - se nv è minore di n 'ritorna' -1.

   La strategia di ricerca viene invece implementata nel main, che
   - richiede di immettere nmax DOPO che è stato lanciato;
   - a ogni tentativo chiama la function pensatore() con n calcolato
     secondo l'algoritmo descritto, finché non riceve 0.
     A quel punto annuncia il numero indovinato.
     
   Inoltre, per farci capire come si sviluppa il gioco è opportuno
   che il main stampi anche il numero di tentativo e il numero n
   che ha comunicato alla function.

   [ nome del programma: ricerca_binaria.c ]


7. Data una variable y che dipende da x secondo la seguente 'expression' di R
      y <- expression( sqrt(x)/sqrt(1+sin(x)^2) )
   si scriva uno script che
   - valuti l'expression della sua derivata, che chiamiamo Dy,
     e la stampi;
   - grafichi nello stesso plot y e Dy nell'intervallo 0 <= x <= pi/2
     (se per valori bassi di x la derivata va fuori scala non è un problema);
   - richieda di cliccare sul plot nel punto dove la derivata
     ha il minimo (valutato a occhio) e, dopo il click, tracci una retta
     verticale in modo da indicare la y in corrispondenza della x
     dove la derivata ha il minimo.

    [ nome dello script: derivata.R ]


8. Si immagini di dover controllare l'accesso a un sistema informatico
   mediante username e password. Viene data una bozza di programma
   nella quale le informazioni sugli utenti sono già state lette dal
   file utenti.txt che contiene per ogni utente:
       cognome, nome, username, password
   Si tratta di completare il programma con le seguenti parti:
   - il programma chiede la username e
     - se non esiste invita a ritentare e termina;
     - se invece esiste chiede la password.
   - quindi 
       - se la password non è corretta invita a ritentare e termina;  
       - se la password corrisponde a quella dell'utente
         - lo saluta con nome e cognome, ad esempio
	     "Benvenuto Alessandro Manzoni"
	   e poi termina	   

   Nota: per confrontare che due string siano uguali si usi l'apposita
         funzione di sistema di string.h (vedi la C Reference Card)

   [ file con i dati degli utenti: utenti.txt]
   [ nome del programma:  accesso_utente.c ]
