BlackBerry Java: Arithmetic Comparisons

This investigation took me longer than I had hoped to get to a conclusion, mainly because the results I was getting weren’t matching my expectations.  I started off by comparing the speed of arithmetic calculations between the BlackBerry Java’s native float implementation and its static class implementation for fixed point math, Fixed32.

When first faced with the need to store fractional values, I gravitated towards the Fixed32 class for two reasons; the first being that I’ve always had to use a fixed point implementation when developing mobile application as floats and doubles are not usually available.  The second reason was that I believed the Fixed32 class existed for a reason, that reason being that the float implementation was so horribly slow that this additional fixed point implementation had to exist to compensate.

It turns out that the Fixed32 class is legacy code of the BlackBerry platform, implemented early on before floats and doubles could be properly supported.  And, the truth was that the float multiplication and division implementations are faster than the Fixed32 implementation’s, though float addition and substraction was still slower due to the fact that Fixed32 is developed to use the integer addition and subtraction operators with no other processing.

These were the preconceptions that I had when developing my own test.  The problem that was hanging me up was that I was seeing better performance out of the float’s add and subtract operators than the Fixed32’s use of the integer operators.  I couldn’t figure out how this could be.  Look how simple this code is, what could I be doing wrong?

public class TestConstants {
    // ...
    public final static int X_MUL_DIV_VALUE = Fixed32.parseFixed32("1.84");
}
 
public class Fixed32Add extends CodeBlock {
    // ...
    public void run() {
        int xResult = 0;
        for(int i = 0; i < TestConstants.NUM_OPERATIONS; i++) {
            xResult += TestConstants.ADD_VALUE_X;
        }
    }
}

So I decided to expand the test and cover arithmetic with all native numerical types, the additional types being byte, short, long, and double.  Once I did that, it became clear what the problem was.  Without Fixed32 being involved, the integer addition/subtraction operators were about 3 times faster than the floating point operator.

There was a sneaky little issue that is nearly impossible to see if you’re not looking for it.  Here’s the code change first:

public class TestConstants {
    // ...
    public final static int X_MUL_DIV_VALUE = Fixed32.parseFixed32("1.84");
}
 
public class Fixed32Add extends CodeBlock {
    // ...
    public void run() {
        int xResult = 0;
        int value = TestConstants.ADD_VALUE_X;
        for(int i = 0; i < TestConstants.NUM_OPERATIONS; i++) {
            xResult += value;
        }
    }
}

The compiler handles the final variables, replacing each reference to the final variable with the code on the right of the declaration, resulting in the parse function being called for every iteration of the loop.  As I said, sneaky.  It’s something to be aware of when declaring final variables.  If you have a native value, the inline processing performed on final variables can be quite beneficial.  However, with objects and function calls to generate the value of the final variable, it can result in additional processing  and memory that hides behind a mask that makes it hard to see.  Just keep it in mind.

Anyway, below are the result tables, one for each device (Curve, Bold and Storm, NUM_OPERATIONS = 5000).  As stated at the beginning, float multiplication/division is faster than Fixed32 multiplication/division.

BlackBerry Curve 8320

Variable Type Add/Sub (ms) Mult (ms) Div (ms)
Fixed32 204 1372 1788
float 700 548 1184
double 1104 824 4376
long 260 260 528
int 196 200 248
short 240 220 272
byte 220 232 272

BlackBerry Bold

Variable Type Add/Sub (ms) Mult (ms) Div (ms)
Fixed32 153 597 776
float 317 242 550
double 514 366 1931
long 114 117 225
int 96 90 114
short 102 102 125
byte 104 107 127

BlackBerry Storm

Variable Type Add/Sub (ms) Mult (ms) Div (ms)
Fixed32 135 863 1089
float 379 293 694
double 599 420 2424
long 150 155 284
int 131 137 162
short 150 150 170
byte 146 144 172

To conclude, make conscious choices about which variable types are right for your arithmetic needs.  If you plan to do a lot of addition and subtraction with fractional outcomes, the Fixed32 class may still be your best bet (if accuracy is not all that important).  However, you’re better off using native floats with multiplication and division. Finally, be careful with final variables.  They’re built in a way to cause problems and hide inefficiencies if care isn’t taken.

1 Comment

  1. BlackBerry Arithmetic Performance - Thinking BlackBerry Says:

    [...] (see next post) and wondering about performance of double/float/Fixed32 arithmetic I came across this post on Blurry Words, which is exactly what I was looking [...]

Leave a comment