2012-05-07 11 views
5

c'è qualcosa che mi lascia perplesso e non ho trovato molte informazioni sulle specifiche VM. È un po 'oscuro e sarebbe bello se qualcuno potesse spiegarmi.Trasmettere un doppio ad un altro tipo numerico

Queste poche linee di codice .....

double myTest = Double.MAX_VALUE; 

System.out.println("1. float: " + (float)myTest); 
System.out.println("2. int: " + (int)myTest); 
System.out.println("3. short: " + (short)myTest); 
System.out.println("4. byte: " + (byte)myTest); 

..... produrre questo output:

  1. float: infinità
  2. int: 2147483647
  3. breve: -1
  4. byte: -1

byte, short e int sono 8, 16, 32 bit con complemento a due. float e double sono 32 e 64 bit IEEE 754 (see here).

Dal mio punto di vista, il valore massimo di un double implica che tutti i bit del mantisse (52 bit) vengono commutati su 1. Pertanto non è (molto) sorprendente che un cast per i ritorni a byte brevi o byte -1 vale a dire tutti i bit sono passati a 1. Sembra che il cast mantenga la "coda" del double in modo che si adatti a 8 bit byte oa 16 bit short.

Ciò che mi sorprende è il cast a int e, in misura minore, il cast a float. Come è possibile ottenere "2. int: 2147483647" che è 0x7FFFFFFF, il valore massimo mentre short e byte 3. e 4. sono -1?

Il cast a float è anche strano. Se i 32 bit della "coda" di myTest sono stati mantenuti, non dovrebbe generare un valore NaN?

risposta

4

JLS enuncia le regole nella sezione 5.1.3 Narrowing Primitive Conversion. Le regole dipendono dal tipo di destinazione.

float:

Un ambito conversione primitiva doppia galleggiare è regolata dalle norme di arrotondamento IEEE 754 (§4.2.4). Questa conversione può perdere precisione, ma anche perdere l'intervallo, risultando in uno zero mobile da un doppio diverso da zero e un infinito float da un doppio finito. Un doppio NaN viene convertito in un NaN float e un doppio infinito viene convertito nell'infinito float con la stessa firma.

int e long:

una delle seguenti due casi devono essere vere:

  • ...
  • il valore deve essere troppo grande (un valore positivo di grande magnitudine o infinito positivo) e il risultato del primo passo è il più grande valore rappresentabile di tipo int o long.

byte, char e short:

Se il tipo di destinazione è byte, char o short, la conversione è in due fasi. Innanzitutto, lo double viene convertito in long come spiegato sopra. Poi, il long viene convertito al tipo finale come segue:

Una conversione restringimento di un intero con segno a un tipo integrale T scarta semplicemente tutti ma i bit di ordine n bassi, dove n è il numero di bit utilizzati per rappresenta il tipo T. Oltre a una possibile perdita di informazioni sulla grandezza del valore numerico, ciò potrebbe causare la differenza tra il segno del valore risultante dal segno del valore di input.

+0

Grazie, è molto interessante. Quindi, una volta che il double è stato castato su un int ("con il più grande valore rappresentabile" nel mio esempio), viene castato su un byte o su un corto con una filosofia diversa ("scarta tutti tranne i bit di ordine inferiore"). – Jerome

+0

@Jerome: praticamente (a parte il fatto che il tipo intermedio è "lungo", ma non influisce sul risultato). – NPE

+0

Vale la pena notare che sebbene lanciare 'double' su' float' può far sì che alcuni valori distinti diventino indistinguibili, questo è un problema minore rispetto al fatto che lanciare 'float' in' double' può causare cose che dovrebbero essere considerate indistinguibili essere classificato * erroneamente *. Ad esempio, dato 'float f = 16777217; double d = 16777216.0000001; ', che è più grande - 'f' o' d'? Che ne dite di 'float ff = 1E38f * 10f; double dd = 1e300; '? Considerare 'ff' e' dd' come "indistinguibili" non sarebbe grandioso, ma dire 'ff> dd 'è sbagliato in centinaia di ordini di grandezza. – supercat

Problemi correlati