The code is ~9x faster than Math.floor(). Replacing the doubles with floats makes it faster, but the results are rather... random, so don't.
public class FastMath { private static final int BIG_ENOUGH_INT = 16 * 1024; private static final double BIG_ENOUGH_FLOOR = BIG_ENOUGH_INT + 0.0000; private static final double BIG_ENOUGH_ROUND = BIG_ENOUGH_INT + 0.5000; private static final double BIG_ENOUGH_CEIL = BIG_ENOUGH_INT + 0.9999; public static int fastFloor(float x) { return (int) (x + BIG_ENOUGH_FLOOR) - BIG_ENOUGH_INT; } public static int fastRound(float x) { return (int) (x + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT; } public static int fastCeil(float x) { return (int) (x + BIG_ENOUGH_CEIL) - BIG_ENOUGH_INT; } }
Clever code, very useful. Thanks for posting.
ReplyDeleteKeith
I'll append to this as I found this to be the fastest version overall. I was using doubles so the speed improvements are different, but I tried 4 different approaches.
ReplyDeletedouble val
Standard Floor: Math.floor(val)
Bound checking: val < 0 ? ((int)val) - 1 : (int)val
Adding/Subtracting (Riven method): ((int)(val + x)) - x
Raw casting (flawed): (int)val
The results, running many loops and first burning it in before timing so it's not a hotspot artifact.
Standard Floor: 30.41 seconds
Bound checking: 14.26 seconds
Adding/Subtracting: 13.24 seconds
Raw casting (flawed): 9.02 seconds
If you're pulling the values from arrays and storing them in arrays(my case), the adding subtracting performs slightly better than the bound checking as you don't have to create a temporary variable/make multiple array access.
(Array Access times)
Standard Floor: 37.46 seconds
Bound checking: 23.01 seconds
Adding/Subtracting: 17.63 seconds
Raw casting (flawed): 12.33 seconds