2009-11-17 24 views
5

¿Hay algún inconveniente en este código, que parece ser una versión más rápida (y correcta) de java.lang.Math.round?¿Implementación más rápida de Math.round?

public static long round(double d) { 

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

Aprovecha el hecho de que, en Java, truncar a rondas largas en cero.

+2

@TrueWill: Si está nítidamente en una función que se llama correctamente ... ¿Realmente importaría? Tal vez está siendo utilizado en un programa intensivo en matemáticas. – Sivvy

+0

Sería raro encontrar una manera significativamente más rápida de hacer algo para un método que ha existido desde 1.0 mientras mantiene el 100% de consistencia con el método original. – TofuBeer

+0

Absolutamente es una micro-optimización, y en un sentido local valió la pena. - pero estos no son recomendados para uso general. – mrjbq7

Respuesta

15

Existen algunos special cases que maneja el método integrado, que su código no maneja. A partir de la documentación:

  • Si el argumento es NaN, el resultado es 0.
  • Si el argumento es infinito negativo o cualquier valor menor o igual al valor de Integer.MIN_VALUE, el resultado es igual al valor de Integer.MIN_VALUE.
  • Si el argumento es infinito positivo o cualquier valor mayor que o igual al valor de Integer.MAX_VALUE, el resultado es igual al valor de Integer.MAX_VALUE.
5

Sí; no estás contabilizando underflow o overflow. Pragmáticamente hablando, esto puede no importar para su aplicación.

3

He estado probando esto, y hay un inconveniente potencial clave que aún no se ha descrito aquí: Está cambiando el método rounding tie-breaking.

Math.round() implementa la regla "round half up", mientras que su método round() implementa la regla "round half away from zero".

Por ejemplo:

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

Esto puede o no ser un problema para usted, pero usted debe entender que el método anterior es no es un reemplazo directo para Math.round(), incluso después de las consideraciones de NaN e infinito ya delineadas.

Otra cuestión relevante: Rounding negative numbers in Java

En cuanto al rendimiento, no hay duda de que el método anterior es significativamente más rápido que Math.round() - se ejecuta en aproximadamente el 35% del tiempo para los valores positivos y negativos generados al azar. Esto puede ser una optimización que vale la pena cuando se llama a este método en un ciclo cerrado. Es aún mejor (25% del tiempo de ejecución) cuando se le dan solo valores positivos, posiblemente debido a que la CPU usa branch prediction.

Math.round() finalmente se implementa mediante una llamada JNI nativa, que puede ser la causa de la diferencia de rendimiento. This Sun/Oracle bug sugiere que puede haber una versión pura de Java en j6u22, pero no puedo ver dónde, y de hecho Math.round() en j6u23 funciona de manera similar a j6u16 en mis pruebas. No he probado en otras versiones.

Cuestiones relacionadas