Overflow, Underflow, NaN e infinito 🇬🇧
Note a cura di Antonino Furnari - antonino.furnari@unict.it🔝
Università di Catania, Dipartimento di Matematica e Informatica
Note disponibili qui: http://www.antoninofurnari.github.iohttps://antoninofurnari.github.io/lecture-notes/it/programmazione-c/overflow-underflow/
Abbiamo visto che i tipi hanno dei limiti ben precisi. E’ quindi lecito chiedersi cosa succede quando superiamo questi limiti. Abbiamo visto che importando l’header <limits.h>
, possiamo utilizzare la costante INT_MAX
, che indica l’intero di dimensione massima. Cosa succede se aggiungiamo una unità a INT_MAX
? Consideriamo questo programma:
|
|
/var/folders/cs/p62_d78d49n3ddj0xlfh1h7r0000gn/T/tmpp_1f709j.c:7:36: warning: overflow in expression; result is -2147483648 with type 'int' [-Winteger-overflow]
printf("INT_MAX+1:\t%d",INT_MAX+1);
^
1 warning generated.
INT_MAX-1: 2147483646
INT_MAX: 2147483647
INT_MAX+1: -2147483648
Come mostrato sopra, la compilazione del programma restituisce un warning. L’espressione ha scatenato un overflow: in pratica non è possibile rappresentare il numero richiesto con un int
. Il risultato sarà un numero negativo (siamo tornati all’estremo inferiore dei limiti di int
):
Possiamo evitare l’underflow promuovendo il risultato della somma ad un long
. Per fare ciò usiamo il letterale 1L
che indica che 1
è un long
, per cui la somma con INT_MAX
sarà un long
:
|
|
INT_MAX+1: 2147483648
Notiamo che abbiamo dovuto specificare il formato %li
per permettere la stampa del risultato come long int.1e-350;
Allo stesso modo, il seguente codice genererà un underflow (non è possibile rappresentare un numero così piccolo in doppia precisione):
|
|
/var/folders/cs/p62_d78d49n3ddj0xlfh1h7r0000gn/T/tmpe9hilh2g.c:5:17: warning: magnitude of floating-point constant too small for type 'double'; minimum is 4.9406564584124654E-324 [-Wliteral-range]
printf("%e",1e-350);
^
1 warning generated.
0.000000e+00
Come possiamo vedere, il numero è stato “arrotondato” a zero, con conseguente perdita di informazione. Per evitare l’underflow, possiamo transformare il letterale in un long double e sistemare il formato di stampa:
|
|
1.000000e-350
Attenzione, il risultato sopra dipende dall’implementazione del compilatore. Alcuni compilatori rappresentano i long double in maniera identica ai double, nel quale caso anche l’istruzione sopra genererebbe un underflow.
Possiamo ottenere un overflow anche con i numeri in virgola mobile:
|
|
inf
In questo caso però non otteniamo un warning, ma il risultato sarà inf
ovvero “infinito”.
Not A Number (NAN) e Infinito
L’header <cmath>
mette a disposizione alcuni simboli speciali, quali NAN, +infinito e -infinito:
|
|
nan
inf
-inf
Va notato che questi tre valori sono tutti considerati come numeri in virgola mobile (e si stampano con il formato %f
). Il significato di questi tre valori è il seguente:
nan
: “Not A Number” - è il risultato di una operazione aritmetica indefinita (come una divisione per zero);inf
: infinito;-inf
: meno infinito.
Possiamo ottenere nan
e infinity
anche con delle operazioni matematiche tra numeri in virgola mobile:
|
|
nan
inf
-inf
0.000000
Domanda Qual è il risultato della seguente riga di codice?
Si compari il risultato con quello della seguente:
Si discutano le eventuali differenze tra i due risultati. |
Esercizi
Esercizio Si scriva un programma che:
|
Esercizio Si scriva un programma che:
|
Esercizio Si scriva un programma che:
|