Математика.ABS возвращает неверное значение для целого числа.Минимальное значение



этот код:



System.out.println(Math.abs(Integer.MIN_VALUE));


возвращает -2147483648



если он не возвращает абсолютное значение как 2147483648 ?

623   6  

6 ответов:

Integer.MIN_VALUE и -2147483648, но самое высокое значение 32-разрядного целого числа может содержать +2147483647. Попытка представить +2147483648 в 32-битном int будет эффективно "перевернуться" до -2147483648. Это связано с тем, что при использовании целых чисел со знаком они дополняют двоичные представления +2147483648 и -2147483648 идентичны. Это не проблема, однако, как +2147483648 считается вне диапазона.

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

поведение, на которое вы указываете, действительно, противоречит интуиции. Однако это поведение определяется javadoc для Math.abs(int):

если аргумент не отрицательный, аргумент возвращается. Если аргумент отрицательный, возвращается отрицание аргумента.

то есть Math.abs(int) должен вести себя как следующий код Java:

public static int abs(int x){
    if (x >= 0) {
        return x;
    }
    return -x;
}

то есть, в отрицательном случае, -x.

по словам JLS раздел 15.15.4 на -x равна (~x)+1, где ~ является побитовым оператором дополнения.

чтобы проверить, правильно ли это звучит, давайте возьмем -1 в качестве примера.

целочисленное значение -1 можно отметить как 0xFFFFFFFF в шестнадцатеричном формате на Java (проверьте это с помощью println или любой другой способ). Принимая выдает:

-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1

так, это завод.

давайте попробуем сейчас с Integer.MIN_VALUE . Зная, что наименьшее целое число может быть представлено 0x80000000, то есть, первый бит установлен в 1, а остальные 31 бит установлен в 0, то есть:

-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 
                     = 0x80000000 = Integer.MIN_VALUE

и поэтому Math.abs(Integer.MIN_VALUE) возвращает Integer.MIN_VALUE. Также обратите внимание, что 0x7FFFFFFF и Integer.MAX_VALUE.

что сказал, как можно избежать проблем из-за этого контр-интуитивно понятный возвращаемое значение в будущем?

  • мы могли бы, как указал @Bombe, закидываем intь long раньше. Мы, однако, должны либо

    • бросил их обратно в ints, который не работает, потому что Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).
    • с longS как-то надеется, что мы никогда не будем звонить Math.abs(long) со значением, равным Long.MIN_VALUE, так как у нас тоже есть Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
  • можно использовать BigInteger s везде, потому что BigInteger.abs() действительно всегда возвращает положительное значение. Это хорошая альтернатива, жесткая немного медленнее, чем манипулирование необработанными целочисленными типами.

  • мы можем написать нашу собственную оболочку для Math.abs(int), например:

/**
 * Fail-fast wrapper for {@link Math#abs(int)}
 * @param x
 * @return the absolute value of x
 * @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
 */
public static int abs(int x) throws ArithmeticException {
    if (x == Integer.MIN_VALUE) {
        // fail instead of returning Integer.MAX_VALUE
        // to prevent the occurrence of incorrect results in later computations
        throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
    }
    return Math.abs(x);
}
  • используйте целое побитовое число и очистите старший бит, гарантируя, что результат неотрицателен:int positive = value & Integer.MAX_VALUE (по существу переполнение от Integer.MAX_VALUE до 0 вместо Integer.MIN_VALUE)

как финал обратите внимание, что эта проблема, похоже, известна в течение некоторого времени. См., например,эта запись о соответствующем правиле findbugs.

вот что говорит Java doc для математики.abs () in документация:

обратите внимание, что если аргумент равен значение Integer.MIN_VALUE, the большинство негативных представимое значение типа int , в результате получается то самое значение, которое отрицательный.

чтобы увидеть результат, который вы ожидаете, бросьте Integer.MIN_VALUE to long:

System.out.println(Math.abs((long) Integer.MIN_VALUE));

2147483648 не может быть сохранен в виде целого числа в java, его двоичное представление совпадает с -2147483648.

но (int) 2147483648L == -2147483648 существует одно отрицательное число, которое не имеет положительного эквивалента, поэтому для него нет положительного значения. Вы увидите то же самое поведение с лонгом.МАКСИМАЛЬНОЕ ЗНАЧЕНИЕ.

Comments

    Ничего не найдено.