Значение аргумента 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 например.


Assert.assertTrue(Math.abs(actual-expected) == 0)