valores valor todas tipos sentencia retornar retornan retorna regresan que metodos metodo las excepciones java overflow math long-integer

valor - tipos de excepciones en java



¿Cómo puedo verificar si multiplicar dos números en Java causará un desbordamiento? (14)

¿Tiene Java algo como int.MaxValue? Si es así, prueba

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

editar: visto Long.MAX_VALUE en cuestión

Quiero manejar el caso especial donde multiplicar dos números juntos causa un desbordamiento. El código se ve así:

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

Esa es una versión simplificada. En el programa real a y b se obtienen en otro lugar en tiempo de ejecución. Lo que quiero lograr es algo como esto:

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

¿Cómo sugieres que mejor código esto?

Actualización: a y b siempre son no negativos en mi escenario.


Aquí está la manera más simple en que puedo pensar

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" }


Como se ha señalado, Java 8 tiene métodos Math.xxxExact que arrojan excepciones en overflow.

Si no está utilizando Java 8 para su proyecto, aún puede "tomar prestado" sus implementaciones que son bastante compactas.

Aquí hay algunos enlaces a estas implementaciones en un sitio web de terceros, no hay garantía de si serán válidos pero, en cualquier caso, debería poder acceder a la fuente JDK y ver cómo hacen su magia dentro de la clase java.lang.Math .

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étera etcétera.


Hay bibliotecas de Java que proporcionan operaciones aritméticas seguras, que controlan el desbordamiento / subdesbordamiento largo. Por ejemplo, LongMath.checkedMultiply de Guava (long a, long b) devuelve el producto de b , siempre que no se desborde, y arroja ArithmeticException si a * b desborda en aritmética long firmada.


Java 8 tiene Math.multiplyExact , Math.multiplyExact , etc. para Math.addExact y long. Estos lanzan una ArithmeticException no controlada en overflow.


Me gustaría basarme en la respuesta de John Kugelman sin reemplazarla editándola directamente. Funciona para su caso de prueba ( MIN_VALUE = -10 , MAX_VALUE = 10 ) debido a la simetría de MIN_VALUE == -MAX_VALUE , que no es el caso para los enteros complementarios de dos. En realidad, 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)

Cuando se aplica al verdadero MIN_VALUE y MAX_VALUE , la respuesta de John Kugelman arroja un caso de desbordamiento cuando a == -1 b == cualquier otra cosa (punto señalado por primera vez por Kyle). Aquí hay una manera de solucionarlo:

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 }

No es una solución general para MIN_VALUE y MAX_VALUE , pero es general para Long e Integer Java y cualquier valor de b .


No estoy seguro de por qué nadie está buscando soluciones como:

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

Elija a para ser más grande de los dos números.


Puede usar java.math.BigInteger en su lugar y verificar el tamaño del resultado (no ha probado el código):

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() }


Robado de jruby

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

ACTUALIZACIÓN: Este código es corto y funciona bien; sin embargo, falla para a = -1, b = Long.MIN_VALUE.

Una posible mejora:

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

Tenga en cuenta que esto atrapará algunos desbordamientos sin ninguna división.


Si a y b son positivos, puedes usar:

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

Si necesita lidiar con números positivos y negativos, entonces es más complicado:

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 }

Aquí hay una pequeña mesa que preparé para verificar esto, pretendiendo que el desbordamiento ocurre a -10 o +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


Tal vez:

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

No estoy seguro acerca de esta "solución".

Editar: se agregó b! = 0.

Antes de su voto a favor : a * b / b no será optimizado. Esto sería un error del compilador. Todavía no veo un caso en el que se pueda enmascarar el error de desbordamiento.


Use logaritmos para verificar el tamaño del resultado.


c / c ++ (largo * largo):

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

java (int * int, lo siento, no encontré int64 en 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 el resultado en tipo grande (int * int poner el resultado en long, long * long puesto a int64)

2.cmp resultado >> bits y resultado >> (bits - 1)


tal vez esto te ayude:

/** * @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; } }