2

I've been reading up that floating point math on something like a tiny Arduino microcontroller is bad. So in trying to use less floats, I discovered something odd.

// Baseline
float brightness = 0.05;
int result = someInt * brightness;

// Takes about twice as long
int brightness = 20;
int result = someInt / brightness;

Both have the same goal, to reduce an integer to by one twentieth of its original value. But in doing math optimization, I'm not sure why the float is faster.

Kevin
  • 48,059
  • 14
  • 92
  • 127
Alex Wayne
  • 145,435
  • 42
  • 271
  • 302
  • How did you measure it? – R.. GitHub STOP HELPING ICE May 15 '14 at 00:40
  • 2
    Integer division can be pretty slow – M.M May 15 '14 at 00:42
  • While not a comprehensive answer (hence my posting as a comment), the following link looks like it may be of use: http://forum.arduino.cc/index.php?topic=92684.0 Basically, integer division (of an int) is over 50 times slower than multiplication of an int - due to the division not having a hardware instruction. (the comment asserts that there is a mul instruction, though I haven't bothered to read the datasheet for the 328p and don't know or comment on this) There's an awful lot of time for a software implementation of a floating point mul to be performed. – enhzflep May 15 '14 at 00:49
  • This is for you: http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html – Yves Daoust May 15 '14 at 06:40

4 Answers4

3

native AVR (arduino) does not have multiplication or division functions, much less native floating point handling. When you multiply it's essentially just a bunch of adding. Division is much harder to calculate with subtractions (can't go too far), find remainder - if a float then calculate fraction from remainder which in itself is oodles of add/multiply and subtract.
Float is also slow/bad because the C library has to figure out all that decimal handling with only having integers to work with internally. You will notice that anything that uses a float increases your program size dramatically (addition of floating point library) You should find that a float divide is even slower than a integer divide.

Somehow the float library is more efficient in multiplication with all the fractions overhead than integer division

EkriirkE
  • 2,060
  • 15
  • 13
  • If `int` division is slow, and doing anything with `float`s is slow, is there a standard and accepted super fast integer only way to multiply an integer by a rational number? – Alex Wayne May 15 '14 at 06:05
  • @AlexWayne Might be a little late to the game, but I'd say find a rational number which uses a power of two for the denominator. Then you can use bit shifting to divide and only need integer multiplication which should be faster. – penguin359 Apr 19 '16 at 02:56
3

Also you can use multiplication and shift instead of divide

int brightness = 20;
int multer = 256/20;
int result = (someInt * multer) >> 8;

The more bits is used for "multer" the more precise result.

minorlogic
  • 1,637
  • 12
  • 23
  • So, to generalize, I can get fast integer division by mapping `0-1` to `0-0xFF` and doing `(int8val * int8fract) >> 8`. Is that right? What if both were 16bit? Does `(int16val * int16fract) >> 16` work too? – Alex Wayne May 15 '14 at 17:52
  • You can map to any precision , not only 0-0xFF but 0-0xFFFFFF for int32 and uint8 source/result. (int16val * int16fract) >> 16 - yes it works too, just NOTE if you use signed integers, than you should use 1 bit less for sign. – minorlogic May 16 '14 at 12:49
  • ALthough @EkriirkE provided a better answer to the actual question, this is an incredibly helpful tip. Thank you much! – Alex Wayne May 16 '14 at 14:51
1

You are comparing multiply against divide. Apples and pears.

To divide by 20, you can use integer multiply by floor(2^k/5) or ceiling(2^k/5), followed by a right shift of k+2 bits. Choose the largest k that does not cause overflow.

Yves Daoust
  • 48,767
  • 8
  • 39
  • 84
0

You can use just bit shifts to divide. Look at https://stackoverflow.com/a/19076173/2193968 It has a divide by 10 function:

unsigned divu10(unsigned n) {
    unsigned q, r;
    q = (n >> 1) + (n >> 2);
    q = q + (q >> 4);
    q = q + (q >> 8);
    q = q + (q >> 16);
    q = q >> 3;
    r = n - (((q << 2) + q) << 1);
    return q + (r > 9);
}

So this should divide by 20:

unsigned divu20(unsigned n) {
    return divu10(n)>>1;
}

Bit shifts should be faster than a multiply or divide instruction - especially if (as EkriirkE has already said) that "native AVR (arduino) does not have multiplication or division functions"

Community
  • 1
  • 1
Jerry Jeremiah
  • 7,408
  • 2
  • 21
  • 27
  • 1
    You can also use multiplication to divide by any integer constant, and in fact gcc will make this transformation for you in most cases... – R.. GitHub STOP HELPING ICE May 15 '14 at 02:51
  • I routinely write constants as maths as the precompiler will recognise this and compile the result as the constant, eg `#define x ((100+33)*0.22)` if those numbers had a meaning I wanted to tweak w/o re-calculating – EkriirkE May 15 '14 at 21:39