Реализуйте «толерантный» `equals` и` hashCode` для класса с членами с плавающей запятой

У меня есть класс с полем float . Например:

public class MultipleFields {
  final int   count;
  final float floatValue;

  public MultipleFields(int count, float floatValue) {
    this.count = count;
    this.floatValue = floatValue;
  }

}

Мне нужно иметь возможность сравнивать экземпляры по значению. Теперь, как мне правильно реализовать равно & hashCode ?

Обычный способ реализации equals и hashCode - это просто рассмотреть все поля. Например, Eclipse сгенерирует следующее равное :

  public boolean equals(Object obj) {
    // irrelevant type checks removed
    ....
    MultipleFields other = (MultipleFields) obj;
    if (count != other.count)
      return false;
    if (Float.floatToIntBits(floatValue) != Float.floatToIntBits(other.floatValue))
      return false;
    return true;
  }

(и аналогичный hashCode , который по сути вычисляет count * 31 + Float.floatToIntBits (floatValue) ).

Проблема в том, что мои значения FP подвержены ошибкам округления (они могут поступать из-за ввода пользователем, из БД и т. Д.). Поэтому мне нужно «терпимое» сравнение.

Обычное решение - сравнивать с использованием значения epsilon (см., Например, Сравнение IEEE float и double на равенство ). Однако я не совсем уверен, как я могу реализовать равняется с помощью этого метода и при этом иметь хэш-код , который согласуется с равным .

Моя идея состоит в том, чтобы определить количество значащих цифр для сравнения, а затем всегда округлять до этого количества цифр в обоих равных и hashCode :

long comparisonFloatValue = Math.round(floatValue* (Math.pow(10, RELEVANT_DIGITS)));

Затем, если я заменю все использование floatValue с compareFloatValue в равно и hashCode , я должен получить "терпимое" сравнение, которое согласуется с hashCode .

  • Будет ли это работать?
  • Вы видите какие-либо проблемы с этим подходом?
  • Есть ли лучший способ сделать это? Это кажется довольно сложным.

10
задан Community 23 May 2017 в 10:27
поделиться