Цей код:
System.out.println(Math.abs(Integer.MIN_VALUE));
Повернення -2147483648
Чи не повинен він повертати абсолютне значення як 2147483648?
Цей код:
System.out.println(Math.abs(Integer.MIN_VALUE));
Повернення -2147483648
Чи не повинен він повертати абсолютне значення як 2147483648?
Відповіді:
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.
Відповідно до розділу 15.15.4 JLS , значення -xдорівнює (~x)+1, де ~- побітове операторне доповнення.
Щоб перевірити, чи правильно це звучить, візьмемо -1 як приклад.
Ціле значення -1може бути зазначене, як 0xFFFFFFFFу шістнадцятковій в Java (перевірте це за допомогою printlnбудь-якого іншого методу). Прийом -(-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з до 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.Ми можемо використовувати BigIntegers скрізь, оскільки 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 .
Щоб побачити результат, якого ви очікуєте, перейдіть 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)як виправлення, коли ви показали це як простий спосіб "побачити результат, який очікує запитувач". Вибачте.
Але (int) 2147483648L == -2147483648 є одне негативне число, яке не має позитивного еквівалента, тому для нього немає позитивного значення. Ви побачите таку ж поведінку з Long.MAX_VALUE.
У Java 15 це виправлено, це буде метод int і long. Вони будуть присутні на заняттях
java.lang.Math and java.lang.StrictMath
Методи.
public static int absExact(int a)
public static long absExact(long a)
Якщо ви пройдете
Integer.MIN_VALUE
АБО
Long.MIN_VALUE
Наведено виняток.
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до фрагмента?