# Working with floating point parameters in an integer world

We live in an analog world (Do wereally? I'll let you ponder that question on your own time! ).But the most accurate means to correctly represent the continuousanalog world in software is to use floating point values.

That's great if you have a budget that can support having anexternal floating point processor or your software processing timerequirements are flexible enough that you can implement the floatingpoint arithmetic in software. For the rest of us we have to shave offsome of the precision of the floating point value and stuff it into ascaled fix point data type.

There are several ways for handling floating point parameters withinfixed point processors. One method is to use define them as a macrowith the scaling embedded into the definition.

#define AccelDueToGravity (((9.80665 *

The value for Scaler istypically a power of 2 since integerprocessors like powers of 2 arithmetic. The addition of the 0.5 valueforces the truncation of the number to mimic a round up-down function.Defining the parameter in this manner is fine if the parameter scalaris the identical throughout the code.

One drawback is that in order to determine the scaling of

When working with a fixed point integer processor I have found thefollowing definitions for implementing scalar and fixed pointadjustment macros useful. These eliminate the need for using “magicnumbers” in equations or for defining the numbers explicitly.

Additionally, you get the advantage that the expression iscalculated in the highest numerical precision of the compiler(typically as float or double), scaled to the specified LSB, rounded tothe nearest integer and finally then cast to “type”.

The following are macros that can be used for explicit pre-processconstant calculations. The LSB must be -31< LSB <31. The macroname is derived from Scale 2 (p)os or (n)eg X which translateslinguistically to scale is 2 to the power of positive or negative nwhere n is a numeric value. Below is an example of some of themacrodefinitionscentered on 2^{0} .

#define S2p6 (x,t) ((t)((x)*

#define S2p5 (x,t) ((t)((x)*

#define S2p4 (x,t) ((t)((x)*

#define S2p3 (x,t) ((t)((x)*

#define S2p2 (x,t) ((t)((x)*

#define S2p1 (x,t) ((t)((x)*

#define

#define

#define

#define S2n2 (x,t) ((t)((x)/

#define

#define S2n4 (x,t) ((t)((x)/

#define S2n5 (x,t) ((t)((x)/

#define S2n6 (x,t) ((t)((x)/

The value for x is the number being scaled and

There are times in equations that you need to adjust fixed pointposition. This is usually done to convert the final result to adifferent power of 2 or to match the fixed point of intermediateresults. As a basic example consider the following equation.

x = y + z;

In fixed point math it is logical that y and z are scaled to thesame power of 2 in order for the addition to make any sense. If y wasscaled to 2^{4} and z is scaled to 2^{10} , theresultant x will contain a number. But what is the resultant scalar? Itreally doesn't make sense unless you intentionally coded the equationthis way for job security. Bravoway to keep the jobs at home.

What I would do is to raise thescalar power of x to match that of the value of y, execute the equationand then adjust the scalar value to the required resultant scalar. WhatI just said is implemented by brute force in the following equation.

x = ( (y*(2^{6} )) + z ) / 2^{6}

The resultant scalar in this case the 2^{4} since thedivisor of 2^{6} is used to adjust the final value beforestuffing it into x. Although I did not show it here, there may be theneed to explicitly cast some of the intermediate values to make surethat they fit in the data type.

There is a better way. The solution of course is to use macros. Thefollowing are macros used for fixed point adjustment constantmultipliers. These change the power of the LSB of a variable.

EXAMPLE:SPApY(x) increases the power of the LSB of x by Y, SPAnY(x) decreasesthe power of the LSB of x by Y. These can be used on any numericaloperand type.

#define SAp4 (x) ((x)<<(

#define SAp3 (x) ((x)<<(

#define SAp2 (x) ((x)<<(

#define SAp1 (x) ((x)<<(

#define SAp0 (x) (x)

#define SAn0 (x) (x)

#define SAn1 (x) ((x)/

#define SAn2 (x) ((x)/

#define SAn3 (x) ((x)/

#define SAn4 (x) ((x)/

When used in an equation, once you get used to them, they make theequation easier to maintain. For example:

out =

The output scaling depends on the input scaling of in1 and in2. Whatcan be seen is that both parameters, param1 and param2 , are scaled to 2^{8} and cast to a signed int type.The final result is fixed point adjustedby 8 places to the right. If you have to write this equation as many doyou would get the following:

out = ((s32_t)in1 * (signedint )(param1*256)+(s32_t)in2 * (signedint )(param2*256))/256;

If written like this you may question the last numeric value of 256in the equation. Is it used as a fixed point adjustment or is it someother constant that is used in the equation? In this case, the 256values are magic numbers that litter the equation.

Using the macros for scaling takes some getting used to. But believe it or not, once you get the hang of it, it really does make the code easier to read and debug. You can recognize potential scaling errors without having to refer back to their definitions in external header file.

Dinu P. Madau is a SoftwareTechnical Fellow with Visteon. He has beendeveloping software for embedded systems for over 22 years. He has anMSE in computer and electrical control systems engineering from WayneState University and a BSE in computer engineering. Dinu has developedsafety-critical software for anti-lock brakes, vehicle stabilitycontrol, and suspension controls and is currently working in AdvancedCockpit Electronics and Driver Awareness Systems at Visteon developingsystems leveraging vision and radar technologies. He can be reached bye-mail at dmadau@visteon.com .