java multiplication integer-overflow

java - El desbordamiento se produce con la multiplicación.



multiplication integer-overflow (6)

En este caso -

long m = 24 * 60 * 60 * 1000 * 1000;

El derecho de la asignación se evalúa primero. A la derecha no hay datos de tipo long . Todos son int . Así que la JVM intenta ajustar el resultado en un int luego se produjo el desbordamiento.

Y en el segundo caso ...

long m2 = 24L * 60 * 60 * 1000 * 1000; long m3 = 24 * 60 * 60 * 1000 * 1000L;

Aquí un operando de la multiplicación es long . Por lo que otros se les pide que se long automáticamente. El resultado es tratar de encajar a un long . Finalmente la asignación se realiza con m2 y m3 .

Y sí, la asociatividad de la multiplicación de izquierda a derecha significa que el operando izquierdo se toma primero. Y en base a este hecho, creo que en este escenario deberíamos usar:

long m2 = 24L * 60 * 60 * 1000 * 1000;

esta declaración, ya que en esta declaración la promoción a lugares tomados long antes, lo que reduce el riesgo de desbordamiento.

long m = 24 * 60 * 60 * 1000 * 1000;

El código anterior crea un desbordamiento y no imprime el resultado correcto.

long m2 = 24L * 60 * 60 * 1000 * 1000; long m3 = 24 * 60 * 60 * 1000 * 1000L;

Las 2 líneas anteriores imprimen el resultado correcto.

Mis preguntas son-

  1. ¿Importa al compilador que uso, m2 o m3 ?
  2. ¿Cómo empieza Java a multiplicarse? De izquierda a derecha o de derecha a izquierda? ¿Se calculan primero 24 * 60 o 1000 * 1000?

Esto se debe a que cuando usamos un largo tiempo como un operando y el otro, todos los int tipo int se nos solicitan a long .

La expresión en java se evalúa de izquierda a derecha.


Multiplicando trabajos de izquierda a derecha, e int * int produce int . Asi que

24 * 60 * 60 * 1000 * 1000

es igual que

(((24 * 60)* 60) * 1000) * 1000

lo que nos da

(((1440)* 60) * 1000) * 1000 (( 86400 ) * 1000) * 1000 ( 86400000 ) * 1000

y, finalmente, debido al desbordamiento de enteros (ya que 86400000000 es demasiado grande para un entero cuyo valor máximo es 2147483647 ) el resultado será

500654080

Puede eliminar el desbordamiento de enteros usando long como uno de los argumentos ( int * long y long * int produce long ).

En este caso, puede hacerlo al inicio como lo hizo en el caso de m2 : 24L * 60 que producirá 1440L long que, de nuevo, se multiplicarán por int 60 produciendo nuevos long , y así sucesivamente, produciendo solo valores long .

m3 caso m3 funciona aquí porque está multiplicando 86400000 por 1000L que significa que está evitando el desbordamiento de enteros ya que el resultado será long .


Vamos a multiplicar más números, esta línea se desbordará incluso si hay un 1000L :

long m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L;

Si bien esto dará resultado correcto:

long m3 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000;

Así que estamos seguros de que Java comienza a multiplicarse de izquierda a derecha y debemos comenzar con Long desde la izquierda para evitar el desbordamiento.


Yo usaría la línea m2 lugar de la línea m3 .

Java evalúa el operador de multiplicación * de izquierda a derecha , por lo que primero se evalúa 24 * 60 .

Da la casualidad de que 24 * 60 * 60 * 1000 (un 1000 ) no se desborda, por lo que para el momento en que se multiplique por 1000L (el segundo 1000 ), el producto se promociona long antes de multiplicarse, por lo que el desbordamiento no Tendrá lugar.

Pero como mencionó en sus comentarios, más factores pueden causar un desbordamiento en el tipo de datos int antes de multiplicar el último número long , dando una respuesta incorrecta. Es mejor usar un literal long para el primer número (el más a la izquierda) como en m2 para evitar el desbordamiento desde el principio. Alternativamente, puede convertir el primer literal como un long , por ejemplo, (long) 24 * 60 * ...


Como las expresiones se evalúan de izquierda a derecha , preferiría su primera solución ( m2 = ... ).

Razonamiento: veamos un ejemplo ligeramente diferente.

long g = Integer.MAX_VALUE * 2 * 2L;

Esta expresión se evaluará en -4 ya que solo la última multiplicación convierte la primera expresión en long (que es -2 en este momento, porque ambos operandos son int ). Si tú escribes

long g = Integer.MAX_VALUE * 2L * 2;

en cambio, g mantendrá el valor esperado de 8589934588 ya que la primera multiplicación produce un resultado de tipo long .