Esercizio 1 (Codifica binaria in virgola mobile) Codificare in virgola

Esercizio 1 (Codifica binaria in virgola mobile)
Codificare in virgola mobile a precisione singola I seguenti numeri: N1 = 16; N2 = -1.1
Soluzione: Un numero in virogla mobile è sempre composto in questo modo:
(-1)S * 1.M * 2(E + 127)
Il numero N1:16 è rappresentabile come (-1)0 * 1.0 * 2(4 + 127)
Di conseguenza la codifica di N1 : S = 0 E = 10000011 M = 00000000000000000000000
Il numero N2:-1.1 è rappresentabile come (-1)1 * 1.1 * 2(-127 + 127) . Questo è uno dei numeri che non
ammettono rappresentazione esatta in virgola mobile. Avremo dunque una mantissa periodica.
N2 : S = 1 E = 01111111 M = 00011001100110011001101
Esercizio 2 (Codifica binaria in virgola mobile)
Codificare in virgola mobile a precisione singola Ii seguente numero N: 10.6875
Soluzione: Per codificare un numero qualsiasi in virgola mobile esiste un semplice algoritmo:
1) si converte la parte intera in binario;
2) si converte la parte decimale in binario;
3) si mettono insieme le rappresentaizioni in binario, separate dalla virgola, ottenendo la codifica
in virgola fissa;
4) si sposta la virgola verso sinistra fino a che non rimanga un solo 1 a sinistra della virgola. La
mantissa è rappresentata dai bit a destra della virgola. In caso di necessità si aggiungono tanti 0
a destra fino ad arrivare al numero di bit richiesti per la mantissa
5) Si tiene conto degli spostamenti della virgola effettuati verso sinistra e per ognuno di essi si
aumenta di 1 la potenza di 2 per cui verrà moltiplicata la mantissa. L'esponente di 2 va
aumentato di 127. In questo modo si ottiene l'esponente del numero in virgola mobile.
6) Si determina il bit di segno: 0 se positivo, 1 se negativo.
Nel caso di 10.6875
1010 = 10102
La conversione viene effettuata con il solito algoritmo per la conversione di un numero decimale intero
in binario (Vedi esercitazioni 1 e 2)
0.687510 = 10112
La conversione si effettua con il solito algoritmo per la conversione di un numero decimale frazionario
in binario (Vedi esercitazioni 1 e 2). Si moltiplica la sola parte frazionaria del numero per 2 e si
considera la parte intera del risultato come bit per la codifica. L'algoritmo termina quando si ottiene un
numero intero come risultato di una moltiplicazione o quando termina il numero di bit disponibili per
rappresentare il numero.
Nel nostro caso:
0.6875 *2
(1)0.375 *2 Nel caso che si ottenga un numero >1 per l'iterazione successiva si considera di nuovo solo
la parte frazionaria. L'1 viene comunque considerato per la codifica.
(0).75 * 2
(1).5 *2
(1).000
Alla fine si leggono i bit di codifica ottenuti nell'ordine in cui si sono ottenuti.
Per ricavare la mantissa scriviamo i due numeri ottenuti uno di fianco all'altro separati dal . :
1010.1011
Spostiamo il . Verso sinistra fino a quando non rimane solo un 1 a sinistra del . Contiamo anche gli
sposptamenti fatti e usiamo il numero di spostamenti come esponente del 2 per cui viene moltiplicata la
mantissa:
1.0101011 *23
La mantissa M = 01010110000000000000000
L'esponente E si ottiene sommando 127 al 3 esponente in 23. Si codifica 127+3 = 130 in binario
E = 10000010
Il segno, visto che si tratta di un numero positivo è:
S=0
La codifica di N è la seguente:
S = 0 E = 10000010 M = 01010110000000000000000
Esercizio 3 (Fibonacci)
a) Scrivere un programma che chieda un intero positivo n all’utente e in risposta stampi i
primi n numeri della serie di Fibonacci. La serie di fibonacci ` definita così:
F (n) = F (n − 1) + F (n − 2)
F (0) = 1
F (1) = 1
Quindi la serie è:
F (0) = 1
F (1) = 1
F (2) = 1+1=2
F (3) = 1+2=3
F (4) = 2+3=5
F (5) = 3+5=8
...
b) Il programma stampa il numero appartenente alla serie di fibonacci più vicino (maggiore
o minore) al numero digitato dall’utente. Se il numero digitato dall’utente è equidistante
da due numeri della serie di Fibonacci, entrambi questi numeri vengono stampati.
#include <stdio.h>
int main() {
int prev, curr, temp;
int n;
int i;
prev = 1;
curr = 1;
printf("Dammi un numero:");
scanf("%d", &n);
for (i = 2; i < n; i++) {
temp = curr + prev;
prev = curr;
curr = temp;
}
printf("Il %do numero di Fibonacci e': %d\n", n, temp);
// estensione
// cerca il primo numero di fibonacci piu' grande di n
prev = 1;
curr = 1;
temp = 0;
for (i = 2; temp < n; i++) {
temp = curr + prev;
prev = curr;
curr = temp;
}
if ((curr - n) == (n - prev))
printf("Il numero e' equidistante da due numeri di Fibonacci: %d, %d\n", prev, curr);
else {
if ((curr - n) < (n - prev))
printf("Il numero di Fibonacci piu' vicino e': %d\n", curr);
else
printf("Il numero di Fibonacci piu' vicino e': %d\n", prev);
}
return 0;
}
Nota: la soluzione proposta non fa uso di strutture contenitori. Questo significa che nella parte che
corrisponde all’estensione si ripetono calcoli che sono stati già svolti in precedenza. È possibile
progettare una variante dell’esercizio che utilizza un array per immagazzinare i numeri della sequenza e
che quindi svolge meno calcoli.
Esercizio 4 (Battaglia navale)
Si sviluppi una versione semplificata di un programma per giocare alla battaglia navale. Il
programma presuppone l’esistenza di un unico giocatore. Lo schema e' prefissato, non cambia
da partita a partita. Si distinguono due campi di battaglia: "schema" contiene la disposizione
delle navi sul campo di battaglia; “battaglia" tiene traccia dei colpi effettuati dall'utente (se il
colpo ha dato come risultato 'mancato' o 'colpito').
I simboli usati sono:
'x' = elemento di una nave
'o' = "mancato"
'*' = "colpito"
'.' = casella sulla quale non e' stato effettuato nessun colpo
Il programma visualizza per il giocatore il contenuto di “battaglia”. Il giocatore inserisce
l’informazione sul punto in cui vuole sparare utilizzando il tipico sistema di coppie <lettera,
numero>. Il programma verifica se il colpo è andato a segno o no e lo comunica all’utente.
*/
#include <stdio.h>
#define DIM_OR 6
#define DIM_VERT 6
typedef char matrice_caratteri[DIM_OR][DIM_VERT];
void main() {
/* gli array "schema" e "battaglia" vengono inizializzati al momento
della dichiarazione. Essendo questi degli array di caratteri,
la sintassi per l'inizializzazione e' quella vista sotto, con
sequenze di caratteri (comprese tra "") separate da virgole e
racchiuse tra parentesi graffe. Questa inizializzazione e' ammissibile solo per
matrici di caratteri e solo in fase di dichiarazione */
/*
matrice_caratteri schema = {" 12345", "Axx...", "B...x.", "Cx....", "D.xx..",
"E....x"};
matrice_caratteri battaglia = {" 12345", "A.....", "B.....", "C.....",
"D.....", "E....."}; */
matrice_caratteri schema, battaglia;
/* in alternativa e' possibile inizializzare la matrice schema con due cicli for
innestati, che scorrano la matrice ed assegnino ad ogni cella il valore corretto */
char c1;
int c2;
int i, j;
int pz_rim = 5;
schema[0][0] = ' ';
battaglia[0][0] = ' ';
for(i=1; i<DIM_VERT; i++)
{
schema[0][i] = i+'1'-1;
battaglia[0][i] = i+'1'-1;
}
for(i=1; i<DIM_OR; i++)
{
schema[i][0] = i+'A'-1;
battaglia[i][0] = i+'A'-1;
}
for(i=1; i<DIM_OR; i++)
for(j=1; j<DIM_VERT; j++)
{
schema[i][j]='.';
battaglia[i][j]='.';
}
/* distribuzione delle navi */
schema[1][1]='x';
schema[1][2]='x';
schema[2][4]='x';
schema[3][1]='x';
schema[4][2]='x';
schema[4][3]='x';
schema[5][5]='x';
while(pz_rim > 0) {
for( i=0 ; i<DIM_OR ; i++){
for( j=0 ; j<DIM_VERT ; j++)
printf("%c", battaglia[i][j]);
printf("\n");
}
printf("\n* = colpito, o = mancato, . = acqua\n");
printf("Flotta disponibile 5 navi. Composizione navi: xx xx x x x\n");
printf("Scegli coordinate (lettera, numero) a cui sparare: ");
scanf("%c%d", &c1, &c2);
fflush(stdin);
if(c1>='A' && c1<='E' && c2>=1 && c2<=5 && battaglia[c1-'A'+1][c2] == '.')
{
if(schema[c1-'A'+1][c2] == 'x'){
battaglia[c1-'A'+1][c2] = '*';
pz_rim--;
printf("\n***COLPITO!***\n\n");
}
else {
battaglia[c1-'A'+1][c2] = 'o';
printf("\nMANCATO!\n\n");
}
}
}
printf("\n******************\n");
printf("***HAI VINTO!!!***\n");
printf("******************\n");
}
Esercizio 5. (TDE 18/11/2008)
Per ognuna delle espressioni logiche riportate nelle righe della tabella, assumendo le seguenti
dichiarazioni:
int a = 8, b = 11;
char c=’d’;
indicare se l’espressione è vera o falsa (scrivere V o F nella seconda colonna). Indicare inoltre, nella
terza colonna, se l’espressione è vera per qualsiasi valore delle variabili (scrivere SI o NO) e, nella
quarta colonna, se l’espressione è falsa per qualsiasi valore delle variabili (scrivere SI o NO). Si
giustifichino le risposte. Risposte prive di giustificazione non saranno prese in considerazione.
Espressione
Vera o falsa?
(-a==a) && (a < 11)
(c>’a’ || c<’z’ ) && (a<7 && b>8)
!(b<10 && a>7) || (c!=’h’ &&
c>’a’ )
F
F
V
Sempre
vera?
NO
NO
NO
Sempre falsa?
NO
NO
NO
Giustificazioni
1. L’espressione è vera nel caso a=0 e falsa in tutti gli altri casi
2. L’espressione è falsa per i valori dati per la presenza del termine a<7; è vera, per valori di a<7 e
b>8 perché il termine (c>’a’ || c<’z’) è sempre vero. Di conseguenza, l’espressione non è sempre
falsa.
3. L’espressione è vera perché, indipendentemente dai valori di a e b, si ha che c!=’h’ e c>’a’ sono
entrambe vere; è falsa, per esempio, per a=8, b=9 (che rendono falso il termine !(b<10 && a>7)) e
c=’h’ (che rende falso il termine (c!=’h’ && c>’a’ )), quindi non è sempre vera.
Esercizio 6. (programma misterioso TDE 18/11/2008)
Si consideri il seguente programma C:
#include <stdio.h>
#define MAX 20
typedef int numeri[MAX];
int main() {
numeri A;
int p,j,i=0,s=0;
scanf("%d",&A[i]);
i++;
while (i<MAX && A[i-1]>0) {
scanf("%d",&A[i]);
i++;
}
scanf("%d",&p);
while (p<0||p>i)
scanf("%d",&p);
for (j=0;j<p;j++)
s+=A[j];
for (j=p;j<i;j++)
s-=A[j];
if (s==0)
printf("%d",p);
}
else if (s<0)
for (j=p;j<i;j++)
printf("%d\n",A[j]);
else
for (j=0;j<p;j++)
printf("%d\n",A[j]);
1. Si indichi cosa viene stampato a video se l’utente inserisce questa sequenza: 4 5 12 12 3 3 3 3 7
14 0 4.
2. Che cosa succede se l’utente invece di scrivere 4 come ultimo valore della sequenza scrive 3 ?
Che cosa succede se invece scrive 12?
3. Spiegare brevemente il funzionamento del programma a seconda dei vari possibili ingressi.
Soluzione punto 1
Il programma legge da tastiera una sequenza di numeri fino ad incontrare il valore 0 (o, più in generale,
fino ad incontrare un valore minore o uguale a zero oppure a considerare 20 numeri). Poi legge un
ulteriore valore (nell’esempio il valore 4) che viene usato per dividere la sequenza di numeri letta in
precedenza in due porzioni distinte (nell’esempio, i primi 4 numeri della sequenza e gli altri). Il valore
letto deve essere un indice ammissibile per la sequenza dei numeri, e, di conseguenza, il suo valore
deve essere compreso tra zero ed i, dove i indica il numero di elementi letti in precedenza.
A questo punto il programma calcola la differenza tra la somma dei numeri della prima porzione della
sequenza e la somma dei numeri della seconda porzione della sequenza. Se tale differenza è pari a zero,
il programma stampa il valore che è stato utilizzato per dividere la sequenza in due parti (il valore 4 nel
nostro esempio). Se la differenza è minore di zero il programma stampa tutti i valori nella seconda
porzione della sequenza. Se è maggiore di zero, il programma stampa tutti i valori nella prima porzione
della sequenza. Nel caso dell’esempio specifico, la differenza è pari a zero e, di conseguenza, viene
stampato il valore 4.
Soluzione punto 2
Nel caso in cui l’utente inserisce 3 come ultimo elemento, il programma divide la sequenza nelle due
sottosequenze composte dai numeri {4, 5, 12} la prima e dai numeri {12, 3, 3, 3, 3, 7, 14, 0} la
seconda. In questo caso quindi la differenza calcolata risulta pari a -24. Di conseguenza, il programma
stamperà a video i numeri 12 3 3 3 3 7 14 0. Nel caso in cui l’utente inserisce come ultimo valore il
numero 12, la condizione del ciclo che si
occupa dell’acquisizione dell’ultimo valore risulterà essere vera perché il termine p>=i sarà vero. Di
conseguenza, il programma, rimarrà in attesa di ricevere un nuovo valore.
Soluzione punto 3
Si veda la spiegazione al punto 1.
Esercizio 7. (Venditori di auto TDE 14/11/2005)
Le seguenti dichiarazioni di tipo servono per definire l’archivio di auto vendute da un concessionario.
Per ogni auto, il concessionario tiene traccia del tipo, del numero di telaio, della data di vendita e della
lista di optional istallati.
Si scriva il frammento di programma che stampa a video la data di vendita di tutte le auto nell’archivio
a che nella lista di optional hanno quello con numeroSerie pari a 412. Si assuma che i dati contenuti
nella variabile a siano già stati tutti immessi (in un modo che non viene descritto).
#define MAX_AUTO_VENDIBILI
1000
typedef char stringa[50];
typedef struct{
int giorno;
int mese;
int anno;
}Data;
typedef struct{
stringa tipo;
int
numeroSerie;
}Optional;
typedef struct{
stringa tipo;
/* il tipo di auto */
int numeroTelaio;
Data dataVendita;
Optional listaOptional[10];
int numeroOptional; /* il numero effettivo di optional di un’auto */
} AutoVenduta;
typedef struct{
AutoVenduta archAuto[MAX_AUTO_VENDIBILI];
int numAutoVendute; /* numero di auto vendute effettivamente dal
concessionario */
}ArchivioAutoVendute;
void main() {
ArchivioAutoVendute a;
// INSERIRE QUI LA SOLUZIONE
}
Soluzione
Codice
for (i=0; i<a.numAutoVendute; i++)
for (j=0; j<a.archAuto[i].numeroOptional; j++)
if (a.archAuto[i].listaOptional[j].numeroSerie == 412)
printf("Auto venduta il %d %d %d",
a.archAuto[i].dataVendita.giorno,
a.archAuto[i].dataVendita.mese,
a.archAuto[i].dataVendita.anno);