/
Программирование
/
Курс Java
/

Числа с плавающей точкой

Java: Числа с плавающей точкой

В математике есть разные виды чисел. Например:

  • натуральные, это целые числа от 1 и больше
  • рациональные, это числа с точкой, например 0.5, 1.75, 2.25

С точки зрения математики тут все понятно. А вот с точки зрения компьютера между этими видами чисел лежит пропасть. Попробуйте в уме сложить 0.2 и 0.1. Кажется, что выйдет 0.3. Вот что на это скажет Java:

System.out.println(0.2 + 0.1); // 0.30000000000000004

Вместо привычных 0.3 получается 0.30000000000000004.

Ожидание:   0.1 + 0.2  →  0.3
Реальность: 0.1 + 0.2  →  0.30000000000000004
                             └── погрешность хранения

Тот же результат выдадут JavaScript, C++ и почти все остальные языки.

Почему так происходит

Причина в устройстве компьютера. Память конечна, а рациональных чисел бесконечно много. Между 0.1 и 0.2 помещается бесконечно много других чисел, и сохранить их все компьютер не может. Поэтому он приближает число, стараясь уместить его в доступные биты.

С целыми числами этой беды нет, их ограничивают сверху. У самого большого целого числа в Java даже есть имя:

System.out.println(Integer.MAX_VALUE); // 2147483647

За записью Integer.MAX_VALUE прячется крайнее значение, дальше которого обычное целое число в Java не уходит.

С рациональными числами такой фокус не проходит, ведь они не выстроены в ровную цепочку. Приближенные значения называют числами с плавающей точкой (floating point numbers). Хранение и вычисления с ними подчиняются строгому стандарту IEEE 754, на который опирается большинство языков.

Когда появляются такие числа

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

В первом случае вы сами пишете число с точкой, например 0.1, 2.5 или 3.14.

Во втором случае в делении участвует дробное число:

System.out.println(1.0 / 2); // 0.5
System.out.println(2.0 / 3); // 0.6666666666666666

Тут стоит вспомнить про целочисленное деление. Когда оба операнда целые, Java делит нацело, и 1 / 2 даст 0. Достаточно сделать хотя бы один операнд дробным, и результат становится числом с плавающей точкой. Даже когда результат выглядит красиво, внутри он все равно хранится приближенно. Некоторые дроби, например 1.0 / 3, в двоичной системе вообще не записать точно.

Где это критично

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

В реальных программах с этим борются по-разному. Деньги часто хранят в минимальных единицах, например в копейках, то есть в целых числах. Результат округляют до нужного количества знаков. Числа сравнивают с небольшим допуском. Для точных вычислений берут специальные типы данных.

Что нужно запомнить

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

Задание

Вычислите и выведите на экран произведение двух чисел: 0.39 и 0.22

Полезное

Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются