Подтвердить что ты не робот

Почему Java неявно (без cast) конвертирует `long` в` float`?

Каждый раз, когда я думаю, что понимаю, что касается кастингов и конверсий, я нахожу еще странное поведение.

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

Учитывая, что a long имеет большую глубину бит, чем a float, я ожидаю, что для его компиляции потребуется явное преобразование. И неудивительно, что мы видим, что мы потеряли точность результата.

Почему актер не требуется здесь?

4b9b3361

Ответ 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. Хранение в экспоненциальной форме также является причиной потери точности.