Значение аргумента эпсилон assertEquals для двойных значений - PullRequest
178 голосов
/ 16 апреля 2011

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

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

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

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

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

Ответы [ 7 ]

188 голосов
/ 16 апреля 2011

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

114 голосов
/ 05 декабря 2011

Какая версия JUnit?Я только когда-либо видел дельту, а не эпсилон - но это побочная проблема!

Из JUnit javadoc :

дельта - максимальная дельта между ожидаемымии фактически, для которых оба числа по-прежнему считаются равными.

Вероятно, это излишне, но я обычно использую действительно небольшое число, например

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

К вашему сведению, JUnit 5 также будет сделать дельту необязательной при вызове assertEquals() с двумя двойными числами.Реализация (если вам интересно):

private static boolean doublesAreEqual(double value1, double value2) {
    return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2);
}
55 голосов
/ 16 апреля 2011

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

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

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

11 голосов
/ 16 апреля 2011

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

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

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

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

Или

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

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

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

2 голосов
/ 01 мая 2013

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

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

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

1 голос
/ 16 апреля 2011

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

0 голосов
/ 07 июня 2018
Assert.assertTrue(Math.abs(actual-expected) == 0)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...