2016-05-17 9 views
5

Ich habe Code wie folgt aus:Warum Java Math.round() kann nicht mit dieser Nummer umgehen?

System.out.println("Math.round(1423562400L) => " + Math.round(1423562400L)); 

Und das Ergebnis ist folgendes:

Math.round(1423562400L) => 1423562368 

Dieser Wert ist ein 64-Bit-Integer aber es passt leicht in eine ganze Zahl 32-Bit, die in passen sollte ein Doppel. Was ist los?

+1

Es funktioniert, wenn Sie 'gegossen (double)' zuerst. Anscheinend ist es sonst ein "Float"! – Thilo

+1

Aber warum wird ein 'long' automatisch in einen' float' umgewandelt? – swdev

+0

@swdev [JLS 15.12.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2) sagt, dass sowohl float als auch double anwendbar sind , und [JLS 15.12.2.5] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.5) sagt float ist die ** spezifischste Methode **. – Nier

Antwort

7

Nach dem JLS,

15.12.2.5. Choosing the Most Specific Method

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.

Daraus folgt, dass Math.round(float) spezifischer ist als Math.round(double), und da sie beide valid overloads sind, wählt der Compiler die früher, was zu verlorenen Daten führt.

Um die Ausgabe zu korrigieren, ändern Sie einfach 1423562400L in 1423562400d.

+0

Können Sie erläutern, warum 'float'-Version spezifischer als' double'-Version ist? Also, es versucht zuerst die Float-Version und wenn es kompiliert, dann verwendet es es. Aber warum die Float-Version zuerst. Das ist in der JLS nicht angegeben. – swdev

+0

@swdev Lesen Sie den zweiten Absatz, den ich zitiert habe. Es impliziert, dass die Float-Version spezifischer ist, da ein Float als ein Double übergeben werden kann, aber nicht umgekehrt (ohne die Konvertierung zu verengen). – shmosel

+0

Danke, das erklärt es. Das ist ein seltsames Verhalten im Vergleich zu C++. In dieser Sprache würden Sie den folgenden 'Fehler erhalten: Aufruf der überladenen 'Runde (long int)' ist mehrdeutig 'und übergibt eine Ganzzahl an eine Funktion, bei der beide Gleitkommatypen definiert sind. – swdev

0

Ich glaube nicht Math.round() hat Implementierung, die long Argument unterstützt. Hier ist die Math.round() Signatur.

Math.round(double a); 
Math.round(float a); 

Math.round() nimmt double oder float, Also, wenn Sie long sind vorbei Sie so etwas wie tun (long konvertiert implizit zu schweben)

float x = 1423562400L; 
System.out.println(Math.round(x)); 

dieses Problem zu lösen können Sie Ihre long Wert double zuerst hinzufügen und es wird wie Charme funktionieren.

double x = 1423562400L; 
System.out.println(Math.round(x)); 

Zur Vereinfachung Sie

Math.round((double)1423562400L) 

oder

Math.round(1423562400d) 

hier tun können, ist das Bild, das die wie implizite Konvertierung funktioniert und warum zu umgewandelt zeigt floatlong wird

enter image description here

Bildquelle here

+0

Poste keine Bilder von Text hier. Veröffentlichen Sie den Text. Es ist eine Verschwendung von Zeit, die mir egal ist, und unsere Bandbreite, die mir wichtig ist. Es verhindert auch das Kopieren/Einfügen in Kommentare. Es ist im Grunde sinnlos. – EJP

+0

'Long konvertiert implizit zu float'. True, aber long konvertiert auch implizit (und in diesem Fall ohne Verlust). Aber hier wurde die "engere" Überladung gewählt. – Thilo

+0

Danke @EJP für Tipp .. aktualisiert die Antwort –

-1

Beachten Sie, dass die Unterschrift von Math.round

ist
public static int round(float a) 

es eine 32-Bit-Float akzeptiert, jetzt setzen Sie eine 64-Bit lange auf diese Methode, es schneiden die lange in einen int, und schalten Sie ihn dann zu ein Schwimmer.

System.out.println(Math.round((int)1423562400L)); 
System.out.println(Math.round((float)1423562400L)); 

die Code druckt 1423562368 zu

, wenn Sie wandeln es explitly dann das Ergebnis zu verdoppeln korrekt

+0

Nun, es gibt auch eine "doppelte" Überladung der gleichen Methode. Man hätte hoffen können, dass man sich stattdessen daran gewöhnt. – Thilo

+0

@Thilo, Ja, das war auch meine Hoffnung. – swdev