Vai al contenuto
Appunti di InformaticaUniTo · 2026/27

Programmazione I · Teoria · Canale B · Lezione 03B

Numeri reali in C, float e double, conversioni di tipo

I numeri con la virgola in C si chiamano float e double. Qui vedi come si stampano e si leggono, quante cifre tengono davvero, e soprattutto che cosa succede quando mescoli interi e reali nella stessa espressione: è lì che 5 diviso 2 diventa 2 invece di 2,5.

Slide
03B_floats («Numeri reali in C. Float, double, precisione, conversione») · 25 pagine
Corso
Prof. Elvio Amparore · A.A. 2026/27
Tempo di studio
90 minuti, meglio con gcc a portata di mano
  • Definizione o risultato da sapere
  • Trappola / errore tipico
  • Conta all'esame
  • Oltre le slide
  • L'idea e il metodo, passo per passo
  • Da ricordare

La lezione in 8 punti

  • I numeri con la virgola in C sono di due tipi: float, di solito 4 byte e circa 7 cifre giuste, e double, di solito 8 byte e circa 15–16 cifre giuste.
  • Si stampano con %f (notazione normale, 6 cifre dopo la virgola), %e (notazione scientifica) e %g (la più corta delle due). %.3f tiene 3 cifre dopo la virgola.
  • Con scanf, un double si legge con %lf, non con %f.
  • Sui reali ci sono +, -, *, /, ma non il resto %. Radici, potenze e altre funzioni sono nella libreria math.h.
  • Quando un'espressione mescola tipi diversi, il C li converte da solo: il tipo «più piccolo» diventa quello «più grande». Un intero con un reale dà un reale.
  • Ma tra due interi la divisione resta intera: in float z = 5 / 2; la divisione fa 2, e solo dopo il 2 diventa 2.000000.
  • Mettere un reale in un int taglia la parte dopo la virgola, senza avvisi.
  • Il cast (float)y converte un valore quando lo decidi tu: x / (float)y fa la divisione con la virgola.

Canali A, B e C

Canale B. È la seconda parte della lezione di martedì 13/10, dalle 11 alle 13, dopo la 03A sullo scambio di variabili. Riprende la tabella dei tipi della 02B.

Fondamenti dell'Informatica. Le slide rimandano a Fondamenti per la codifica dei reali, lo standard IEEE 754. L'idea è nella lezione 03 di Fondamenti: segno, esponente e mantissa, con un formato da 8 bit invece di 32 o 64.

Canali A e C. Le slide 2026/27 dei canali A e C per questa lezione non le ho viste. L'esame è unico, e le conversioni di tipo sono una fonte di errori in tutti gli esercizi con le medie.

Laboratorio. Il Laboratorio 02 fa provare tutto questo con aritmetica.c, media.c e circonferenza.c.

§1

I numeri con la virgola: float e double

slide 2–3

Per contare le persone in aula bastano gli interi. Ma per la media dei voti, il prezzo al chilo dei pomodori o la velocità di un'auto servono i numeri con la virgola: una parte intera e una parte frazionaria. In C si chiamano numeri reali e hanno due tipi principali.

TipoDimensione tipicaCifre giuste, circaIntervallo, circaQuando usarlo
float32 bit, 4 byte7 cifre decimalida a per risparmiare memoria, o per calcoli poco delicati
double64 bit, 8 byte15–16 cifre decimalida a calcoli scientifici, quando serve precisione

Il nome double viene da «doppia precisione»: usa il doppio dei bit di float. In memoria funzionano come la virgola mobile della lezione 03 di Fondamenti: un bit di segno, un esponente che dice dove sta la virgola, e una mantissa con le cifre. Lo standard che lo descrive si chiama IEEE 754.

Le cifre giuste sono poche

«Circa 7 cifre» vuol dire proprio questo: dopo la settima cifra il numero è approssimato. Ho provato sul mio PC tre stampe con tante cifre:

float f = 0.1f;
double d = 0.1;
printf("%.20f\n%.20f\n", f, d);
0.10000000149011611938
0.10000000000000000555

Un decimo non si scrive esattamente in base 2, come un terzo non si scrive esattamente in base 10. Il float sbaglia dall'ottava cifra, il double dalla diciottesima. Per la stessa ragione 0.1 + 0.2 in double vale 0.30000000000000004.

Trappola · I reali non si confrontano con ==

Siccome quasi tutti i reali sono approssimati, due calcoli che «dovrebbero» dare lo stesso numero spesso differiscono nell'ultima cifra. Confrontare due double con == è quasi sempre un errore. Lo vedrai con le condizioni: si controlla che la differenza sia molto piccola.

Le operazioni

Sui reali ci sono le quattro operazioni: +, -, *, /. La divisione / tra due reali è quella vera, con la virgola: 5.0 / 2.0 fa 2.5.

Il resto % non c'è: con due double gcc si ferma con error: invalid operands to binary % (have 'double' and 'double'). Le slide avvisano che esiste una funzione di libreria, fmod, ma nel corso non si usa.

Prova tu

Quale tipo usi per: (a) il numero di studenti in aula; (b) la temperatura in gradi; (c) un risultato di fisica con 12 cifre giuste?

(a) int: è un numero intero. (b) float o double: ha la virgola; basta anche float. (c) double: il float ha solo circa 7 cifre giuste.

Da ricordare

  • float: 4 byte, circa 7 cifre. double: 8 byte, circa 15–16 cifre.
  • I reali sono quasi sempre approssimati: niente == tra reali.
  • Niente % tra reali.
§2

Stampare e leggere i reali

slide 4–5

Con printf un reale si può stampare in tre modi. Con double z = 2.5;:

SpecificatoreChe cosa stampaEsempioQuando usarlo
%fnotazione con la virgola fissa, 6 cifre dopo la virgola2.500000la scrittura «naturale» di un numero
%enotazione scientifica2.500000e+00numeri molto grandi o molto piccoli
%gla più corta tra %f e %e, senza zeri inutili2.5una stampa compatta

e+00 vuol dire «per 10 alla 0». Così 1.5e+03 è .

Quante cifre dopo la virgola

Tra il % e la lettera si può scrivere un punto e un numero: è quante cifre stampare dopo la virgola.

printf("z vale %f\n", z);      // z vale 2.500000
printf("z vale %.3f\n", z);    // z vale 2.500
printf("z vale %.3e\n", z);    // z vale 2.500e+00

Le slide dicono «troncata al terzo decimale». In realtà printf arrotonda all'ultima cifra stampata: printf("%.2f", 1.0 / 3) stampa 0.33, e printf("%.2f", 2.0 / 3) stampa 0.67.

Un'altra cosa da sapere: printf usa %f sia per i float sia per i double. Quando passi un float a printf, il C lo trasforma da solo in double. Per questo i messaggi di errore di gcc su %f parlano sempre di double.

Leggere un double

Con scanf le cose cambiano. scanf non riceve un valore ma un indirizzo (lezione 02C), e deve sapere quanti byte scrivere: 4 per un float, 8 per un double. Per questo:

  • un float si legge con %f;
  • un double si legge con %lf (o %le, %lg).
double x;
float y;
int letti = scanf("%lf %f", &x, &y);

Con l'input 3.25 1.5 il programma legge tutti e due i valori: letti vale 2.

Trappola · %f con un double in scanf

double x; scanf("%f", &x); con -Wall -Werror non compila: error: format '%f' expects argument of type 'float *', but argument 2 has type 'double *'. Senza le opzioni compila, ma scrive solo 4 degli 8 byte di x e il valore letto è sbagliato. In printf invece %f va bene per tutti e due.

Prova tu

Che cosa stampano printf("%.1f", 3.14159) e printf("%g", 0.5)? E come leggi un double chiamato peso?

3.1 e 0.5. Il double si legge con scanf("%lf", &peso);.

Da ricordare

  • printf: %f, %e, %g per float e double; %.3f dà 3 cifre dopo la virgola.
  • scanf: %f per float, %lf per double.
§3

Calcoli con i reali e math.h

slide 6–10

Il primo programma delle slide divide due float:

#include <stdio.h>

int main(void) {
    float x = 5, y = 2, z;
    z = x / y;
    printf("La var x vale %f\n", x);
    printf("La var y vale %f\n", y);
    printf("La var z vale %f\n", z);
}
La var x vale 5.000000
La var y vale 2.000000
La var z vale 2.500000

float x = 5 mette nel float il numero 5, che diventa 5.0. La divisione tra due float è con la virgola: 2.5.

Le slide 7 e 8 rifanno lo stesso programma con i double, e poi con x e y di tipo float e z di tipo double. Il risultato stampato è sempre 2.500000; cambia solo lo spazio in memoria: 4 byte per ogni float, 8 per ogni double.

La libreria math.h

Gli operatori del C fanno solo le operazioni di base. Per radici, potenze, logaritmi e trigonometria c'è la libreria math.h, da includere con #include <math.h>. Le funzioni più usate:

FunzioneChe cosa calcolaEsempio
sqrt(x)la radice quadratasqrt(9.0) vale 3.0
pow(x, y) elevato alla pow(9.0, 2) vale 81.0
sin(x), cos(x)seno e coseno, con l'angolo in radianticos(0.0) vale 1.0
floor(x), ceil(x), round(x)arrotonda per difetto, per eccesso, al più vicinoround(2.5) vale 3.0
#include <stdio.h>
#include <math.h>

int main(void) {
    float num = 9.0, radice, quadrato;
    quadrato = pow(num, 2);
    radice = sqrt(num);
    printf("Il quadrato di %.0f e' %.2f\n", num, quadrato);
    printf("La radice di %.0f e' %.2f\n", num, radice);
}
Il quadrato di 9 e' 81.00
La radice di 9 e' 3.00

Nota · -lm su Linux

Su Linux le funzioni di math.h stanno in una libreria a parte, e va aggiunta quando si compila: gcc programma.c -lm. La m sta per math. Su Windows con gcc, sul mio PC, non serve, ma aggiungerla non fa danni. Al laboratorio Turing, che usa Linux, mettila. Tutto il riferimento della libreria è su cppreference.

Prova tu

Scrivi l'espressione C per la diagonale di un rettangolo con lati a e b, cioè la radice di .

sqrt(a * a + b * b), oppure sqrt(pow(a, 2) + pow(b, 2)). Serve #include <math.h>.

Da ricordare

  • Divisione tra due reali: con la virgola.
  • math.h per sqrt, pow, floor, ceil, round e le altre; su Linux si compila con -lm.
§4

Mescolare i tipi: le conversioni

slide 11–14

In un'espressione puoi mettere insieme un int, un float e un char. Ma i tre tipi sono scritti in memoria in modi diversi: per fare il conto, il C deve prima portarli tutti allo stesso formato. Questo passaggio si chiama conversione di tipo, e ce ne sono di due modi:

  • conversione implicita: la fa il compilatore da solo, senza che tu scriva niente;
  • conversione esplicita, o cast: la chiedi tu, scrivendo il tipo tra parentesi.

Tutte e due possono perdere informazione: cifre, o l'intera parte dopo la virgola.

L'idea

È come versare un liquido da un contenitore all'altro. Da un bicchiere in una caraffa non perdi niente. Dalla caraffa al bicchiere, quello che non ci sta va perso.

Le conversioni dell'assegnamento

L'assegnamento è il caso più comune: il valore a destra viene convertito nel tipo della variabile a sinistra. La tabella delle slide, con i valori che ho ottenuto sul mio PC:

ConversioneSi perde qualcosa?EsempioRisultato
int → floatno, tranne con interi molto grandiint x = 5; float y = x;y vale 5.0
float → intsì, la parte dopo la virgolafloat x = 3.7; int y = x;y vale 3
int → doublenoint x = 42; double y = x;y vale 42.0
double → intsì, la parte dopo la virgola; comportamento indefinito se il numero non ci stadouble x = 9.9; int y = x;y vale 9
double → floatsì, cifre di precisionedouble a = 3.14159; float b = a;b circa 3.14159, meno preciso
char → intno: il codice ASCIIchar c = 'A'; int x = c;x vale 65
int → int*non si puòint x = 5; int *p = x;errore di compilazione

Tre osservazioni.

  1. La parte dopo la virgola viene tagliata, non arrotondata. 9.9 diventa 9, non 10. Con i negativi il taglio va verso lo zero: −2.7 diventa −2.
  2. Gli interi molto grandi non stanno in un float, che ha solo 24 bit di mantissa. 16 777 217 messo in un float diventa 16 777 216.
  3. Un double fuori dall'intervallo degli int, come 3 miliardi, non si può convertire: il comportamento è indefinito. Sul mio PC (int)3e9 dà −2 147 483 648, ma non è garantito.

L'ultima riga della tabella è un errore vero: con gcc 16.1, anche senza opzioni, int *p = x; dà error: initialization of 'int *' from 'int' makes pointer from integer without a cast. Un numero e un indirizzo non sono la stessa cosa (lezione 02C).

Trappola · Il compilatore non avvisa

Le conversioni con perdita di dati della tabella non danno errori né avvisi, nemmeno con -Wall -Werror. int y = 3.7; compila e mette 3 in y, in silenzio. gcc ha un'opzione che avvisa, -Wconversion, ma non fa parte di -Wall (lezione 02B).

Prova tu

Quanto valgono a, b e c dopo int a = 7.99; int b = -7.99; char ch = 'C'; int c = ch;?

a vale 7 e b vale −7: la parte dopo la virgola è tagliata verso lo zero. c vale 67, il codice ASCII di C (65 è A).

Da ricordare

  • Da un tipo più piccolo a uno più grande non si perde niente; al contrario sì.
  • Reale in un int: la parte dopo la virgola sparisce, in silenzio.
§5

La promozione di tipo

slide 15–16

Quando un operatore come + o / riceve due valori di tipo diverso, il compilatore li porta allo stesso tipo prima di fare il conto. Per non perdere informazione sceglie sempre il tipo più ampio. Questo si chiama promozione di tipo.

  • I tipi interi piccoli salgono: char → short → int → long.
  • I reali salgono: float → double.
  • Un intero con un reale diventa un reale.

Esempi delle slide:

  • char + int: il char diventa int, il risultato è int. Così 'A' + 2 vale 67, e 'a' - 'A' vale 32.
  • int + double: l'int diventa double, il risultato è double. Così 3 + 0.5 vale 3.5.

Metodo · Leggere il tipo di un'espressione

  1. Parti dalle operazioni più interne, rispettando le precedenze della lezione 02B.
  2. Per ogni operatore guarda i tipi dei due valori. Se sono interi tutti e due, il risultato è intero, e la divisione è intera. Se almeno uno è reale, il risultato è reale.
  3. Solo alla fine, nell'assegnamento, il risultato si converte nel tipo della variabile.

Il passo 2 è il punto chiave: la promozione guarda un operatore alla volta, non tutta l'espressione. Lo mostra la prossima sezione.

Prova tu

Di che tipo è, e quanto vale, ciascuna espressione? (a) 7 / 2; (b) 7 / 2.0; (c) 7.0 / 2; (d) 'B' - 'A'.

(a) int, 3: divisione intera. (b) double, 3.5. (c) double, 3.5. (d) int, 1.

Da ricordare

  • Due tipi diversi: si sale al più ampio. Intero con reale: reale.
  • La promozione si decide operatore per operatore.
§6

La divisione che inganna

slide 17–22

Ecco il caso più traditore della lezione. Il risultato va in un float, eppure la divisione perde la virgola.

int main(void) {
    int x = 5, y = 2;
    float z = x / y;
    printf("La var x vale %d\n", x);
    printf("La var y vale %d\n", y);
    printf("La var z vale %f\n", z);
}
La var x vale 5
La var y vale 2
La var z vale 2.000000

Perché 2.000000 e non 2.500000? Segui il metodo: l'operatore / riceve due int, quindi fa la divisione intera, che dà 2. Solo dopo, nell'assegnamento, il 2 viene convertito in float e diventa 2.000000. Il fatto che z sia un float arriva troppo tardi: la parte frazionaria è già persa.

L'idea

Il tipo della variabile a sinistra non cambia il modo in cui si calcola la destra. Prima si calcola la destra, con i suoi tipi; poi il risultato si converte.

Il caso opposto

Le slide 20–22 fanno il contrario: due float e il risultato in un int.

float x = 5, y = 2;
int z = x / y;

Qui la divisione è tra due reali e dà 2.5, giusto. Ma poi l'assegnamento mette 2.5 in un int: la parte dopo la virgola sparisce e z vale 2. Il risultato è lo stesso del caso di prima, ma la perdita avviene in un momento diverso: nell'assegnamento, non nella divisione.

ProgrammaDivisioneRisultato della divisioneAssegnamentoz
int x, y; float z = x / y;tra interi2int → float2.000000
float x, y; int z = x / y;tra reali2.5float → int2
float x, y; float z = x / y;tra reali2.5nessuna conversione2.500000

Prova tu

Con int a = 7, b = 2; quanto vale double r = a / b * 2.0;? E double s = a * 2.0 / b;?

r vale 6.0: prima a / b tra interi fa 3, poi 3 * 2.0 fa 6.0. s vale 7.0: prima a * 2.0 fa 14.0, un reale, e poi 14.0 / 2 fa 7.0. Stessi numeri, ordine diverso, risultato diverso.

Da ricordare

  • float z = 5 / 2; dà 2.0: la divisione tra interi taglia prima dell'assegnamento.
  • int z = 5.0 / 2.0; dà 2: l'assegnamento taglia dopo la divisione.
§7

Il cast: convertire a comando

slide 23–25

Per avere 2.5 da due int bisogna fare in modo che la divisione veda almeno un reale. Si fa con il cast esplicito: il nome del tipo tra parentesi, davanti al valore da convertire.

int x = 5, y = 2;
float z = x / (float)y;   // y convertito in float: risultato 2.5

(float)y vale 2.0, un float. Ora la divisione è tra un int e un float: per la promozione l'int sale a float, e il risultato è 2.5.

Definizione · Cast (slide 23 e 25)

Il cast (tipo)espressione converte il valore dell'espressione nel tipo scritto tra parentesi. Agisce solo sull'espressione immediatamente alla sua destra, e cambia il tipo del valore solo durante quel calcolo: non cambia il tipo delle variabili.

Come si legge. (float)y si legge «y convertito in float». Dopo il calcolo y è ancora un int che vale 2: il cast ha creato un valore nuovo, non ha cambiato y.

Dove si mette il cast

La posizione delle parentesi decide tutto. Con int x = 5, y = 2;, ho provato tre versioni:

EspressioneChe cosa succedeValore
x / (float)yy diventa 2.0, divisione con la virgola2.5
(float)x / yx diventa 5.0, divisione con la virgola2.5
(float)(x / y)prima x / y tra interi fa 2, poi 2 diventa 2.02.0

Nel terzo caso il cast arriva troppo tardi: la parte dopo la virgola è persa dentro la parentesi. È lo stesso errore della sezione prima, scritto con il cast.

Nota · Un dettaglio nella slide 24

Nella slide 24 il codice stampa x e y con %d, ma il terminale disegnato mostra 5.000000 e 2.000000. Con il codice della slide l'uscita vera è La var x vale 5 e La var y vale 2, e poi La var z vale 2.500000. È solo una svista del disegno: il punto della slide, il 2.5, è giusto.

Trappola · Il cast di un intero già diviso

(double)(somma / n) sembra calcolare una media con la virgola, ma la divisione dentro la parentesi è tra interi. Il cast va su uno dei due valori prima della divisione: (double)somma / n.

Prova tu

Con int somma = 17, n = 4; scrivi un'espressione che calcoli la media 4.25 con un cast, e una che sembri giusta ma dia 4.0.

Giusta: (double)somma / n, oppure somma / (double)n. Sbagliata: (double)(somma / n), che divide tra interi e dà 4, poi lo converte in 4.0.

Da ricordare

  • (tipo)espressione converte solo l'espressione subito a destra.
  • Il cast non cambia il tipo delle variabili.
  • Per una divisione con la virgola tra interi, il cast va su un operando, non sul risultato.
§8

I simboli di questa lezione

SimboloSi leggeVuol direEsempio
float«float»reale, 4 byte, circa 7 cifrefloat t = 21.5f;
double«dabol»reale, 8 byte, circa 15–16 cifredouble pi = 3.14159265;
%f«percento effe»in printf: reale con 6 cifre dopo la virgola2.500000
%.2f«percento punto due effe»reale con 2 cifre dopo la virgola2.50
%e«percento e»notazione scientifica2.500000e+00
%g«percento gi»la scrittura più corta2.5
%lf«percento elle effe»in scanf: un doublescanf("%lf", &x);
(float)y«y convertito in float»cast esplicitox / (float)y
math.h«math punto acca»libreria delle funzioni matematichesqrt(2.0)
-lm«meno elle emme»opzione di gcc per la libreria matematica su Linuxgcc p.c -lm
§9

Verso l'esame

esame

L'esame di Programmazione I è al PC, unico per i tre canali: appelli lunedì 25/01/2027 e giovedì 11/02/2027. CodeRunner confronta le stampe del tuo programma con quelle attese, carattere per carattere: un 2.000000 al posto di 2.500000 è un test fallito.

Gli errori che costano

  1. La media tra interi. Sommare interi e dividere per il numero di elementi dà una divisione intera. Serve un cast su un operando, o una costante reale come 3.0.
  2. %lf dimenticato in scanf con un double: con -Wall -Werror non compila.
  3. Lo specificatore sbagliato in printf: %d con un double, o %f con un int, non compila con -Wall -Werror.
  4. Il numero di cifre: se il testo chiede due cifre dopo la virgola, serve %.2f; con %f ne escono sei e il test fallisce.
  5. I reali confrontati con ==: con le condizioni, nelle prossime lezioni.

Metodo · Prima di dividere

  1. Guarda i tipi dei due operandi del /.
  2. Se sono tutti e due interi e vuoi la virgola, metti un cast su uno dei due, oppure usa una costante con la virgola.
  3. Controlla con un esempio a mano: 5 diviso 2 deve dare 2.5.

Conta all'esame · La media di tre numeri

Il programma media.c del Laboratorio 02 è proprio questo esercizio: con i voti 1, 2, 5, la media intera dà 2, la media con il cast sul risultato dà 2.000000, quella giusta dà 2.666667. È un modello di errore che negli esercizi d'esame si ripete in ogni calcolo di media.

§10

Quiz

come all'esame
  1. Con int x = 5, y = 2; quanto vale float z = x / y;?
  2. Con float x = 5, y = 2; quanto vale int z = x / y;?
  3. Con int x = 5, y = 2; quale espressione vale 2.5?
  4. Come si legge un double chiamato d con scanf?
  5. Che cosa stampa printf("%.2f\n", 2.0 / 3);?
  6. Quale riga dà un errore di compilazione con gcc 16.1, anche senza opzioni?
  7. Con int a = 7, b = 2; quanto vale double r = a / b * 2.0;?
  8. Di che tipo è il risultato di 'A' + 1.5?
  9. Che cosa vale (int)-3.7?
§11

Esercizi

con soluzioni

1 · Riscaldamento: il tipo e il valore base

Con int i = 9; double d = 2.0; scrivi tipo e valore di: (a) i / 2; (b) i / d; (c) i % 2; (d) (double)i / 2; (e) (double)(i / 2).

Soluzione

(a) int, 4. (b) double, 4.5. (c) int, 1. (d) double, 4.5: il cast è su i. (e) double, 4.0: la divisione intera avviene prima del cast.

2 · Riscaldamento: stampe dei reali base

Con double z = 1234.5678; scrivi che cosa stampano %f, %.1f, %e e %g. Poi provalo.

Soluzione
  • %f: 1234.567800
  • %.1f: 1234.6, arrotondato
  • %e: 1.234568e+03
  • %g: 1234.57: %g tiene 6 cifre significative in tutto

3 · Riscaldamento: assegnamenti che perdono base

Che cosa valgono le variabili? int a = 9.99; int b = -9.99; float c = 1/4; float d = 1.0/4; double e = 'a';

Soluzione

a = 9 e b = −9: taglio verso lo zero. c = 0.0: divisione intera, 1/4 fa 0. d = 0.25. e = 97.0: il codice ASCII di a.

4 · Il programma delle slide 17–19, corretto medio

Il programma con int x = 5, y = 2; float z = x / y; stampa 2.000000. Correggilo in due modi diversi perché stampi 2.500000, senza cambiare il tipo di x e y.

Soluzione
#include <stdio.h>

int main(void) {
    int x = 5, y = 2;
    float z1 = x / (float)y;   // cast su un operando
    float z2 = (float)x / y;   // cast sull'altro operando
    printf("%f %f\n", z1, z2);
}

Stampa 2.500000 2.500000. Anche x * 1.0 / y funziona, ma con il cast chi legge vede subito che vuoi una divisione con la virgola.

5 · Radice e potenza medio

Scrivi un programma che legge un double con scanf e stampa il suo quadrato e la sua radice quadrata con 3 cifre dopo la virgola. Prova con 2.

Soluzione
#include <stdio.h>
#include <math.h>

int main(void) {
    double x;
    printf("Inserisci un numero: ");
    scanf("%lf", &x);
    printf("Quadrato: %.3f\n", pow(x, 2));
    printf("Radice: %.3f\n", sqrt(x));
}

Con 2 stampa Quadrato: 4.000 e Radice: 1.414. Su Linux si compila con gcc -Wall -Werror radice.c -o radice -lm.

6 · La media di tre voti tipo esame

Scrivi un programma che legge tre voti interi e stampa la loro media con 2 cifre dopo la virgola. Con 1, 2, 5 deve stampare 2.67. Poi spiega che cosa stamperebbe con double m = (a + b + c) / 3;.

Soluzione
#include <stdio.h>

int main(void) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    double m = (a + b + c) / 3.0;
    printf("%.2f\n", m);
}

Stampa 2.67. Con (a + b + c) / 3 la somma 8 è divisa per l'intero 3: divisione intera, 2, poi convertito in 2.0. Stamperebbe 2.00. Programma provato con gcc 16.1 e -Wall -Werror.

7 · Trova i tre errori tipo esame

Questo programma dovrebbe leggere il lato di un quadrato con la virgola e stampare l'area con 2 cifre. Trova gli errori: double lato; scanf("%f", &lato); int area = lato * lato; printf("Area: %.2f\n", area);

Soluzione
  1. scanf("%f", &lato): per un double serve %lf. Con -Wall -Werror non compila.
  2. int area: l'area con la virgola va in un double; in un int perde la parte frazionaria.
  3. printf("%.2f", area) con un int: lo specificatore non corrisponde al tipo. Con -Wall -Werror non compila.

Corretto: double lato; scanf("%lf", &lato); double area = lato * lato; printf("Area: %.2f\n", area);.

§12

Domande di ripasso

autoverifica

Rispondi a voce alta o per iscritto, poi apri la risposta.

Che differenza c'è tra float e double?

float usa di solito 4 byte e ha circa 7 cifre giuste; double usa 8 byte e ha circa 15–16 cifre giuste, con un intervallo molto più ampio.

Con quale specificatore si legge un double con scanf? E si stampa con printf?

Si legge con %lf. Si stampa con %f, %e o %g, perché printf riceve i float già convertiti in double.

Perché float z = 5 / 2; vale 2.0?

Perché 5 / 2 è una divisione tra due interi e dà 2. Solo dopo, nell'assegnamento, il 2 diventa il float 2.0.

Che cosa succede mettendo 3.7 in un int?

La parte dopo la virgola viene tagliata, senza arrotondare e senza avvisi: l'int vale 3.

Che cos'è la promozione di tipo?

La conversione automatica dei due operandi di un operatore al tipo più ampio, prima di fare il conto: un intero con un reale diventa un reale.

Che differenza c'è tra (double)a / b e (double)(a / b) con a e b interi?

Nel primo il cast è su a, e la divisione è con la virgola. Nel secondo la divisione tra interi avviene prima, e il cast converte un risultato già tagliato.

Perché non si confrontano due double con ==?

Perché quasi tutti i reali sono approssimati: due calcoli che dovrebbero dare lo stesso valore possono differire nell'ultima cifra.

§13

Glossario

termini
float
Tipo reale, di solito 4 byte, con circa 7 cifre decimali giuste.
double
Tipo reale in doppia precisione, di solito 8 byte, con circa 15–16 cifre decimali giuste.
IEEE 754
Lo standard che descrive come sono scritti in memoria i numeri reali: segno, esponente e mantissa.
%f, %e, %g
Specificatori di printf per i reali: virgola fissa, notazione scientifica, scrittura più corta.
%lf
Specificatore di scanf per leggere un double.
math.h
Libreria del C con le funzioni matematiche: sqrt, pow, floor, ceil, round, sin, cos.
Conversione implicita
Cambio di tipo fatto dal compilatore da solo, per esempio in un assegnamento o in un'espressione mista.
Promozione di tipo
Conversione automatica degli operandi al tipo più ampio prima di un'operazione.
Cast
Conversione esplicita scritta con il tipo tra parentesi, come (float)y; vale solo per l'espressione subito a destra.
Comportamento indefinito
Situazione in cui il linguaggio non dice che cosa succede, come un double troppo grande messo in un int.
§14

Checklist

0 su 8

Spunta quando sai fare la cosa senza guardare gli appunti. Le spunte restano salvate in questo browser.