更快地实现Math.round?

时间:2009-11-17 18:13:49

标签: java math rounding micro-optimization

此代码是否存在任何缺陷,这似乎是java.lang.Math.round的更快(且更正确)的版本?

public static long round(double d) {

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

它充分利用了这样一个事实:在Java中,截断为长轮到零。

3 个答案:

答案 0 :(得分:15)

内置方法处理的内容有special cases,代码无法处理。来自文档:

  • 如果参数为NaN,则结果为0.
  • 如果参数为负无穷大或任何小于或等于Integer.MIN_VALUE的值,则结果等于Integer.MIN_VALUE的值。
  • 如果参数为正无穷大或任何大于或的值 等于Integer.MAX_VALUE的值,结果等于Integer.MAX_VALUE的值。

答案 1 :(得分:5)

是;你没有考虑下溢或溢出。从语用上讲,这可能与您的申请无关。

答案 2 :(得分:3)

我一直在测试这个,有一个关键的潜在缺点,这里还没有描述:你正在改变rounding tie-breaking方法。

Math.round()实现了“round half up”规则,而你的round()方法实现了“从零开始的一半”规则。

例如:

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

这对您来说可能是一个问题,也可能不是问题,但是您应该理解上述方法不是Math.round()的替代方法,即使已经概述了NaN和无穷大的考虑因素。

另一个相关问题:Rounding negative numbers in Java

至于性能,毫无疑问,上述方法明显快于Math.round() - 它在大约35%的时间内运行,随机生成的正负值。在紧密循环中调用此方法时,这可能是一个值得优化的。当仅给出正值时,它甚至更好(运行时的25%),可能是因为CPU使用branch prediction

Math.round()最终由本机JNI调用实现,这可能是性能差异的原因。 This Sun/Oracle bug表明在j6u22中可能存在纯Java版本,但是我无法看到j6u23中的Math.round()在我的测试中与j6u16类似地执行。我没有在其他版本上测试过。