A project a couple of colleagues are working on requires them to wring every last little bit of speed out of their code. The code is fairly maths intensive and the data given to them is unsigned bytes. Initially the data was converted to shorts as shorts occupy less space in memory and the data is moderately large. During a performance review it was noted that a lot of the algorithms used ints and therefore there was quite a bit of implicit and explicit casting going on. We wondered if this casting was slowing things down. I suspected casting between privative types would be fairly cheap but a little bit of code was needed to prove it.

package example;

import java.text.DecimalFormat;

public class PrimativeCast {

   
private int loopCount = 1000000000;
   
   
public PrimativeCast() {
       
for( int i = 0, n = 1; i < n; i++ )
        {
           
System.out.println( "--------------------------------" );
            System.out.println
( "Test Run: " + i );
            System.out.println
( "--------------------------------" );
           
            intControl
();
            shortControl
();
            castIntToShort
();
            castShortToInt
();
           
long mb = multiplyBytes();
           
long ms = multiplyShorts();
           
long mi = multiplyInts();
           
long ml = multiplyLongs();
           
long mf = multiplyFloats();
           
long md = multiplyDoubles();
           
            DecimalFormat format =
new DecimalFormat( "0.00" );
            System.out.println
( "--- the following figures use int as their reference ---" );
            System.out.println
( "multiply byte time - multiply int time = " + ( mb - mi ) + "ms" );
            System.out.println
( "byte execution speed compared to int: " + format.format( ( 100.0 / mi ) * mb ) + "%" );           
            System.out.println
( "multiply short time - multiply int time = " + ( ms - mi ) + "ms" );
            System.out.println
( "short execution speed compared to int: " + format.format( ( 100.0 / mi ) * ms ) + "%" );
            System.out.println
( "multiply long time - multiply int time = " + ( ml - mi ) + "ms" );
            System.out.println
( "long execution speed compared to int: " + format.format( ( 100.0 / mi ) * ml ) + "%" );
           
            System.out.println
( "--- the following figures use float as their reference ---" );
            System.out.println
( "multiply float time - multiply double time = " + ( md - mf ) + "ms" );
            System.out.println
( "double execution speed compared to float: " + format.format( ( 100.0 / mf ) * md ) + "%" );
       
}
    }
   
   
private int intControl() {
       
int testInt = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
int result = testInt;
            testInt++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("int to int (control): " + duration);
       
       
return duration;
   
}
   
   
private int shortControl() {
       
short testShort = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
short result = (short)testShort;
            testShort++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("short to short (control): " + duration);
       
       
return duration;
   
}
   
   
private int castIntToShort() {
       
int testInt = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
short result = (short)testInt;
            testInt++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("int to short (simple cast): " + duration);
       
       
return duration;
   
}
   
   
private int castShortToInt() {
       
short testShort = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
int result = testShort;
            testShort++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("short to int (simple automatic cast): " + duration);
       
       
return duration;
   
}
   
   
private int multiplyBytes() {
       
byte test = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
byte result = (byte)(test * test);
            test++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("multiplying bytes: " + duration );
       
       
return duration;
   
}
   
   
private int multiplyShorts() {
       
short test = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
short result = (short)(test * test);
            test++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("multiplying shorts: " + duration );
       
       
return duration;
   
}
   
   
private int multiplyInts() {
       
int testInt = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
int result = testInt * testInt;
            testInt++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("multiplying ints: " + duration );
       
       
return duration;
   
}
   
   
private int multiplyLongs() {
       
long test = 0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
long result = test * test;
            test++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("multiplying longs: " + duration );
       
       
return duration;
   
}
   
   
private int multiplyFloats() {
       
float test = 0.0f;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
float result = test * test;
            test++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("multiplying floats: " + duration );
       
       
return duration;
   
}
   
   
private int multiplyDoubles() {
       
double test = 0.0;
       
       
long start = System.currentTimeMillis();
       
for (int i = 0, n = loopCount; i < n; i++) {
           
double result = test * test;
            test++;
            result++;
       
}
       
long end = System.currentTimeMillis();
       
int duration = (int)(end - start);
        System.out.println
("multiplying doubles: " + duration );
       
       
return duration;
   
}

   
/**
     *
@param args
     */
   
public static void main(String[] args) {
       
new PrimativeCast();
   
}

}

The code above runs a number of tests converting shorts to int and vice versa. It them multiplies the various privative types. As suspected ints are the fastest integer (non-floating point) type number but surprisingly there is very little, if any, difference between floats and doubles. I suspect that the reason for the better speed of ints over the other privative types is better optimization in the processor although I'm open to other suggestions. An example run of the code can be seen below:

--------------------------------
Test Run: 0
--------------------------------
int to int (control): 2747
short to short (control): 2747
int to short (simple cast): 3029
short to int (simple automatic cast): 3137
multiplying bytes: 5120
multiplying shorts: 4277
multiplying ints: 3434
multiplying longs: 8554
multiplying floats: 9194
multiplying doubles: 9210
--- the following figures use int as their reference ---
multiply byte time - multiply int time = 1686ms
byte execution speed compared to int: 149.10%
multiply short time - multiply int time = 843ms
short execution speed compared to int: 124.55%
multiply long time - multiply int time = 5120ms
long execution speed compared to int: 249.10%
--- the following figures use float as their reference ---
multiply float time - multiply double time = -16ms
double execution speed compared to float: 100.17%

You can see here that ints are 30% faster than shorts so it's well worth the effort of converting data from shorts to ints up front if you are doing a lot of maths. Longs take more than twice as long to process than int which isn't surprising as they are handled as two words on 32 bit machines. I would be interested to see how this changes on a 64bit machine running a 64bit VM - as far as I understand it the execution speed of longs should drop to the same as ints.