Java. Отображение float и double [дубликат]

176
11 апреля 2019, 19:50

На данный вопрос уже ответили:

  • Вычисления на числах с плавающей точкой не работают 2 ответа

Есть простейший код:

private static float val = 0f;
public static void main(String[] args) {
    for (int i = 0; i < 100000; i++ ) {
        val = val + 0.1f;
        System.out.println(val);
    }
}

Ожидаю в конце получить 100000*0,1 = 10000. Но последнее значение: 9998.557. Если запустите код - увидите, что значения отображаются неточно, должны быть четко с шагом 0,1 но вместо 0,8 - 0.8000001, вместо 2000 - 2000.0587 и дальше ближе к максимальному значению - все больше погрешность. В чем дело?

Answer 1

Дело в типах double и float. В вычислениях, связанных с ними, практически всегда есть погрешности в вычислениях, связанные с округлением. Если хотите точности в таких числах, используйте BigDecimal.

Answer 2

У Float типа точность гораздо ниже чем у Double. Если для вас критичен результат, то используйте Double.

Простейший пример демонстрирующий погрешность:

public static void main(String[] args) {
    double dob = 0.1f;
    float flo = 0.1f;
    System.out.println("Float: " + flo);
    System.out.println("Double: " + dob);
}

Результат:

Float: 0.1
Double: 0.10000000149011612

В вашем коде если тип переменной изменить на Double, то получится то что вы ожидали от кода:

private static double val = .0;
public static void main(String[] args) {
        for (int i = 0; i < 100000; i++ ) {
            val = val + 0.1f;
            System.out.println(val);
        }
    }

Результат:

9999.700149007142
9999.800149008632
9999.900149010122
10000.000149011612

А если инкремент

val = val + 0.1f;

сменить на

val = val + 0.1;

то точность ещё больше возрастёт.

Answer 3

Это фундаментальная проблема. 0.1 (как и большинство других дробных чисел) невозможно точно записать в двоичной системе, всегда будет погрешность. Чем больше разрядность (процессора), тем погрешность меньше, но она будет всегда. И чем больше вычислений накладываются друг на друга, тем больше отличия "компьютерного" результата от математического.

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

float epsilon = 0.00000001;    
float diff = f1 - f2;
if (diff < epsilon && diff > -epsilon){
    // здесь код
}
READ ALSO
Мониторинг поля БД Postgresql

Мониторинг поля БД Postgresql

ситуация вот какая: есть таблица в бд Postgresql,в ней есть поле "статус"Требуется выполнить некий кусок Java-кода, при любом изменении статуса

158
Запрос по JDBC только для одного потока

Запрос по JDBC только для одного потока

Есть два потока, которые обращаются к одному классу, который делает запрос в БДМне необходимо сделать так, что бы они физически не могли сделать...

147
Анимация градиента SVG под углом

Анимация градиента SVG под углом

Как правильно реализовать анимацию градиента SVG элемента под углом и с задержкой?

228
CSS - градиент на background

CSS - градиент на background

Есть рабочий код:

181