Значение аргумента epsilon assertEquals для двойных значений
У меня вопрос о JUnit assertEquals для проверки двойных значений. Чтение API doc я вижу:
@Deprecated public static void assertEquals(double expected, double actual)
устаревшие. Использование assertEquals (double ожидаемый, двойной фактический, двойной Эпсилон) вместо
что означает значение epsilon? (Эпсилон-буква греческого алфавита, верно?).
может кто-нибудь объяснит мне, как его использовать?
7 ответов
Epsilon-это значение, на которое могут быть отключены 2 числа. Поэтому он будет утверждать, пока Math.abs(expected - actual) < epsilon
какая версия JUnit это? Я только когда - либо видел дельту, а не Эпсилон-но это побочный вопрос!
из JUnit javadoc:
delta-максимальная дельта между ожидаемым и фактическим, для которых оба числа по-прежнему считаются равными.
это, вероятно, перебор, но я обычно использую очень небольшое число, например
private static final double DELTA = 1e-15;
@Test
public void testDelta(){
assertEquals(123.456, 123.456, DELTA);
}
если вы используете hamcrest утверждения, вы можете просто используйте стандарт equalTo()
С двумя двойниками (он не использует дельту). Однако, если вы хотите дельту, вы можете просто использовать closeTo()
(см. javadoc), например,
private static final double DELTA = 1e-15;
@Test
public void testDelta(){
assertThat(123.456, equalTo(123.456));
assertThat(123.456, closeTo(123.456, DELTA));
}
FYI предстоящий JUnit 5 также сделать delta необязательным при вызове assertEquals()
С двух дублей. The реализация (если вам интересно) это:
private static boolean doublesAreEqual(double value1, double value2) {
return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2);
}
вычисления с плавающей запятой не точны-часто возникают ошибки округления и ошибки из-за представления. (Например, 0.1 не может быть точно представлены в двоичном формате с плавающей точкой.)
из-за этого прямое сравнение двух значений с плавающей запятой для равенства обычно не является хорошей идеей, потому что они могут отличаться на небольшую сумму, в зависимости от того, как они были вычислены.
"Дельта", как ее называют в JUnit javadocs, описывает сумма разницы, которую вы можете терпеть в значениях, чтобы они по-прежнему считались равными. Размер этого значения полностью зависит от сравниваемых значений. При сравнении двойников я обычно использую ожидаемое значение, деленное на 10^6.
дело в том, что два двойника могут быть не совсем равными из-за проблем точности, присущих числам с плавающей запятой. С помощью этого Дельта-значения можно управлять оценкой равенства на основе коэффициента ошибки.
также некоторые значения с плавающей запятой могут иметь специальные значения, такие как NAN и-Infinity/+Infinity, которые могут влиять на результаты.
Если вы действительно намерены сравнить, что два двойника точно равны, лучше сравнить их как длинный представление
Assert.assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(result));
или
Assert.assertEquals(0, Double.compareTo(expected, result));
которые могут учитывать эти нюансы.
Я не углублялся в рассматриваемый метод Assert, но я могу только предположить, что предыдущий был устаревшим для такого рода проблем, и новый учитывает их.
обратите внимание, что если вы не занимаетесь математикой, нет ничего плохого в утверждении точных значений с плавающей запятой. Например:
public interface Foo {
double getDefaultValue();
}
public class FooImpl implements Foo {
public double getDefaultValue() { return Double.MIN_VALUE; }
}
в этом случае вы хотите убедиться, что это действительно MIN_VALUE
, а не ноль или -MIN_VALUE
или MIN_NORMAL
или какое-то другое очень небольшое значение. Вы можете сказать
double defaultValue = new FooImpl().getDefaultValue();
assertEquals(Double.MIN_VALUE, defaultValue);
но это даст вам предупреждение об устаревании. Чтобы избежать этого, вы можете позвонить :
// really you just need one cast because of autoboxing, but let's be clear
assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
и, если вы действительно хотите выглядеть умный:
assertEquals(
Double.doubleToLongBits(Double.MIN_VALUE),
Double.doubleToLongBits(defaultValue)
);
или вы можете просто использовать утверждения Hamcrest fluent-style:
// equivalent to assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
assertThat(defaultValue, is(Double.MIN_VALUE));
если значение, которое вы проверяете тут приходите от выполнения некоторых математических задач, хотя, используйте Эпсилон.
Эпсилон-это разница между expected
и actual
ценности, которые вы можете принять, думая, что они равны. Вы можете установить .1
например.