Вычисление остатка от двух удвоений в java

#java #double

#java #удвоение

Вопрос:

У меня есть следующий код :

 Double x = 17.0;
Double y = 0.1;

double remainder = x.doubleValue() % y.doubleValue();
  

Когда я запускаю это, я получаю остаток = 0,0999999999999906

Есть идеи, почему??

Мне в основном нужно проверить, что x полностью делится на y . Можете ли вы предложить альтернативные способы сделать это в java.

Спасибо

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

1. Арифметика с плавающей запятой является лишь приближением к арифметике действительных чисел: en.wikipedia.org/wiki/Floating_point#Accuracy_problems

2. Это с точностью до 14 значащих цифр. Чего еще вы ожидаете от double, который обладает примерно такой точностью?

Ответ №1:

Из-за того, как представлены числа с плавающей запятой.

Если вам нужны точные значения, используйте BigDecimal :

 BigDecimal remainder = BigDecimal.valueOf(x).remainder(BigDecimal.valueOf(y));
  

Другой способ добиться этого — умножить каждое значение на 10 (или 100, 1000), преобразовать в int , а затем использовать % .

Ответ №2:

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

 if (remainder < ERROR || remainder > 0.1 - ERROR)
  

Кроме того, не используйте Double, когда вы собираетесь использовать double

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

1. Это правильный ответ, который следует использовать, когда ваши данные действительно поступают из источников с плавающей запятой / double (а не просто дискретные данные, маскирующиеся под значения с плавающей запятой), и вы хотите знать, x является ли «очень близким» к точному кратному y .

Ответ №3:

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

Этот код будет делать то, что вы хотите:

 public static void main(String[] args) {
    BigDecimal x = BigDecimal.valueOf(17.0);
    BigDecimal y = BigDecimal.valueOf(0.1);

    BigDecimal remainder = x.remainder(y);
    System.out.println("remainder = "   remainder);

    final boolean divisible = remainder.equals(BigDecimal.valueOf(0.0));
    System.out.println("divisible = "   divisible);

}
  

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

1. Просто дополнение: вы можете использовать BigDecimal.ZERO вместо valueOf(0.0) для удобства чтения. Если возможно, лучше используйте new BigDecimal(String) конструктор, поскольку valueOf(double) по-прежнему возможны ошибки точности / округления.