2012-05-07 10 views
5

jest coś dziwnego i nie znalazłem wiele informacji na temat specyfikacji VM. Jest trochę niejasny i byłoby miło, gdyby ktoś mógł mi wyjaśnić.Rzut podwójny na inny numeryczny

Te kilka linijek kodu .....

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); 

..... produkować tego wyjścia:

  1. pływaka: Nieskończoność
  2. int: 2147483647
  3. skrócie: -1
  4. bajt: -1

byte, short i int są 8, 16, 32-bitowe z dopełnieniem dwóch. float i double są 32 i 64-bitowe IEEE 754 (see here).

Z mojego rozumowania, maksymalna wartość double sugeruje, że wszystkie bity mantysy (52 bity) są przełączone na 1. Dlatego nie jest (bardzo) zaskakujące, że rzut na krótki lub na bajt zwraca -1, wszystkie bity są przełączane na 1. Wygląda na to, że obsada utrzymuje "ogon" double tak, że pasuje do 8 bitów byte lub 16 bitów short.

Co mnie zaskakuje to obsada do int i, w mniejszym stopniu, obsada do float. Jak to jest uzyskać "2. int: 2147483647", który jest 0x7FFFFFFF, maksymalna wartość podczas short i bajt 3. i 4. to -1?

Obsada do float jest również dziwna. Jeśli zachowano 32 bity przy "ogonie" myTest, to czy nie powinno to generować NaN?

Odpowiedz

4

JLS określa zasady w sekcji 5.1.3 Narrowing Primitive Conversion. Reguły zależą od typu celu.

float:

zwężenie prymitywna konwersja z double float jest regulowane przez IEEE 754 zasad zaokrąglania (§4.2.4). Konwersja ta może stracić precyzję, ale również stracić zasięg, co powoduje, że wartość zerowa z niezerowego podwójnego i nieskończoności swobodnej z skończonego podwójnego. Podwójny NaN jest konwertowany na pływający NaN, a podwójna nieskończoność jest konwertowana na nieskończoną sygnaturę o tym samym znaku.

int i long:

jeden z dwóch następujących przypadkach muszą być spełnione:

  • ...
  • Wartość musi być zbyt duża (wartość dodatnia dużej jasności lub dodatniej nieskończoności), a wynikiem pierwszego kroku jest największa reprezentowalna wartość typu int lub long.

byte, char i short:

Jeżeli typ celem jest byte, char lub short konwersja jest dwuetapowa. Po pierwsze, double jest konwertowane na long, jak wyjaśniono powyżej. Następnie long przeprowadza się w końcowej typu w następujący sposób:

Konwersja zwężenie liczba całkowita ze znakiem na integralnej typu T po prostu odrzuca wszystkie jednak n najniższe bity rzędu, gdzie N jest to liczba bitów używana do reprezentuje typ T. Oprócz możliwej utraty informacji o wielkości wartości liczbowej może to spowodować, że znak uzyskanej wartości będzie różnił się od znaku wartości wejściowej.

+0

To bardzo interesujące. Tak więc, kiedy double jest rzutowany na int ("o największej reprezentowalnej wartości" w moim przykładzie), jest on rzutowany na bajt lub skrót o innej filozofii ("odrzuca wszystkie oprócz n najniższych rzędów"). – Jerome

+0

@Jerome: Dość (poza tym uważam, że pośrednim typem jest 'long', ale nie ma to wpływu na wynik). – NPE

+0

Warto zauważyć, że chociaż rzutowanie 'double' na' float' może spowodować, że niektóre odrębne wartości staną się nierozróżnialne, jest to niewielki problem w porównaniu do faktu, że rzutowanie 'float' na' double' może powodować rzeczy, które zamiast tego powinny być uważane za nierozróżnialne być posortowane * niesłusznie *. Na przykład, biorąc pod uwagę 'float f = 16777217; double d = 16777216.0000001; ', który jest większy -' f' lub 'd'? Co powiesz na 'float ff = 1E38f * 10f; podwójne dd = 1e300; '? Jeśli chodzi o 'ff' i' dd' jako "nierozróżnialne" nie byłoby wspaniale, ale powiedzenie 'ff> dd' jest błędne o setki rzędów wielkości. – supercat