Страницы

Поиск по вопросам

суббота, 7 декабря 2019 г.

Десятичные дроби типа double в java [дубликат]

#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 . Или округляйте, если большая точность не важна. Кстати, это не связано с языком программирования, а скорее с архитектурой процессора и памяти :)

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

Отправить комментарий