简体   繁体   English

更快地实现Math.round?

[英]Faster implementation of Math.round?

Are there any drawbacks to this code, which appears to be a faster (and correct) version of java.lang.Math.round ? 这段代码是否有任何缺点,这似乎是java.lang.Math.round的更快(和更正确)的版本?

public static long round(double d) {

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

It takes advantage of the fact that, in Java, truncating to long rounds in to zero. 它利用了这样一个事实,即在Java中,截断到长轮到零。

There are some special cases which the built in method handles, which your code does not handle. 内置方法处理的一些特殊情况 ,代码无法处理。 From the documentation: 从文档:

  • If the argument is NaN , the result is 0. 如果参数为NaN ,则结果为0。
  • If the argument is negative infinity or any value less than or equal to the value of Integer.MIN_VALUE , the result is equal to the value of Integer.MIN_VALUE . 如果参数为负无穷大或任何小于或等于Integer.MIN_VALUE值的值,则结果等于Integer.MIN_VALUE的值。
  • If the argument is positive infinity or any value greater than or equal to the value of Integer.MAX_VALUE , the result is equal to the value of Integer.MAX_VALUE . 如果参数为正无穷大或任何大于或等于Integer.MAX_VALUE值的值,则结果等于Integer.MAX_VALUE的值。

I've been testing this, and there is one key potential drawback which has not yet been described here: You are changing the rounding tie-breaking method. 我一直在测试这个,有一个关键的潜在缺点,这里还没有描述:你正在改变舍入打破平局的方法。

Math.round() implements the "round half up" rule, whereas your round() method implements the "round half away from zero" rule. Math.round()实现了“round half up”规则,而round()方法实现了“round round of zero”规则。

For example: 例如:

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

This may or may not be a problem for you, but you should understand that the above method is not a drop-in replacement for Math.round() , even after the NaN and infinity considerations already outlined. 这对您来说可能是也可能不是问题,但您应该理解上述方法不是Math.round()替代品,即使已经概述了NaN和无穷大的考虑因素。

Another relevant question: Rounding negative numbers in Java 另一个相关问题: 在Java中舍入负数

As for the performance, there is no doubt that the above method is significantly faster than Math.round() - it runs in about 35% of the time for randomly generated positive and negative values. 至于性能,毫无疑问,上述方法明显快于Math.round() - 它在大约35%的时间内运行,用于随机生成的正值和负值。 This can be a worthwhile optimisation when calling this method in a tight loop. 在紧密循环中调用此方法时,这可能是一个值得优化的。 It's even better (25% of the runtime) when given only positive values, possibly because of the CPU using branch prediction . 当仅给出正值时,它甚至更好(运行时的25%),可能是因为CPU使用分支预测

Math.round() is ultimately implemented by a native JNI call, which might be the cause of the performance difference. Math.round()最终由本机JNI调用实现,这可能是性能差异的原因。 This Sun/Oracle bug suggests there might be pure-Java version in j6u22, but I can't see where, and indeed Math.round() in j6u23 performs similarly to j6u16 in my tests. 这个Sun / Oracle漏洞表明在j6u22中可能有纯Java版本,但是我无法看到j6u23中的Math.round()在我的测试中与j6u16类似。 I have not tested on other versions. 我没有在其他版本上测试过。

Yes; 是; you're not accounting for underflow or overflow. 你没有考虑下溢或溢出。 Pragmatically speaking, this may not matter for your application. 从语用上讲,这对您的申请可能无关紧要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM