2016-05-17 19 views
5

Ho codice come questo:Perché Math.round() di Java non può gestire questo numero?

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

e il risultato è questo:

Math.round(1423562400L) => 1423562368 

Questo valore è un intero a 64 bit ma si adatta facilmente all'interno di un numero intero di 32 bit, che dovrebbe corrispondere un doppio. Cosa sta succedendo?

+1

Funziona quando si esegue il cast a '(doppia)' prima. Apparentemente, è un "float" altrimenti ?! – Thilo

+1

Ma perché un 'long' viene lanciato automaticamente su un' float'? – swdev

+0

@swdev [JLS 15.12.2] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2) indica che sono applicabili sia la virgola mobile che la doppia e [JLS 15.12.2.5] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.5) indica che float è il ** metodo più specifico **. – Nier

risposta

7

Secondo il 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.

Ne consegue che Math.round(float) è più specifico di Math.round(double), e dato che sono entrambi valid overloads, il compilatore sceglie la precedente, con conseguente perdita di dati.

Per correggere l'output, è sufficiente modificare 1423562400L a 1423562400d.

+0

Puoi spiegare perché la versione 'float' è più specifica della versione' double'? Quindi, prova prima la versione float e se la compila la usa. Ma perché prima la versione float. Questo non è specificato nel JLS. – swdev

+0

@swdev Leggi il secondo paragrafo che ho citato. Implica che la versione float sia più specifica perché un float può essere passato come un double, ma non viceversa (senza restringere la conversione). – shmosel

+0

Grazie, questo lo spiega. Questo è un comportamento strano rispetto a C++. In quella lingua si otterrebbe il seguente 'errore: call of overloaded 'round (long int)' è ambiguo 'passando un intero a una funzione con entrambi i tipi di float definiti. – swdev

0

Non credo che Math.round() abbia implementazione che supporta l'argomento long. Ecco la firma Math.round().

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

Math.round() accetta double o float, così quando si passa long si sta facendo qualcosa di simile (long converte a stare a galla in modo implicito)

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

Per risolvere questo si può aggiungere il valore long-double prima e funzionerà come fascino.

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

Per semplificare si può fare

Math.round((double)1423562400L) 

o

Math.round(1423562400d) 

Ecco la foto che mostra il come implicite di conversione opere e perché long viene convertito in float

enter image description here

Fonte immagine here

+0

Non pubblicare immagini di testo quì. Pubblica il testo. È uno spreco di tempo, che non mi interessa, e la nostra larghezza di banda, che mi interessa. Inoltre impedisce la copia/incolla nei commenti. È fondamentalmente inutile. – EJP

+0

'long convertts to float implicitly'. Vero, ma anche a lungo converte in doppio implicitamente (e senza perdita in questo caso). Ma qui è stato scelto il sovraccarico "più stretto". – Thilo

+0

Grazie a @EJP per il suggerimento .. ha aggiornato la risposta –

-1

Si noti che la firma di Math.round è

public static int round(float a) 

accetta un galleggiante a 32 bit, ora si mette a 64 bit a lungo per questo metodo, ha tagliato il tempo per un int, e poi girare a un galleggiante.

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

il codice stampe 1423562368 troppo

se si converte a raddoppiare explitly allora il risultato è corretto

+0

Bene, c'è anche un overload 'double' dello stesso metodo. Uno avrebbe potuto sperare che quello si abitui invece. – Thilo

+0

@Thilo, sì, anche questa era la mia speranza. – swdev

Problemi correlati