简体   繁体   中英

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 ?

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.

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.
  • 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 .
  • 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 .

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.

For example:

  • Math.round(-0.5d) => 0L
  • 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.

Another relevant question: Rounding negative numbers in 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. 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 .

Math.round() is ultimately implemented by a native JNI call, which might be the cause of the performance difference. 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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