# Q1.15 calculation

Started by 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.

```
```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.
>
>
>
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

--
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))

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

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))
>
> 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

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
```