Je veux gérer le cas particulier où la multiplication de deux nombres ensemble provoque un débordement. Le code ressemble à ceci:
int a = 20;
long b = 30;
// if a or b are big enough, this result will silently overflow
long c = a * b;
C'est une version simplifiée. Dans le programme réel a
et b
proviennent ailleurs au moment de l'exécution. Ce que je veux réaliser est quelque chose comme ceci:
long c;
if (a * b will overflow) {
c = Long.MAX_VALUE;
} else {
c = a * b;
}
Comment me suggérez-vous de coder au mieux cela?
Mise à jour: a
et b
sont toujours non négatifs dans mon scénario.
java
math
long-integer
integer-overflow
Steve McLeod
la source
la source
Réponses:
Java 8 a
Math.multiplyExact
,Math.addExact
etc. pour les entiers et les longs. Ceux-ci lancent unArithmeticException
débordement non contrôlé .la source
Si
a
etb
sont tous les deux positifs, vous pouvez utiliser:Si vous devez gérer à la fois des nombres positifs et négatifs, c'est plus compliqué:
Voici un petit tableau que j'ai créé pour vérifier cela, en prétendant que le débordement se produit à -10 ou +10:
la source
n
,n > x
c'est la même chose quen > floor(x)
. Pour les entiers positifs, la division fait un plancher implicite. (Pour les nombres négatifs, il arrondit à la place)a = -1
etb = 10
, voir ma réponse ci-dessous.Il existe des bibliothèques Java qui fournissent des opérations arithmétiques sûres, qui vérifient les longs débordements / sous-débordements. Par exemple, LongMath.checkedMultiply de Guava (long a, long b) renvoie le produit de
a
etb
, à condition qu'il ne déborde pas, et renvoieArithmeticException
sia * b
déborde enlong
arithmétique signée .la source
Vous pouvez utiliser java.math.BigInteger à la place et vérifier la taille du résultat (je n'ai pas testé le code):
la source
Utilisez des logarithmes pour vérifier la taille du résultat.
la source
ceil(log(a)) + ceil(log(b)) > log(Long.MAX)
:?Java a-t-il quelque chose comme int.MaxValue? Si oui, essayez
edit: vu Long.MAX_VALUE en question
la source
Math.Abs(a)
ne fonctionne pas sia
c'est le casLong.MIN_VALUE
.Voici le moyen le plus simple auquel je puisse penser
la source
Volé à jruby
MISE À JOUR: Ce code est court et fonctionne bien; cependant, il échoue pour a = -1, b = Long.MIN_VALUE.
Une amélioration possible:
Notez que cela rattrapera certains débordements sans aucune division.
la source
Comme cela a été souligné, Java 8 a des méthodes Math.xxxExact qui lèvent des exceptions en cas de débordement.
Si vous n'utilisez pas Java 8 pour votre projet, vous pouvez toujours «emprunter» leurs implémentations qui sont assez compactes.
Voici quelques liens vers ces implémentations dans le référentiel de code source JDK, aucune garantie que ceux-ci resteront valides, mais dans tous les cas, vous devriez pouvoir télécharger la source JDK et voir comment ils font leur magie à l'intérieur de la
java.lang.Math
classe.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.
MISE À JOUR: les liens invalides vers le site Web tiers ont été remplacés par des liens vers les référentiels Mercurial d'Open JDK.
la source
Je ne sais pas pourquoi personne ne cherche une solution comme:
Choisissez a pour être le plus grand des deux nombres.
la source
a
soit le plus grand ou le plus petit qui importe ?J'aimerais m'appuyer sur la réponse de John Kugelman sans la remplacer en la modifiant directement. Cela fonctionne pour son cas de test (
MIN_VALUE = -10
,MAX_VALUE = 10
) en raison de la symétrie deMIN_VALUE == -MAX_VALUE
, ce qui n'est pas le cas pour les entiers complémentaires à deux. En réalité,MIN_VALUE == -MAX_VALUE - 1
.Lorsqu'elle est appliquée au vrai
MIN_VALUE
etMAX_VALUE
, la réponse de John Kugelman produit un cas de débordement quanda == -1
etb ==
quoi que ce soit d'autre (point soulevé en premier par Kyle). Voici un moyen de résoudre ce problème:Ce n'est pas une solution générale pour tout
MIN_VALUE
etMAX_VALUE
, mais elle est générale pour JavaLong
etInteger
et toute valeur dea
etb
.la source
MIN_VALUE = -MAX_VALUE - 1
, pas dans n'importe quel autre cas (y compris votre exemple de cas de test). J'aurais beaucoup à changer.Peut être:
Pas sûr de cette "solution".
Edit: Ajouté b! = 0.
Avant de voter contre : a * b / b ne sera pas optimisé. Ce serait un bogue du compilateur. Je ne vois toujours pas de cas où le bug de débordement peut être masqué.
la source
a * b / b
est susceptible d'être optimiséea
dans de nombreux autres contextes.peut-être que cela vous aidera:
la source
long
.c / c ++ (long * long):
java (int * int, désolé je n'ai pas trouvé int64 dans java):
1. enregistrez le résultat en grand type (int * int met le résultat à long, long * long mis à int64)
2.cmp résultat >> bits et résultat >> (bits - 1)
la source