Binary Division

The AVR architecture does not include hardware division so it must be done in software. Even simple division routines are very costly in terms of execution time and code size, so here are a few things to think about when considering doing it in your program:

  • Don't if you can help it
  • Always use shifts if you are dividing by powers of 2
  • Use an approximation if you don't need perfect accuracy
  • Seriously, don't if you can help it

Unfortunately, there are somtimes no acceptable alternatives and software division must be done. Here we will look at how to implement division routines in assembly.

Decimal Division

Writing a division routine for your microcontroller requires an understanding of binary division. And the best way to learn starts with reviewing regular decimal division

Consider dividing 182 by 13. Here 182 is referred to as the dividend, while 13 is the divisor. An example of this worked with long division is shown below:

	014
	---
13      182		; divide 13 into 182

	↓		; bring down first digit from dividend
*0	1		; 13 goes into 1 zero times

	 ↓		; bring down another digit from dividend
	18
*1     -13		; 13 goes into 18 one time, subtract 13*1 from remainder
	---
	05		; remainder is 5

	  ↓		; bring down another digit from dividend
	052
*4     -052		; 13 goes into 52 four times, subtract 4*13 from remainder
	---
	000		; remainder is 0

Let's take a look at this step by step.

To begin with, we attempt to divide the first digit of the divisor with the dividend

1 ÷ 13 = 0 rem 13

In decimal notation we normally don't include leading zeros, but for clarity (and for the sake of the following examples) we will make a note if this division by placing the result 0 above the first digit in the dividend.

        0
        ------
13      1 8 2

Since 13 goes into 1 less than one time, we have to pull another digit from the dividend:

18 ÷ 13 = 1 rem 5

Another way to think of this is that we shift 1 to the next power of 10 and we shift 8 into the lowest power of 10

1*101 + 8*100 ÷ 13 = 1 rem 5

We make a note of the result 1 by placing it above the second digit of the dividend.

        0 1
        ------
13      1 8 2

Now we need to figure out how many times 13 goes into the remainder 5. If we've done the previous steps correctly, the remainder will be less than our divisor, so, like before, we must shift another digit from our divisor like so

5*101 + 2*100 ÷ 13 = 4 rem 0

We've divided the remainder and obtained a result 4 so we make a note by placing it above the third digit of the dividend

        0 1 4
        ------
13      1 8 2

And we're done. We've determined that 13 goes into 182 14 times with a remainder of 0.

Binary division can be done in the exact same way, except that every digit can only take one of two values, as opposed to the nine possible in decimal. This means that unlike in decimal where we must decide how many times the divisor can go into the remainder each step, in binary it either divides in or it doesn't (0 or 1!).

Note that the remainder of a division step like

5*101 + 2*100 ÷ 13 = 4 rem 0

can be calculated by subtracting the result multiplied by the divisor from the dividend, i.e.

5*101 + 2*100 - 4*13 = 5

This only works if we know the how many times our divisor goes into the remainder. But since in binary the result can only be a 1 or 0, we just need to compare the divisor and the remainder. If the divisor is less it will go in once, otherwise its zero

Binary Division

The exact same division of 182 by 13 is shown below in 8-bit binary

		00001110
		--------
00001101	10110110	; divide 13 into 182

		↓
	 00000001		; bring down digit from dividend
	-00001101		; subtract 13 from it
	---------
		-		; result is negative, place 0 above digit 1

		 ↓
	  00000010		; bring down digit from dividend
	 -00001101		; result is negative, place 0 above digit 2

		  ↓
	   00000101		; bring down digit from dividend
	  -00001101		; result is negative, place 0 above digit 3

		   ↓
 	    00001011		; bring down digit from dividend
	   -00001101		; result is negative, place 0 above digit 4

         	    ↓
	     00010110		; bring down digit from dividend
	    -00001101		; result is positive, place 1 above digit 5
	    ---------
	     00001001		; remainder

        	     ↓
	      00010011		; bring down digit from dividend
	     -00001101		; result is positive, place 1 above digit 6
	     ---------
	      00000110         	; remainder

                      ↓
               00001101		; bring down digit from dividend
              -00001101		; result is positive, place 1 above digit 7
	      ---------
	       00000000		; remainder

                       ↓
                00000000	; bring down digit from dividend
               -00001101	; result is negative, place 0 above digit 8
	       ---------
		00000000	; remainder

Looking at this step by step, we take the first digit of the dividend, shift it into the LSB and subtract our divisor from it.

		00000001 ← 1 0110110
	       -00001101

Since the result of the subtraction is a negative number, we know our divisor will go into it less than one time. So we put a 0 above the first digit of our dividend

		0
                --------
00001101        10110110

Then we pull another digit from our divisor, shift our first digit up and place the new one in the LSB, and try again

		00000010 ← 0 110110
	       -00001101

The result of subtraction is negative, so we note another zero in our quotient

		00
                --------
00001101        10110110

then shift another digit from the dividend and try again

		00000101 ← 1 10110
	       -00001101

which yields

		000
                --------
00001101        10110110

And again

		00001011 ← 1 0110
	       -00001101

Keeping track of our quotient

		0000
                --------
00001101        10110110

And finally, we've pulled enough digits from our dividend that the result of subtraction is non-negative

		00010110 ← 0 110
	       -00001101
		--------
		00001001

We place a 1 in our quotient

		00001
                --------
00001101        10110110

Now we shift another digit from our dividend into the remainder

		00010011 ← 1 10
	       -00001101
		--------
		00000110

Since the result of subtraction is positive, We place a 1 in our quotient

		000011
                --------
00001101        10110110

Another shift and subtract

		00001101 ← 00
	       -00001101
		--------
		00000000

And we place another 1 in our quotient

		0000111
                --------
00001101        10110110

Now our last shift

		00000000 ← 0
	       -00001101

With the negative result we place a 0 in our quotient and we're done!

		00001110
                --------
00001101        10110110

There you have it, the result 00000110 is equal to 14, the same as before.

Conclusion

Now that you understand how binary division works, it's time to take a look at how to implement it in AVR.

rjhcoding.com 2018