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
한, 「 않는다」, 「넘치다」를 던집니다ArithmeticException
a * 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_VALUE
2의 보완정수에는 해당되지 않습니다.사실,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
'programing' 카테고리의 다른 글
일반 ES6 클래스 메서드에서 스태틱 메서드를 호출합니다. (0) | 2022.09.13 |
---|---|
int의 크기는 컴파일러나 프로세서에 따라 달라집니까? (0) | 2022.09.13 |
jQuery $(문서)ready 및 Update Panels? (0) | 2022.09.13 |
Conda를 통해 Python OpenCV를 설치하려면 어떻게 해야 하나요? (0) | 2022.09.13 |
Mac OS Lion 명령줄에서 MySQL 서버를 시작하는 방법 (0) | 2022.09.13 |