# Excessive AVR static RAM usage with mixed-type math operations

I've narrowed down an issue in my code which creates an extra 260 bytes of static RAM usage:

BYTE Height = 150;

{
float samp;
//int samp;
BYTE level;

level = 100-(samp*100/Height);

return level;
}


BYTE here is a uint8_t type. If I comment out float samp and turn it into an int type, the static RAM usage goes back down to what I expect it to be. I suppose this has something to do with the math operation level = 100-(samp*100/Height); but I don't know what it is. What is happening to create such behavior?

• If you're using a program like AVR Studio, you should be able to take a look at the disassembler and find out what the C code for your function is being compiled to; that might give you some hints to what's happening. I'd avoid using floating point at all on the AVR unless it were absolutely necessary. Commented Jul 6, 2011 at 5:14

For many mathematical functions there's a trade-off between RAM usage and speed. I guess the AVR floating-point library will be optimized for speed.
Bitrex is right: try to avoid floating-point in microcontrollers unless absolutely necessary. Do you really need floating-point, or will fixed-point do? You can emulate fixed-point by placing a virtual decimal point somewhere in an int.

In your example you multiply samp by $\frac{2}{3}$. The result, stored in a BYTE won't have a very high precision. In a case like that you can pick a scaling factor which is easier to calculate than the $\frac{2}{3}$. Find an approximation of the form $\frac{A}{2^N}$. In this case $\frac{171}{256}$ ~ 0.668 is a good choice, with an error of only 0.2%. And it's a lot easier to calculate: multiply by 171, and shift right 8 bits. No division needed.

• just remember to cast a uint8_t to an int16_t before multiplying it by 171 or you will likely get "interesting" results Commented Jul 6, 2011 at 12:54
• @vicatcu: Is that the same "interesting" like the Chinese curse "May you live in interesting times"? :) Commented Dec 10, 2013 at 16:45

Are you using floats anywhere else ? If not, the float here may be pulling in the whole floating-point library, which may be allocating memory for itself. There's very rarely any need to use floating point in embedded apps as you don't need the large range of PF to process the limited range of values from real-world inputs like ADCs etc. Remember FP gives you range, not accuracy. It's almost always much smaller and faster to use fixed-point, and a fixed-point value will always be more accurate than a FP one of the same size.

• "Remember FP gives you range, not accuracy". That's not quite true. IEEE-754 gives you 23 digits in single precision (52 in double), which I'd rather call very accurate. In engineering you often don't need more than 4 significant digits. Commented Jul 6, 2011 at 8:12
• @stevenvh It's still only an approximation - I once came across a problem adding some simple currency figures together that were stored in floats - the result of something like $45.82 plus$22.18 ended up as something like \$67.99999999999... not what was expected, but exactly what the IEEE float methodology says it should be... Commented Jul 6, 2011 at 8:37
• @Matt - Base conversions aren't always perfect, but you're never going to need those 23 significant digits, and rounding to even 20 (which you still don't want!) will usually fix the problem. (Writing down pi in 23 digits and saying it's only an approximation is worse than just nit-picking.) Commented Jul 6, 2011 at 8:51
• @Matt - to illustrate how absurd 23 digits are: they allow you to give the distance earth-sun to 1 pm (that's right, a picometer) exact! Commented Jul 6, 2011 at 8:56
• @stevenh, IEEE 754 gives you 23 BITS in single precision. This results in about 7 significant digits in base 10. In order to represent the distance from the sun to earth with picometer resolution, you would need about 74 bits in the mantissa.
– W5VO
Commented Jul 6, 2011 at 12:50

What you are probably seeing is what is known as Variable Promotion.

When doing any mathematical operation involving multiple variable types, all the variables within the formula are promoted to types of the highest accuracy (float in your case). Thus, the Height variable will be being copied into a temporary float variable before the operation is done.

This will only account for a small part of the increased memory usage.

The rest is more than likely caused by the inclusion of the entire floating point library into the system. Without knowing the internals of the AVR's floating point library I am unable to say what it would be doing with said memory (the majority of memory used would be program memory and not RAM).

As stevenvh has mentioned, there are far more efficient ways of doing these kind of operations which don't use the floating point library at all, and floating point, as has been rightly mentioned elsewhere, is not really what you are after here as it has an inherent error factor in it. What you are really wanting is double not float as this is a fixed precision with a better accuracy than float - still not as efficient as doing 100% integer mathematics though.

I've seen a flash memory utilization explosion in avr-gcc if you fail to use the -lm flag in the linker to link in the avr optimized floating point emulation routines via the math library. You should also probably have the unused functions removal (-ffunction-sections) set in the compiler flags and -Wl,-gc-sections set in the linker flags if you care about minimizing the memory footprint. Note the leading dashes in all the flags.

For reference, the avr-gcc manual FAQ explicitly talks about this. Here is also another good reference for optimizations you can apply in avr-gcc.

All of the above being said, you will save the most memory by simply not using floating point variables in your code, if you can formulate your problem in strictly integer or fixed point math you should!