programing

Java에서 두 숫자를 곱하면 오버플로가 발생하는지 어떻게 확인할 수 있습니까?

shortcode 2022. 9. 13. 22:24
반응형

Java에서 두 숫자를 곱하면 오버플로가 발생하는지 어떻게 확인할 수 있습니까?

두 숫자를 곱하면 오버플로가 발생하는 특별한 경우를 다루고 싶습니다.코드는 다음과 같습니다.

int a = 20;
long b = 30;

// if a or b are big enough, this result will silently overflow
long c = a * b;

단순화된 버전입니다. 프로그램 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★」a ★★★★★★★★★★★★★★★★★」b는 런타임에 다른 곳에서 발신됩니다.제가 이루고 싶은 것은 다음과 같습니다.

long c;
if (a * b will overflow) {
    c = Long.MAX_VALUE;
} else {
    c = a * b;
}

이걸 어떻게 코드화하면 좋을까요?

데트트 update:a ★★★★★★★★★★★★★★★★★」b제 시나리오에서는 항상 부정적이지 않습니다.

에는 Java 8이 탑재되어 있습니다.Math.multiplyExact,Math.addExact및 long long의 경우 등입니다은 체크되지 않은 것을 .ArithmeticException넘쳐서

ifa ★★★★★★★★★★★★★★★★★」b 다 과 같이쓸 수 .

if (a != 0 && b > Long.MAX_VALUE / a) {
    // Overflow
}

양수와 음수를 모두 처리해야 하는 경우에는 더 복잡합니다.

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if (a != 0 && (b > 0 && b > maximum / a ||
               b < 0 && b < maximum / a))
{
    // Overflow
}

아래는 오버플로가 -10 또는 +10에서 발생하는 것처럼 보이게 하기 위해 작성한 작은 테이블입니다.

a =  5   b =  2     2 >  10 /  5
a =  2   b =  5     5 >  10 /  2
a = -5   b =  2     2 > -10 / -5
a = -2   b =  5     5 > -10 / -2
a =  5   b = -2    -2 < -10 /  5
a =  2   b = -5    -5 < -10 /  2
a = -5   b = -2    -2 <  10 / -5
a = -2   b = -5    -5 <  10 / -2

긴 오버플로/언더플로우를 체크하는 안전한 산술 연산을 제공하는 Java 라이브러리가 있습니다.예를 들어, Guava의 LongMath.checkedMultiply(긴 a, b)는 다음 곱을 반환합니다.a ★★★★★★★★★★★★★★★★★」b한, 「 않는다」, 「넘치다」를 던집니다ArithmeticExceptiona * b된 「」의 long★★★★★★ 。

java.math를 사용할 수 있습니다.대신 BigInteger를 사용하여 결과 크기를 확인합니다(코드 테스트 없음).

BigInteger bigC = BigInteger.valueOf(a) * multiply(BigInteger.valueOf(b));
if(bigC.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
  c = Long.MAX_VALUE;
} else {
  c = bigC.longValue()
}

대수를 사용하여 결과의 크기를 확인합니다.

여기 내가 생각할 수 있는 가장 간단한 방법이 있다.

int a = 20;
long b = 30;
long c = a * b;

if(c / b == a) {
   // Everything fine.....no overflow
} else {
   // Overflow case, because in case of overflow "c/b" can't equal "a"
}

자바에는 int 같은 것이 있나요?최대값?만약 그렇다면, 시도해 보세요.

if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))
{
 // it will overflow
}

편집: 길게 표시됨.문제의 MAX_VALUE

jruby에서 도난당했습니다.

    long result = a * b;
    if (a != 0 && result / a != b) {
       // overflow
    }

업데이트: 이 코드는 짧고 잘 작동하지만 a = -1, b = 긴 경우 실패합니다.최소값

한 가지 기능 강화:

long result = a * b;
if( (Math.signum(a) * Math.signum(b) != Math.signum(result)) || 
    (a != 0L && result / a != b)) {
    // overflow
}

분할하지 않고 오버플로우를 포착하는 것에 주의해 주십시오.

앞서 설명한 바와 같이 Java 8에는 Math.xxxExact 메서드가 있어 오버플로우 시 예외를 발생시킵니다.

프로젝트에 Java 8을 사용하지 않는 경우에도 매우 콤팩트한 구현을 "빌려" 사용할 수 있습니다.

코드 저장소에에 대한 몇 가지 구현이 되지 않지만, 하여 JDK 내에서 할 수 . 이러한 구현이 유효한지 여부는 보증할 수 없지만, 어떤 경우에도 JDK 소스를 다운로드하여 어떻게 기능하는지 확인할 수 있어야 합니다.java.lang.Math를 누릅니다

Math.multiplyExact(long, long) http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Math.java#l925

Math.addExact(long, long) http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Math.java#l830

기타 등

업데이트: 서드파티 웹 사이트에 대한 비활성 링크를 Open JDK의 Mercurial 저장소에 대한 링크로 전환했습니다.

왜 아무도 다음과 같은 솔루션을 검토하지 않는지 잘 모르겠습니다.

if (Long.MAX_VALUE/a > b) {
     // overflows
} 

두 숫자 중 a를 더 크게 선택합니다.

존 쿠겔만의 답변을 직접 편집하여 대체하지 않고 기반으로 하고 싶습니다.테스트 케이스에 유효합니다(MIN_VALUE = -10,MAX_VALUE = 10)의 대칭성 때문에MIN_VALUE == -MAX_VALUE2의 보완정수에는 해당되지 않습니다.사실,MIN_VALUE == -MAX_VALUE - 1.

scala> (java.lang.Integer.MIN_VALUE, java.lang.Integer.MAX_VALUE)
res0: (Int, Int) = (-2147483648,2147483647)

scala> (java.lang.Long.MIN_VALUE, java.lang.Long.MAX_VALUE)
res1: (Long, Long) = (-9223372036854775808,9223372036854775807)

참에 적용되었을 때MIN_VALUE그리고.MAX_VALUE, John Kugelman의 답변은, 다음의 경우에 오버플로우 케이스를 낳는다.a == -1그리고.b ==다른 것(카일이 처음 제기한 점)은 없습니다.이 문제를 해결하는 방법은 다음과 같습니다.

long maximum = Long.signum(a) == Long.signum(b) ? Long.MAX_VALUE : Long.MIN_VALUE;

if ((a == -1 && b == Long.MIN_VALUE) ||
    (a != -1 && a != 0 && ((b > 0 && b > maximum / a) ||
                           (b < 0 && b < maximum / a))))
{
    // Overflow
}

일반적인 솔루션은 아닙니다.MIN_VALUE그리고.MAX_VALUE단, Java의 경우 일반적입니다.Long그리고.Integer및 기타 가치a그리고.b.

아마도:

if(b!= 0 && a * b / b != a) //overflow

이 "솔루션"에 대해서는 잘 모르겠습니다.

편집: b!= 0이 추가되었습니다.

다운투표를 하기 에: a * b / b는 최적화되지 않습니다.컴파일러 버그일 수 있습니다.오버플로우 버그를 가릴 수 있는 경우는 아직 보이지 않습니다.

이것이 도움이 될 수도 있습니다.

/**
 * @throws ArithmeticException on integer overflow
 */
static long multiply(long a, long b) {
    double c = (double) a * b;
    long d = a * b;

    if ((long) c != d) {
        throw new ArithmeticException("int overflow");
    } else {
        return d;
    }
}

대답하지 않지만 자바 코드를 보면 간단합니다.JDK8에서는 롱 연산으로 변환하여 결과를 int 값으로 다운캐스트하고 롱 결과와 비교하여 값이 변경되었는지 여부를 확인합니다.아래 코드는 나보다 더 잘 설명된다.

@HotSpotIntrinsicCandidate
public static int multiplyExact(int x, int y) {
    long r = (long)x * (long)y;
    if ((int)r != r) {
        throw new ArithmeticException("integer overflow");
    }
    return (int)r;
}

c / c + + (긴 * 긴):

const int64_ w = (int64_) a * (int64_) b;    
if ((long) (w >> sizeof(long) * 8) != (long) w >> (sizeof(long) * 8 - 1))
    // overflow

java (int * int, java에서 int64를 찾지 못해 죄송합니다):

const long w = (long) a * (long) b;    
int bits = 32; // int is 32bits in java    
if ( (int) (w >> bits) != (int) (w >> (bits - 1))) {
   // overflow
}

1. 결과를 큰 글씨로 저장(int*int는 결과를 long, long*int64에 저장)

2. cmp result >> 비트와 result >> (비트 - 1)

언급URL : https://stackoverflow.com/questions/1657834/how-can-i-check-if-multiplying-two-numbers-in-java-will-cause-an-overflow

반응형