Нахождение абсолютного значения числа без использования Math.abs()

Есть ли способ найти абсолютное значение числа без использования метода Math.abs() в java.


person Theja    schedule 13.06.2012    source источник
comment
И причина нежелания использовать этот метод...   -  person Thilo    schedule 13.06.2012
comment
Указано ли число как целочисленный тип, int, byte, short, long или это число с плавающей запятой (float, double) или класс упаковки (Integer, Double,...) или BigDecimal, BigInteger или что-то еще? Неопределенные?   -  person user unknown    schedule 13.06.2012
comment
Мне нужно использовать его в цикле. Поэтому я ищу любой другой лучший подход.   -  person Theja    schedule 14.06.2012
comment
вы можете использовать Math.abs в цикле. Не делайте микрооптимизацию. JVM обычно делает это достаточно быстро. Если вы действительно думаете, что это слишком медленно, измерьте его.   -  person Thilo    schedule 14.06.2012
comment
@Thilo, я проверил. работает хорошо, я пытаюсь найти разные подходы, чтобы использовать лучший подход в соответствии со своими потребностями.   -  person Theja    schedule 14.06.2012


Ответы (10)


Если вы заглянете внутрь Math.abs, вы, вероятно, найдете лучший ответ:

Например, для поплавков:

    /*
     * Returns the absolute value of a {@code float} value.
     * If the argument is not negative, the argument is returned.
     * If the argument is negative, the negation of the argument is returned.
     * Special cases:
     * <ul><li>If the argument is positive zero or negative zero, the
     * result is positive zero.
     * <li>If the argument is infinite, the result is positive infinity.
     * <li>If the argument is NaN, the result is NaN.</ul>
     * In other words, the result is the same as the value of the expression:
     * <p>{@code Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))}
     *
     * @param   a   the argument whose absolute value is to be determined
     * @return  the absolute value of the argument.
     */
    public static float abs(float a) {
        return (a <= 0.0F) ? 0.0F - a : a;
    }
person mihaisimi    schedule 13.06.2012

Да:

abs_number = (number < 0) ? -number : number;

Для целых чисел это работает нормально (за исключением Integer.MIN_VALUE, абсолютное значение которого не может быть представлено как int).

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

Чтобы не разбираться с такими тонкостями самостоятельно, я бы посоветовал придерживаться Math.abs().

person NPE    schedule 13.06.2012
comment
Хороший вопрос о плавающих точках. Это не так уж и плохо, вот источник двойного пресса из java.lang.Math: return (a <= 0.0D) ? 0.0D - a : a; и версия с плавающей запятой выглядит аналогично. - person Thilo; 13.06.2012
comment
@Thilo: Суть здесь в том, что математика с плавающей запятой полна тонкостей. Если нет действительно убедительных аргументов против, следует просто придерживаться стандартных функций. - person NPE; 13.06.2012
comment
Я знаю тестовый пример, в котором это не работает для Int, Long, Byte и Short. - person user unknown; 13.06.2012
comment
@userunknown: Конечно, но это свойство представления целых чисел в виде дополнения до двух, а не метода вычисления abs(). - person NPE; 13.06.2012
comment
@aix: ? Так это повод его игнорировать? 2-дополнение виновато? - person user unknown; 13.06.2012
comment
@userunknown: Если вы читаете вопрос, ОП пытается эмулировать Math.abs(). Код в моем ответе ведет себя точно как Math.abs(int) для Integer.MIN_VALUE. - person NPE; 13.06.2012
comment
@aix: Может быть, вы посетите нас в чате?? Я не читаю «подражать Math.abs» — я читаю без использования Math.abs. И я бы сказал, что метод в Javalibs не работает по этой конкретной причине. - person user unknown; 13.06.2012
comment
@userunknown: Спасибо за приглашение, но этот вопрос просто недостаточно важен для меня лично, чтобы оправдать затраты времени на его дальнейшее обсуждение. - person NPE; 13.06.2012
comment
Правильный код всегда должен быть важен - я думаю, вы не даете лучший пример новичку. :) Прятаться за авторитетом java.lang.Math.abs тоже нехорошо, имхо. Но я не могу заставить тебя. - person user unknown; 13.06.2012

Как это:

if (number < 0) {
    number *= -1;
}
person tibtof    schedule 13.06.2012
comment
Я знаю тестовый пример, где это не удается. - person user unknown; 13.06.2012
comment
@userunknown вы имеете в виду MIN_VALUE? - person tibtof; 13.06.2012
comment
@userunknown Положительное значение MIN_VALUE не может содержаться в данных того же типа, поэтому это не поток. Посмотрите здесь: en.wikipedia.org/wiki/Two%27s_complement - person tibtof; 13.06.2012
comment
давайте продолжим это обсуждение в чате - person user unknown; 13.06.2012

Поскольку Java является статически типизированным языком, я ожидаю, что метод abs, который принимает целое число, возвращает целое число, если он ожидает, что число с плавающей запятой возвращает число с плавающей запятой, для двойного значения возвращается двойное число. Может быть, он мог бы всегда возвращать упакованный или неупакованный тип для двойных и двойных и так далее.

Таким образом, вам нужен один метод для каждого типа, но теперь у вас есть новая проблема: для byte, short, int, long диапазон для отрицательных значений на 1 больше, чем для положительных значений.

Итак, что должно быть возвращено для метода

byte abs (byte in) {
   // @todo
}

Если пользователь вызывает абс на -128? Вы всегда можете вернуть следующий больший тип, чтобы диапазон гарантированно соответствовал всем возможным входным значениям. Это приведет к проблемам на долгое время, когда не существует нормального большего типа, и заставит пользователя всегда отбрасывать значение после тестирования - может быть, хлопотно.

Второй вариант — выдать арифметическое исключение. Это предотвратит приведение и проверку возвращаемого типа в ситуациях, когда известно, что ввод ограничен, например, X.MIN_VALUE не может произойти. Подумайте о MONTH, представленном как int.

byte abs (byte in) throws ArithmeticException {
   if (in == Byte.MIN_VALUE) throw new ArithmeticException ("abs called on Byte.MIN_VALUE"); 
   return (in < 0) ? (byte) -in : in; 
}

Привычка "давайте игнорировать редкие случаи MIN_VALUE" не вариант. Сначала заставьте код работать, а затем сделайте его быстрым. Если пользователю нужно более быстрое, но глючное решение, он должен написать его сам. Самое простое решение, которое может сработать, означает: простое, но не слишком простое.

Поскольку код не зависит от состояния, метод можно и нужно сделать статическим. Это позволяет быстро проверить:

public static void main (String args []) {
    System.out.println (abs(new Byte ( "7")));
    System.out.println (abs(new Byte ("-7")));
    System.out.println (abs((byte)  7));
    System.out.println (abs((byte) -7));
    System.out.println (abs(new Byte ( "127")));
    try
    {
        System.out.println (abs(new Byte ("-128")));
    }
    catch (ArithmeticException ae)
    {
        System.out.println ("Integer: " + Math.abs (new Integer ("-128")));
    }
    System.out.println (abs((byte)  127));
    System.out.println (abs((byte) -128));
}

Я перехватываю первое исключение и пропускаю его во второе просто для демонстрации.

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


Если вам интересно, почему отрицательное значение больше, чем положительное, у меня есть для вас диаграмма.

person user unknown    schedule 13.06.2012

Хотя это не должно быть узким местом, поскольку проблемы ветвления на современных процессорах обычно не являются проблемой, но в случае с целыми числами вы можете выбрать решение без ветвлений, как описано здесь: http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs.

(x + (x >> 31)) ^ (x >> 31);

Однако это не удается в очевидном случае Integer.MIN_VALUE, поэтому это решение используется на ваш страх и риск.

person Joe C    schedule 01.04.2016
comment
Да, это отлично, если вы хотите сбить с толку многих людей, особенно если вы называете функцию a() или что-то подобное расплывчатое. - person niken; 20.06.2016

В случае абсолютного значения целого числа x без использования Math.abs(), условий или побитовых операций ниже может быть возможное решение в Java.

(int)(((long)x*x - 1)%(double)x + 1);

Поскольку Java обрабатывает a%b как a - a/b * b, знак результата будет таким же, как «a», независимо от того, какой знак у «b»; (x*x-1)%x будет равно abs(x)-1; приведение типа "long" предотвращает переполнение, а double позволяет делить на ноль.

Опять же, x = Integer.MIN_VALUE вызовет переполнение из-за вычитания 1.

person Young    schedule 31.08.2017

Вы можете использовать :

abs_num = (num < 0) ? -num : num;
person CP Soni    schedule 13.06.2012

Вот однострочное решение, которое вернет абсолютное значение числа:

abs_number = (num < 0) ? -num : num;
person chaitu    schedule 13.06.2012

-num будет равно num для Integer.MIN_VALUE как

 Integer.MIN_VALUE =  Integer.MIN_VALUE * -1
person ouertani    schedule 07.08.2014

Используйте класс Математика

Math.abs(num);
person Victor Urrutia    schedule 19.08.2014
comment
В вопросе конкретно говорится без использования Math.abs(). - person Kenster; 19.08.2014