Dlaczego Java domyślnie (bez cast) konwertuje 'long' na`float'?

Za każdym razem, gdy myślę, że rozumiem casting i konwersje, znajduję inne dziwne zachowanie.

long l = 123456789L;
float f = l;
System.out.println(f);  // outputs 1.23456792E8

Biorąc pod uwagę, że a long ma większą głębię bitową niż a float, spodziewałbym się, że aby to skompilować, wymagany będzie wyraźny rzut. I nic dziwnego, że widzimy, że straciliśmy precyzję w wyniku.

Dlaczego obsada nie jest tutaj wymagana?

Author: Eric Wilson, 2009-08-18

4 answers

To samo pytanie można zadać od long do double - obie konwersje mogą utracić informacje.

Sekcja 5.1.2 specyfikacji języka Java mówi:

Rozszerzające się prymitywne konwersje nie utrata informacji o ogólnej wielkość wartości liczbowej. Rzeczywiście., konwersje rozszerzające się od całki typu do innego typu całkowego nie utrata jakichkolwiek informacji; wartość liczbowa jest zachowana dokładnie. Konwersje z float to podwójne w wyrażeniach strictfpzobacz też zachowaj dokładnie wartość liczbową; jednak takie konwersje, które nie są strictfp może utracić informacje o ogólna wielkość przeliczanej wartość.

Konwersja wartości int lub long float, lub o długiej wartości do podwójne, może spowodować utratę precyzja-czyli wynik może stracić niektóre z najmniej znaczących bitów wartość. W tym przypadku wynik wartość zmiennoprzecinkowa będzie prawidłowo zaokrąglona wersja wartość całkowita, przy użyciu IEEE 754 tryb rundy do najbliższej (§4.2.4).

Innymi słowy, nawet jeśli możesz stracić informacje, wiesz, że wartość nadal będzie w ogólnym zakresie typu docelowego.

Z pewnością można było dokonać wyboru wymagającego, aby wszystkie niejawne konwersje nie traciły żadnych informacji - tak więc int i long do float byłyby jawne, a long do double byłyby jawne. (int to double jest OK; a double ma wystarczającą precyzję, aby dokładnie przedstawić wszystkie wartości int.)

W niektórych przypadkach byłoby to przydatne - w niektórych przypadkach nie. W projektowaniu języka chodzi o kompromis; nie można wygrać wszystkich. Nie jestem pewien, jaką decyzję bym podjął...

 41
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 16:03:41

Specyfikacja języka Java, Rozdział 5: Konwersja i promocja rozwiązuje ten problem:

5.1.2 Rozszerzenie Prymitywnej Konwersji

Następujące 19 konkretnych konwersji na prymitywnych typach nazywane są rozszerzenie prymitywnych konwersji:

  • byte to short, int, long, float, or double
  • short to int, long, float, or double
  • char to int, long, float, or double
  • int to long, float, or double
  • long to float or double
  • float to double

Rozszerzenie prymitywnych konwersji nie traci informacji o ogólnej wielkości wartości liczbowej.

...

Konwersja int lub długiej wartości na float lub długiej na double może spowodować utratę precyzji-to znaczy, wynik może stracić niektóre z najmniej znaczących bitów wartości. W takim przypadku otrzymana wartość zmiennoprzecinkowa będzie prawidłowo zaokrąglona wersja wartości całkowitej

Mówiąc inaczej, JLS rozróżnia utratę wielkość i utrata precyzja.

int Na przykład do byte jest (potencjalną) stratą wielkości, ponieważ nie można przechowywać 500 W byte.

long to float jest potencjalną utratą precyzji, ale nie wielkości, ponieważ zakres wartości dla pływaków jest większy niż dla longów.

Więc zasada jest:

  • utrata wielkości: wymagana jest wyraźna Obsada;
  • utrata precyzji: nie wymaga odlewu.
Subtelne? Jasne. Ale mam nadzieję, że to wszystko wyjaśni.
 37
Author: cletus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 14:01:21

Chociaż masz rację, że long używa więcej bitów wewnętrznie niż float, język java działa na rozszerzającej się ścieżce:

Byte -> short -> int -> long -> float - > double

Aby konwertować z lewej Na prawą (konwersja rozszerzająca), nie ma potrzeby rzucania (dlatego dozwolone jest long to float). Do konwersji z prawej na lewą (konwersja zwężająca) konieczny jest wyraźny rzut.

 14
Author: Peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 13:41:14

Gdzieś to słyszałem. Float może przechowywać w postaci wykładniczej, tak jak to piszemy. '23500000000' jest zapisywane jako '2.35e10'. float ma więc miejsce do zajmowania zakresu wartości long. Przechowywanie w postaci wykładniczej jest również przyczyną utraty precyzji.

 1
Author: george,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-25 15:10:18