2016-05-17 12 views
5

mam kod jak poniżej:Dlaczego Java Math.round() nie może obsłużyć tej liczby?

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

A wynik jest taki:

Math.round(1423562400L) => 1423562368 

Ta wartość jest 64-bitowa liczba całkowita, ale łatwo mieści się wewnątrz 32-bitową liczbę całkowitą, która powinna w podwójny. Co się dzieje?

+1

Działa gdy rzucisz na '(podwójne)' pierwszy. Podobno jest to "float" inaczej?! – Thilo

+1

Ale dlaczego 'long' automatycznie rzuca się na' float'? – swdev

+0

@ swdev [JLS 15.12.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2) mówi, że zarówno zmienna jak i podwójna mają zastosowanie , a [JLS 15.12.2.5] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.5) mówi, że float jest ** najbardziej szczegółową metodą **. – Nier

Odpowiedz

7

Według 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.

Wynika stąd, że Math.round(float) jest bardziej szczegółowy niż Math.round(double), a ponieważ są one zarówno valid overloads, kompilator wybiera byłego, powodując utratę danych.

Aby poprawić wyniki, po prostu zmień 1423562400L na 1423562400d.

+0

Czy możesz wyjaśnić, dlaczego 'float' wersja jest bardziej specyficzna niż wersja' double'? Dlatego najpierw próbuje wersji float i jeśli ją kompiluje, to ją używa. Ale dlaczego najpierw jest wersja float. Nie jest to określone w JLS. – swdev

+0

@ swdev Przeczytaj drugi akapit cytowany. Oznacza to, że wersja zmiennoprzecinkowa jest bardziej specyficzna, ponieważ zmienna float może być przekazywana jako podwójna, ale nie odwrotnie (bez zawężającej konwersji). – shmosel

+0

Dzięki, to wyjaśnia. To dziwne zachowanie w porównaniu z C++. W tym języku otrzymasz następujący komunikat: "błąd: wywołanie przeciążonej" rundy (long int) "jest niejednoznaczny" przekazując liczbę całkowitą do funkcji z dwoma zdefiniowanymi typami float. – swdev

0

Nie sądzę, że Math.round() ma implementację, która obsługuje argument long. Oto podpis Math.round().

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

Math.round() akceptuje double lub float, więc gdy jesteś przejazdem long robisz coś podobnego (long przekształca się unosić w sposób dorozumiany)

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

Aby rozwiązać ten problem można dodać wartość long do double pierwszy i zadziała jak urok.

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

Dla uproszczenia można zrobić

Math.round((double)1423562400L) 

lub

Math.round(1423562400d) 

Oto obraz, który pokazuje how niejawna konwersja działa i dlaczego long zostanie przekonwertowany do float

enter image description here

źródło obrazu here

+0

Nie publikuj zdjęć tekst tutaj. Opublikuj tekst. To marnowanie czasu, którego nie obchodzi, i nasza przepustowość, na której mi zależy. Zapobiega również kopiowaniu/wklejaniu komentarzy. Jest to w zasadzie bezcelowe. – EJP

+0

'długo konwertuje do unosu niejawnie'. Prawda, ale długo także konwertuje się podwójnie pośrednio (i bez straty w tym przypadku). Ale tutaj wybrano "węższe" przeciążenie. – Thilo

+0

Dzięki @EJP za wskazówkę .. zaktualizowano odpowiedź –

-1

Zauważ, że podpis Math.round jest

public static int round(float a) 

akceptuje pływaka 32bit, teraz można umieścić 64bit długo do tej metody, go wyciąć długie do int, a następnie włączyć go do pływak.

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

drukuje kod 1423562368 zbyt

jeśli przekształcić go podwoić explitly wtedy wynik jest prawidłowy

+0

Istnieje również "podwójne" przeciążenie tej samej metody. Można było mieć nadzieję, że ten zostanie użyty zamiast tego. – Thilo

+0

@Thilo, Tak, to była także moja nadzieja. – swdev

Powiązane problemy