## Fixed Point Maths

6 posts / 0 new
Author
Message

Ok, this is maiking my head hurt. To save on floating-point-maths libraries, i've written my own fixed-point maths routines.

Say I enter in 1.5 into my keypad. To convert this with my routine, first I store 1 into a unsigned long, then I shift it two bytes and OR it with the 5:

000000000000000000010000010100000000

I can then later extract the 1 by getting the upper int, adding a decimal point onto my LCD and then adding the lower int (with appropriate itoa conversion function, of course).

The problem comes later. Say I have another number, like 150. I shift this two bytes too:

000000000000100101100000000000000000

Ok, that's the easy bit. Now, I need to divide my first number by four and subtract it from the first number. How the hell do I do this? I've been pondering it all afternoon, and have tried all sorts of convulted routines which waste a lot of time and flash space. How do I turn my first unsigned long into the equivelent of 1.5 which I can shift right twice to divide it b four to get:

000000000000000000011000000000000000

All help appreciated. I think i'm gonna have to bite the bullet and just use floating point maths routines :(.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Firstly, decide how many decimal places you want. Say you want 2, this means the integer portion is multiplied by 100 (10^2). The value of 1.5 is stored as 150. So to display it, do the itoa and then massage the string and put in the decimal point or divide up the variable like this:
the fractional part is frac = var % 100;
the integer part is intgr = var / 100;

You should've listened in maths when the teacher was talking about indices. I think I learnt this in year 10.

Your mistake was working in two number bases - doing bit shifting is base 2, whereas you're output (decimal) is base 10.

Hi.

it depends on your range.
If your resolution is enough with 1/65536 then you can handle this with two bytes (right of the decimal point) and the upper limit is 65535 then you need two (integer) bytes on the left side of the decimal point:

XXXXXXXX XXXXXXXX . XXXXXXXX XXXXXXXX
range is: 0 ... 0.00001525 .... 65535.999985

150 (dec) is then
00000000 10010110 . 00000000 00000000

1.5 is
00000000 00000001 . 10000000 00000000

subtract the values as if they where integers (assembler with: SUB-SBC-SBC-SBC)

devide it by 4 with shifting 2 bit to the right. (assembler: LSR-ROR-ROR-ROR)

similar can be done with signed values.

Klaus
********************************
Look at: www.megausb.de (German)
********************************

You should use some conversion functions to convert between the formats.
Like this one, that will convert a float to a fixed value :

#define DOUBLE_TO_FIXED(x) ((LONG) ((x) * 65536.0 + 0.5))
It is using 16.16 fixed point math, which is pretty common, and which gives good resolution.

I've attached two files with fixedpoint vector math, which I used a long time ago. You should be able to get some more ideas from there.

## Attachment(s): Fixed point vector math Header file for fixed point vector math

/Jesper
http://www.yampp.com
The quick black AVR jumped over the lazy PIC.
What boots up, must come down.

As usual, you guys rule. My problem was that I was thinking of binary fixed point maths, where you shift the data left to preserve more its, while I should have been thinking in conventional maths - indicies as Kartman said (sadly, I explained this correctly only last week, yet it slipped my mind ;)).

Thanks!
- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!