1. Arrotondamento dei numeri reali

Come abbiamo già discusso, quando un numero reale viene assegnato a una intvariabile, viene sempre arrotondato per difetto all'intero più piccolo più vicino: la parte frazionaria viene semplicemente scartata.

Ma è facile immaginare una situazione in cui un numero frazionario deve essere arrotondato all'intero più vicino in entrambe le direzioni o addirittura arrotondato per eccesso. Cosa fai in questo caso?

Per questo e per molte situazioni simili, Java ha la Mathclasse, che ha i metodi round(), ceil()e floor().


Math.round()metodo

Il Math.round()metodo arrotonda un numero all'intero più vicino:

long x = Math.round(real_number)

Ma c'è un'altra sfumatura qui: questo metodo restituisce un longnumero intero (non un int). Poiché i numeri reali possono essere molto grandi, i creatori di Java hanno deciso di utilizzare il tipo intero più grande disponibile di Java: long.

Di conseguenza, se un programmatore desidera assegnare il risultato a una intvariabile, deve indicare esplicitamente al compilatore che accetta l'eventuale perdita di dati (nel caso in cui il numero risultante non rientri in un inttipo).

int x = (int) Math.round(real_number)

Esempi:

Dichiarazione Risultato
int x = (int) Math.round(4.1);
4
int x = (int) Math.round(4.5);
5
int x = (int) Math.round(4.9);
5

Math.ceil()metodo

Il Math.ceil()metodo arrotonda un numero per eccesso a un numero intero. Ecco alcuni esempi:

Dichiarazione Risultato
int x = (int) Math.ceil(4.1);
5
int x = (int) Math.ceil(4.5);
5
int x = (int) Math.ceil(4.9);
5

Math.floor()metodo

Il Math.floor()metodo arrotonda un numero per difetto a un numero intero. Ecco alcuni esempi:

Dichiarazione Risultato
int x = (int) Math.floor(4.1);
4
int x = (int) Math.floor(4.5);
4
int x = (int) Math.floor(4.9);
4

Naturalmente, quando si arrotonda un numero per difetto a un numero intero, è più semplice utilizzare semplicemente un operatore di cast di tipo:(int)

Dichiarazione Risultato
int x = (int) 4.9
4

Se trovi difficile ricordare questi nomi, una breve lezione di inglese ti aiuterà:

  • Mathsignifica matematica
  • Roundsignifica rotondo
  • Ceilingsignifica soffitto
  • Floorsignifica pavimento

2. Come sono strutturati i numeri in virgola mobile

Il doubletipo può memorizzare valori nell'intervallo da a . Questa vasta gamma di valori (rispetto al tipo) è spiegata dal fatto che il tipo (così come ) ha una struttura interna completamente diversa rispetto ai tipi interi. Internamente, il tipo codifica il proprio valore come due numeri: il primo è chiamato mantissa e il secondo è chiamato esponente .-1.7*10308+1.7*10308intdoublefloatdouble

Diciamo che abbiamo il numero 123456789e lo memorizziamo come doublevariabile. Quando lo facciamo, il numero viene convertito in e internamente il tipo memorizza due numeri — e . Il significante ("parte significativa del numero" o mantissa) è evidenziato in rosso, mentre l'esponente è evidenziato in blu.1.23456789*108double234567898

Questo approccio consente di memorizzare sia numeri molto grandi che numeri molto piccoli. Ma poiché la rappresentazione del numero è limitata a 8 byte (64 bit) e alcuni dei bit vengono utilizzati per memorizzare l' esponente (così come il segno della mantissa e il segno dell'esponente), le cifre massime disponibili per rappresentare la mantissa è 15 .

Questa è una descrizione molto semplificata di come sono strutturati i numeri reali.


3. Perdita di precisione quando si lavora con numeri reali

Quando lavori con i numeri reali, tieni sempre presente che i numeri reali non sono esatti . Potrebbero esserci sempre errori di arrotondamento ed errori di conversione durante la conversione da decimale a binario. Inoltre, la fonte di errore più comune è la perdita di precisione durante l'aggiunta/sottrazione di numeri su scale radicalmente diverse.

Quest'ultimo fatto è un po' strabiliante per i programmatori alle prime armi.

Se sottraiamo da , otteniamo .1/109109109

Sottrarre numeri su scale radicalmente diverse Spiegazione
 1000000000.000000000;
-         0.000000001;
 1000000000.000000000;
Il secondo numero è estremamente piccolo , il che farà sì che il suo significato (evidenziato in grigio) venga ignorato. Le 15 cifre significative sono evidenziate in arancione.

Cosa possiamo dire, la programmazione non è la stessa cosa della matematica.


4. Insidia quando si confrontano numeri reali

Un altro pericolo attende i programmatori quando confrontano i numeri reali. Sorge quando si lavora con numeri reali, perché possono accumularsi errori di arrotondamento. Il risultato è che ci sono situazioni in cui ci si aspetta che i numeri reali siano uguali, ma non lo sono. O viceversa: i numeri dovrebbero essere diversi, ma sono uguali.

Esempio:

Dichiarazione Spiegazione
double a = 1000000000.0;
double b = 0.000000001;
double c = a - b;
Il valore della variabile a sarà 1000000000.0
Il valore della variabile c sarà 1000000000.0
(il numero nella b variabile è eccessivamente piccolo)

Nell'esempio precedente, ae cnon dovrebbero essere uguali, ma lo sono.

Oppure facciamo un altro esempio:

Dichiarazione Spiegazione
double a = 1.00000000000000001;
double b = 1.00000000000000002;
Il valore della variabile a sarà 1.0
Il valore della variabile b sarà1.0

5. Un fatto interessante sustrictfp

Java ha una strictfpparola chiave speciale ( strict f loating point ), che non si trova in altri linguaggi di programmazione. E sai perché ne hai bisogno? Peggiora la precisione delle operazioni con numeri in virgola mobile. Ecco la storia di come è nato:

I creatori di Java:
Vogliamo davvero che Java sia super popolare e che esegua programmi Java su quanti più dispositivi possibile. Quindi ci siamo assicurati che le specifiche per la macchina Java dicessero che tutti i programmi devono essere eseguiti allo stesso modo su tutti i tipi di dispositivi!
Produttori di processori Intel:
Ciao a tutti! Abbiamo migliorato i nostri processori e ora tutti i numeri reali sono rappresentati utilizzando 10 byte anziché 8 byte all'interno dei nostri processori. Più byte significa cifre più significative. Che cosa significa? Giusto! Ora i tuoi calcoli scientifici saranno ancora più accurati!
Scienziati e tutti coloro che sono coinvolti in calcoli ultraprecisi:
Freddo! Ben fatto. Ottima notizia!
I creatori di Java:
No-no-no, ragazzi! Ti abbiamo già detto che tutti i programmi Java devono essere eseguiti allo stesso modo su tutti i dispositivi . Disabiliteremo forzatamente la possibilità di utilizzare numeri reali a 10 byte all'interno dei processori Intel.
Ora va di nuovo tutto bene! Non ringraziarci.
Scienziati e tutti coloro che sono coinvolti in calcoli ultraprecisi:
Sei diventato completamente pazzo? Riporta velocemente tutto com'era!
I creatori di Java:
Ragazzi, questo è per il vostro bene! Immagina: tutti i programmi Java funzionano allo stesso modo su tutti i dispositivi . È così fico!
Scienziati e tutti coloro che sono coinvolti in calcoli ultraprecisi:
No. Non è affatto bello. Rimetti subito tutto com'era! O sai dove metteremo il tuo Java?
I creatori di Java:
Hmm. Perché non l'hai detto subito? Ovviamente lo rimettiamo a posto.
Abbiamo ripristinato la tua capacità di utilizzare tutte le funzionalità dei processori più recenti.
A proposito... Abbiamo anche aggiunto appositamente la strictfpparola chiave alla lingua. Se lo scrivi prima del nome di una funzione, tutte le operazioni che coinvolgono numeri reali all'interno di quella funzione saranno ugualmente negative su tutti i dispositivi !