Jak sprawdzić, czy mnożenie dwóch liczb w Javie spowoduje przepełnienie?
Chcę zająć się szczególnym przypadkiem, w którym mnożenie dwóch liczb razem powoduje przepełnienie. Kod wygląda mniej więcej tak:
int a = 20;
long b = 30;
// if a or b are big enough, this result will silently overflow
long c = a * b;
To uproszczona wersja. W rzeczywistym Programie a
i {[3] } są pozyskiwane gdzie indziej w czasie wykonywania. To co chcę osiągnąć to coś takiego:
long c;
if (a * b will overflow) {
c = Long.MAX_VALUE;
} else {
c = a * b;
}
Jak mam to zakodować?
Update: a
i b
są zawsze nie-negatywne w moim scenariuszu.
14 answers
Java 8 mA Math.multiplyExact
, Math.addExact
itd. dla ints i long. Te rzucają niekontrolowane ArithmeticException
na przepełnienie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-24 12:13:01
Jeśli a
i b
są dodatnie, możesz użyć:
if (a != 0 && b > Long.MAX_VALUE / a) {
// Overflow
}
Jeśli musisz poradzić sobie zarówno z liczbami dodatnimi, jak i ujemnymi, to jest to bardziej skomplikowane:
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
}
Oto mały stolik, który podniosłem, aby to sprawdzić, udając, że przepełnienie dzieje się przy -10 lub +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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 15:14:17
Istnieją Biblioteki Javy, które zapewniają bezpieczne operacje arytmetyczne, które sprawdzają długi przepełnienie/niedopełnienie. Na przykład, Guava ' s LongMath.checkedMultiply (long A, long b) Zwraca iloczyn a
i b
, pod warunkiem, że nie przepełnia się i rzuca ArithmeticException
Jeśli a * b
przepełnia się w arytmetyce podpisanej long
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-14 11:47:52
Możesz użyć Javy.matematyka.Zamiast tego BigInteger i sprawdź rozmiar wyniku (nie testowałem kodu):
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()
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-01 18:19:39
Użyj logarytmów, aby sprawdzić rozmiar wyniku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-30 02:37:24
Czy Java ma coś takiego jak int.MaxValue? Jeśli tak, spróbuj
if (b != 0 && Math.abs(a) > Math.abs(Long.MAX_VALUE / b))
{
// it will overflow
}
Edit: seen Long.MAX_VALUE w pytaniu
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 11:38:24
Skradziony z jruby
long result = a * b;
if (a != 0 && result / a != b) {
// overflow
}
UPDATE: ten kod jest krótki i działa dobrze; jednak zawodzi dla a = -1, B = Long.MIN_VALUE.
Jedno możliwe rozszerzenie:
long result = a * b;
if( (Math.signum(a) * Math.signum(b) != Math.signum(result)) ||
(a != 0L && result / a != b)) {
// overflow
}
Zauważ, że to wychwyci pewne przepełnienia bez podziału.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 18:37:25
Nie wiem dlaczego nikt nie patrzy na rozwiązanie typu:
if (Long.MAX_VALUE/a > b) {
// overflows
}
Wybierz a, aby była większa z dwóch liczb.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-30 02:37:32
Chciałbym oprzeć się na odpowiedzi Johna Kugelmana bez zastępowania jej przez edycję bezpośrednio. To działa dla jego przypadku testowego (MIN_VALUE = -10
, MAX_VALUE = 10
) ze względu na symetrię MIN_VALUE == -MAX_VALUE
, co nie ma miejsca w przypadku dwóch liczb całkowitych dopełniających. W rzeczywistości, 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)
Po zastosowaniu do prawdziwych MIN_VALUE
i MAX_VALUE
, odpowiedź Johna Kugelmana daje przypadek przepełnienia, gdy a == -1
i b ==
cokolwiek innego (punkt pierwszy podniesiony przez Kyle ' a). Oto jak to naprawić:
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
}
To nie jest ogólne rozwiązanie dla dowolne MIN_VALUE
i MAX_VALUE
, ale jest ogólne dla Long
i Integer
oraz dowolnych wartości a
i b
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 18:26:24
Może:
if(b!= 0 && a * b / b != a) //overflow
Nie jestem pewien co do tego "rozwiązania".
Edit: Dodano b != 0.
Zanim przegłosujesz: a * b / b nie będzie zoptymalizowane. To byłby błąd kompilatora. Nadal nie widzę przypadku, w którym błąd przepełnienia może być maskowany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 08:22:03
Może to ci pomoże:
/**
* @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;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 08:48:57
Jak już wspomniano, Java 8 ma matematykę.metody xxxExact rzucające wyjątki na przepełnienie.
Jeśli nie używasz Javy 8 do swojego projektu, nadal możesz "pożyczyć" ich implementacje, które są dość kompaktowe.
Oto kilka linków do tych implementacji na stronie 3rd party, nie ma gwarancji, czy pozostaną one ważne, ale w każdym razie powinieneś być w stanie wejść do źródła JDK i zobaczyć, jak robią swoją magię wewnątrz java.lang.Math
klasy.
Math.multiplyExact(long, long)
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Math.java?av=f#882
Math.addExact
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/lang/Math.java?av=f#805
Etc, etc.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-18 15:14:31
Oto najprostszy sposób, jaki mogę wymyślić
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"
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-25 02:33:20
C / C ++ (long * long):
const int64_ w = (int64_) a * (int64_) b;
if ((long) (w >> sizeof(long) * 8) != (long) w >> (sizeof(long) * 8 - 1))
// overflow
Java (int * int, sorry I didn ' t find int64 in java):
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.save the result in large type (int*int put the result to long, long*long put to int64)
2.CMP result > > bits and result > >(bits-1)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-05 06:18:17