2012-09-01 13 views
24

Duplicar posibles:
How can I check if multiplying two numbers in Java will cause an overflow?Cómo evitar el desbordamiento de enteros en el código de Java?

Supongamos que tengo un método de clase Java, que utiliza * y + operaciones.

 
int foo(int a, int b) { 
    ... // some calculations with + and * 
} 

cómo asegurarse de que ningún desbordamiento se produce en foo?

supongo que tampoco puedo usar BigDecimal o reemplazar todos + y * con "envoltorios" como:

 
int sum(int a, int b) { 
    int c = a + b; 
    if (a > 0 && b > 0 && c < 0) 
    throw new MyOverfowException(a, b) 
    return c; 
} 

int prod(int a, int b) { 
    int c = a * b; 
    if (a > 0 && b > 0 && c < 0) 
    throw new MyOverfowException(a, b) 
    return c; 
} 

¿Hay mejores maneras de asegurarse de que ningún int desbordamiento se produce en un método de Java?

+3

¿Por qué compruebas si está por debajo de cero? Un int puede ir muy por debajo de 0. – 11684

+0

Para ser precisos, este es el rango de un int: -2,147,483,648 a 2,147,483,647 – 11684

+0

¿Desea fijar los valores? –

Respuesta

17

Es un problema difícil desde una perspectiva de ingeniería.

El sitio Secure Coding recomienda:

  • uso de condiciones previas; es decir, comprueba las entradas para que el desbordamiento sea imposible, haciendo cada operación aritmética individual utilizando el siguiente tipo entero primitivo más grande y comprobando explícitamente el desbordamiento, o
  • usando BigInteger.

Este Dr Dobbs article sugiere crear una biblioteca de métodos aritméticos primitivos que hagan cada operación primitiva con una verificación de desbordamiento explícita. (Puede ver esto como una implementación del punto número 2 anterior). Pero los autores van más allá al sugerir que use la reescritura de código byte para reemplazar bytecodes aritméticos con llamadas a los métodos equivalentes que incorporan comprobaciones de desbordamiento.

Desafortunadamente, no hay manera de habilitar la verificación de desbordamiento de forma nativa en Java.(Pero lo mismo se aplica a muchos otros lenguajes; por ejemplo, C, C++ ...)

+0

el segundo de ellos es lo que hace mi respuesta – Alnitak

+1

"Es un problema difícil desde una perspectiva de ingeniería". - No es tan difícil: solo genere código de máquina para verificar el indicador de registro de desbordamiento después de cada operación. Eso es lo que hace el bloque "# checked" de C#. El problema es que Java no ofrece eso como una opción, no porque esté más allá del ingenio del hombre. – Rich

+0

@Rich: es difícil si no está en condiciones de modificar el compilador de Java. La mayoría de las personas no lo son! –

5

Suma: Compruebe si b es mayor que la diferencia del valor máximo que puede almacenar en int menos el valor de a. Si a y/o b pueden ser negativos, debe (i) tener cuidado de no obtener un desbordamiento para el control de diferencia y (ii) realizar un control similar para el mínimo.

Producto: Eso es más difícil. Yo dividiría los enteros en dos enteros de longitud media (es decir, si int es de 32 bits, divídelo en dos números de 16 bits usando el enmascaramiento de bits y el desplazamiento). Luego haz la multiplicación y luego mira si el resultado se ajusta a 32 bits.

Todo bajo la condición de que no desea simplemente tomar long para el resultado temporal.

20

Una forma de comprobar si hay un desbordamiento es hacer que los operandos sean promovidos a un tipo más grande (del doble de la longitud del bit del operando original) luego realizar la operación y ver si el valor resultante es demasiado grande para el original p.ej

int sum(int a, int b) { 
    long r = (long)a + b; 
    if (r >>> 32 != 0) { // no sign extension 
     throw new MyOverflowException(a, b); 
    } 
    return (int)r; 
} 

Si el tipo de original es un long, que tendría que utilizar BigInteger como el tipo más grande.

+0

Sé que esta respuesta es antigua, pero no se garantiza que esta solución funcione, ya que el tipo más grande puede desbordarse y terminar en un rango que parece normal para el tipo más pequeño. – yitzih

+0

@yitzih está equivocado: la suma de dos enteros (positivos) no puede exceder un valor más de 1 bit más largo que el operando más largo. No hay forma, dadas las restricciones de la pregunta, de terminar con un "mayor desbordamiento de tipo propio" – Alnitak

+0

@yitzihI Olvidé que la multiplicación también está involucrada, pero también, el producto de dos enteros positivos de 31 bits no puede exceder los 62 bits. – Alnitak

3

Supongamos que tanto a como b son positivos o negativos, y si el signo de a + b no es igual al signo de a y b, luego ocurre desbordamiento. Puede usar esta regla para juzgar si ocurre desbordamiento y lanzar una excepción. Cuando capte esta expceción, puede tratarla de acuerdo con el método mencionado en las respuestas anteriores. Otro método es realizar operaciones utilizando el tipo de rango más grande que no se desbordará. Puede utilizar long para la operación entre enteros.

Cuestiones relacionadas