2013-08-11 10 views
7

Ho questo codiceottenere risultati inaspettati quando il tipo di fusione tra il lungo e doppio

public class LimitTest{ 
    public static void main(String[] args){ 
     long l; 
     double d; 
     l = 9223372036854775807L;// The largest number a long can hold. 
     d = l; 
     System.out.println(l); 
     System.out.println(d); 
     System.out.println(l == d); 
    } 
} 

Ora, il risultato che produce è un pò inaspettato, ma ancora una volta, io non sono molto esperto con le conversioni di tipo.

uscita

9223372036854775807 
9.223372036854776E18 
true 

Ora, i due numeri stampati sono chiaramente Non uguale, quindi perché fa l == d ritorno true?

risposta

5

Le variabili l e d hanno tipologie diverse, quindi l'espressione long == double proietta l'long ad un double ...

P.S. l è un nome variabile errato imho, dal momento che assomiglia molto a 1 quando si guarda il codice.

2

quindi perché non l == d return true ;

Perché long viene convertito in double prima del confronto. E quindi il risultato è vero.

Questo è specificato in JLS - Section 5.6.2:

Allargamento conversione primitiva (§5.1.2) viene applicato per convertire uno o entrambi gli operandi come specificato dalle seguenti regole:

  • Se uno degli operandi è di tipo doppio, l'altro viene convertito in doppio.

si sta vedendo risultato diverso per double, perché non tutti long valori possono essere rappresentati da un valore unico double. Quindi, potresti avere molti valori doppi per un singolo valore lungo. C'è una possibile perdita di precisione durante la conversione da long a double.

Da JLS Section 5.1.2:

Una conversione allargamento di int o un lungo valore di galleggiare, o una lunga valore di raddoppiare, può causare la perdita di precisione - cioè, il risultato può perdere alcuni dei bit meno significativi del valore.

2

Per confrontare due valori devono avere lo stesso tipo. Qui il valore lungo viene convertito implicitamente nel tipo double e il risultato della conversione dà lo stesso valore di un assegnamento.

I valori sono diversi in primo luogo perché il tipo doppio ha meno "significato" (ha una mantissa a 53 bit per l'archiviazione di cifre reali, il resto dei bit utilizzati per il segno e l'esponente) piuttosto che lungo (tutti i 64 bit). Non tutti i valori lunghi possono essere rappresentati come un doppio valore unico.

2

9223372036854775807 e 9.223372036854776E18sono uguali

Note le prime 15 cifre di precisione 922337203685477 sono uguali. Il resto del primo numero 5807 viene arrotondato a 6 in modo che sia possibile aggiungere E18.

9223372036854775807 in notazione scientifica è:

9.223372036854775807 x 10^18 == 9.223372036854775807E18 

Confronta:

9.223372036854775807E18 
9.223372036854776E18 

Il valore viene memorizzato con maggiore precisione di quanto lo è visualizzata con, vedere questo per la prova:

long l; 
    double d; 
    l = Long.MAX_VALUE;// The largest number a long can hold. 
    d = l; //This is implicitly cast to (double) 
    System.out.println("long: " + l); 
    System.out.println("double: " + d); 
    System.out.println("double back to long: " + (long) d); 

lungo: 9223372036854775807
doppia: 9.223372036854776E18
doppio di nuovo a lungo: 9223372036854775807

C'è anche la questione secondaria di come float e double sono memorizzati. Mentre i tipi interi (byte, short, int, long) sono esatti, float e double use IEEE754 stile mantissa-esponente che consente loro di rappresentare una gamma maggiore di numeri ma con meno precisione. http://en.wikipedia.org/wiki/IEEE_754-1985

Problemi correlati