2015-06-02 15 views
17
long m = 24 * 60 * 60 * 1000 * 1000; 

Der obige Code erstellt Überlauf und druckt das richtige Ergebnis nicht.Überlauf tritt bei Multiplikation auf

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

Die obigen 2 Zeilen geben das korrekte Ergebnis aus.

Meine Fragen sind-

  1. Ist es für den Compiler Rolle, die ich benutze, m2 oder m3?
  2. Wie beginnt Java zu multiplizieren? Von links nach rechts oder von rechts nach links? Wird 24 * 60 zuerst oder 1000 * 1000 berechnet?
+1

oops- lange m2 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000; lang m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L; m2 und m3 geben nicht dasselbe Ergebnis, wenn multipliziert mehr sagen um einen Faktor von 1000 * 1000. Es scheint also, dass die Multiplikation von links nach rechts erfolgt. – rents

+2

Rechts, benutze 'm2', so dass jede Zwischenmultiplikation zu' long' befördert wird. Multiplikation ist linksassoziativ, also von links nach rechts. – GriffeyDog

+0

Multiplikation ist assoziativ, so dass die Reihenfolge keine Rolle spielt. Es wird jedoch von links nach rechts berechnet, wenn es darauf ankommt, wie zum Beispiel Aufrufmethoden, die eine Zahl zurückgeben. –

Antwort

16

Ich würde die m2 Linie anstelle der m3 Linie verwenden.

Java wertet den Multiplikationsoperator * von left to right aus, so dass 24 * 60 zuerst ausgewertet wird.

Es passiert einfach so, dass 24 * 60 * 60 * 1000 (ein 1000) nicht überläuft, so dass durch die Zeit, die Sie durch 1000L (die zweiten 1000) multiplizieren, das Produkt vor der Multiplikation zu long gefördert wird, so daß ein Überlauf erfolgt nicht Ort.

Aber wie Sie in Ihren Kommentaren erwähnt haben, können mehr Faktoren einen Überlauf im int-Datentyp verursachen, bevor Sie die letzte long-Nummer multiplizieren, was zu einer falschen Antwort führt. Es ist besser, ein long Literal für die erste (am weitesten links liegende) Nummer zu verwenden, wie in m2, um einen Überlauf vom Start zu vermeiden. Alternativ können Sie das erste Literal als long, z. .

19

In dieser Fall -

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

Das Recht der Zuordnung wird zuerst ausgewertet. Rechts gibt es keine long Art Daten. Alle sind int. Also versuchen die JVM das Ergebnis in eine int passen, dann ist der Überlauf aufgetreten.

Und im zweiten Fall -

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

Hier ein Operand der Multiplikation ist long. So werden andere automatisch zu long aufgefordert. Das Ergebnis ist der Versuch, zu einem long passen. Abschließend erfolgt die Zuordnung mit m2 und m3.

Und ja die Assoziativität der Multiplikation von links nach rechts - bedeutet der linke Operand wird zuerst genommen. Und Basierend auf dieser Tatsache glaube ich, in diesem Szenario sollten wir nutzen -

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

diese Aussage, da bei dieser Aussage die Förderung zu long genommen Orten früher, was das Risiko von Überlauf reduziert.

+0

"Das linke der Aufgabe wird zuerst ausgewertet." ... meintest du das Richtige? – Mints97

+0

Es ist immer noch ein Tippfehler im zweiten Satz :) – Ruslan

+0

@Ruslan, ich glaube, ich habe ein Problem mit Links-Rechts :(. Danke – Razib

6

Multiplikation funktioniert von links nach rechts, und int * int produziert int.So

24 * 60 * 60 * 1000 * 1000 

ist die gleiche wie

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

die uns

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

und schließlich wegen der Integer-Überlauf gibt (da 86400000000 zu groß ist für ganze Zahl, die Max-Wert ist 2147483647) Ergebnis wird sein

500654080 

Sie können den Integer-Überlauf eliminieren, indem Sie long als eines der Argumente verwenden (int * long und long * int produziert long).

In diesem Fall, dass Sie es am Anfang tun können, wie Sie bei m2 tat 24L * 60 die long1440L die wiederum von int 60 multipliziert wird produzieren neue long produzieren, und so weiter, nur long Werte zu erzeugen.

m3 Fall funktioniert hier, weil Sie 86400000 von 1000L multiplizieren, was bedeutet, dass Sie Integer-Überlauf werden vermieden, da Ergebnis long sein wird.

9

Since expressions are evaluated from left to right, würde ich die Ihre erste Lösung (m2 = ...) bevorzugen.

Reasoning: Lassen Sie sich in einem etwas anderen Beispiel.

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

wird dieser Ausdruck in -4 bewerten, da nur die letzte Multiplikation den ersten Ausdruck zu long wirft (die -2 zu diesem Zeitpunkt ist, da beide Operanden int sind). Wenn Sie

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

schreiben stattdessen wird l den erwarteten Wert von 8589934588 halten, da die erste Multiplikation ein Ergebnis vom Typ long ergibt.

4

Lassen Sie uns mehr Zahlen multiplizieren, wird diese Linie überlaufen noch gibt es eine 1000L:

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

Während dies korrekte Ergebnis geben:

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

So sind wir sicher, dass Java von links beginnen Multiplikation nach rechts und wir müssen mit Long von links beginnen Überlauf zu verhindern.

2

Dies ist, weil, wenn wir lange als ein Operand verwenden die anderen alle int Operand aufgefordert werden, long.

Der Ausdruck in Java von links nach rechts ausgewertet.