Подтвердить что ты не робот

Тест для равенства с плавающей точкой. (FE_FLOATING_POINT_EQUALITY)

Я использую findbugs в ANT script, и я не могу понять, как исправить две мои ошибки. Я прочитал документацию, но не понимаю. Вот мои ошибки и код, который идет с ними:

Ошибка 1: проверка равенства с плавающей точкой. (FE_FLOATING_POINT_EQUALITY)

private boolean equals(final Quantity other) {
    return this.mAmount == convertedAmount(other);
}

Ошибка 2: EQ_COMPARETO_USE_OBJECT_EQUALS

public final int compareTo(final Object other) {
    return this.description().compareTo(((Decision) other).description());
}

Я прочитал документацию для проблемы ComparesTo, в которой указано

Настоятельно рекомендуется, но строго не требуется, чтобы (x.compareTo(y) == 0) == (x.equals(y)). Вообще говоря, любой класс, реализующий интерфейс Comparable и нарушающий это условие, должен четко указывать этот факт. Рекомендуемый язык: "Примечание: этот класс имеет естественный порядок, который несовместим с равными".

а также документы о равенстве с плавающей запятой

Эта операция сравнивает два значения с плавающей запятой для равенства. Поскольку вычисления с плавающей запятой могут включать округление, расчетные значения float и double могут быть неточными. Для значений, которые должны быть точными, например, денежные значения, следует использовать тип фиксированной точности, такой как BigDecimal. Для значений, которые не обязательно должны быть точными, рассмотрите сравнение для равенства в пределах некоторого диапазона, например: if (Math.abs(x - y) <.0000001). См. Спецификацию языка Java, раздел 4.2.4.

Я не понимаю. Кто-нибудь может помочь?

4b9b3361

Ответ 1

Проблема 1:

Для проблемы FE_FLOATING_POINT_EQUALITY вам не следует сравнивать два значения float непосредственно с оператором ==, поскольку из-за крошечных ошибок округления значения могут быть семантически "равны" для вашего приложения, даже если условие value1 == value2 не выполняется.

Чтобы исправить это, измените свой код следующим образом:

private boolean equals(final Quantity other) {
    return (Math.abs(this.mAmount - convertedAmount(other)) < EPSILON);
}

Где EPSILON - это константа, которую вы должны определить в своем коде, и представляет собой небольшие различия, приемлемые для вашего приложения, например. 0,0000001.

Проблема 2:

Для проблемы EQ_COMPARETO_USE_OBJECT_EQUALS: Настоятельно рекомендуется, чтобы везде, где x.compareTo(y) возвращает ноль, x.equals(y) должен быть true. В коде вы реализовали compareTo, но вы не переопределили equals, поэтому вы наследуете реализацию equals от Object, и указанное выше условие не выполняется.

Чтобы исправить это, переопределите equals (и, возможно, hashCode) в своем классе, так что, когда x.compareTo(y) возвращает 0, тогда x.equals(y) вернет true.

Ответ 2

Для предупреждения с плавающей точкой вы должны иметь в виду, что float - это неточный тип. Стандартная ссылка для этого (что, возможно, стоит прочитать один раз):

Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой Дэвида Голдберга.

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

Сопоставимый интерфейс ожидает определенного поведения его разработчиком; предупреждение говорит вам, что вы не придерживаетесь этого и предлагаете предлагаемые действия.

Ответ 3

Я не согласен с ответами выше. Равновесия и сравнение Неправильное место для внедрения эпсилонов в сравнении с плавающей точкой.

Значения с плавающей запятой можно сравнить точно с помощью equals и compareTo, просто используя оператор "==".
Если ваше приложение использует поплавки, которые являются результатом расчета, необходимо сравнить эти значения с эпсилонным подходом, он должен делать это только в том месте, где это необходимо. Например, в математическом методе пересечения линий.
Но не на равных и сравнивать.

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

static final double INVALID_VALUE = -99.0;
if (f == INVALID_VALUE)

где f инициализируется INVALID_VALUE, в java всегда будет работать отлично. Но findbugs и sonarcube по-прежнему будут жаловаться.

Поэтому просто добавьте фильтр игнорирования в findbugs, так как у вас есть два класса MyPoint2D и Myrectangle2D

<Match>
        <OR>
            <Class name="~.*\.MyPoint2D" />
            <Class name="~.*\.MyRectangle2D" />
        </OR>
        <Bug code="FE" />
        <Justification author="My Name" />
        <Justification
            text="Floating point equals works (here)." />
    </Match>