Почему Java неявно (без cast) конвертирует `long` в` float`?
Каждый раз, когда я думаю, что понимаю, что касается кастингов и конверсий, я нахожу еще странное поведение.
long l = 123456789L;
float f = l;
System.out.println(f); // outputs 1.23456792E8
Учитывая, что a long
имеет большую глубину бит, чем a float
, я ожидаю, что для его компиляции потребуется явное преобразование. И неудивительно, что мы видим, что мы потеряли точность результата.
Почему актер не требуется здесь?
Ответы
Ответ 1
Можно задать тот же вопрос от long
до double
- оба конверсии могут потерять информацию.
Раздел 5.1.2 Спецификации языка Java гласит:
Расширение примитивных преобразований не потерять информацию об общем величина числового значения. В самом деле, конверсии, расширяющиеся от интеграла тип другому интегральному типу не вообще потерять любую информацию; числовое значение сохраняется точно. Конверсии, расширяющиеся от float до double в выражениях strictfp также точно сохранить числовое значение; однако такие преобразования, которые не являются strictfp может потерять информацию о общая величина преобразованных значение.
Преобразование значения int или long плавать или иметь длинное значение для двойной, может привести к потере точность, то есть результат может потерять некоторые из наименее значимых бит Значение. В этом случае результат значение с плавающей запятой будет правильно округленная версия целочисленное значение, используя IEEE 754 от круглого до ближайшего режима (§4.2.4).
Другими словами, даже если вы можете потерять информацию, вы знаете, что значение все равно будет находиться в общем диапазоне целевого типа.
Возможно, выбор был сделан для того, чтобы потребовать, чтобы все неявные преобразования потеряли никакой информации вообще - поэтому int
и long
to float
были бы явными и long
to double
были бы явными, (int
to double
в порядке, a double
имеет достаточную точность, чтобы точно представлять все значения int
.)
В некоторых случаях это было бы полезно - в некоторых случаях - нет. Дизайн языка - это компромисс; вы не можете победить их всех. Я не уверен, какое решение я бы сделал...
Ответ 2
Спецификация языка Java, глава 5: Преобразование и продвижение устраняет эту проблему:
5.1.2 Расширение примитивного преобразования
Следующие 19 конкретных преобразований на примитивные типы называются расширение примитивных преобразований:
- byte для коротких, int, long, float или double
- short для int, long, float или double
- char для int, long, float или double
- int для long, float или double
- долго плавать или удваивать
- float для двойного
Расширение примитивных преобразований не теряет информации об общей величине числового значения.
...
Преобразование значения int или long для float или длинного значения в double может привести к потере точности, то есть результат может потерять некоторые из наименее значимых бит значения. В этом случае полученное значение с плавающей запятой будет правильно округленной версией целочисленного значения
Другими словами, JLS различает потерю величины и потерю точности.
int
to byte
, например, является (потенциальной) потерей величины, потому что вы не можете сохранить 500 в byte
.
long
to float
- потенциальная потеря точности, но не величина, потому что диапазон значений для float больше, чем для longs.
Итак, это правило:
- Потеря магнитуды: требуется явное приведение,
- Утрата точности: не требуется бросок.
Тонкое? Конечно. Но я надеюсь, что это очистит.
Ответ 3
Хотя вы правы, что long использует больше бит внутри, чем float, язык java работает по расширяющемуся пути:
byte → short → int → long → float → double
Чтобы преобразовать слева направо (расширенное преобразование), нет необходимости в литье (поэтому разрешено долго плавать). Чтобы преобразовать справа налево (сужение преобразования), необходим явный приведение.
Ответ 4
Где-то я слышал это. Поплавок может храниться в экспоненциальной форме, так как мы его пишем. "23500000000" хранится как "2.35e10". Таким образом, у float есть место, чтобы занять диапазон значений long. Хранение в экспоненциальной форме также является причиной потери точности.