2012-06-13 2 views
15

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

+25

И причины не желая использовать этот метод ... – Thilo

+0

ли число определяется как интегральный типа, INT, байты, короткие, длинное или это плавающая точка (float, double) или класс бокса (Integer, Double, ...) или BigDecimal, BigInteger или что-то еще? Неопределенные? –

+0

Мне нужно использовать его в цикле. Поэтому я ищу любой другой подход. – Theja

ответ

49

Если вы посмотрите внутрь 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; 
    } 
13

Как это:

if (number < 0) { 
    number *= -1; 
} 
+0

Я знаю тест, где это не удается. –

+0

@userunknown вы имеете в виду MIN_VALUE? – tibtof

+0

Да, конечно. –

19

Да:

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

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

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

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

+0

Хороший вопрос о плавающих точках. Это не так уж плохо, однако, вот источник для двойного абс из java.lang.Math: 'return (a <= 0.0D)? 0.0D - a: a; 'и версия с плавающей точкой выглядит аналогично. – Thilo

+0

@Thilo: Реальная точка здесь в том, что математика с плавающей запятой полна тонкостей. Если в действительности нет убедительного аргумента, нужно просто придерживаться стандартных функций. – NPE

+0

Нет конкурса там ...:-) – Thilo

0

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

abs_num = (num < 0) ? -num : num; 
0

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

abs_number = (num < 0) ? -num : num; 
5

Поскольку Java является статически типизированным языком, я бы ожидал, что абс-метод, который принимает int, возвращает int, если он ожидает, что float вернет float, для Double вернет Double. Возможно, он может всегда возвращать коробку или распакованный тип для парных и парных разрядов и так далее.

Так что вам нужен один метод для каждого типа, но теперь у вас есть новая проблема: для байта 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)); 
} 

Я ловлю первое исключение и дайте ему поработать в секунду, просто для демонстрации.

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


Если вам интересно, почему есть еще один отрицательный, чем положительное значение, у меня есть diagram for you.

0

-число будет равна NUM для Integer.MIN_VALUE в

Integer.MIN_VALUE = Integer.MIN_VALUE * -1 
2

Используйте класс Math

Math.abs(num); 
+6

Вопрос конкретно говорит «без использования Math.abs()». – Kenster

2

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

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

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

+0

Да, это отлично, если вы хотите запутать ад из многих людей, особенно если вы назовете функцию a() или что-то подобное смутное – sloven

0

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

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

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

Опять x = Integer.MIN_VALUE приведет к переполнению в результате вычитания 1.