Quiero manejar el caso especial en el que la multiplicación de dos números provoca un desbordamiento. El código se parece a esto:
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 codifique mejor esto?
Actualización: a
y b
siempre son no negativos en mi escenario.
java
math
long-integer
integer-overflow
Steve McLeod
fuente
fuente
Respuestas:
Java 8 tiene
Math.multiplyExact
,Math.addExact
etc. para ints y long. Éstos arrojan unArithmeticException
desbordamiento sin control .fuente
Si
a
yb
ambos son positivos, puede usar:Si necesita lidiar con números positivos y negativos, entonces es más complicado:
Aquí hay una pequeña mesa que preparé para verificar esto, fingiendo que el desbordamiento ocurre en -10 o +10:
fuente
n
,n > x
es lo mismo quen > floor(x)
. Para enteros positivos, la división tiene un piso implícito. (Para números negativos, se redondea hacia arriba)a = -1
yb = 10
, consulte mi respuesta a continuación.Hay bibliotecas de Java que proporcionan operaciones aritméticas seguras, que verifican el desbordamiento / subdesbordamiento largos. Por ejemplo, LongMath.checkedMultiply de Guava (long a, long b) devuelve el producto de
a
yb
, siempre que no se desborde, y arrojaArithmeticException
si sea * b
desborda enlong
aritmética con signo .fuente
En su lugar, podría usar java.math.BigInteger y verificar el tamaño del resultado (no he probado el código):
fuente
Utilice logaritmos para comprobar el tamaño del resultado.
fuente
ceil(log(a)) + ceil(log(b)) > log(Long.MAX)
?¿Java tiene algo como int.MaxValue? Si es así, intente
editar: visto Long.MAX_VALUE en cuestión
fuente
Math.Abs(a)
no funciona sia
es asíLong.MIN_VALUE
.Esta es la forma más sencilla que se me ocurre
fuente
Robado de jruby
ACTUALIZACIÓN: este código es corto y funciona bien; sin embargo, falla para a = -1, b = Long.MIN_VALUE.
Una posible mejora:
Tenga en cuenta que esto detectará algunos desbordamientos sin ninguna división.
fuente
Como se ha señalado, Java 8 tiene métodos Math.xxxExact que arrojan excepciones al desbordamiento.
Si no está utilizando Java 8 para su proyecto, aún puede "tomar prestadas" sus implementaciones, que son bastante compactas.
Aquí hay algunos enlaces a estas implementaciones en el repositorio de código fuente de JDK, no hay garantía de que sigan siendo válidas, pero en cualquier caso, debería poder descargar la fuente de JDK y ver cómo hacen su magia dentro de la
java.lang.Math
clase.Math.multiplyExact(long, long)
http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Math.java#l925Math.addExact(long, long)
http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Math.java#l830etcétera etcétera.
ACTUALIZADO: se cambiaron los enlaces no válidos a sitios web de terceros por enlaces a los repositorios Mercurial de Open JDK.
fuente
No estoy seguro de por qué nadie está buscando una solución como:
Elija a para que sea mayor de los dos números.
fuente
a
es más grande o más pequeño.Me gustaría aprovechar 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 deMIN_VALUE == -MAX_VALUE
, que no es el caso de los enteros en complemento a dos. En la actualidad,MIN_VALUE == -MAX_VALUE - 1
.Cuando se aplica al verdadero
MIN_VALUE
yMAX_VALUE
, la respuesta de John Kugelman produce un caso de desbordamiento cuandoa == -1
yb ==
cualquier otra cosa (punto planteado por primera vez por Kyle). He aquí una forma de solucionarlo:No es una solución general para cualquier
MIN_VALUE
eMAX_VALUE
, pero es general para JavaLong
yInteger
y cualquier valor dea
yb
.fuente
MIN_VALUE = -MAX_VALUE - 1
, no en cualquier otro caso (incluido su caso de prueba de ejemplo). Tendría que cambiar mucho.Tal vez:
No estoy seguro de esta "solución".
Editar: Se agregó b! = 0.
Antes de votar en contra : a * b / b no se optimizará. Este sería un error del compilador. Todavía no veo un caso en el que se pueda enmascarar el error de desbordamiento.
fuente
a * b / b
es probable que una expresión como se optimice soloa
en muchos otros contextos.tal vez esto te ayude:
fuente
long
.c / c ++ (largo * largo):
java (int * int, lo siento, no encontré int64 en java):
1.Guarde el resultado en tipo grande (int * int pone el resultado en long, long * long puesto en int64)
2.cmp resultado >> bits y resultado >> (bits - 1)
fuente