Understanding Floating Point Math Under Palm OS


When I first started to play around with Palm OS programming, I was surprised that floating point support is highly restricted, supporting only basic math. Even though I understood that, due to obvious system restrictions, a reasonable part of the standard C library was not implemented as either a part of OS or a separate library, my senses have not afforded it quietly. Initially, Palm OS has supported only 16-bit precision math; then, NewFloatMgr.lib and fp68k.lib came out for 32- and 64-bit floating point arithmetic. There also was MathLib for more complicated functions that you usually find inside math.h of the standard C library.

Fortunately, the latest versions of Palm OS made a step forward. You do not need to explicitly link any additional libs for basic math. Moreover, programs such as CodeWarrior produce the necessary code to use MathLib via Project Wizard. Palm OS Developer Suite (PODS) has exposed new APIs for Palm OS Garnet and Cobalt. Nevertheless, you still can’t use the %f-like style to format a floating point value to its string reprpesentation…

Basic Types: Getting Started

The good news is that you can freely use standard C types: double and float. Float is a 32-bit value, whereas double is a 64-bit length. The compiler will automatically generate the appropriate calls to the required libs. So, the following code will work just fine:

double d1, d2, d3;
d1 = 1.205;
d2 = 2.32;
d3 = d1 / d2;

In addition, the MathLib library also operates with doubles as function arguments and return values. Hence, if you need to carry out some floating point calculations without any conversions to other types, you’re perfectly set up. In reality, you will want to manipulate these simple decimal numbers and get additional information about them. I believe this article will help you to understand which options you have with floating point math under Palm OS.

You can start exploring Palm OS Float Manager by taking a look at its data structures:

typedef Int32 FlpFloat;
typedef _sfpe_64_bits FlpDouble;
typedef _sfpe_64_bits FlpLongDouble;

typedef struct {
   UInt32  sign : 1;
   Int32   exp  : 11;
   UInt32  manH : 20;
   UInt32  manL;
} FlpDoubleBits;            // for accessing specific fields

typedef union {
   double         d;        // for easy assignment of values
   FlpDouble      fd;       // for calling New Floating point
                            // manager routines
   UInt32         ul[2];    // for accessing upper and lower longs
   FlpDoubleBits  fdb;      // for accessing specific fields
} FlpCompDouble;

typedef union {
   float     f;             // for easy assignment of values
   FlpFloat  ff;            // for calling New Floating point
                            // manager routines
   UInt32    ul;            // for accessing bits of the float
} FlpCompFloat;

The preceding structures give you a convenient mechanism for transparent manipulations over floating point data. For instance, you can assign double values to a variable of FlpCompDouble type, send it to Float Manager functions, get access to specific bits, and so forth. Later in this article, you’ll use them a lot. The tiny code snippet below just shows the common manner:

double d1, d2, d3;
char szBuffer[32];
FlpCompDouble fd;

d1 = 1.205;
d2 = 2.32;
d3 = d1 / d2;

fd.d = d3;
FlpFToA(fd.fd, szBuffer);

Running Simple Arithmetic Operations

After basic data types are defined, you are ready to investigate what functions Palm OS Float Manager supports. First, there are several useful macros that you can use to manipulate a variable of FlpCompDouble type:

#define FlpGetSign(x)      ((__HI32(x) & 0x80000000) != 0)
#define FlpIsZero(x)       ( ((__HI32(x) & 0x7fffffff) |
                           (__LO32(x))) == 0)

#define FlpGetExponent(x)  (((__HI32(x) & 0x7ff00000) >> 20) - 1023)

#define FlpNegate(x)       (((FlpCompDouble *)&x)->ul[__HIX]
                                              ^= 0x80000000)
#define FlpSetNegative(x)  (((FlpCompDouble *)&x)->ul[__HIX] |
                                              = 0x80000000)
#define FlpSetPositive(x)  (((FlpCompDouble *)&x)->ul[__HIX] &
                                              = ~0x80000000)

With these macros, you can conduct sign and zero checks, set or reset the variable’s sign, and so forth. The next group of functions is quite standard:

Err        FlpBase10Info(FlpDouble a, UInt32 *mantissaP,
                         Int16 *exponentP, Int16 *signP)
Err        FlpFToA(FlpDouble a, Char *s)
FlpDouble  FlpAToF(const Char *s)
FlpDouble  FlpCorrectedAdd(FlpDouble firstOperand,
                           FlpDouble secondOperand, Int16 howAccurate)
FlpDouble  FlpCorrectedSub(FlpDouble firstOperand,
                           FlpDouble secondOperand, Int16 howAccurate)

FlpBase10Info returns detailed info about a floating number. Note here that, as it’s referred to in the SDK documentation, FlpBase10Info reports that zero is a “negative” value. To avoid mistakes, you should check the sign and mantissa instead of just the sign.

FlpFToA and FlpAToF make conversions between decimal and string representations of a floating point value. When you convert such a number to a string, the output buffer will be filled by text in a form such as “5.1939655e-01”. That is not always an acceptable result. In many cases, you will want to produce more attractive formats; for example, “5.20” and so forth. Unfortunately, Palm OS still has no support for ‘%f’-like formatting. Nevertheless, you can find useful implementations of good workarounds all over the Web; for example, here. Well, based on the appropriate example, you may always enjoy writing your own formatting function…

The two last functions enable you to obtain the result of addition to subtraction with desired accuracy. When operands are similar, the result can be very small. In fact, it possibly should be zero if the result’s exponent and that of the operands is close to the number of significant bits expressible by the mantissa. Due to difficulty in representing a fractional part as a binary value, after several calculations errors can appear in significant bits. The howAccurate parameter gives you a control over forcing the result to be zero. Supplying 0 here will produce a default level of accuracy, which is equivalent to howAccurate = 48 (bits).

More by Author

Previous article
Next article

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read