#java #типы_данных #double
This question already has answers here: Вычисления на числах с плавающей точкой не работают (2 ответа) Closed 4 года назад. Есть код: public class Drob { public static void main(String[] args) { double x = 0.1; System.out.println(x+x); System.out.println(x+x+x); // Три раза прибавили X System.out.println(x+x+x+x+x); // Пять раз прибавили X System.out.println(x+x+x+x+x+x+x+x+x+x); //Десять раз прибавили X } } На выходе он даёт это: 0.2 0.30000000000000004 0.5 0.9999999999999999 Против первого и третьего ответа у меня возражений нет. Но откуда на хвосте 4*(10^-17) во втором ответе? И как это соотносится с -1*(10^-16) в четвертом ответе?
Ответы
Ответ 1
Давайте зайдём с другой стороны. По стандарту IEEE 754*, число типа double хранится в виде ± n × 2k. Это значит, что при записи double d = 0.1; число в переменной d вовсе не будет равно 0.1, потому что 0.1 не представимо в указанном виде. Ясно, почему?** Вместо этого в d будет записано какое-то приближение к 0.1. Поэтому и d + d + (10 раз) + d не будет в точности равно 1. Дополнительное чтение по теме: OMG Ponies!!! *По стандарту языка, числа с плавающей запятой соответствуют стандарту IEEE 754. (И не только в Java, кстати.) **Потому что все числа упомянутого в стандарте IEEE 754 вида представляются в виде натуральной дроби, знаменатель которой есть степень двойки, а 1/10 таким числом не является. Действительно, если m/2n = 1/10, то 10 × m = 2n, и левая часть делится на 5, а правая нет.Ответ 2
Дело в том, что данные в компьютере хранятся в бинарной системе исчесления, а не десятичной. Поэтому, если вычисления критичные, например работа с деньгами, double или float использовать нельзя. Для работы с дробями используйте класс BigDecimal . Или округляйте, если большая точность не важна. Кстати, это не связано с языком программирования, а скорее с архитектурой процессора и памяти :)
Комментариев нет:
Отправить комментарий