#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)
по-прежнему возможны ошибки точности / округления.