Maestro
Maestro

Reputation: 9508

Can you replace floating points divisions by integer operations?

The Cortex MCU I'm using doesn't have support for floating point divisions in hardware. The GCC compiler solves this by doing them software based, but warns that it can be very slow.

Now I was wondering how I could avoid them altogether. For example, I could blow up the value factor 10000 (integer multiplication), and divide by another large factor (integer division), and get the exact same result.

But would these two operations be actually faster in general than a single floating point operation? For example, does it make sense to replace:

int result = 100 * 0.95f

by

int result = (100 * 9500) / 10000

to get 95% ?

Upvotes: 0

Views: 1645

Answers (2)

Clifford
Clifford

Reputation: 93446

Yes the integer expression will be faster -the integer divide and multiply instructions are single machine instructions whereas the floating point operations will be either function calls (for direct software floating point) or exception handlers (for FPU instruction emulation) - either way, each operation will comprise multiple instructions.

However, while for simple operations, integer expressions and ad-hoc fixed-point (scaled integer) expressions may be adequate, for math intensive applications involving trigonometry functions and logarithms etc. in can become complex. For that you might employ a common fixed-point representation and library. This is easiest in C++ rather than C, as exemplified by Anthony Williams' fixed point library, where due to extensive operator and function overloading, in most cases you can simply replace the float or double keywords with fixed and existing expressions and algorithms will work with comparable performance to to an FPU equiped ARM for many operations. If you are not comfortable using C++, the rest of your code need not use any C++ specific features, and can essentially be C code compiled as C++.

Upvotes: 1

Paul R
Paul R

Reputation: 212929

It's better to get rid of division altogether if you can. This is relatively easy if the divisor is a compile-time constant. Typically you arrange things so that any division operation can be replaced by a bitwise shift. So for your example:

 unsigned int x = 100;
 unsigned int y = (x * (unsigned int)(0.95 * 1024)) >> 10; // y = x * 0.95

Obviously you need to be very aware of the range of x so that you can avoid overflow in the intermediate result.

And as always, remember that premature optimisation is evil - only use fixed point optimisations such as this if you have identified a performance bottleneck.

Upvotes: 2

Related Questions