CAPÍTULO 4 ESTRUTURAS DE REPETIÇÃO
4.3 O comando while
Para introduzir uma nova estrutura de repetição e cotejá-la com o comando for, considere um programa para encontrar um divisor próprio de um inteiro dado (um divisor próprio de um inteiro n é um divisor de n menor que n e diferente de 1. Esta questão é importante na verificação da primalidade de um inteiro: um número que não tem divisores próprios é primo, conforme [Evaristo, J. 2002]). Com a utilização do comando for, teríamos a seguinte solução para esta questão.
{Programa que determina um divisor próprio de um inteiro}
program DivisorProprio;
var Num, i, Divisor : integer;
begin
write('Digite um numero: ');
readln(Num);
Divisor := 0;
for i := 2 to Num - 1 do if Num mod = 0
then
Divisor := i;
if Divisor <> 0 then
writeln(Divisor, ' eh divisor proprio de ', Num);
else
writeln(Num, ' eh primo');
end.
Um problema com este programa é que ele retorna sempre, se existir, o maior divisor próprio. Isto significa que, se a entrada for um número par, a estrutura de repetição não é interrompida quando o divisor 2 é encontrado, o que, evidentemente, vai prejudicar a performance do programa. Este problema pode ser resolvido em alguns compiladores Pascal que permitem que uma variável de controle de um comando for tenha o seu conteúdo alterado dentro do próprio comando. Com isto, o programa acima ficaria da seguinte forma.
{Programa que determina um divisor próprio de um inteiro}
program DivisorProprio;
var Num, i, Divisor : integer;
begin
write('Digite um numero: ');
readln(Num);
Divisor := 0;
for i := 2 to Num - 1 do if Num mod = 0
then begin
Divisor := i;
i := Num – 1;
end;
if Divisor <> 0 then
writeln(Divisor, ' eh divisor proprio de ', Num);
else
writeln(Num, ' eh primo');
end.
Nesta versão, quando o primeiro divisor próprio é encontrado, o comando i := Num – 1 e o seguinte incremento da variável i faz com que a execução do comando for seja interrompida. A prática de alterar o conteúdo da variável de controle não será aqui incentivada pelo fato de que outras linguagens não a permitem. Na verdade, a questão central é que o comando for deve ser utilizado quando o número de repetições de execução de uma seqüência de comandos é conhecido a priori. Quando isto não acontece (que é o caso do exemplo anterior: não se sabe a priori se e quando um divisor próprio vai ser encontrado), deve-se usar o comando while, que possui a seguinte sintaxe:
while Expressão lógica do seqüência de comandos
Quando da sua execução, a Expressão lógica é avaliada. Se for verdadeira, a seqüência de comandos é executada e o processamento retorna ao próprio comando while. Se for falsa, a seqüência não é executada e o processamento se transfere para o comando seguinte.
Naturalmente, pode ocorrer que a seqüência não seja executada nenhuma vez, isto acontecendo se a Expressão lógica for falsa quando da “primeira” execução do comando. Por outro lado, se a tal expressão lógica permanecer verdadeira, a seqüência de comandos terá sua execução infinitamente repetida o que implicará a não-execução da tarefa. Se isto acontece, dizemos que o programa está em looping e é necessária a digitação da combinação das teclas <Ctrl> + <Break> para interromper a sua execução.
Com o comando while as questões levantadas acima sobre o programa para determinar um divisor próprio de um inteiro dado são resolvidas e temos o seguinte programa:
{Programa que determina o menor divisor próprio de um inteiro}
program DivisorProprio;
var Num, Divisor : integer;
begin
write('Digite um numero: ');
readln(Num);
Divisor := 2;
while Num mod Divisor <> 0 do Divisor := Divisor + 1;
if Divisor < Num then
writeln(Divisor, ' eh divisor proprio de ', Num);
else
writeln(Num, ' e primo');
end.
Como todo inteiro é divisor de si mesmo, a estrutura while sempre será interrompida. Se foi interrompida com Divisor < Num, é porque um divisor próprio foi encontrado; se foi interrompida com Divisor = Num, então Num é primo.
Evidentemente esta versão é bem mais eficiente do que aquela que utilizava o comando for e o interessante é que ela ainda pode ser melhorada, pois a matemática prova que, se um inteiro não possui um divisor próprio menor do que sua raiz quadrada, então ele é primo (ver [Evaristo, J 2002]). Levando em conta este fato, teríamos o seguinte programa:
{Programa que determina o menor divisor próprio de um inteiro}
program DivisorProprio;
var Num, Divisor : integer;
begin
write('Digite um numero: ');
readln(Num);
Divisor := 2;
while (Num mod Divisor <> 0) and (Divisor <= SqrT(Num)) do Divisor := Divisor + 1;
if Divisor <= SqrT(Num) then
writeln(Divisor, ' e divisor proprio de ', Num);
else
writeln(Num, ' e primo');
end.
Na procura de se aprender a escrever programas mais eficientes, observe que a função SqrT foi executada duas vezes para o mesmo valor. Num caso como este, é mais interessante considerar uma variável para armazenar o valor da função e utilizar o conteúdo da variável nos outros comandos. Desta forma o programa anterior poderia ser assim escrito:
{Programa que determina o menor divisor próprio de um inteiro}
program DivisorProprio;
var Num, Divisor : integer;
Raiz : real;
begin
write('Digite um numero: ');
readln(Num);
Raiz := SqrT(Num);
Divisor := 2;
while (Num mod Divisor <> 0) and (Divisor <= Raiz) do Divisor := Divisor + 1;
if Divisor <= Raiz then
writeln(Divisor, ' e divisor proprio de ', Num);
else
writeln(Num, ' e primo');
end.
Aproveitando o ensejo, vale observar que o comando Divisor := 2; dos programas acima atribuiu um valor inicial à variável Divisor. Este valor era modificado quando não era um divisor de Num. Um comando de atribuição de um valor inicial a uma variável é chamado inicialização da variável.
Uma outra aplicação importante do comando while diz respeito a execuções sucessivas de um programa.
O leitor deve ter observado que os programas anteriores são executados apenas para uma entrada. Se quisermos a sua execução para outra entrada, precisamos executar o programa de novo.
Pode-se repetir a execução de um programa quantas vezes se queira, colocando-o numa estrutura definida por um comando while, controlada pelo valor de algum dado de entrada. Neste caso, o valor que encerra a execução pode ser informado dentro da mensagem que indica a necessidade da digitação da entrada. O programa anterior poderia ser então escrito da seguinte forma.
{Programa que determina o menor divisor próprio de vários inteiros}
program DivisorProprio;
var Num, Divisor : integer;
Raiz : real;
begin
Num := 1;
while Num <> 0 do begin
write('Digite um numero (0 para encerrar): ');
readln(Num);
Raiz := SqrT(Num);
Divisor := 2;
while (Num mod Divisor <> 0) and (Divisor <= Raiz) do Divisor := Divisor + 1;
if Divisor <= Raiz then
writeln(Divisor, ' eh divisor proprio de ', Num);
else
writeln(Num, ' eh primo');
end;
end.