Почему Java преобразует тип double в тип float в этой ситуации? - PullRequest
0 голосов
/ 03 марта 2019

Сегодня я определил две переменные с плавающей запятой f1 и f2 .Затем я выполняю сложение арифметической операции «+» и присваиваю переменную с плавающей запятой f .

float f1 = 0.5048076923076923F;
float f2 = 0.5048076923076923F;
float f = f1 + f2;

Это вывод:
enter image description here

Согласно этому рисунку, все значения с плавающей запятой ( float и double ) в арифметической операции ( +, -, *, / ) преобразуются в тип double : источник изображения: http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/04/mixed.html
image

Я нашел такой же вопрос, но он не объясняет почему.Почему у затмения нет никаких советов по проблеме?Это причина того, что значение "f1 + f2" является типом с плавающей запятой?И почему Java автоматически преобразует тип double в тип float, как показано на картинке выше?picture source: https://www.homeandlearn.co.uk/java/short_float_variables.html

PS: английский не мой родной язык, пожалуйста, прости меня, если у этого вопроса есть некоторые грамматические проблемы.Благодарю.:)

Ответы [ 4 ]

0 голосов
/ 03 марта 2019

Чего не хватает другим ответам, так это аппаратного уровня.Обычно процессоры с плавающей запятой преобразуют все операции в двойные (или четырехкратные), а затем возвращают результат с требуемой точностью.Спецификация Java может не распознавать преобразование, но если оно использует аппаратное обеспечение с плавающей запятой, преобразование происходит.

0 голосов
/ 03 марта 2019

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

float f1 = 0.5048076923076923F;
float f2 = 0.5048076923076923F;
float f = f1 + f2;

На самом деле преобразования нет.Все значения float.

В частности, литерал 0.5048076923076923F представляет собой float.Трейлинг F делает его float.Если вам нужен двойной литерал, пропустите F или замените его на D.

Когда ваш учитель говорит, что «все значения с плавающей запятой преобразованы в double», он ошибается.JLS говорит (в действительности), что числовой примитивный операнд будет преобразован в double , когда другой операнд является double.Если оба операнда float, то операция будет выполняться с использованием арифметики с плавающей запятой одинарной точности.

Ссылка JLS: JLS 5.6.2: двоичное числовое продвижение .


Было отмечено, что на аппаратном уровне могут происходить дополнительные преобразования.Например, JLS говорит следующее:

В выражении, не являющемся строгим с точки зрения FP, предоставляется некоторая свобода для реализации, чтобы использовать расширенный диапазон экспонент для представления промежуточных результатов;общий эффект, грубо говоря, состоит в том, что вычисление может дать «правильный ответ» в ситуациях, когда исключительное использование набора значений с плавающей запятой или набора двойных значений может привести к переполнению или потере.

Однако:

  • Это допустимо, только если выражение не strictfp.
  • Это не «преобразования», о которых JLS говорит в JLS 5.6.2.
  • Это все еще противоречит тому, что говорит преподаватель ОП.Он (или она) заявляет, что все вычисления с плавающей запятой выполняются с использованием double.JLS утверждает, что при определенных обстоятельствах , аппаратная платформа может использовать арифметику с расширенной точностью (возможно, с большей точностью, чем 64-битная с плавающей запятой), а в других обстоятельствах не должнасделай это .
0 голосов
/ 03 марта 2019

Привет для значений с плавающей запятой. JVM использует такие инструкции:

'+': fadd: выдает два числа с плавающей запятой, добавляет их и отправляет результат с плавающей запятой
'-': fsub: выдает два числа с плавающей запятойвычитает их и толкает результат flot

аналогично, поскольку для других операторов, таких как * и / и т. д., устанавливаются другие инструкции

Таким образом, с точки зрения реализации JVM float + float приведет кплавать.
Но float + double приведет к удвоению.

Для получения дополнительной информации вы можете прочитать главу 14. Арифметика с плавающей точкой книги "Внутри виртуальной машины Java"

0 голосов
/ 03 марта 2019

Ваш учитель неверен, пожалуйста, обратитесь к разделу 5.6.2 Спецификации языка Java , в котором говорится:

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

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

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

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

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

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

То есть сумма двух чисел с плавающей запятой, но сумма чисел с плавающей точкой и числа с двойным есть двойная.

PS: И нет, Java не будетконвертировать double в число с плавающей запятой, если вы явно не попросите его об этом, например:

float f = (float) Math.PI;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...