|
La regola della promozione è importante da comprendere per rendersi bene conto di come avvengono i calcoli quando si programma in Java. In realtà si capisce meglio il senso di queste regole quando si immagina quello che avviene sotto il pavimento. I calcoli vengono effettuati dalla JVM, ovvero l'interprete Java. Questo interprete assomiglia molto un microprocessore, che ha dei registri per fare dei calcoli. Quando si deve fare una somma, il valore da sommare devono venir caricati nei registri, e solo dopo si può operare. Le operazioni richiedono che entrambi registri abbiano la stessa dimensione. I registri della JVM sono a 32 bit per quanto riguarda l'aritmetica intera, e a 64 bit per quanto riguarda l'aritmetica in virgola mobile.
  |
Nei Calcoli |
Quando si effettua un calcolo, questo viene suddiviso in tanti passi, in cui ci prendono due operanti e si opera su di essi. Per effettuare un passo bisogna per prima cosa caricare i valori in due registri di pari dimensione.
  |
ogni valore intero inferiore ad int diventa int. |
per cui se devo operare tra due valori interi, per prima cosa questi devono essere caricati sui registri interi. Siccome i registri sono almeno a 32 bit, ecco che avviene il primo passo della promozione: tutti valori interi di dimensione inferiore ai 32 bit vengono promossi a 32 bit.
  |
ogni valore float diventa double |
analogamente se per caso uno due operanti diventa in virgola mobile, la dimensione dei registri virgola mobile è di 64 bit, per cui calcoli in virgola mobile vengono sempre fatti nella precisione del double.
  |
un operatore opera solo su valori della stessa dimensione |
  |
tra due operandi, (a + b) il "più grosso" decide |
  |
l'altro viene ingrandito |
In tutti gli altri casi, quando uno due operanti e più piccolo dell'altro, il più piccolo viene convertito nel più grosso. In particolare se è uno è long, anche l'altro diventa long. E se uno dei due è double, anche l'altro diventa double.
  |
per assegnare a variabili più piccole bisogna "convertire" (troncando) |
Alla fine dei calcoli si ottiene un numero che ha alla precisione dell'operando più grosso, ma non è detto che il risultato stia nella variabile che si vuole assegnare. Per questo motivo esiste un operatore di conversione, o cast, che serve a convertire esplicitamente nella precisione che serve. Se si vuole ampliare non c'è problema, conversione è addirittura implicita e non occorre specificarlo. Più problematico nel quando si vuole ridurre dimensione o si vuol passare da un numero in virgola mobile un numero intero. In questi casi occorre troncare o arrotondare, con il rischio di perdere informazioni. Per questo motivo l'arrotondamento finale deve essere esplicito. Il programmatore deve sapere, ed deve ordinarlo esplicitamente, che c'è il rischio di perdere precisione.
01. byte b=1;
02. short s=2;
03. long l=3;
04. double d=4.0;
05. int t=b+s; // è int (32 bit)
06. t+l // è long (64 bit)
07. l+d // è double (64 bit)
08. byte n=t+l; // ERRORE
09. byte n=(byte)t+l; // OK
esaminando quest'esempio passo passo possiamo renderci conto di quello che succede. Nelle righe da 1 a 4, stiamo semplicemente assegnando del valore a delle variabili. Nelle riga 5 stiamo facendo una somma di uno short con un byte. Per regola che i calcoli interi vengono effettuati almeno in precisione intera, sia b che s diventano interi, e il risultato è intero. Sommando un intero ad un long, otteniamo che l'intero è promosso a long, il risultato è long. Allo stesso modo, sommando un long ad un double, il risultato è doble. Nelle righe 8 vediamo come il tentativo di assegnare un long ad un byte fallisce. Quel codice non compila. Questo perché non si può mettere valore a 32 bit dentro una scatola che può contenere solo 8 senza buttarne via 24. Usando "(byte)" viene effettuata la conversione e l'eventuale troncamento.
|