Java는 정수 언더 플로 및 오버플로를 어떻게 처리하며 어떻게 확인합니까?


226

Java는 정수 언더 플로우 및 오버 플로우를 어떻게 처리합니까?

그로부터 앞서서, 이것이 어떻게 발생하고 있는지 어떻게 확인 / 테스트하겠습니까?


28
C #에서 와 같이 Java가 CPU의 오버플로 플래그에 대한 간접 액세스를 제공하지 않는 것은 너무 나쁩니다 .
Drew Noakes

@ DrewNoakes 그리고 C #이 checked내가 아는 한 기본값이되지 않는 것은 너무 나쁩니다 . 나는 그것이 많이 사용되는 것을 보지 못하고 타이핑 checked { code; }은 메소드를 호출하는 것만 큼 많은 일입니다.
Maarten Bodewes

2
@MaartenBodewes, 어셈블리를 컴파일하는 동안 기본값으로 설정할 수 있습니다. csc /checked ...또는 Visual Studio의 프로젝트 속성 창에서 속성을 설정하십시오.
Drew Noakes

@DrewNoakes 좋아, 재미있다. 그래도 코드 외부의 설정이라는 것이 조금 이상합니다. 일반적으로 이러한 설정 (어설 션 제외)에 관계없이 프로그램의 동일한 동작을 원합니다.
Maarten Bodewes

@MaartenBodewes, 나는 추론에 사소한 성능 오버 헤드가 있다고 생각합니다. 따라서 다른 많은 종류의 어설 션과 마찬가지로 디버그 빌드에서 활성화 한 다음 릴리스 빌드에서 비활성화 할 수 있습니다.
Drew Noakes

답변:


217

오버플로가 발생하면 최소값 으로 돌아가서 계속 진행됩니다. 언더 플로가 발생하면 최대 값 으로 돌아가서 계속 진행합니다.

다음과 같이 미리 확인할 수 있습니다.

public static boolean willAdditionOverflow(int left, int right) {
    if (right < 0 && right != Integer.MIN_VALUE) {
        return willSubtractionOverflow(left, -right);
    } else {
        return (~(left ^ right) & (left ^ (left + right))) < 0;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    if (right < 0) {
        return willAdditionOverflow(left, -right);
    } else {
        return ((left ^ right) & (left ^ (left - right))) < 0;
    }
}

(당신은 대체 할 수 있습니다 int에 의해 long동일한 검사를 수행 long)

이 문제가 자주 발생한다고 생각되면 더 큰 값을 저장할 수있는 데이터 유형 또는 객체를 사용하는 것이 좋습니다 (예 : long또는) java.math.BigInteger. 마지막은 오버플로가 아니며 실제로 사용 가능한 JVM 메모리가 한계입니다.


이미 Java8에 될 일 경우에, 당신은 새로운 사용 할 수 있습니다 Math#addExact()Math#subtractExact()을 던질 것이다 방법 ArithmeticException오버 플로우에 있습니다.

public static boolean willAdditionOverflow(int left, int right) {
    try {
        Math.addExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

public static boolean willSubtractionOverflow(int left, int right) {
    try {
        Math.subtractExact(left, right);
        return false;
    } catch (ArithmeticException e) {
        return true;
    }
}

소스 코드는 여기여기에서 각각 찾을 수 있습니다 .

물론 boolean유틸리티 메소드 에 숨기지 않고 바로 사용할 수도 있습니다 .


13
@dhblah, Java가 int에 허용하는 최대 값과 최소값은 +100, -100각각 이라고 가정 해 봅시다 . Java 정수에 1을 추가하는 경우 프로세스가 오버플로되면 다음과 같이 표시됩니다. 98, 99, 100, -100, -99, -98, .... 더 이해가 되나요?
Austin A

6
코드를 즉시 사용하는 대신 유틸리티 메소드를 사용하는 것이 좋습니다. 유틸리티 메소드는 본질적이며 기계 별 코드로 대체됩니다. 빠른 테스트에서 Math.addExact가 복사 된 메소드 (Java 1.8.0_40)보다 30 % 빠릅니다.
TilmannZ

1
@ErikE Math#addExact는 javadocs를 작성할 때 일반적으로 사용되는 구문입니다. 일반적으로로 변환 Math.addExact되지만 때로는 다른 형식이 사용됩니다.
Pokechu22

1
If it underflows, it goes back to the maximum value and continues from there.-부정적인 오버플로로 언더 플로를 혼동 한 것 같습니다. 정수의 언더 플로는 항상 발생합니다 (결과가 분수 인 경우).
본당

1
en.wikipedia.org/wiki/Arithmetic_underflow에 따르면 언더 플로는 컴퓨터 프로그램의 조건으로 계산 결과가 컴퓨터의 실제 메모리에서 실제로 표현할 수있는 것보다 훨씬 작은 절대 값입니다. 따라서 언더 플로는 Java 정수에 적용되지 않습니다. @BalusC
Jingguo Yao

66

음, 원시 정수 유형에 이르기까지 Java는 Over / Underflow를 전혀 처리하지 않습니다 (float과 double의 동작이 다르면 IEEE-754 명령과 같이 +/- 무한대로 플러시됩니다).

두 개의 int를 추가하면 오버플로가 발생해도 표시되지 않습니다. 오버플로를 확인하는 간단한 방법은 다음으로 큰 유형을 사용하여 실제로 작업을 수행하고 결과가 여전히 소스 유형의 범위에 있는지 확인하는 것입니다.

public int addWithOverflowCheck(int a, int b) {
    // the cast of a is required, to make the + work with long precision,
    // if we just added (a + b) the addition would use int precision and
    // the result would be cast to long afterwards!
    long result = ((long) a) + b;
    if (result > Integer.MAX_VALUE) {
         throw new RuntimeException("Overflow occured");
    } else if (result < Integer.MIN_VALUE) {
         throw new RuntimeException("Underflow occured");
    }
    // at this point we can safely cast back to int, we checked before
    // that the value will be withing int's limits
    return (int) result;
}

throw 절 대신 수행 할 작업은 응용 프로그램 요구 사항에 따라 다릅니다 (던지기, 최소 / 최대로 플러시 또는 아무 것도 기록). 긴 작업에서 오버플로를 감지하려면 프리미티브를 사용하는 것이 좋지 않습니다. 대신 BigInteger를 사용하십시오.


편집 (2014-05-21) :이 질문은 자주 언급되는 것처럼 보이며 동일한 문제를 직접 해결해야했기 때문에 CPU가 V 플래그를 계산하는 것과 동일한 방법으로 오버플로 조건을 평가하기가 쉽습니다.

기본적으로 결과와 함께 두 피연산자의 부호를 포함하는 부울 표현식입니다.

/**
 * Add two int's with overflow detection (r = s + d)
 */
public static int add(final int s, final int d) throws ArithmeticException {
    int r = s + d;
    if (((s & d & ~r) | (~s & ~d & r)) < 0)
        throw new ArithmeticException("int overflow add(" + s + ", " + d + ")");    
    return r;
}

Java에서 표현식을 if의 전체 32 비트에 적용하고 <0을 사용하여 결과를 확인하는 것이 더 간단합니다 (이는 부호 비트를 효과적으로 테스트합니다). 원리는 모든 정수 기본 유형에 대해 정확히 동일하게 작동 하며 위의 메소드에서 모든 선언을 long으로 변경하면 오래 작동합니다.

더 작은 유형의 경우 int 로의 암시 적 변환으로 인해 (자세한 내용은 비트 단위 연산에 대해서는 JLS 참조) <0을 검사하는 대신 검사 비트를 명시 적으로 마스크해야합니다 (짧은 피연산자의 경우 0x8000, 바이트 피연산자의 경우 0x80, 캐스트 조정). 적절하게 매개 변수 선언) :

/**
 * Subtract two short's with overflow detection (r = d - s)
 */
public static short sub(final short d, final short s) throws ArithmeticException {
    int r = d - s;
    if ((((~s & d & ~r) | (s & ~d & r)) & 0x8000) != 0)
        throw new ArithmeticException("short overflow sub(" + s + ", " + d + ")");
    return (short) r;
}

(위의 예는 빼기 오버플로 감지에 필요한 표현을 사용합니다 )


그렇다면 이러한 부울 표현식은 어떻게 / 왜 작동합니까? 첫째, 일부 논리적 사고는 두 인수의 부호가 동일한 경우 에만 오버플로가 발생할 수 있음을 나타냅니다 . 하나의 인수가 음수이고 하나의 양수인 경우 추가의 결과 0에 가까워 지거나 극단적 인 경우 하나의 인수는 다른 인수와 같은 0이어야합니다. 스스로 인수가 있기 때문에 할 수없는 오버 플로우 조건을 만들고, 그 합은 하나 오버 플로우를 만들 수 없습니다.

두 인수 모두 같은 부호를 가지면 어떻게됩니까? MAX_VALUE 유형보다 더 큰 합계를 생성하는 두 개의 인수를 추가하면 항상 음수 값이 생성되므로 arg1 + arg2> MAX_VALUE 인 경우 오버플로가 발생합니다 . 이제 발생할 수있는 최대 값은 MAX_VALUE + MAX_VALUE입니다 (극단의 경우 두 인수 모두 MAX_VALUE). 127 + 127 = 254를 의미하는 바이트 (예)의 경우 두 개의 양수 값을 추가하여 발생할 수있는 모든 값의 비트 표현을 살펴보면 오버플로 된 (128-254) 비트가 모두 7로 설정되어 있음을 알 수 있습니다. 오버플로되지 않는 (0-127) 비트 7 (맨 위, 부호)이 지워졌습니다. 그것이 표현식의 첫 번째 (오른쪽) 부분이 정확히 확인하는 것입니다.

if (((s & d & ~r) | (~s & ~d & r)) < 0)

(~ s & ~ d & r)은 피연산자 (s, d) 모두 양수이고 결과 (r)가 음수 인 경우에만 적용됩니다 (표현식은 모든 32 비트에서 작동하지만 우리가 관심있는 유일한 비트는 가장 최상위 (부호) 비트이며 <0에 의해 검사됩니다).

이제 두 인수가 모두 음수이면 합계가 인수보다 0에 가까워 질 수 없으며, 합계 마이너스 무한대에 가까워 야합니다 . 우리가 생성 할 수있는 가장 극단적 인 값은 MIN_VALUE + MIN_VALUE이며, 바이트 예제의 경우 범위 값 (-1 ~ -128)에 대해 부호 비트가 설정되어 있지만 오버플로 값 (-129 ~ -256)이 표시됩니다 )의 부호 비트가 지워졌습니다. 따라서 결과의 부호는 다시 오버플로 조건을 나타냅니다. 왼쪽 절반 (s & d & ~ r)은 두 인수 (s, d)가 모두 음수이고 결과가 긍정적 인 경우를 확인합니다. 논리는 긍정적 인 경우와 거의 같습니다. 두 개의 음수 값을 추가하여 발생할 수있는 모든 비트 패턴 은 언더 플로가 발생한 경우에만 부호 비트가 지워집니다 .



1
이것은 작동하지만 성능이 좋지 않을 것이라고 가정합니다.
chessofnerd

33

기본적으로 Java의 int 및 long math는 오버플로 및 언더 플로를 자동으로 감 쌉니다. (다른 정수 유형에 대한 정수 연산은 먼저 JLS 4.2.2에 따라 피연산자를 int 또는 long으로 승격하여 수행됩니다 .)

자바 8, 현재로 java.lang.Math제공 addExact, subtractExact, multiplyExact, incrementExact, decrementExactnegateExactINT와 오버 플로우에 arithmeticexception이 던지는 명명 된 작업을 수행 긴 인수를 모두 정적 방법. (divideExact 메소드는 없습니다. 하나의 특별한 경우를 MIN_VALUE / -1직접 확인해야합니다 .)

Java 8부터 java.lang.Math는 toIntExactlong을 int로 캐스팅하여 long 값이 int에 맞지 않으면 ArithmeticException을 발생시킵니다. 이것은 예를 들어 확인되지 않은 긴 수학을 사용하여 정수의 합계를 계산 한 다음 toIntExact끝에 int로 캐스트하는 데 사용 하지만 유용합니다 (그러나 합계가 오버플로되지 않도록주의하십시오).

이전 버전의 Java를 계속 사용하는 경우 Google Guava는 확인 된 덧셈, 뺄셈, 곱셈 및 지수화 (오버플로 발생)를 위해 IntMath 및 LongMath 정적 메소드를 제공합니다 . 이 클래스는 또한 MAX_VALUE오버플로시 리턴 되는 계승 및 이항 계수를 계산하는 메소드를 제공합니다 (확인하기가 덜 편리함). 구아바의 원시 유틸리티 클래스는, SignedBytes, UnsignedBytes, ShortsInts제공 checkedCast큰 유형 (아래 / 오버 플로우에, IllegalArgumentException를 던지는 축소하는 방법 하지 않고 ArithmeticException를)뿐만 아니라 saturatingCast방법 돌려 MIN_VALUE또는 MAX_VALUE오버 플로우에 있습니다.


32

Java는 int 또는 long 기본 유형의 정수 오버플로로 아무것도하지 않으며 양수 및 음수로 오버플로를 무시합니다.

이 답변은 먼저 정수 오버플로에 대해 설명하고 식 평가의 중간 값으로도 어떻게 발생할 수 있는지에 대한 예를 제공 한 다음 정수 오버플로를 방지하고 감지하기위한 자세한 기술을 제공하는 리소스에 대한 링크를 제공합니다.

예기치 않은 또는 감지되지 않은 오버플로에서 발생하는 정수 산술 및 식은 일반적인 프로그래밍 오류입니다. 예기치 않거나 감지되지 않은 정수 오버플로는 특히 배열, 스택 및 목록 객체에 영향을 미치므로 잘 알려진 악용 가능한 보안 문제입니다.

양수 또는 음수 값이 해당 기본 유형의 최대 값 또는 최소값을 초과하는 양수 또는 음수 방향으로 오버플로가 발생할 수 있습니다. 오버플로는 식 또는 연산 평가 중 중간 값에서 발생할 수 있으며 최종 값이 범위 내에있을 것으로 예상되는 식 또는 연산의 결과에 영향을줍니다.

때때로 부정적인 오버플로는 언더 플로라고 잘못 부릅니다. 언더 플로는 표현이 허용하는 것보다 값이 0에 가까울 때 발생합니다. 언더 플로는 정수 산술로 발생하며 예상됩니다. 정수 언더 플로우는 정수 평가가 -1과 0 또는 0과 1 사이 일 때 발생합니다. 소수 결과는 0으로 잘립니다. 이는 정수 산술에서는 정상이며 오류로 간주되지 않습니다. 그러나 코드가 예외를 발생시킬 수 있습니다. 정수 언더 플로의 결과가 식의 제수로 사용되는 경우 "ArithmeticException : / by zero"예외가 그 예입니다.

다음 코드를 고려하십시오.

int bigValue = Integer.MAX_VALUE;
int x = bigValue * 2 / 5;
int y = bigValue / x;

x에 0이 할당되고 bigValue / x에 대한 후속 평가에서 y에 값 2가 할당되는 대신 "ArithmeticException : / by zero"(예 : 0으로 나눔) 예외가 발생합니다.

x에 대한 예상 결과는 858,993,458이며 최대 int 값 2,147,483,647보다 작습니다. 그러나 Integer.MAX_Value * 2 평가의 중간 결과는 최대 int 값을 초과하고 2의 보수 정수 표현에 따라 -2 인 4,294,967,294입니다. -2/5의 후속 평가는 0으로 평가되어 x에 할당됩니다.

x를 계산하기위한 표현식을 평가할 때 다음 코드를 곱하기 전에 나누는 표현식으로 재 배열합니다.

int bigValue = Integer.MAX_VALUE;
int x = bigValue / 5 * 2;
int y = bigValue / x;

x에 858,993,458이 할당되고 y에 2가 할당되어 예상됩니다.

bigValue / 5의 중간 결과는 429,496,729이며 int의 최대 값을 초과하지 않습니다. 429,496,729 * 2의 후속 평가는 int의 최대 값을 초과하지 않으며 예상 결과는 x에 할당됩니다. y에 대한 평가는 0으로 나누지 않습니다. x와 y에 대한 평가는 예상대로 작동합니다.

Java 정수 값은 2의 보수 부호있는 정수 표현에 따라 저장되고 동작합니다. 결과 값이 최대 또는 최소 정수 값보다 크거나 작을 경우 2의 보수 정수 값이 대신 발생합니다. 가장 일반적인 정수 산술 상황 인 2s 보수 동작을 사용하도록 명시 적으로 설계되지 않은 상황에서는 결과 2s 보수 값으로 인해 위의 예와 같이 프로그래밍 논리 또는 계산 오류가 발생합니다. 훌륭한 Wikipedia 기사에서 2의 칭찬 이진 정수에 대해 설명합니다 : 2의 보수-Wikipedia

의도하지 않은 정수 오버플로를 피하는 기술이 있습니다. Techinque는 사전 조건 테스트, 업 캐스팅 및 BigInteger를 사용하여 분류 될 수 있습니다.

사전 조건 테스트는 산술 연산 또는 표현식으로 들어가는 값을 검사하여 해당 값으로 오버플로가 발생하지 않는지 확인합니다. 프로그래밍과 디자인은 입력 값이 오버플로를 유발하지 않도록 테스트를 생성 한 다음 입력 값이 발생하면 오버플로를 유발할 조치를 결정해야합니다.

업 캐스팅은 더 큰 기본 유형을 사용하여 산술 연산 또는 표현식을 수행 한 다음 결과 값이 정수의 최대 값 또는 최소값을 초과하는지 여부를 판별합니다. 업 캐스팅을 수행하더라도 조작 또는 표현식의 값 또는 일부 중간 값이 업 캐스트 유형의 최대 값 또는 최소값을 초과하여 오버 플로우가 발생하여 오버 플로우가 발생할 수 있으며, 이는 감지되지 않으며 예기치 않은 원하지 않는 결과를 초래할 수 있습니다. 업 캐스팅없이 예방할 수 없거나 실용적이지 않은 경우 분석 또는 사전 조건을 통해 업 캐스팅으로 오버플로를 방지 할 수 있습니다. 해당 정수가 이미 긴 기본 유형 인 경우 Java의 기본 유형으로 업 캐스팅 할 수 없습니다.

BigInteger 기술은 BigInteger를 사용하는 라이브러리 메소드를 사용하여 산술 연산 또는 표현식에 BigInteger를 사용하는 것으로 구성됩니다. BigInteger가 오버 플로우되지 않습니다. 필요한 경우 사용 가능한 모든 메모리를 사용합니다. 산술 방법은 일반적으로 정수 연산보다 약간 덜 효율적입니다. BigInteger를 사용한 결과가 정수의 최대 값 또는 최소값을 초과 할 수 있지만 결과로 이어지는 산술에서는 오버 플로우가 발생하지 않습니다. 프로그래밍 및 디자인은 BigInteger 결과가 원하는 기본 결과 유형 (예 : int 또는 long)의 최대 값 또는 최소값을 초과하는 경우 수행 할 조치를 결정해야합니다.

Carnegie Mellon Software Engineering Institute의 CERT 프로그램과 Oracle은 안전한 Java 프로그래밍을위한 일련의 표준을 만들었습니다. 정수 오버플로를 방지하고 감지하는 기술이 표준에 포함되어 있습니다. 이 표준은 자유롭게 액세스 할 수있는 온라인 리소스로 게시됩니다. Java 용 CERT Oracle Secure Coding Standard

정수 오버플로 방지 또는 감지를위한 코딩 기술의 실제 예를 설명하고 포함하는 표준 섹션은 다음과 같습니다. NUM00-J. 정수 오버플로 감지 또는 방지

CERT Oracle Secure Coding Standard for Java의 서적 및 PDF 양식도 제공됩니다.


그것은 분명 언더 플로우가 무엇인지 상태로 이것이 가장 좋은 대답 여기 (허용 대답하지 않습니다)도 / 언더 오버 플로우를 처리하기위한 기술을 나열
본당

12

이 문제를 직접 해결 한 다음은 내 곱셈과 덧셈에 대한 해결책입니다.

static boolean wouldOverflowOccurwhenMultiplying(int a, int b) {
    // If either a or b are Integer.MIN_VALUE, then multiplying by anything other than 0 or 1 will result in overflow
    if (a == 0 || b == 0) {
        return false;
    } else if (a > 0 && b > 0) { // both positive, non zero
        return a > Integer.MAX_VALUE / b;
    } else if (b < 0 && a < 0) { // both negative, non zero
        return a < Integer.MAX_VALUE / b;
    } else { // exactly one of a,b is negative and one is positive, neither are zero
        if (b > 0) { // this last if statements protects against Integer.MIN_VALUE / -1, which in itself causes overflow.
            return a < Integer.MIN_VALUE / b;
        } else { // a > 0
            return b < Integer.MIN_VALUE / a;
        }
    }
}

boolean wouldOverflowOccurWhenAdding(int a, int b) {
    if (a > 0 && b > 0) {
        return a > Integer.MAX_VALUE - b;
    } else if (a < 0 && b < 0) {
        return a < Integer.MIN_VALUE - b;
    }
    return false;
}

잘못되었거나 단순화 될 수 있으면 자유롭게 수정하십시오. 나는 대부분의 경우에 곱셈 방법으로 테스트를했지만 여전히 잘못 될 수 있습니다.


곱셈에 비해 나눗셈이 느립니다. 에 대해 int*int, 나는 단순히 캐스팅 long하고 결과가 맞는지 보는 int것이 가장 빠른 접근법이라고 생각합니다. 의 경우 long*long, 피연산자를 양수로 정규화하는 경우 각각을 상위 및 하위 32 비트 반으로 나누고 각 반을 길게 늘리고 (부호 확장에주의하십시오) 두 부분 제품을 계산할 수 있습니다 [상위 절반 중 하나는 0이 되십시오].
supercat

"long * long의 경우 피연산자가 양수로 정규화되면 ..."라고 말하면 Long.MIN_VALUE를 정규화하는 방법은 무엇입니까?
fragorl

실제로 계산을 수행 하기 전에 오버플로가 발생하는지 테스트해야하는 경우 이러한 방법이 유용 할 수 있습니다 . 예를 들어 예외가 발생할 때 예외를 잡는 대신 그러한 계산에 사용되는 사용자 입력과 같은 테스트에 유용 할 수 있습니다.
Maarten Bodewes

8

정수 오버 플로우 / 언더 플로우를 검사하는 안전한 산술 연산을 제공하는 라이브러리가 있습니다. 예를 들어, Guava의 IntMath.checkedAdd (int a, int b) 는 오버플로되지 않은 경우 a및 의 합을 반환하고 부호있는 산술 에서 오버플로 bArithmeticException발생하면 throw 됩니다 .a + bint


Java 8 이상이 아닌 경우 Math클래스에 유사한 코드가 포함되어 있는 것이 좋습니다 .
Maarten Bodewes

6

그것은 감싸고 있습니다.

예 :

public class Test {

    public static void main(String[] args) {
        int i = Integer.MAX_VALUE;
        int j = Integer.MIN_VALUE;

        System.out.println(i+1);
        System.out.println(j-1);
    }
}

인쇄물

-2147483648
2147483647

잘! 그리고 이제 복잡한 미적분으로 어떻게 탐지 할 수 있습니까?
Aubin

5

나는 당신이 이와 같은 것을 사용해야한다고 생각하며 그것을 업 캐스팅이라고합니다.

public int multiplyBy2(int x) throws ArithmeticException {
    long result = 2 * (long) x;    
    if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE){
        throw new ArithmeticException("Integer overflow");
    }
    return (int) result;
}

여기에서 더 읽을 수 있습니다 : 정수 오버플로 감지 또는 방지

그것은 믿을만한 출처입니다.


3

언더 / 오버플로가 발생합니다.

오버플로 된 계산의 결과 인 "-1"은 다른 정보로 인한 "-1"과 다르지 않습니다. 따라서 어떤 상태를 통해 또는 오버플로 여부를 검사하여 알 수 없습니다.

그러나 오버플로를 피하기 위해 계산이 현명 할 수 있습니다. 당신의 상황은 어떻습니까?


그것은 실제로 상황이 아니며, 내가 궁금하고 생각하는 것입니다. 예제 사용 사례가 필요한 경우 여기에 하나가 있습니다. 'seconds'라는 자체 내부 변수가있는 클래스가 있습니다. 정수를 매개 변수로 사용하고 두 번째로 '초'를 늘리거나 줄이는 두 가지 방법이 있습니다. 언더 플로 / 오버플로가 발생하고 있는지 어떻게 유닛 테스트하고 어떻게 방지 할 수 있습니까?
KushalP

1
static final int safeAdd(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left + right;
}

static final int safeSubtract(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left < Integer.MIN_VALUE + right
                : left > Integer.MAX_VALUE + right) {
    throw new ArithmeticException("Integer overflow");
  }
  return left - right;
}

static final int safeMultiply(int left, int right)
                 throws ArithmeticException {
  if (right > 0 ? left > Integer.MAX_VALUE/right
                  || left < Integer.MIN_VALUE/right
                : (right < -1 ? left > Integer.MIN_VALUE/right
                                || left < Integer.MAX_VALUE/right
                              : right == -1
                                && left == Integer.MIN_VALUE) ) {
    throw new ArithmeticException("Integer overflow");
  }
  return left * right;
}

static final int safeDivide(int left, int right)
                 throws ArithmeticException {
  if ((left == Integer.MIN_VALUE) && (right == -1)) {
    throw new ArithmeticException("Integer overflow");
  }
  return left / right;
}

static final int safeNegate(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return -a;
}
static final int safeAbs(int a) throws ArithmeticException {
  if (a == Integer.MIN_VALUE) {
    throw new ArithmeticException("Integer overflow");
  }
  return Math.abs(a);
}

2
이것은 테스트를 처리합니다. Java가 정수 언더 플로 및 오버플로를 처리하는 방법을 설명하지는 않지만 설명 할 텍스트를 추가하십시오.
스펜서 Wieczorek

1

나는 이것이 괜찮을 것이라고 생각한다.

static boolean addWillOverFlow(int a, int b) {
    return (Integer.signum(a) == Integer.signum(b)) && 
            (Integer.signum(a) != Integer.signum(a+b)); 
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.