Q1.15 calculation

Started by Frank June 8, 2010
Hey guys,

I was wondering if you could help me optimize the code below (if possible):

R = (B*X);
tmp = (int16_t) (R>>15);
R = ((int32_t)tmp)+Z;
tmp = (int16_t)R;
R = (A*((int32_t)Y));
tmp2 = -(int16_t) (R>>15);
Rout=tmp+tmp2;

Rout is a SINT16 variable containing a Q1.15 value
A and B will be replaced by a number between -32768 and 32767
tmp and tmp2 are SINT16 variables; each containing a Q1.15 value
Z is a SINT32 variable containing a Q1.15 value
Y is a SINT16 variable containing a Q1.15 value
R is a SINT32 variable containing the result of an operation on two Q1.15 
values
X is a SINT32 variable containing a Q1.15 value

The above code looks too messy to me and I'm sure it can be optimized..Or 
maybe I am wrong?
Basically I just want to do some operations on Q1.15 numbers in a 32-bit 
cell.

Thank you in advance.


On Jun 8, 5:49&#2013266080;am, "Frank" <Fr...@invalidmail.com> wrote:
> > Basically I just want to do some operations on Q1.15 numbers in a 32-bit > cell.
so left-justify it and call it a Q1.31 number (where the 16 LSBs are zero). or right justify it and call it a Q16.16 number. the code looks like C where you've typedeffed some things. r b-j
On 06/08/2010 02:49 AM, Frank wrote:
> Hey guys, > > I was wondering if you could help me optimize the code below (if possible): > > R = (B*X); > tmp = (int16_t) (R>>15); > R = ((int32_t)tmp)+Z; > tmp = (int16_t)R; > R = (A*((int32_t)Y)); > tmp2 = -(int16_t) (R>>15); > Rout=tmp+tmp2; > > Rout is a SINT16 variable containing a Q1.15 value > A and B will be replaced by a number between -32768 and 32767 > tmp and tmp2 are SINT16 variables; each containing a Q1.15 value > Z is a SINT32 variable containing a Q1.15 value > Y is a SINT16 variable containing a Q1.15 value > R is a SINT32 variable containing the result of an operation on two > Q1.15 values > X is a SINT32 variable containing a Q1.15 value > > The above code looks too messy to me and I'm sure it can be > optimized..Or maybe I am wrong? > Basically I just want to do some operations on Q1.15 numbers in a 32-bit > cell. > > Thank you in advance. > >
Is this C? Do you have to stick to C? C really doesn't like Q1.anything -- it's only native fixed-point data type is integer, and it sticks to it like glue. You can do fractional fixed-point arithmetic _much_ faster in assembly -- if I'm working with a processor that doesn't have really fast floating point math then I'll write one -- it usually takes less than a day. See chapter 10 of my book -- http://www.wescottdesign.com/actfes/actfes.html -- it presents a Q1.31 library for the x86; if you can understand assembly language programming at all it should make clear what you need to do for Q1.whatever math on your processor. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com
> Is this C? Do you have to stick to C?
It is C and I have to stick to C.
>C really doesn't like Q1.anything -- it's only native fixed-point data type >is integer, and it sticks to it like glue. You can do fractional >fixed-point arithmetic _much_ faster in assembly -- if I'm working with a >processor that doesn't have really fast floating point math then I'll write >one -- it usually takes less than a day.
I was trying to do it with some defines like these: #define TOQ15(x32) (((int16_t)(x32>>15)) & (int16_t)(((x32>>31)<<15) | 65535)) The idea here is to shift a 32 bit value 15 bits down set bit 15 (the sign bit) correctly. #define MULXY(x16,y16) TOQ15(((int32_t)x16)*((int32_t)y16)) #define ADDXY(x16,y16) TOQ15(((int32_t)x16)+((int32_t)y16)) Some basic operations. However, there seems to be an error in the above defines...Have to debug it...
> See chapter 10 of my book -- > http://www.wescottdesign.com/actfes/actfes.html -- it presents a Q1.31 > library for the x86; if you can understand assembly language programming > at all it should make clear what you need to do for Q1.whatever math on > your processor.
Thank you. I will have a look at it (even though I still have to do the operations in C)....
>so left-justify it and call it a Q1.31 number (where the 16 LSBs are >zero). or right justify it and call it a Q16.16 number.
Yeah...i guess...but how does that answer my question? :o)
On 06/08/2010 09:55 AM, Frank wrote:
>> Is this C? Do you have to stick to C? > > It is C and I have to stick to C. > > >> C really doesn't like Q1.anything -- it's only native fixed-point data >> type is integer, and it sticks to it like glue. You can do fractional >> fixed-point arithmetic _much_ faster in assembly -- if I'm working >> with a processor that doesn't have really fast floating point math >> then I'll write one -- it usually takes less than a day. > > I was trying to do it with some defines like these: > > #define TOQ15(x32) (((int16_t)(x32>>15)) & (int16_t)(((x32>>31)<<15) | > 65535)) > > The idea here is to shift a 32 bit value 15 bits down set bit 15 (the > sign bit) correctly. > > #define MULXY(x16,y16) TOQ15(((int32_t)x16)*((int32_t)y16)) > #define ADDXY(x16,y16) TOQ15(((int32_t)x16)+((int32_t)y16)) > > Some basic operations. However, there seems to be an error in the above > defines...Have to debug it... > > >> See chapter 10 of my book -- >> http://www.wescottdesign.com/actfes/actfes.html -- it presents a Q1.31 >> library for the x86; if you can understand assembly language >> programming at all it should make clear what you need to do for >> Q1.whatever math on your processor. > > Thank you. I will have a look at it (even though I still have to do the > operations > in C)....
You can do it all in ANSI-C as well (and I show it in the book, although in the context of implementing Q1.31 using long long for arithmetic). I just make functions and a test framework rather than using defines -- even with function call overhead you'll still be way faster than floating point if the processor doesn't support it. You're on the right track. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com
> You're on the right track. >
Worked on it and came up with these macros: #define TOQ15(x32) (((x32>>31)<<15)|(x32&0x7fff)) #define MULXY(x32,y32) TOQ15(((x32*y32)>>15)) So when I execute this code: int16_t x1=-24576; // representing -0.75 in Q1.15 int16_t x2=4915; // representing 0.15 in Q1.15 int32_t acc=0; // expected 16bit signed integer value -3687 acc=MULXY(x1,x2); I get -3687 in acc..... Any comments ? Have I overlooked something?
On 06/08/2010 12:07 PM, Frank wrote:
> >> You're on the right track. >> > > Worked on it and came up with these macros: > > #define TOQ15(x32) (((x32>>31)<<15)|(x32&0x7fff)) > #define MULXY(x32,y32) TOQ15(((x32*y32)>>15)) > > So when I execute this code: > > int16_t x1=-24576; // representing -0.75 in Q1.15 > int16_t x2=4915; // representing 0.15 in Q1.15 > int32_t acc=0; // expected 16bit signed integer value -3687 > > acc=MULXY(x1,x2); > > I get -3687 in acc..... > > Any comments ? Have I overlooked something?
Test the hell out of it. In particular test it for x1 = x2 = 0x8000 -- that's an amazing number in two's complement, and it can cause much grief. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com
"Frank" <Frank@invalidmail.com> writes:

>> You're on the right track. >> > > Worked on it and came up with these macros: > > #define TOQ15(x32) (((x32>>31)<<15)|(x32&0x7fff)) > #define MULXY(x32,y32) TOQ15(((x32*y32)>>15)) > > So when I execute this code: > > int16_t x1=-24576; // representing -0.75 in Q1.15 > int16_t x2=4915; // representing 0.15 in Q1.15 > int32_t acc=0; // expected 16bit signed integer value -3687 > > acc=MULXY(x1,x2); > > I get -3687 in acc..... > > Any comments ? Have I overlooked something?
Hi Frank, You're making a mess! First note that the compiler promotes the 16x16 bit multiply to a 32-bit result in MULXY. Then note that shifting a 32-bit value right 31 bits makes the LSB of the result either 0 or 1. Since these are signed values, the compiler sign-extends the shift. Shifting 0 or 1 back left 15 bits gives you 0 or -32768, respectively. OR'ing that with the x32&0x7FFF buys you nothing. So all the work is really done in the argument to TOQ15, x32*y32 >> 15, which is the right way to multiply two Q1.15 numbers and get a Q17.15 result. -- Randy Yates % "So now it's getting late, Digital Signal Labs % and those who hesitate mailto://yates@ieee.org % got no one..." http://www.digitalsignallabs.com % 'Waterfall', *Face The Music*, ELO
Tim Wescott <tim@seemywebsite.now> writes:
> [...] > Is this C? Do you have to stick to C? C really doesn't like > Q1.anything -- it's only native fixed-point data type is integer, and > it sticks to it like glue.
Er, all fixed-point processing uses plain integer operations. Fixed-point is all in how you interpret things. There is nothing inherently "non-fixed-point" in C. C is just fine for fixed-point processing. -- Randy Yates % "Maybe one day I'll feel her cold embrace, Digital Signal Labs % and kiss her interface, mailto://yates@ieee.org % til then, I'll leave her alone." http://www.digitalsignallabs.com % 'Yours Truly, 2095', *Time*, ELO