0%
Pular para o conteúdo principal
0%

1.2.5 Máximo Divisor Comum

O máximo divisor comum (MDC, ou GCD em inglês) de dois inteiros aa e bb é definido como sendo o maior inteiro que divide tanto aa quanto bb sem resto. Por exemplo, o MDC de 16 e 28 é 4. No capítulo 2, quando investigarmos como implementar aritmética de números racionais, precisaremos ser capazes de calcular MDCs a fim de reduzir números racionais aos menores termos. (Para reduzir um número racional aos menores termos, devemos dividir tanto o numerador quanto o denominador pelo seu MDC. Por exemplo, 16/28 reduz para 4/7.) Uma maneira de encontrar o MDC de dois inteiros é fatorá-los e procurar fatores comuns, mas existe um algoritmo famoso que é muito mais eficiente.

A ideia do algoritmo é baseada na observação de que, se rr é o resto quando aa é dividido por bb, então os divisores comuns de aa e bb são precisamente os mesmos que os divisores comuns de bb e rr. Assim, podemos usar a equação

MDC(a,b)=MDC(b,r)\textrm{MDC}(a, b) = \textrm{MDC}(b, r)

para reduzir sucessivamente o problema de calcular um MDC ao problema de calcular o MDC de pares de inteiros cada vez menores. Por exemplo,

MDC(206,40)=MDC(40,6)=MDC(6,4)=MDC(4,2)=MDC(2,0)=2\begin{array}{lll} \textrm{MDC}(206,40) &= &\textrm{MDC}(40,6) \\ &= &\textrm{MDC}(6,4) \\ &= &\textrm{MDC}(4,2) \\ &= &\textrm{MDC}(2,0) \\ &= &2 \end{array}

reduz MDC(206,40)\textrm{MDC}(206, 40) a MDC(2,0)\textrm{MDC}(2, 0), que é 2. É possível mostrar que começando com quaisquer dois inteiros positivos e realizando reduções repetidas sempre eventualmente produzirá um par onde o segundo número é 0. Então o MDC é o outro número no par. Este método para calcular o MDC é conhecido como Algoritmo de Euclides.1

É fácil expressar o Algoritmo de Euclides como uma função:

Carregando playground de código...

Isso gera um processo iterativo, cujo número de passos cresce como o logaritmo dos números envolvidos.

O fato de que o número de passos necessários pelo Algoritmo de Euclides tem crescimento logarítmico tem uma relação interessante com os números de Fibonacci:

Teorema de Lamé: Se o Algoritmo de Euclides requer kk passos para calcular o MDC de algum par, então o menor número no par deve ser maior ou igual ao kk-ésimo número de Fibonacci.2

Podemos usar este teorema para obter uma estimativa de ordem de crescimento para o Algoritmo de Euclides. Seja nn o menor dos dois argumentos de entrada da função. Se o processo leva kk passos, então devemos ter nFib(k)ϕk/5n\geq \textrm{Fib}(k)\approx\phi^k/\sqrt{5}. Portanto, o número de passos kk cresce como o logaritmo (na base ϕ\phi) de nn. Portanto, a ordem de crescimento é Θ(logn)\Theta(\log n).

Exercício 1.20

O processo que uma função gera é, claro, dependente das regras usadas pelo interpretador. Como exemplo, considere a função iterativa gcd dada acima. Suponha que fôssemos interpretar esta função usando avaliação em ordem normal, como discutido na seção 1.1.5. (A regra de avaliação em ordem normal para expressões condicionais é descrita no exercício 1.5.) Usando o método de substituição (para ordem normal), ilustre o processo gerado ao avaliar gcd(206, 40) e indique as operações % (resto) que são realmente realizadas. Quantas operações de resto são realmente realizadas na avaliação em ordem normal de gcd(206, 40)? Na avaliação em ordem aplicativa?


Notas de Rodapé

1 O Algoritmo de Euclides é assim chamado porque aparece nos Elementos de Euclides (Livro 7, ca. 300 a.C.). Segundo Knuth (1997a), ele pode ser considerado o mais antigo algoritmo não trivial conhecido. O antigo método egípcio de multiplicação (exercício 1.18) é certamente mais antigo, mas, como Knuth explica, o Algoritmo de Euclides é o mais antigo conhecido por ter sido apresentado como um algoritmo geral, em vez de como um conjunto de exemplos ilustrativos.

2 Este teorema foi provado em 1845 por Gabriel Lamé, um matemático e engenheiro francês conhecido principalmente por suas contribuições à física matemática. Para provar o teorema, consideramos pares (ak,bk)(a_k, b_k), onde akbka_k\geq b_k, para os quais o Algoritmo de Euclides termina em kk passos. A prova é baseada na afirmação de que, se (ak+1,bk+1)(ak,bk)(ak1,bk1)(a_{k+1}, b_{k+1}) \rightarrow (a_{k}, b_{k}) \rightarrow (a_{k-1}, b_{k-1}) são três pares sucessivos no processo de redução, então devemos ter bk+1bk+bk1b_{k+1}\geq b_{k} + b_{k-1}. Para verificar a afirmação, considere que um passo de redução é definido aplicando a transformação ak1=bka_{k-1} = b_{k}, bk1=resto de ak dividido por bkb_{k-1} = \textrm{resto de}\ a_{k}\ \textrm{dividido por}\ b_{k}. A segunda equação significa que ak=qbk+bk1a_{k} = qb_{k} + b_{k-1} para algum inteiro positivo qq. E como qq deve ser pelo menos 1, temos ak=qbk+bk1bk+bk1a_{k} = qb_{k} + b_{k-1} \geq b_{k} + b_{k-1}. Mas no passo de redução anterior temos bk+1=akb_{k+1}= a_{k}. Portanto, bk+1=akbk+bk1b_{k+1} = a_{k}\geq b_{k} + b_{k-1}. Isso verifica a afirmação. Agora podemos provar o teorema por indução em kk, o número de passos que o algoritmo requer para terminar. O resultado é verdadeiro para k=1k=1, pois isso meramente requer que bb seja pelo menos tão grande quanto Fib(1)=1\text{Fib}(1)=1. Agora, assuma que o resultado é verdadeiro para todos os inteiros menores ou iguais a kk e estabeleça o resultado para k+1k+1. Seja (ak+1,bk+1)(ak,bk)(ak1,bk1)(a_{k+1}, b_{k+1})\rightarrow(a_{k}, b_{k}) \rightarrow(a_{k-1}, b_{k-1}) pares sucessivos no processo de redução. Por nossas hipóteses de indução, temos bk1Fib(k1)b_{k-1}\geq \textrm{Fib}(k-1) e bkFib(k)b_{k}\geq \textrm{Fib}(k). Assim, aplicando a afirmação que acabamos de provar junto com a definição dos números de Fibonacci dá bk+1bk+bk1Fib(k)+Fib(k1)=Fib(k+1)b_{k+1} \geq b_{k} + b_{k-1}\geq \textrm{Fib}(k) + \textrm{Fib}(k-1) = \textrm{Fib}(k+1), o que completa a prova do Teorema de Lamé.

📝 Encontrou algo errado nesta página?

Sua ajuda é muito importante para melhorar a qualidade da tradução!

🐛 Encontrou um erro?

Se você encontrou:

  • Erro de tradução (palavra incorreta, termo técnico errado)
  • Erro de ortografia ou gramática
  • Link quebrado
  • Código de exemplo que não funciona
  • Problema de formatação

Reporte um bug →

❓ Tem uma dúvida?

Se você tem:

  • Dúvida sobre o conteúdo desta seção
  • Pergunta sobre um conceito do SICP
  • Dificuldade em entender algum exemplo
  • Questão sobre a tradução de algum termo

Inicie uma discussão →

💡 Tem uma sugestão de melhoria?

Se você quer sugerir:

  • Melhoria na explicação
  • Exemplo adicional
  • Recurso visual (diagrama, ilustração)
  • Qualquer outra ideia

Sugira uma melhoria →

🌍 Quer discutir a tradução?

Se você quer debater:

  • Escolha de tradução de algum termo
  • Consistência de terminologia
  • Nuances do português

Discussão de tradução →

Obrigado por ajudar a melhorar o SICP.js PT-BR! ✨