2016-03-27 1 views
0

В Java, когда я печатаю что-то вроде этогоКак Java обрабатывает точность для нескольких типов?

System.out.println(1.0f*1l)); 

я получаю выход

1.0 

или с

System.out.println(((byte)1)*'A'); 

я получаю выход

65 

В обоих случаях один из типов больше, чем другой. Длины 64 бит, а поплавки - 32 бита, а байты - 8 бит, а символы - 16 бит. Несмотря на это, Java выводит результат на меньший тип. Разве это не будет считаться потерей точности?

+2

Это подробно описано в Спецификации языка Java. Существует целая глава [Конверсии и контексты] (http://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html). –

+1

https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.6.2 –

ответ

4

Спецификация языка Java предоставляет список правил, определяющих тип результата на основе типов операндов.

В частности, раздел 4.2.4 говорит, что

Если по крайней мере один из операндов бинарного оператора имеет тип с плавающей точкой, то операция является операцией с плавающей точкой, даже если другое является интегральным.

, который объясняет, почему float «выигрывает» против long.

Целочисленная арифметика объясняется в разделе 5.6.2. В частности, он говорит, что

Расширяя примитивные преобразования (§5.1.2) применяется для преобразования одного или обоих операндов, как указано по следующим правилам:

• Если один из операндов имеет тип double, другой преобразуется в double.

• В противном случае, если один из операндов имеет тип float, другой преобразуется в float.

• В противном случае, если один из операндов имеет тип long, другой конвертирован в long.

• В противном случае оба операнда преобразуются в тип int.

Вот почему в вашем втором примере результат 65, имеет тип int.

0

Java расширяет тип в зависимости от диапазона возможных значений. Это означает, что float считается более широким, чем long.

Также целые операции, которые не являются long, выполняются как int. A byte * char является int

0

Вы спрашиваете о Binary Numeric Promotion (JLS 5.6.2) (курсив мой):

Когда оператор применяет двоичный цифровой продвижение к паре операндов, каждый из которых должен обозначать значение, которое конвертируется в числовой тип, применяются следующие правила, в следующем порядке:

  1. Если какой-либо из операндов имеет ссылочного типа, его подвергают конверсии (распаковки §5.1.8).
  2. Widening примитивного преобразования (§5.1.2) применяются для преобразования любого или оба операнда, как указано по следующим правилам:
    • Если один из операндов имеют типа double, другой преобразуется в double.
    • В противном случае , если один из операндов имеет тип float, другой преобразован в float.
    • В противном случае, если один из операндов имеет тип long, другой конвертируется в long.
    • В противном случае оба операнда преобразуются в тип int.

Выражение 1.0f*1l является float и long, поэтому long преобразуется в float.

((byte)1)*'A' Выражение является byte и char, так что они оба преобразованы в int.

0

В дополнение к другим ответам, в которых подробно изложены правила, я думаю, что также стоит подумать, почему так должно быть. Предположим, вы сделали

2.7F * 2L 

Настоящий математический ответ на это умножение - 5.4. Поэтому, если ответ был long, он должен был бы быть 5L (5 - ближайшее целое число до 5.4). Из-за такого рода вещей гораздо более важно, чтобы результат умножения значения с плавающей запятой на целое число считался значением с плавающей запятой. Я думаю, что будет много вопросов об этом в Stack Overflow, если следующая строка кода напечатана 5.

System.out.println(2.7F * 2L); 

Фактически он печатает 5.4.

Также имеет смысл, что все операции между целыми типами (кроме long) выполняются с помощью int. В конце концов, byte обычно считается небольшим пакетом данных, а char обычно считается персонажем. Из этих перспектив умножение значений byte или char значений не имеет смысла. Намного больше смысла держать правила простыми и просто выполнять операции с int.

Смежные вопросы