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

Преобразование из double в float в Java

Если я работаю с double, и я конвертирую его в float, как это работает? Получается ли значение усеченного, чтобы оно входило в поплавок? Или значение округляется по-другому? Извините, если это звучит немного исправно, но я пытаюсь понять концепцию преобразований float и double.

4b9b3361

Ответ 1

Из Спецификация Java Language, раздел 5.1.3:

Сужение примитивного преобразования из double в float регулируется правилами округления IEEE 754 (§4.2.4). Это преобразование может потерять точность, но также и потерять диапазон, в результате чего получается ноль с плавающей точкой от ненулевого двойника и бесконечность с плавающей точкой от конечного двойника. Двойной NaN преобразуется в float NaN, а двойная бесконечность преобразуется в бесконечную бесконечность с плавающей точкой.

и в разделе 4.2.4 говорится:

Язык программирования Java требует, чтобы арифметика с плавающей запятой вела себя так, как если бы каждый оператор с плавающей запятой округлял результат с плавающей запятой с точностью до результата. Неточные результаты должны округляться до представляемого значения, ближайшего к бесконечно точному результату; если два ближайших представимых значения одинаково близки, выбирается единица с наименьшим значащим битом нуль. Это стандартный режим округления по стандарту IEEE 754, известный как от округлой до ближайшей.

Ответ 2

Я бы предположил, что типы с плавающей запятой наиболее целесообразно рассматривать как представляющие диапазоны значений. Причина, по которой 0,1f отображается как 0,1, а не как 0,100000001490116119384765625, состоит в том, что она действительно представляет диапазон чисел от 13421772,5/134217728 до 13421773,5/134217728 (то есть от 0,0999999977648258209228515625 до 0,1000000052154064178466796875); было бы бессмысленно добавлять дополнительные цифры, указывающие, что число больше 0.100, когда оно может быть меньше, или не использовать строку из девяти, указывающую, что число меньше 0.100, когда оно может быть больше.

Приведение double к float выберет float, диапазон значений которого включает диапазон удвоений, представленных двойным. Обратите внимание, что, хотя эта операция не обратима, результат операции будет, как правило, арифметически корректным; единственный раз, когда он не был бы на 100% арифметически правильным, было бы, если бы кто-то бросал, чтобы плавать двойник, чей диапазон был точно центрирован на границе между двумя поплавками. В этой ситуации система будет выбирать поплавок с одной или с другой стороны двойного диапазона; если двойной на самом деле представляет число на неправильной стороне диапазона, то полученное преобразование будет немного неточным.

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

Важно отметить, что отбрасывание float в double является гораздо более опасной операцией, чем приведение double в float, хотя Java позволяет использовать это неявно без предупреждения, но сквозит на последнем. Литье поплавка в двойное приводит к тому, что система выбирает двойной, диапазон которого центрирован относительно центра поплавкового диапазона. Это почти всегда приводит к значению, фактическая неопределенность которого намного больше, чем это было бы типично для чисел с двойной точностью. Например, если один из них удваивает 0,1f, полученный двойной будет представлять собой число в диапазоне от 0,10000000149011611 до 0,10000000149011613, хотя число, которое оно должно представлять (одна десятая), относительно говоря, нигде близко к этому диапазону.