이 코드 :
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
. 부호있는 정수를 사용하는 경우, 2 개의이 바이너리 표현을 보완하기 때문이다 +2147483648
과 -2147483648
동일하다. 그러나 +2147483648
범위를 벗어난 것으로 간주 되므로 문제가되지 않습니다 .
이 문제에 대해 조금 더 읽으려면 Two'scomplement에 대한 Wikipedia 기사 를 확인하십시오 .
당신이 지적하는 행동은 실제로 반 직관적입니다. 그러나이 동작은 다음에 대해 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에서 16 진수 로 표시 할 수 있습니다 ( 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
전에. 그러나 우리는
int
s
로 다시 캐스팅하면 Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
의 어떻게 든 우리가 호출하지 않을거야 바라고 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 규칙에 대한이 항목을 참조하십시오 .
예상 한 결과를 보려면 다음으로 캐스트 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)
. "요청자가 기대하는 결과를 볼"수있는 간단한 방법으로 보여 주셨을 때, 당신이 픽스로 의 사용을 제안했다고 강인했습니다. 죄송합니다.
이것에 대한 수정이 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가 전달되는지 확인하고 싶습니다. 양수 값은 예외가 아니라 반환됩니다.