Continue to Site

[SOLVED]fixed point arithmetic in c

Status
Not open for further replies.

curious_mind

Full Member level 4
I am looking for a C code to perform Q15 addition, subtraction, multiplication, division , sine(x) and cosine(x). Can anybody provide good reference that works?

I'd start with searching "fixed point [add/subtract/mult]" etc. There are different options for each. Saying its fixed point also doesn't tell us if you have hardware multiply/divide support though I'll assume no.

Understand that a lot of it comes down to designing your algorithms around the limitations. For example if you don't have hardware multiply then plan around doing power of 2 shift divides with << and >>. Sin and cos are typically implemented with a look-up-table.

short a, b, c;
Addition: c = a + b;
Subtraction: c = a - b;
Multiplication: c = (short)((a * (long)b) >> 15);

how to take care of oveflow for addition and subtraction? c should be short or long?

Last edited:

how to take care of oveflow for addition and subtraction? c should be short or long?

You'd need to use long - or an MCU that supports saturating fixed-point types.

Hi

I am considering 2's complement unsigned data that varies from 0 to 65535. What would happen if I would add 10 with 32767. The result is a negative number. How would I guard this?

Your specification is rather shallow. You say "take care of overflow". How? Saturate? Generate an exception?

In case, additional code is required. The CPU may be already able to detect a signed integer overflow. Or you detect it by monitoring the arguments and result signs.

I came up with the following custom c code. Your view on this will be helpful
Code:
unsigned int add (unsigned int a ,unsigned  int b)
{
unsigned int res;
unsigned long tmp;
tmp=a+b;
if((a<=32767) && (b<=32767))   // both numbers are positive
{
if (tmp>32767)
{
res=32767;
}
}

else if((a>32767) && (b>32767))  // both numbers are negative
{
if (tmp>32768)
{
res=32768;
}
}
else
{
res=tmp & 0xffff;
}
return(res);
}

unsigned int sub (unsigned int a ,unsigned  int b)
{
unsigned int res;
unsigned long tmp;

if((a<=32767) && ( b>=32768) || (a>=32768) && (b<=32767))
{
if(a>b)
{
res=32768;
}
else
{
res=32767;
}
}
else
{
tmp=a-b;
res=tmp & 0xffff;
}

return(res);
}

Last edited by a moderator:

Looks O.K. as a demonstration but can be coded more efficiently using bit operations.

Stuck with basics operations again in Q1.15 multiplication. What should be the result of multiplication of 23166 (0.707) and 65535 (0.0), the result is 46332 and not 65535. Could it be clarified? It is very basic question

Apparently you don't scale the multiply result correctly.

I used the following code

a=23166, b=65535;

long result,a,b;

result =(a*b)>>15;

b=65535 is outside Q1.15 (int16) range. Should be -1.

Q1.15 range is -1.0 to +1.0 , -32768 to 32767, in hex it is 0x8000-0xffff for negative range and 0x0000-0x7fff for positive range, so 65535 is around -1. So I guess it is the valid range.

The two's complement format is good for addition/subtraction, but bad for multiplication/division.
You want to multiply Q1.15 values 23166 (0.707) with 65535 (-0.0003)
The simplest solution is to separate the sign calculation from the magnitude calculation.
You multiply a positive value with a negative value, so the result will be negative.
For the magnitude calculation, convert the negative value 65535 to the corresponding positive value 1.
Multiply 23166 with 1 => 23166.
Shift down 15 bits => 0
With rounding before shift, the result will be 1.
We then remember that the result should be negative, so we convert 1 to 65535.

so 65535 is around -1
Not when represented with long data type as in post #12.

fixed point multiplication issue is resolved. Thanks for all help

Status
Not open for further replies.