1. Numeri a virgola mobile
Supponiamo che tu decida di scrivere una calcolatrice semplicissima. O qualsiasi altro programma in cui servono calcoli (dal banale conteggio del denaro alla fisica complessa). Non tutto nella vita reale è un numero intero — e non ci si può fare nulla!
Quindi armiamoci di un nuovo tipo di dati!
In programmazione i numeri decimali vengono anche chiamati reali o numeri a virgola mobile (floating-point). In Java, come nella maggior parte dei linguaggi, servono per memorizzare non solo interi, ma anche valori «decimali»: vari 3.14, -28.57, 2.718281828...
I numeri a virgola mobile sono di due tipi principali:
| Tipo | Contiene | Intervallo di valori (circa) | Precisione | Dimensione tipica |
|---|---|---|---|---|
|
Numeri | ±1.5 × 10-45 ... ±3.4 × 1038 | ~7 cifre significative | 4 byte |
|
Numeri | ±5.0 × 10-324 ... ±1.7 × 10308 | ~15–16 cifre significative | 8 byte |
Tipo float
Il tipo float prende il nome da floating-point number — numero a virgola mobile. I numeri reali sono numeri della matematica, hanno proprietà ben definite. Ma il computer ha molte limitazioni. Perciò non è del tutto corretto chiamare i numeri decimali in Java «reali». Per essi si usa il nome «numeri a virgola mobile».
Il tipo float di solito memorizza 7 cifre significative (ad esempio, 0.1234567), l’esponente della base 10 e occupa 4 byte di memoria. È molto poco per calcoli precisi, quindi si è passati rapidamente ai numeri a doppia precisione.
Tipo double
Il tipo double prende il nome da doppia (double) precisione. Occupa 8 byte di memoria (2 volte più di float) e può memorizzare fino a 15 cifre significative: 0.123456789012345. È più che sufficiente per la maggior parte dei calcoli con numeri decimali, perciò double è il tipo principale per memorizzare numeri a virgola mobile in Java.
In questa lezione l’accento principale sarà sul tipo double: è consigliato di default per tutti i numeri «normali» a virgola mobile. Ma più avanti vedremo anche il tipo float.
2. Dichiarazione e inizializzazione delle variabili di tipo double
Tutto come con int — solo che ora usiamo double.
// Dichiariamo una variabile e le assegniamo il valore di pi greco
double pi = 3.1415926;
// Si può dichiarare anche senza inizializzarla
double averageSalary;
averageSalary = 91234.56;
// Si può calcolare!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666... (e non 2)
Particolarità della sintassi:
- Come separatore decimale si usa il punto (3.14). Se usi la virgola — otterrai un errore di compilazione!
- A rigore, scrivendo double d = 3; non otterrai un errore — i tipi vengono convertiti automaticamente (il numero intero si trasforma in «virgola mobile» senza perdite).
3. Input e output di numeri a virgola mobile con Scanner
Per prima cosa proviamo a stampare un numero con la virgola:
double amount = 42.75;
System.out.println(amount); // Stamperà: 42.75
Tutto bene! E se aggiungiamo del testo:
System.out.println("Sul tuo conto: " + amount + " euro."); // Sul tuo conto: 42.75 euro.
Input da tastiera
Per leggere un double bisogna usare un metodo specifico della classe Scanner: console.nextDouble().
Scanner console = new Scanner(System.in);
System.out.println("Inserisci la temperatura esterna:");
double temperature = console.nextDouble(); // Inseriamo direttamente un double
System.out.println("All'esterno adesso: " + temperature + " gradi.");
4. Il tipo double in azione: aritmetica
Tutte le operazioni consuete (+, -, *, /) funzionano come per int:
double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25
System.out.println("Velocità media: " + speed); // Velocità media: 50.25
E questo è tutto per l’aritmetica. Unica differenza: il risultato della divisione è sempre un numero decimale, se almeno uno degli operandi è double.
Confrontiamo con int
int a = 5, b = 2;
System.out.println(a / b); // 2 (il resto viene scartato)
double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5
5. Errori tipici e stranezze con double
Errore di conversione dell'input
Situazione classica: l’utente inserisce 3,14 — ma il programma si aspetta 3.14. In Java il metodo Scanner.nextDouble() dipende dalla locale corrente: nella locale russa/tedesca la virgola è ammessa, in quella inglese è richiesto il punto. Se necessario, imposta la locale per Scanner oppure leggi una stringa ed esegui il parsing manualmente.
// Questo causerà un problema in Locale.US se viene inserito "3,14"
double value = console.nextDouble();
Errore di «imprecisione» dei numeri nel computer
Qui di solito i principianti iniziano a stupirsi un po’:
double x = 0.1 + 0.2;
System.out.println(x); // Hmm... 0.30000000000000004
Congratulazioni, vi siete imbattuti nella «magia» della rappresentazione dei numeri decimali all’interno del computer. Il punto è che molti numeri non possono essere rappresentati con esattezza in base binaria. Di solito ciò non è critico per la maggior parte delle applicazioni, ma ci sono sfumature in finanza e nelle scienze esatte.
6. Importante: double e int — conversione automatica ed esplicita
Può capitare di sommare un intero e un decimale, o di assegnare un int a una variabile double — non ci saranno errori:
int i = 2;
double d = i; // Tutto ok!
System.out.println(d); // 2
double dd = 3.7;
int ii = (int) dd; // Bisogna convertire esplicitamente il tipo double in int!
System.out.println(ii); // 3, la parte decimale è stata scartata
Spesso questo sorprende — perché dopo la conversione la parte decimale è sparita? Semplicemente perché il tipo int non può memorizzare frazioni (tutto ciò che viene dopo il punto scompare per sempre).
Maggiori dettagli sulla conversione da double a int e sull’operatore (int) nella prossima lezione.
7. Output formattato: stampiamo double in modo elegante
Spesso, di default, un double viene stampato con un sacco di zeri superflui. Possiamo formattare l’output:
double temp = 23.56789;
System.out.println(temp); // 23.56789
// 2 cifre decimali
System.out.println(String.format("%.2f", temp)); // 23.57
// 1 cifra decimale
System.out.println(String.format("%.1f%n", temp)); // 23.6
| Formato | Risultato | Descrizione |
|---|---|---|
|
23.57 | numero con 2 cifre decimali |
|
23.6 | numero con 1 cifra decimale |
8. Errori tipici nell’uso di float e double
Errore n. 1: conversione implicita da double a float
float f = 1.23; // Errore!
Il compilatore non sarà contento: «Stai cercando di mettere double in float — questo può portare a perdita di precisione!» Aggiungi sempre il suffisso f.
Errore n. 2: hai dimenticato che la divisione di due int dà un risultato int
int a = 7, b = 2;
double result = a / b; // 3.0, non 3.5
Per ottenere la parte decimale, converti esplicitamente almeno uno degli operandi:
double result = (double) a / b; // 3.5
Errore n. 3: confronto di numeri a virgola mobile
Non confrontare numeri a virgola mobile per l’uguaglianza usando ==. Usa un confronto con una piccola tolleranza (epsilon).
Errore n. 4: perdita di precisione con float
Non memorizzare numeri grandi o valori molto precisi in float — potrebbero «rompersi» o perdere cifre importanti.
GO TO FULL VERSION