AVR GCC Fixed-Point vs. Floating Point Comparison

apples vs. oranges

This is a follow up to previous posts here and here. Using native fixed point support in GCC, on a generic ATMega328P running 16MHz on the AtmelStudio 6.2 simulator, I performed this overly simplified comparison of fixed vs. floating point math. The results posted below compare the fixed point accum type with a float.

The accum typedef allows for an unsigned 16.16 fixed format (+/-16.15 if signed). The fract typedef provides an unsigned 0.16 format (+/-0.15 if signed). Short, long and long long modifiers are also allowed.

It is very difficult to find supporting documentation on (AVR) fixed point. A basic overview of the types supported is here and here. The ISO standard for C (embedded extensions) fixed point is located here.

#include <avr/io.h>
#include <stdfix.h>

int main(void) {
  volatile accum fx1, fx2 = 2.33K, fx3 = 0.66K;
  volatile float fl1, flt2 = 2.33, fl3 = 0.66;
  fx1 = fx2 + fx3;
  fl1 = fl2 + fl3;

  fx1 = fx2 – fx3;
  fl1 = fl2 - fl3;

  fx1 = fx2 * fx3;
  fl1 = fl2 * fl3;

  fx3 = fx2 / fx3;
  fl3 = fl2 / fl3;

  //fl1 = (float)fx3;


In all cases except division, the fixed point versions are faster. All fixed point versions produce smaller code. The use of a fract type can further reduce code size and improve speed (Note: since fract division is a 16-bit version, speed is increased and size is reduced compared to floating point). Obviously, the accuracy/precision is lacking in all cases with fixed point. The results are summarized below:

Fixed-point results:
= 2.98996
27 cycles or 1.69us (4.5x faster)
code size: 238 bytes

Floating-point results:
= 2.99
123 cycles or 7.69us
Code size: 598 bytes

Fixed-point results:
= 1.670013
27 cycles or 1.69us (4.8x faster)
code size: 238 bytes

Floating-point results:
= 1.67
131 cycles or 8.19us
Code size: 598 bytes

Fixed-point results:
= 5.428833
132 cycles or 8.25us (12% faster)
code size: 394 bytes

Floating-point results:
= 5.428837
156 cycles or 9.25us
Code size; 578 bytes

Fixed-point results:
= 3.530426
700 cycles or 43.75us (30% slower)
code size: 378 bytes

Floating-point results:
= 3.530303
492 cycles or 30.75us
Code size: 604 bytes

Note: To my knowledge, this will not compile with the Arduino IDE because the arduino IDE will not link to the AVR libm library which contains the fixed point routines. See my posting here for arduino compatible routines.

About Jim Eli

µC experimenter
This entry was posted in Uncategorized and tagged , , , , , , , . Bookmark the permalink.

9 Responses to AVR GCC Fixed-Point vs. Floating Point Comparison

  1. sean says:

    something is wrong here, multiplication should also be much faster like addition and subtraction if there is a mul instruction. Did you enable optimizations and specify the mcu? Inspect the generated assembly?

    • Jim Eli says:

      Optimizations turned off. The comparisons just used the built-in assembler routines for fp and integer multiplication. I don’t remember if HW multiplication was used or not. However, if HW mul was, it would have been used for both fp and fixed, making it a fair comparison.

      • sean says:

        I think optimizations should have been on, but now after looking at the latest gcc sources, it appears that georg implemented saturating fixed point types, and in the meantime decided to follow the fixed point spec to ensure routing. This means the multiplications won’t ever overflow but are considerably slower than originally should have been around 60 cycles for 16.16×16.16 multiplication.

  2. Brad says:

    Why are you using volatile? typically you would use volatile only where the contents of the variable could be changed by something else, like a hardware register. This may be affecting optimisation and code size, I guess it depends on how smart gcc is.

  3. toto says:

    And what are the size of theses different types? Are you sure of the multiplication result?

  4. Олег Павлов says:

    Hello, I would like to know how you counted cycles, by analysing assembly instructions or there is an easier way?

    • Jim Eli says:

      To do it by hand, you examine the underlying assembly code and count each instruction clock cycle per the datasheet. Analyze the code to determine the number of loops, etc. The easier method is to use the clock cycle counter inside Atmel Studio and run the code using the simulator.

Leave a Reply to Jim Eli Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s