web-dev-qa-db-fra.com

Comment éviter le débordement d'entier dans Java code?

Duplicata possible:
Comment puis-je vérifier si la multiplication de deux nombres dans Java provoquera un débordement?

Supposons que j'ai une méthode de classe Java, qui utilise * et + opérations.

 int foo (int a, int b) {
 ... // quelques calculs avec + et * 
} 

Comment s'assurer qu'aucun débordement ne se produit dans foo?

Je suppose que je peux utiliser BigDecimal ou remplacer tous les + et * par des "wrappers" comme:

 int sum (int a, int b) {
 int c = a + b; 
 if (a> 0 && b> 0 && c <0) 
 lancer une nouvelle MyOverfowException (a, b) 
 retourner c; 
} 
 
 int prod (int a, int b) {
 int c = a * b; 
 si (a> 0 && b> 0 && c <0) 
 lève une nouvelle MyOverfowException (a, b) 
 renvoie c; 
 } 

Y a-t-il de meilleures façons de s'assurer qu'aucun int débordement ne se produit dans une méthode Java?

30
Michael

C'est un problème difficile du point de vue de l'ingénierie.

Le site Secure Coding recommande:

  • utilisation de conditions préalables; c.-à-d. vérifier la portée des entrées de sorte qu'un débordement soit impossible
  • effectuer chaque opération arithmétique individuelle en utilisant le type entier primitif suivant le plus grand et en vérifiant explicitement le débordement, ou
  • en utilisant BigInteger.

Cette article du Dr Dobbs suggère de créer une bibliothèque de méthodes arithmétiques primitives qui effectuent chaque opération primitive avec une vérification de débordement explicite. (Vous pouvez voir cela comme une implémentation du point n ° 2 ci-dessus.) Mais les auteurs vont plus loin en suggérant d'utiliser la réécriture de bytecodes pour remplacer les bytecodes arithmétiques par des appels aux méthodes équivalentes qui incorporent des vérifications de débordement.

Malheureusement, il n'y a aucun moyen d'activer la vérification des débordements en natif en Java. (Mais la même chose s'applique dans de nombreux autres langages; par exemple C, C++ ...)

20
Stephen C

Une façon de vérifier un débordement consiste à faire passer les opérandes à un type plus grand (de doubler la longueur de bits de l'opérande d'origine) puis à effectuer l'opération, puis à voir si la valeur résultante est trop grande pour le type d'origine, par ex.

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 votre type d'origine est un long, vous devez utiliser BigInteger comme type plus grand.

23
Alnitak

Somme: Vérifiez si b est supérieur à la différence de la valeur maximale que vous pouvez stocker en entier moins la valeur de a. Si a et/ou b peuvent être négatifs, vous devez (i) faire attention à ne pas déjà avoir un débordement pour le contrôle de différence et (ii) effectuer un contrôle similaire pour le minimum.

Produit: c'est plus difficile. Je diviserais les entiers en deux entiers de demi-longueur (c'est-à-dire si int est 32 bits, le diviser en deux nombres de 16 bits en utilisant le masquage de bits et le décalage). Effectuez ensuite la multiplication, puis vérifiez si le résultat tient en 32 bits.

Tout à condition que vous ne vouliez pas simplement prendre long pour le résultat temporaire.

6
JohnB

Supposons que a et b soient positifs ou négatifs, et si le signe de a + b n'est pas égal au signe de a et b, alors un débordement se produit. Vous pouvez utiliser cette règle pour juger si un débordement se produit et lever une exception. Lorsque vous attrapez cette expcetion, vous pouvez la traiter selon la méthode mentionnée dans les réponses précédentes. Une autre méthode consiste à effectuer une opération en utilisant le type de plage le plus large qui ne débordera pas. Vous pouvez utiliser long pour l'opération entre les entiers.

3
Macok