IT TIP

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

itqueen 2020. 10. 16. 19:20
반응형

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


이 코드 :

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

보고 -2147483648

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


Integer.MIN_VALUE입니다 -2147483648만, 32 비트 정수가 포함 할 수있는 가장 높은 값이다 +2147483647. +214748364832 비트 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을 예로 들어 봅시다.

정수 값 -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 규칙에 대한이 항목을 참조하십시오 .


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

Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.


To see the result that you are expecting, cast Integer.MIN_VALUE to long:

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

2147483648 cannot be stored in an integer in java, its binary representation is the same as -2147483648.


But (int) 2147483648L == -2147483648 There is one negative number which has no positive equivalent so there is not positive value for it. You will see the same behaviour with Long.MAX_VALUE.

참고URL : https://stackoverflow.com/questions/5444611/math-abs-returns-wrong-value-for-integer-min-value

반응형