Этот код:
System.out.println(Math.abs(Integer.MIN_VALUE));
Возврат -2147483648
Должен ли он не возвращать абсолютное значение как 2147483648
?
java
absolute-value
user665319
источник
источник
Указанное вами поведение действительно противоречит интуиции. Однако это поведение указано в javadoc для
Math.abs(int)
:То есть
Math.abs(int)
должен вести себя как следующий код Java:public static int abs(int x){ if (x >= 0) { return x; } return -x; }
То есть в отрицательном случае
-x
.Согласно разделу 15.15.4 JLS ,
-x
равно(~x)+1
, где~
- оператор поразрядного дополнения.Чтобы проверить, правильно ли это звучит, возьмем -1 в качестве примера.
Целочисленное значение
-1
может быть записано как0xFFFFFFFF
шестнадцатеричное в Java (проверьте это с помощью aprintln
или любого другого метода).-(-1)
Таким образом, взятие дает:-(-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
s вlong
ранее. Однако мы должны либоint
s, что не работает, потому чтоInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
s, как-то надеясь, что мы никогда не будем вызывать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-документ для Math.abs () в javadoc :
источник
Чтобы увидеть ожидаемый результат, приведите
Integer.MIN_VALUE
кlong
:System.out.println(Math.abs((long) Integer.MIN_VALUE));
источник
Math.abs
который противоречитMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? Кроме того, поведение четко задокументировано в документации API.Math.abs(long)
. Приношу извинения за свою ошибку здесь: я думал, что вы предложили использоватьMath.abs(long)
в качестве исправления, когда вы показали это как простой способ «увидеть результат, которого ожидает спрашивающий». Сожалею.2147483648 не может быть сохранено в виде целого числа в java, его двоичное представление такое же, как -2147483648.
источник
Но
(int) 2147483648L == -2147483648
есть одно отрицательное число, которое не имеет положительного эквивалента, поэтому для него нет положительного значения. Вы увидите такое же поведение с Long.MAX_VALUE.источник
Есть исправление этого в Java 15 будет методом int и long. Они будут присутствовать на занятиях
Методы.
public static int absExact(int a) public static long absExact(long a)
Если вы пройдете
ИЛИ
Выдается исключение.
https://bugs.openjdk.java.net/browse/JDK-8241805
Я хотел бы увидеть, передается ли Long.MIN_VALUE или Integer.MIN_VALUE, будет возвращено положительное значение, а не исключение, но.
источник
Math.abs не всегда работает с большими числами. Я использую эту небольшую логику кода, которую я выучил, когда мне было 7 лет!
if(Num < 0){ Num = -(Num); }
источник
s
здесь?Num
равноInteger.MIN_VALUE
?