Expensive to cast float to double and vice versa?

Hi,



I have a situation where I want to perform some calculations using double instead of float (since float's precision is not that good).  Is it expensive to cast back and forth between the two?  Do you all have any other recommendations? 



Thanks



Dana

It's pretty cheap, to keep it simple, let's say about the same as just another simple math function.


Actually, in my experience, "downcasting" is even cheaper than the cheapest math functions. At least, this is what I observed trying to improve performance of a custom dynamic terrain block (some Math.floor() is going on in there when determining the corner vertices for height interpolation in getHeight() in TerrainBlock). Casting to int is 6-7 times faster than using the floor function on my machines (Linux and WinXP on Intel and AMD, in any combination). I was going to suggest that for FastMath.floor(), but never got around to it. Of course, there might be important reasons to use Math.floor() instead that I am not aware of?

1 Like

It shouldn't matter in our case… Did you test if it was faster by creating a new method, or just by replacing the method call with the cast?



I should have said math operator ( + / - * ) instead of function, since that's what I meant… but like I said, to keep it simple… nothing to worry about.

Well, here's my test:

public class TestFloorSpeed {
    public static void main(String[] args) {
        final int repetitions = 100;
        final float testValue = (float) Math.E;
        long before;
       
        before = System.nanoTime();
        for(int i=0; i<repetitions; i++){
            float f = floorMath(testValue);
        }
        float nanosMath = System.nanoTime() - before;
       
        before = System.nanoTime();
        for(int i=0; i<repetitions; i++){
            float f = floorCast(testValue);
        }
        float nanosCast = System.nanoTime() - before;
       
        System.out.println("Math method:     "+nanosMath/(double)repetitions+" nanoseconds average.");
        System.out.println("Cast method:     "+nanosCast/(double)repetitions+" nanoseconds average.");
        System.out.println("Ratio Math/Cast: "+nanosMath/nanosCast);
        System.out.println("Repetitions:  "+repetitions);
    }
   
    public static float floorMath(float fValue) {
        return (float) Math.floor(fValue);
    }
    public static float floorCast(float fValue) {
        return (float) (int) (fValue);
    }
}


I experimented with different testValues first, but it didn't seem to have any impact. Different repetition times, however, changed the result notifiably. Here's my results on a Centrino Duo 2x980MHz running Sun's Java 1.5 on WinXP, compiled with debug option on:








repetitions ratio
100 7.44228
1000 3.0771024
10000 1.209835
100000 6.4843884
1000000 5.340595
10000000 5.1416383

I think it's quite interesting to see how the ratio drops at 10000 repetitions (of course I ran each test several times and chose a rather representative result for the table above). If anybody has any ideas about why that might be, I'd love to hear them!

You should "warm up" the VM first… to give it time to compile, inline, etc.


 for(int i=0; i<100000; i++){
            float f1 = floorMath(testValue);
            float f2 = floorCast(testValue);
        }


And maybe a sleep after that.. this makes the results more consistent.

I guess it's JNI overhead, the casting to double.. and accomodating NaN maybe? Sounds like somthing we could put in FastMath.. however, try testing this too :)


for(int i=0; i<repetitions; i++){
            float f =  (float) (int) testValue;
        }

Here's my results with llama's suggestions applied:





Math  method:    75.0103168 nanoseconds average.

Cast  method:    19.5240736 nanoseconds average.

Direct cast :    4.0893744 nanoseconds average.





The VM was warmed up with the suggested loop, and a 100ms sleep after that. "Direct cast" is llama's "direct" version of the cast, without a method wrapped around it, and repetitions was 10000000 for this test.

So you can see my point… I don't think we need a FastMath method, but that doesn't mean we can't optimize TerrainBlock…

and beware of the differences between casting and floor() for negative numbers…