**EDA/IP**

# Fixed-point math in C

**Keywords:C language
fixed-point math algorithm
integer functions
**

When adding, subtracting, or performing logical comparisons on two variables with different-resolution fixed-point numbers, first scale the different resolution number to the same resolution as the result. Listing 4 shows a small routine that performs some mixed operations and prints the results. This routine performs the same function as Listing 3.

**Listing 4: Simple math on different granularity variables ****void Test7_9(FIXED7_9 a, FIXED1_7 b){FIXED7_9 temp; **

**printf("\nResults of operations on 7_9 and 1_7 variables\n");**

temp.full = a.full + (b.full < < 2);

printf("Addition result is %d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

if (a.full < (b.full < < 2))

{

printf("a is less than b. Subtraction overflows.\n");

}

if (a.full == (b.full < < 2))

{

printf("a is the same as b. Result = 0.\n");

}

if (a.full > (b.full < < 2))

{

temp.full = a.full—(b.full < < 2);

printf("Subtraction result is

%d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

}

temp.full = a.full + (b.full < < 2);

printf("Addition result is %d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

if (a.full < (b.full < < 2))

{

printf("a is less than b. Subtraction overflows.\n");

}

if (a.full == (b.full < < 2))

{

printf("a is the same as b. Result = 0.\n");

}

if (a.full > (b.full < < 2))

{

temp.full = a.full—(b.full < < 2);

printf("Subtraction result is

%d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

}

When multiplying or dividing variables of the same-resolution fixed-point numbers, use the macros previously defined. Listing 5 shows a small routine that performs each operation and prints the result. This routine simply performs the multiply and divide without checking, then displays the results. With multiply and divide, you cannot pass the full value, so you must pass the structure name.

**Listing 5: Multiplication and division on same granularity variables ****void Test7_9_X(FIXED7_9 a, FIXED7_9 b){ FIXED7_9 temp; **

**printf("\nResults of multiply and**

divide on 7_9 variables.\n");

temp.full = MULT7_9(a,b);

printf("Multiply result is %d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

temp.full = DIV7_9(a,b);

printf("Divide result is

%d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

}

divide on 7_9 variables.\n");

temp.full = MULT7_9(a,b);

printf("Multiply result is %d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

temp.full = DIV7_9(a,b);

printf("Divide result is

%d.%1.1d\n", temp.part.integer,

(temp.part.fraction*10+256)/512);

}

When multiplying or dividing variables of different-resolution fixed-point numbers, use the same macro as the result and scale the operands as with addition and subtraction. Listing 6 shows a small routine that performs an operation like this and prints the results.

**Listing 6: Multiplication and division on different granularity ****void Test11_21(FIXED11_21 a, FIXED7_9 b)**

**{}FIXED11_21 temp; **

}

**printf("\nResults of multiply and divide on 11_21 and 7_9 variables.\n");**

} temp.full = b.full < < 12;

} temp.full = MULT11_21(a,temp);

} printf("Multiply result is %d.%2.2d\n",

}temp.part.integer,

}(temp.part.fraction*100+1048576)/2097152);

}temp.full = b.full < < 12;

}temp.full = DIV11_21(a,temp);

}printf("Divide result is %d.%2.2d\n", temp.part.integer,

}

}(temp.part.fraction*100+1048576)/2097152);

}}

} temp.full = b.full < < 12;

} temp.full = MULT11_21(a,temp);

} printf("Multiply result is %d.%2.2d\n",

}temp.part.integer,

}(temp.part.fraction*100+1048576)/2097152);

}temp.full = b.full < < 12;

}temp.full = DIV11_21(a,temp);

}printf("Divide result is %d.%2.2d\n", temp.part.integer,

}

}(temp.part.fraction*100+1048576)/2097152);

}}

The value can be displayed using the integer and fractional portions of the structure.

**Words of caution**

When these algorithms are implemented, a few areas of caution need to be addressed. If they aren't, erroneous results may be obtained.

The C language does not check integer arithmetic for overflows or underflows. The programmer must take care to either prevent or check for these conditions. This is usually accomplished by using a subroutine, possibly in assembly language, for each math operation and checking the limits. However, it can also be accomplished by adding bits to the integer portion, and limiting to a smaller number after each math operation.

The compiler may perform signed integer arithmetic in a subroutine and may not provide a tremendous benefit.

A rounding error may be injected in the result due to the value of the least significant bit. Since the expectation is an LSB of 0.1, and in fact the value is something less, an error of 1 LSB is injected that can compound during mathematical operations. For example, using our FIXED1_7 example, 0.02 is represented as a full number of 3, and 0.06 is represented as a full number of 8. The sum should be 0.08, or a full number of 10. The actual result is 11, which is closer to 0.09. To limit this error, use a larger number such as 16 bits, and increase the granularity from 7 bits to 15 bits.

Fixed-point math provides a small, fast alternative to floating-point numbers in situations where small rounding errors are acceptable. After implementing the algorithms described in this article, your application will be able to harness the power of C and still retain the efficiency of assembly.

All examples in this article were tested using Microsoft Visual C++ v. 4.0 Standard edition.

- **Joseph Lemieux Senior Applied Specialist EDS Embedded Solutions**

To download the PDF version of this article, click here.

Related Articles | Editor's Choice |

Visit Asia Webinars to learn about the latest in technology and get practical design tips.