On integer division
1 Integer division
The integer division of an integer , the dividend, by another non nul integer
, the divisor, is the
determination of two integers: the quotient
and the remainder
such that
and
. With this definition, there are two results if
is not a divisor of
. To make the result unique,
one has to impose an additional condition.
Three such conditions are in use. But first a word about the notations used in this document. is
the real division of
by
. When an uniquifying condition is implied by the context,
is the
quotient and
is the remainder of an integer division. When the uniquifying condition is not
important
is the quotient and
is the remainder.
When defining the uniquifying conditions, we’ll also make use the two functions:
![8>!1 0 8> 0
< <
sgn >:0 0 trunc >:0 0
1 0 0](division15x.png)
1.1 Truncating division
The truncating division can be defined in two equivalent ways: one relating the value of with the
result of the real division (which explains the name we use), the other binding the sign of
with the
sign of the dividend:
![trunc --
0 sgn sgn](division18x.png)
![! %! %
! % %! !( % )
! rem !( rem )
rem ! rem](division19x.png)
![0](division20x.png)
![0](division21x.png)
![2 !1](division22x.png)
![0](division23x.png)
![](division24x.png)
![](division25x.png)
1.2 Floor division
Again, two equivalent ways of defining the division:
![j k
--
0 sgn sgn](division26x.png)
![! %! %
! rem ! !( rem )
( )rem rem](division27x.png)
![0](division28x.png)
1.3 Positive remainder division
There is only one condition to define this division:
![05](division29x.png)
![%! !( % )
rem ! rem
( )rem rem](division30x.png)
To illustrate, here are some examples:
![]() |
Mathematicians tend to define the version they want before using it if it is important. Programmers often don’t have that luxery and have to make with what the system they use provides them. It happens that processors and languages seem to have standardized on the floor division even if the other two (they differ only for negative dividend, which seems rare) appear to be more in use among the mathematicians. Exceptions exist, some languages even provides two remainders (the truncating and the floor one).
Going from one version to the other isn’t difficult, but it can be tedious. It is just adding or substracting one to the quotient, and adding or substracting the divisor to the remainder depending on the sign of the dividend and the divisor. As an example, here is an algorithm computing the floor division assuming that the truncating one is available (in practice the most common case):
![A %](division32x.png)
![A rem](division33x.png)
if
![0](division34x.png)
![O](division35x.png)
![0W 0](division36x.png)
![A !1](division37x.png)
![A](division38x.png)
end if
2 Long division
In this section, we’ll see how to divide a digit number
whose digits in some base
are
by a
digits number
whose digits are
using only numbers less
that
.
The algorithm we’ll use is the long division, the pencil and paper method by which we have learned
how to do division. We’ll consider that there is an additional digit for :
, currently its value is
and it just helps to take into account to fact that such division sometimes produces
digits and
sometimes
; it will be needed in the final version of the algorithm anyway. The algorithm is thus
the following:
At the end, is the quotient and the remainder is
.
The only difficulty in applying this algorithm is getting the next digit:
![c](division57x.png)
for which we known that .
Well, it is easy to do it if :
In the other cases, as we are using numbers less that , the obvious idea is the use
![]() |
(we are temporarily dropping the indices). Let’s try to find out how near we are from the true value.
First we deduce:
Then bound out the other direction:
so if then
. Knuth [1, section 4.3.1] using
![ˆ max ( c -------!1c---!1 \c !1)
!1c !1](division70x.png)
shows that then is sufficient.
In order to tighen our bound on , let’s try to impose
:
This last condition can be computed without overflow if and
(if it isn’t, the condition is
false).
We’ll then have
If one consider that can differ of
only in the last digit, one see that to be more
precise, one need to take all the digits into account.
Let’s modify our initial algorithm using the above properties. To take advantage of the fact that if
then
, we’ll multiply both dividend and divisor by
(the
dividend will need the additional digit we have already introduced, the divisor won’t need another digit,
but its first digit will be
) and divide the remainder by the same value at the end. We’ll
first use
then adjust
until
(the
condition in the algorithm is a little more complicated in order to prevent overflow). Then we are
sure that
is at most one too big, so after having subtracted
from
we check if the result had a borrow and add back
in that case. The result is algorithm
4.
![!16 c/2](division91x.png)
2:
![A c ( !1 1)](division92x.png)
3: if
![1](division93x.png)
4:
![( !1[[[ 1 0)A ( !1[[[ 1 0)](division94x.png)
5:
![( [[[ 1 0)A ( [[[ 1 0)](division95x.png)
6: end if
7: Now determine each digits.
8: for
![[[[0](division96x.png)
9: Get our estimate
10:
![ˆ A ( c !1) !1](division97x.png)
11:
![ˆ A ( c !1)mod ˆ !1](division98x.png)
12: Refine if needed
13: while
![ˆ 6 c (ˆ c ˆ !2 c ˆ !2)](division99x.png)
14:
![ˆA ˆ !1](division100x.png)
15:
![ˆ A ˆ !1](division101x.png)
16: end while
17: Do the substraction
18:
![0](division102x.png)
19: for
![0[[[ !1](division103x.png)
20:
![A ! ˆ](division104x.png)
21:
![A mod c](division105x.png)
22:
![A c](division106x.png)
23: end for
24: If there is a borrow, that mean the refinement wasn’t enough to get it right, add back
![](division107x.png)
![ˆ](division108x.png)
25: if
![W 0](division109x.png)
26:
![( !1[[[ 1 )A ( !1[[[ 1 ) ( !1[[[ 1 0)](division110x.png)
27:
![ˆA ˆ !1](division111x.png)
28: end if
29:
![A ˆ](division112x.png)
30: end for
31: Finally undo the adjustment of the remainder
32: if
![1](division113x.png)
33:
![( !1[[[ 1 0)A ( !1[[[ 1 0)](division114x.png)
![O](division115x.png)
34: end if
For even
, the refinement loop will be executed at most twice, so unrolling the loop
should be considered in an implementation.
With odd, it is possible to get
(for example
and
). But as the additional condition we use to ensure
doesn’t depend
on
, unrolling the loop twice would be enough, the add back step will handle final
adjustment.
References