Сравнение чисел в Java - PullRequest
       22

Сравнение чисел в Java

19 голосов
/ 09 июля 2010

В Java все числовые типы начинаются с java.lang.Number.Было бы хорошей идеей иметь метод, подобный следующему:

public boolean areEqual(Number first, Number second) {
    if (first != null && second != null) {
        return first.equals(second);
    }
}

Я обеспокоен случаями, когда двойной 2.00000 не равен int 2. Они обрабатываются встроенным равным?Если нет, есть ли способ написать простую функцию сравнения чисел в Java?(внешние библиотеки, такие как Apache Commons, в порядке)

Ответы [ 7 ]

38 голосов
/ 09 июля 2010

A Double равно НИКОГДА equals до Integer.Более того, double - это не то же самое, что Double.

. Java имеет примитивные типы и ссылочные типы.По-настоящему числовые типы в Java не расширяются от Number, потому что они являются примитивами.

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

Смежные вопросы

Вкл. int против Integer:

Вкл. Number сравнение:

См. также


При вычислениях смешанного типа

Расчеты смешанного типа являются предметомне менее 4 головоломок в Java Puzzlers .

Вот различные выдержки:

как правило, лучше избегать смешанного типавычисления [...] потому что они по своей сути сбивают с толку [...] нигде это не проявляется так явно, как в условных выражениях.Сравнения смешанного типа всегда сбивают с толку, потому что система вынуждена преобразовывать один операнд в соответствие с типом другого.Преобразование невидимо и может не дать ожидаемых результатов

Предписание : Избегайте вычислений, которые смешивают целочисленные типы и типы с плавающей запятой.Предпочитайте целочисленную арифметику плавающей точке.

11 голосов
/ 27 февраля 2013

Я знаю, это старая тема, но .... Для сравнения двух чисел в Java вы можете использовать метод CompareTo из BigDecimal.BigDecimal может содержать все, от короткого до двойного или BigInteger, так что это идеальный класс для этого.

Так что вы можете попробовать написать что-то вроде этого:

public int compareTo(Number n1, Number n2) {
    // ignoring null handling
    BigDecimal b1 = new BigDecimal(n1.doubleValue());
    BigDecimal b2 = new BigDecimal(n2.doubleValue());
    return b1.compareTo(b2);
}

Это, безусловно, не самый лучшийподход к производительности.До сих пор работали следующие тесты, по крайней мере с JDK7:

assertTrue(compareTo(new Integer(1), new Integer(2)) == -1);
assertTrue(compareTo(new Integer(1), new Double(2.0)) == -1);
assertTrue(compareTo(new Integer(1), new Double(Double.MAX_VALUE)) == -1);
assertTrue(compareTo(new Integer(1), new Double(Double.MIN_VALUE)) == 1);
assertTrue(compareTo(new Integer(1), new Double(1.000001)) == -1);
assertTrue(compareTo(new Integer(1), new Double(1.000)) == 0);
assertTrue(compareTo(new Integer(1), new Double(0.25*4)) == 0);
assertTrue(compareTo(new Integer(1), new AtomicLong(1)) == 0);
6 голосов
/ 09 июля 2010

Конкретный метод, который вы предлагаете, потерпит неудачу, потому что он использует equals(), унаследованный от Object.То есть он проверял бы, были ли Number объекты одинаковыми, а не были ли их значения одинаковыми.

Если это былопросто иллюстративный пример, я обновлю свой ответ.

ответ полигена на самом деле в значительной степени покрывает основу, к которой я стремился.Вы также можете быть заинтересованы в этом вопросе: Почему java.lang.Number не реализует Comparable? .

4 голосов
/ 09 июля 2010

Если вы хотите узнать, совпадают ли ссылки на объекты, то существующие методы соответствуют требованиям.Double, представляющий 2.0, и Integer, представляющий 2, безусловно, являются разными объектами и, безусловно, не являются взаимозаменяемыми в общем смысле.

Если вы просто хотите узнать, совпадают ли числовые значенияВы можете использовать метод Number.doubleValue () , чтобы преобразовать оба числа в двойные, а затем сравнить эти числа вместе (возможно, с учетом небольшого допуска, поскольку большинство чисел представлены неточно, например 1.99999999996583 для того, что должнобудет 2, в зависимости от промежуточных этапов расчета).Примерно так:

private static final double EPSILON = 0.000000000000001d;    

public static boolean areEquivalentNumbers(Number a, Number b)
{
   if (a == null)
   {
      return b == null;
   }
   else if (b == null)
   {
      return false;
   }
   else
   {
      return Math.abs(a.doubleValue() - b.doubleValue()) < EPSILON;
   }
}
1 голос
/ 09 июля 2010

Относительно пары ответов, могу ли я предложить вместо того, чтобы написать что-то вроде:

boolean compare(Object o1, Object o2)
{
  if (o1==null)
    return o2==null;
  if (o2==null)
    return false;
  return o1.equals(o2);
}

Это гораздо более кратко, и я считаю, что немного более эффективно, написать:

boolean compare(Object o1, Object o2)
{
  return o1==o2 || o1!=null && o2!=null && o1.equals(o2);
}

Если оба значения равны нулю, o1 == o2 вернет true. Если это не так, но это один и тот же объект, это тоже хорошо.

Технически, o2! = Null не является необходимым для большинства реализаций equals, но если бы вы действительно были настолько универсальны, чтобы сделать это на объектах, как в приведенном выше примере, вы, конечно, не знали бы, как записывалось каждое переопределение .

1 голос
/ 09 июля 2010

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

public boolean areEqual(Number first, Number second) {
    if (first == null) {
        return second == null;
    }
    if (second == null) {
        return false;
    }

    return first.toString().equals(second.toString());
}
0 голосов
/ 09 июля 2010

вы не можете позвонить

number.equals(number2);

, потому что, если число равно Double, а число 2 является целым числом, они не будут принадлежать к одному классу, и вы получите исключение, сообщающее вам об этом факте.

Вы можете написать класс сравнения самостоятельно, который принимает объекты Number, но вам придется учитывать различные подклассы Number

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...