Значение аргумента epsilon для assertEquals для двойных значений

У меня вопрос о junit assertEquals для проверки двойных значений. Чтение API-документа я вижу:

@Deprecated
public static void assertEquals(double expected, double actual)

Устаревшие. Используйте assertEquals (double ожидаемый, двойной фактический, двойной epsilon) вместо

Что означает значение эпсилон? (Эпсилон - это буква в греческом алфавите, верно?).

Может кто-нибудь объяснить мне, как его использовать?

Ответ 1

Epsilon - это значение, из-за которого 2 числа могут быть отключены. Таким образом, он будет отстаивать true до тех пор, пока Math.abs(expected - actual) < epsilon

Ответ 2

Какая версия 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() с двумя удвоениями. реализация (если вам интересно):

private static boolean doublesAreEqual(double value1, double value2) {
    return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2);
}

Ответ 3

Расчеты с плавающей точкой не являются точными - часто возникают ошибки округления и ошибки из-за представления. (Например, 0,1 не может быть точно представлено в двоичной плавающей запятой.)

Из-за этого прямое сравнение двух значений с плавающей запятой для равенства обычно не является хорошей идеей, потому что они могут быть разными на небольшую сумму, в зависимости от того, как они были вычислены.

"Дельта", как она называется в JUnit javadocs, описывает величину разницы, которую вы можете терпеть в значениях для них все еще считаются равными. Размер этого значения полностью зависит от значений, которые вы сравниваете. При сравнении удвоений я обычно использую ожидаемое значение, деленное на 10 ^ 6.

Ответ 4

Дело в том, что два двойных не могут быть точно равными из-за ошибок точности, присущих номерам с плавающей запятой. С помощью этого значения дельта вы можете контролировать оценку равенства на основе коэффициента ошибки.

Также некоторые значения с плавающей запятой могут иметь специальные значения, такие как NAN и -Infinity/+ Infinity, которые могут влиять на результаты.

Если вы действительно собираетесь сравнить, что два удвоения в точности равны, лучше сравнить их как длинное представление

Assert.assertEquals(Double.doubleToLongBits(expected), Double.doubleToLongBits(result));

или

Assert.assertEquals(0, Double.compareTo(expected, result));

Что может учитывать эти нюансы.

Я не разбираюсь в рассматриваемом методе Assert, но могу предположить, что предыдущий был устаревшим для такого рода проблем, и новый учитывает их.

Ответ 5

Обратите внимание: если вы не выполняете математику, нет ничего плохого в утверждении точных значений с плавающей запятой. Например:

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);

но это даст вам предупреждение об устаревании. Чтобы этого избежать, вы можете вызвать assertEquals(Object, Object) вместо:

// really you just need one cast because of autoboxing, but let be clear
assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);

И, если вы действительно хотите выглядеть умным:

assertEquals(
    Double.doubleToLongBits(Double.MIN_VALUE), 
    Double.doubleToLongBits(defaultValue)
);

Или вы можете просто использовать утверждения Hamcrest в свободном стиле:

// equivalent to assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
assertThat(defaultValue, is(Double.MIN_VALUE));

Если значение, которое вы проверяете, исходит от выполнения некоторой математики, однако, используйте epsilon.

Ответ 6

Epsilon - это разница между значениями expected и actual, которые вы можете принять, думая, что они равны. Вы можете установить .1, например.

Ответ 7

Нет необходимости включать epsilon или delta.

Assert.assertTrue("Not equals", expectedDouble -  actualDouble == 0);