2009-11-17 18 views
5

Ci sono degli svantaggi in questo codice, che sembra essere una versione più veloce (e corretta) di java.lang.Math.round?Implementazione più veloce di Math.round?

public static long round(double d) { 

    if (d > 0) { 
     return (long) (d + 0.5d); 
    } else { 
     return (long) (d - 0.5d); 
    } 
} 

Si avvantaggia del fatto che, in Java, troncatura a cicli lunghi a zero.

+2

@TrueWill: Se è ordinatamente in una funzione denominata correttamente ... Sarebbe davvero importante? Forse viene usato in un programma a uso intensivo di matematica. – Sivvy

+0

Sarebbe raro trovare un modo significativamente più veloce di fare qualcosa per un metodo che è in circolazione dall'1.0 mantenendo la coerenza al 100% con il metodo originale. – TofuBeer

+0

Assolutamente è un micro-ottimizzazione, e in un senso locale è valsa la pena. - ma questi non sono raccomandati per uso generale. – mrjbq7

risposta

15

Ci sono alcuni special cases che gestisce il metodo integrato, che il codice non gestisce. Dalla documentazione:

  • Se l'argomento è NaN, il risultato è 0.
  • Se l'argomento è infinito negativo o qualsiasi valore inferiore o uguale al valore di Integer.MIN_VALUE, il risultato è pari al valore di Integer.MIN_VALUE.
  • Se l'argomento è infinito positivo o qualsiasi valore maggiore di o uguale al valore di Integer.MAX_VALUE, il risultato è uguale al valore di Integer.MAX_VALUE.
5

Sì; non stai tenendo conto di underflow o overflow. Pragmaticamente parlando, questo potrebbe non avere importanza per la tua applicazione.

3

Ho provato questo, e c'è un potenziale svantaggio chiave che non è stato ancora descritto qui: Stai cambiando il metodo rounding tie-breaking.

Math.round() implementa la regola "round half up", mentre il metodo round() implementa la regola "round half from zero".

Ad esempio:

  • Math.round(-0.5d) =>0L
  • Your.round(-0.5d) =>-1L

Questo può o non può essere un problema per voi, ma si dovrebbe capire che il metodo di cui sopra è non una sostituzione drop-in per Math.round(), anche dopo le considerazioni di NaN e infinito già delineate.

Un'altra questione rilevante: Rounding negative numbers in Java

quanto riguarda le prestazioni, non v'è alcun dubbio che il metodo di cui sopra è notevolmente più veloce rispetto Math.round() - viene eseguito in circa il 35% del tempo per i valori positivi e negativi generati casualmente. Questo può essere un'ottimizzazione utile quando si chiama questo metodo in un ciclo stretto. È ancora meglio (25% del tempo di esecuzione) quando vengono dati solo valori positivi, probabilmente a causa della CPU che utilizza branch prediction.

Math.round() viene infine implementato da una chiamata JNI nativa, che potrebbe essere la causa della differenza di prestazioni. This Sun/Oracle bug suggerisce che potrebbe esserci una versione puramente Java in j6u22, ma non riesco a vedere dove, e in effetti Math.round() in j6u23 funziona in modo simile a j6u16 nei miei test. Non ho provato su altre versioni.