Я хотел бы получить несколько советов от людей, которые имеют больший опыт работы с примитивным double
равенством в Java. Использование d1 == d2
для двух двойных d1
и d2
недостаточно из-за возможных ошибок округления.
Мои вопросы:
Является ли Java
Double.compare(d1,d2) == 0
обработкой ошибок округления в какой-то степени? Как описано в документации 1.7 он возвращает значение0
, еслиd1
численно равноd2
. Кто-нибудь уверен, что именно они подразумевают под числовым равенством?Используя расчет относительной ошибки относительно некоторого значения дельты, есть ли общее (не зависящее от приложения) значение дельты, которое вы бы порекомендовали? См. Пример ниже.
Ниже приведена общая функция для проверки равенства с учетом относительной ошибки. Какое значение delta
вы бы порекомендовали для выявления большинства ошибок округления из простых операций +, -, /, * операции?
public static boolean isEqual(double d1, double d2) {
return d1 == d2 || isRelativelyEqual(d1,d2);
}
private static boolean isRelativelyEqual(double d1, double d2) {
return delta > Math.abs(d1- d2) / Math.max(Math.abs(d1), Math.abs(d2));
}
isRelativelyEqual
- правильный подход (помимо проблем с NaN) для тотальной атаки на проблему. Вы бы выбралиdelta
на основе количества бит точности в вашем формате с плавающей запятой, фактически 53 бит или 16 десятичных цифр для двойной точности, и насколько близко вы хотите быть. В качестве альтернативы вы можете использоватьdoubleToLongBits
для чисел, округлить дробь, чтобы исключить 1–3 дробных бита, а затем сравнить на равные. - person Hot Licks   schedule 06.08.2014