Выполняет ли java некоторое округление, чтобы избежать неточности в представлении IEEE-754

#java #ieee-754

Вопрос:

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

 public class Main {
    public static void main(String[] args) {

        float one_point_six = 1.6f; // According to IEEE-754, should be 1.60000002384185791015625
        float zero_point_four = 0.4f; // According to IEEE-754, should be 0.4000000059604644775390625
        float sum = one_point_six   zero_point_four; // shouldn't this be 2.0000000298023223876953125?

        System.out.println(Math.ceil(sum)); // Prints 2.0. Shouldn't this be 3?
        System.out.println(sum > 2f); // Prints false. Why?
    }
}
 

Результат остается неизменным, даже если я заменяю числа с плавающей запятой на удвоения. Java выполняет некоторые округления или я что-то упускаю?
Я использовал https://www.h-schmidt.net/FloatConverter/IEEE754.html для определения «фактического» значения, которое сохраняется.

Ответ №1:

разве это не должно быть 2.0000000298023223876953125?

Нет. Как вы знаете, float имеет ограниченную точность, поэтому она недостаточно точна для хранения числа с такой точностью. Пытаясь использовать ваш конвертер и введя туда 2.0000000298023223876953125, вы обнаружите, что фактическое сохраненное значение равно всего лишь «2».

Комментарии:

1. Да, это имеет смысл. Чтобы проверить это, я изменил тип данных sum с float на double и добавил приведение к double для one_point_six при суммировании. Это дало мне результаты 3 и true. Спасибо!