Ich möchte den Sonderfall behandeln, bei dem das Multiplizieren zweier Zahlen einen Überlauf verursacht. Der Code sieht ungefähr so aus:
int a = 20;
long b = 30;
// if a or b are big enough, this result will silently overflow
long c = a * b;
Das ist eine vereinfachte Version. Im realen Programm a
und b
werden zur Laufzeit an anderer Stelle bezogen. Was ich erreichen möchte, ist ungefähr so:
long c;
if (a * b will overflow) {
c = Long.MAX_VALUE;
} else {
c = a * b;
}
Wie schlagen Sie vor, dass ich dies am besten codiere?
Update: a
und b
sind in meinem Szenario immer nicht negativ.
java
math
long-integer
integer-overflow
Steve McLeod
quelle
quelle
Antworten:
Java 8 hat
Math.multiplyExact
,Math.addExact
usw. für ints und lang. Diese werfen einen ungeprüftenArithmeticException
Überlauf auf.quelle
Wenn
a
undb
beide positiv sind, können Sie verwenden:Wenn Sie sowohl mit positiven als auch mit negativen Zahlen umgehen müssen, ist dies komplizierter:
Hier ist eine kleine Tabelle, die ich zusammengestellt habe, um dies zu überprüfen, und so getan habe, als ob ein Überlauf bei -10 oder +10 auftritt:
quelle
n
,n > x
ist das gleiche wien > floor(x)
. Für positive ganze Zahlen ergibt die Division eine implizite Untergrenze. (Für negative Zahlen wird stattdessena = -1
undb = 10
Ausgabe, siehe meine Antwort unten.Es gibt Java-Bibliotheken, die sichere arithmetische Operationen bereitstellen und lange Über- / Unterläufe überprüfen. Zum Beispiel gibt Guavas LongMath.checkedMultiply (long a, long b) das Produkt von
a
und zurückb
, sofern es nicht überläuft, und wirft,ArithmeticException
wenn esa * b
in vorzeichenbehafteterlong
Arithmetik überläuft .quelle
Sie können stattdessen java.math.BigInteger verwenden und die Größe des Ergebnisses überprüfen (den Code wurde nicht getestet):
quelle
Verwenden Sie Logarithmen, um die Größe des Ergebnisses zu überprüfen.
quelle
ceil(log(a)) + ceil(log(b)) > log(Long.MAX)
?Hat Java so etwas wie int.MaxValue? Wenn ja, dann versuchen Sie es
edit: gesehen Long.MAX_VALUE in Frage
quelle
Math.Abs(a)
funktioniert nicht, wenn es soa
istLong.MIN_VALUE
.Hier ist der einfachste Weg, den ich mir vorstellen kann
quelle
Von jruby gestohlen
UPDATE: Dieser Code ist kurz und funktioniert gut. es schlägt jedoch für a = -1, b = Long.MIN_VALUE fehl.
Eine mögliche Verbesserung:
Beachten Sie, dass dies einige Überläufe ohne Teilung auffängt.
quelle
Wie bereits erwähnt, verfügt Java 8 über Math.xxxExact-Methoden, die beim Überlauf Ausnahmen auslösen.
Wenn Sie Java 8 nicht für Ihr Projekt verwenden, können Sie die recht kompakten Implementierungen trotzdem "ausleihen".
Hier sind einige Links zu diesen Implementierungen im JDK-Quellcode-Repository. Keine Garantie, ob diese gültig bleiben. In jedem Fall sollten Sie jedoch in der Lage sein, die JDK-Quelle herunterzuladen und zu sehen, wie sie ihre Magie innerhalb der
java.lang.Math
Klasse entfalten.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#l830usw. usw.
AKTUALISIERT: Es wurden ungültige Links zur Website eines Drittanbieters zu Links zu den Mercurial-Repositorys von Open JDK ausgetauscht.
quelle
Ich bin mir nicht sicher, warum niemand nach einer Lösung sucht wie:
Wählen Sie eine der beiden Zahlen, um größer zu sein.
quelle
a
der größere oder der kleinere ist?Ich möchte auf John Kugelmans Antwort aufbauen, ohne sie durch direkte Bearbeitung zu ersetzen. Es funktioniert für seinen Testfall (
MIN_VALUE = -10
,MAX_VALUE = 10
) aufgrund der Symmetrie vonMIN_VALUE == -MAX_VALUE
, was bei Zweierkomplement-Ganzzahlen nicht der Fall ist. In WirklichkeitMIN_VALUE == -MAX_VALUE - 1
.Wenn John Kugelmans Antwort auf das wahre
MIN_VALUE
und angewendet wird,MAX_VALUE
ergibt sich ein Überlauf, wanna == -1
undb ==
was auch immer (Punkt, der zuerst von Kyle angesprochen wurde). Hier ist eine Möglichkeit, dies zu beheben:Es ist keine allgemeine Lösung für irgendein
MIN_VALUE
undMAX_VALUE
, aber es ist allgemein für JavaLong
undInteger
und jeden Wert vona
undb
.quelle
MIN_VALUE = -MAX_VALUE - 1
kein anderer Fall (einschließlich Ihres Beispieltestfalls). Ich würde viel ändern müssen.Vielleicht:
Ich bin mir nicht sicher über diese "Lösung".
Bearbeiten: Hinzugefügt b! = 0.
Bevor Sie abstimmen : a * b / b wird nicht optimiert. Dies wäre ein Compiler-Fehler. Ich sehe immer noch keinen Fall, in dem der Überlauffehler maskiert werden kann.
quelle
a * b / b
wird wahrscheinlich nura
in vielen anderen Kontexten optimiert .Vielleicht hilft dir das:
quelle
long
.c / c ++ (lang * lang):
java (int * int, sorry, ich habe int64 in java nicht gefunden):
1. Speichern Sie das Ergebnis in großer Schrift (int * int setzt das Ergebnis auf long, long * long auf int64)
2.cmp Ergebnis >> Bits und Ergebnis >> (Bits - 1)
quelle