Um algoritmo para dividir inteiros positivos - IME-USP

Propaganda
Um algoritmo para dividir inteiros positivos
Walter Mascarenhas
Nota de aula de MAC0122
16 de setembro de 2004
Nesta nota eu apresento um algoritmo para dividir um número n da forma
a22k + b por um número d, onde a, b e c são inteiros não negativos e menores
que 22k . Este algoritmo não tenta ser o “melhor” nem o mais o eficiente; ele
só ilustra idéias. Se você quiser algo feito com detalhes então procure Internet.
Veja por exemplo o site http://www.swox.com/gmp.
O primeiro passo para se fazer um algoritmo para divisão é entender o que
é divisão. As pessoas esquecem a definição de divisão e pensam no quociente e
no resto separadamente. Na verdade, o quociente e o resto são definidos juntos:
dividir n por d é encontrar, simultaneamente, um par de números q e r tais que
n = qd + r,
com 0 ≤ r < |d|.
(1)
Esta é a definição matemática de divisão. Porém esta NÃO É a forma como
os números inteiros com sinal são usualmente divididos no computador. Felizmente, a matemática e a computação concordam quando n e d são positivos,
e como o nosso algoritmo só lida com números positivos nós não vamos nos
preocupar com isso. Para nós, dividir n por d significará fazer a decomposição
de n nas duas partes descritas na equação (1).
A idéia do nosso algoritmo para dividir a22k + b por d é quebrar b e d em
números menores, ou seja, fazer b = 2k b0 + b1 e d = 2k d0 + d1 , com 0 ≤
bi , di < 2k . Por exemplo, no caso que estudamos na aula a base é 232 e farı́amos
b = 216 b0 +b1 . Com isto nós podemos multiplicar os bi e di sem risco de overflow
(assumimos que o nosso computador lida com números até 22k − 1 de forma
exata.)
1
Com aquecimento, na próxima seção nós analisamos este caso particular no
qual d0 = 0. Este é o caso mais simples, que você aprendeu a resolver no
primário. Na seção seguinte tratamos o caso d0 > 0. Para isso, estudaremos
um problema auxiliar mais simples. Este problema auxiliar é discutido nas duas
última seção desta nota, que completa a apresentação do algoritmo de divisão.
1
O caso d0 = 0
No caso d0 = 0 temos que d é menor que 2k e portanto o resto também deve
ser menor que 2k . Com isto, se fizermos q = q0 22k + q1 2k + q2 , com q0 < 22k e
q1 , q2 < 2k escrevermos a equação (1) por extenso obteremos
n = a22k + b0 2k + b1 = d1 q0 22k + d1 q1 2k + d1 q2 + r1 .
(2)
Aplicamos então o mesmo algoritmo que usamos para dividir quando estamos
trabalhando na base 10. Este algoritmo pode ser expresso assim:
1. Faça a divisão a = d1 q0 + x para obter q0 . Substituindo em (2) reduzimos
o problema à equação
a22k + b0 2k + b1 = (d1 q0 + x)22k + b0 2k + b1 = d1 q0 22k + d1 q1 2k + d1 q2 + r1 ,
que com o cancelamento do termo d1 q0 22k leva a
x22k + b0 2k + b1 = d1 q1 2k + d1 q2 + r1 .
(3)
2. Faça a divisão x2k + b0 = d1 q1 + y para obter q1 . Substituindo em (2)
obtemos
(x2k + b0 )2k + b1 = (d1 q1 + y)2k + b1 = d1 q1 2k + d1 q2 + r1 ,
que com o cancelamento do termo d1 q1 2k leva a
y2k + b1 = d1 q2 + r1 .
3. Finalmente, faça a divisão y2k + b1 = d1 q2 + r1 para obter q2 e r1 .
Pronto, calculamos q = q0 22k + q1 2k + q2 e r = r0 2k + r1 .
2
(4)
2
O caso d0 > 0
Este caso é mais complexo. Para lidar com ele resolveremos o problema auxiliar:
Como dividir x = y2k + z por d = d0 2k + d1 se y < 22k , z < 2k e d0 > 0? (5)
Este problema auxiliar é mais simples, pois podemos representar q com apenas
um dı́gito. De fato, note que
q=b
y2k + z
(22k − 1)2k + 2k − 1
23k − 1
c≤b
c
≤
b
c = 22k − 1.
k
k
d
d0 2 + d1
2
Logo q pode ser representado em um único dı́gito.
Na próxima seção eu explicarei como resolver este problema auxiliar. Vamos
assumir então que já sabemos fazer a divisão
y2k + z = qd + r,
quando y < 22k , z < 2k e d0 > 0.
O algoritmo para d0 fica assim então:
1. Usando o algoritmo da próxima seção, faça
a2k + b0 = qa d + ra .
Com isto, n passa a ser dado pela expressão
n = (qa d + ra )2k + b1 = qa 2k d + ra 2k + b1 = qd + r.
2. Use novamente o algoritmo da próxima seção para obter
ra 2k + b1 = qb d + r
Isto leva a
n = (qa 2k + qb )d + r.
3. Finalmente, faça a multiplicação e a soma qa 2k + qb para obter q.
Assim completamos a divisão para d0 > 0. Agora só resta analisar a solução do
problema (5) na próxima seção.
3
3
O problema auxiliar
Nesta seção eu explico como resolver o problema auxiliar (5):
Como dividir x = y2k + z por d = d0 2k + d1 se y < 22k , z < 2k e d0 > 0?
A idéia do algoritmo é simples: ao invés de dividir sempre por d = d0 2k + d1 ,
faça uma divisão por d0 + 1 na hora certa. Aqui está o algoritmo:
1. Faça a divisão
y = qy d + ry ,
obtendo um resto ry < d.
2. O passo anterior reduz o problema a decompor
x = qy d2k + ry 2k + z.
Agora faça a divisão
ry = q1 (d0 + 1) + r1 .
Observe que r1 < d0 + 1 implica r1 < 2k e
ry
d
d0 2k + d1
d0 2k + 2k
q1 ≤
<
=
<
= 2k .
d0 + 1 d0 + 1
d0 + 1
d0 + 1
Logo q1 (2k − d1 ) < 22k e r1 2k + z < 22k e podemos computar os termos da
equação abaixo sem problemas:
x = qy d2k + (q1 (d0 + 1) + r1 )2k + z =
qy d2k + q1 (d0 2k + d1 ) + r1 2k + q1 (2k − d1 ) + z = q2 d + q1 (2k − d1 ) + (r1 2k + z),
para q2 = qy 2k + q1 .
3. Agora faça as divisões
r1 2k + z = q2 d + r2 ,
q1 (2k − d1 ) = q3 d + r3 ,
4
que levam a
x = q4 d + r1 + r2 .
para q4 = q1 + q2 + q3 . Se r1 ≥ d − r2 então faça
x = qd + r
para r = r1 − (d − r2 ) < d e q = q4 + 1. Caso contrário, faça
x = qd + r.
para q = r1 + r2 < d e q = q4 . Como sabemos que q < 22k não precisamos
nos preocupar com overflow ao avaliarmos os q’s. É isto, este é o algoritmo.
5
Download