Fixed Point Math on Propeller
Sal Ammoniac
Posts: 213
I'm trying to avoid the use of floating point math in my weather data logging application to keep execution time to a minumum. One of the things that's got me stumped is how to deal with the fact that all 32-bit numbers on the prop are signed.
Here's a simple example: one of my sensors returns temperature in celsius and I'd like to convert it to Fahrenheit. The formula is simple: Tf = Tc * 1.8 + 32.
Normally I'd use the multiply-high operator (**) as follows:
Tc * 1.8 -->· Tc + Tc**B where B is Int(0.8 * $ffff_ffff) = 3_435_973_836
Since I want to keep two digits to the right of the decimal, I multiply Tc by 100 first, therefore
Tf = (Tc * 100) + (Tc * 100) ** 3_435_973_836 + 3200
As an example, if Tc = 42.2, then
Tf = 4220 + 4220**3_435_973_836· + 3200
The problem arises when the ** operator treats 3_435_973_836·as a negative number, since its high bit is set. This seems to be different from how ** behaves on the Basic Stamp (aside from the fact that ** works with 16-bit numbers on the BS rather than 32 bits as on the propeller).
Is there a graceful way to work around this issue and still use ** in this way?
(As an aside, when I replaced the floating point calls (FloatMath) in my application with fixed point, the computation time to calculate barometric pressure and temperature from the raw sensor output fell from 4.3 msec to 91 usec, which is a worthwhile improvement.)·
Here's a simple example: one of my sensors returns temperature in celsius and I'd like to convert it to Fahrenheit. The formula is simple: Tf = Tc * 1.8 + 32.
Normally I'd use the multiply-high operator (**) as follows:
Tc * 1.8 -->· Tc + Tc**B where B is Int(0.8 * $ffff_ffff) = 3_435_973_836
Since I want to keep two digits to the right of the decimal, I multiply Tc by 100 first, therefore
Tf = (Tc * 100) + (Tc * 100) ** 3_435_973_836 + 3200
As an example, if Tc = 42.2, then
Tf = 4220 + 4220**3_435_973_836· + 3200
The problem arises when the ** operator treats 3_435_973_836·as a negative number, since its high bit is set. This seems to be different from how ** behaves on the Basic Stamp (aside from the fact that ** works with 16-bit numbers on the BS rather than 32 bits as on the propeller).
Is there a graceful way to work around this issue and still use ** in this way?
(As an aside, when I replaced the floating point calls (FloatMath) in my application with fixed point, the computation time to calculate barometric pressure and temperature from the raw sensor output fell from 4.3 msec to 91 usec, which is a worthwhile improvement.)·
Comments
The conversion is: Tf = (9/5) * Tc + 32
If both Tf and Tc are scaled by 100, you'd use:
Tf := (Tc * 9) / 5 + 3200
Multiplication and division in fixed point arithmetic don't use the scale factor. You've got plenty of space in a 32 bit word to handle the multiplication and division.