Math.abs가 Integer.Min_VALUE에 대해 잘못된 값을 반환합니다.


90

이 코드 :

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

보고 -2147483648

절대 값을 다음과 같이 반환하지 않아야 2147483648합니까?

답변:


102

Integer.MIN_VALUE입니다 -2147483648만, 32 비트 정수가 포함 할 수있는 가장 높은 값이다 +2147483647. +214748364832 비트 int 로 표현하려고 하면 효과적으로 "롤오버"됩니다 -2147483648. 부호있는 정수를 사용하는 경우, 2 개의이 바이너리 표현을 보완하기 때문이다 +2147483648-2147483648동일하다. 그러나 +2147483648범위를 벗어난 것으로 간주 되므로 문제가되지 않습니다 .

이 문제에 대해 조금 더 읽으려면 Two'scomplement에 대한 Wikipedia 기사 를 확인하십시오 .


6
글쎄요, 문제는 그 영향을 과소 평가하는 것이 아니라 문제를 의미 할 수 있습니다. 개인적으로 나는 더 높은 수준의 언어에서 동적으로 성장하는 예외 또는 숫자 체계를 원합니다.
Maarten Bodewes

40

당신이 지적하는 행동은 실제로 반 직관적입니다. 그러나이 동작은 다음에 대해 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을 예로 들어 봅시다.

정수 값 -10xFFFFFFFFJava에서 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전에. 그러나 우리는

    • ints 로 다시 캐스팅하면 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.
  • 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);
}
  • 정수 비트 AND를 사용하여 상위 비트를 지우고 결과가 음수가 아닌지 확인합니다. int positive = value & Integer.MAX_VALUE(본질적 Integer.MAX_VALUE으로 0대신 에서 ~ 까지 오버플 로 됨 Integer.MIN_VALUE)

마지막으로이 문제는 한동안 알려진 것으로 보입니다. 예를 들어 해당 findbugs 규칙에 대한이 항목을 참조하십시오 .


12

다음은 javadoc의 Math.abs ()에 대한 Java 문서의 내용입니다 .

인수가 가장 음의 표현 가능한 int 값인 Integer.MIN_VALUE의 값과 같으면 결과는 동일한 값인 음수입니다.


4

예상 한 결과를 보려면 다음으로 캐스트 Integer.MIN_VALUE하십시오 long.

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

1
실제로 가능한 수정! 그러나,이 사실은 해결되지 않습니다 Math.abs: 음의 번호를 반환하여 직관적 인입니다Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
버나드 폴 러스

1
@bernardpaulus, 음, 던지는 것 외에 무엇을해야 ArithmeticException합니까? 또한 동작은 API 문서에 명확하게 문서화되어 있습니다.
Bombe 2013-06-21

귀하의 질문에 대한 좋은 답변이 없습니다 ... 버그의 원인이되는이 동작이을 사용하여 수정되지 않는다는 점을 지적하고 싶습니다 Math.abs(long). 여기서 제 실수에 대해 사과드립니다 Math.abs(long). "요청자가 기대하는 결과를 볼"수있는 간단한 방법으로 보여 주셨을 때, 당신이 픽스로 의 사용을 제안했다고 강인했습니다. 죄송합니다.
bernard paulus

실제로 새 메소드가있는 Java 15에서는 예외가 발생합니다.
chiperortiz

1

2147483648은 Java의 정수로 저장할 수 없으며 이진 표현은 -2147483648과 동일합니다.


0

그러나 (int) 2147483648L == -2147483648 양수 등가물이없는 음수가 하나 있으므로 양수 값이 없습니다. Long.MAX_VALUE에서도 동일한 동작을 볼 수 있습니다.


0

이것에 대한 수정이 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가 전달되는지 확인하고 싶습니다. 양수 값은 예외가 아니라 반환됩니다.


-1

Math.abs는 큰 숫자로 항상 작동하지 않습니다. 저는 7 살 때 배운이 작은 코드 논리를 사용합니다!

if(Num < 0){
  Num = -(Num);
} 

여기는 무엇입니까 s?
aioobe

원래 코드에서 업데이트하는 것을 잊었 어 죄송합니다
Dave

스 니펫 앞에서 Num같으면 결과는 무엇 Integer.MIN_VALUE입니까?
aioobe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.