Programação de Computadores I
UFOP
DECOM
2013–2
Aula prática 6
Comandos de repetição — while
Resumo
Nesta aula vamos trabalhar com problemas cuja solução envolve realizar um cálculo ou
tarefa repetidas vezes, enquanto uma determinada condição é satisfeita. Em outras palavras,
a implementação da solução de tais problemas requer o uso de um comando de repetição,
tal como o comando while.
Sumário
1 Comandos de repetição - while
A solução de diversos problemas, em computação, envolve a repetição de uma sequência
de tarefas, ou comandos, enquanto uma determinada condição é satisfeita. Esse processo de
repetição, ou loop, é implementado por meio do comando while, que tem a seguinte sintaxe:
while condição
bloco de comandos while
end
A condição deve ser uma expressão booleana, isto é, cujo valor é verdadeiro (%t) ou é
falso (%f). O bloco de comandos é qualquer sequência de comandos, incluindo, possivelmente,
comandos de atribuição, de entrada e saída, de desvio ou outros comandos de repetição.
A execução de um comando while é feita do seguinte modo:
1. a condição do while é avaliada;
2. se a condição avalia para %t (verdadeira), o bloco de comandos while é executado, e
volta-se ao passo 1;
3. caso contrário, isto é, se a condição avalia para %f (falso), comando while termina. A
execução do programa prossegue a partir do comando imediatamente subsequente ao end
do comando while.
Note que, se a condição for inicialmente falsa, isto é, se o resultado for %f na primeira vez
em que a condição é avaliada, o bloco de comandos while não é executado nenhuma vez. Por
outro lado, se o valor da condição permanece sempre verdadeiro, em cada iteração do comando
while, a execução desse comando prossegue indefinidamente.
2 Exemplos
2.1
Exemplo 1
Suponha que queremos determinar a menor sequência 1, 2, . . . , k, tal que a soma 1+2+· · ·+k
é maior ou igual a um dado valor n. Uma possível maneira de resolver este problema, seria
calcular a soma 1 + 2 + · · · + k repetidamente, para valores crescentes de k, até que essa soma
seja maior ou igual a n. Isso pode ser implementado, em Scilab, do seguinte modo:
1
// Menor sequência 1, 2, ..., k cujo somatório é maior ou igual a n
n = input("Digite um número inteiro positivo: ")
nums = []
// sequência de números considerados
soma = 0
// soma de todos os valores da sequência nums
next = 1
// próximo inteiro a ser incluído na sequência
while soma < n
nums(1,next) = next // inclui o o valor de next no vetor nums
soma = soma + next // adiciona o valor de next à soma da sequência next
next = next + 1 // próximo número a ser considerado na sequência
end
printf("A menor sequência 1, 2, ..., k cujo somatório é >= %g é:", n)
disp(nums)
Exemplo de execução da aplicação
Digite um número inteiro positivo:
10
A menor sequência 1, 2, ..., k cujo somatório é >= 10 é:"
1.
2.
3.
4.
Observações:
1. No corpo do comando while do programa acima, a execução do comando
nums(1,next) =
next
atribui ao elemento da linha 1, coluna next, do vetor nums, o valor contido na variável
next. Por exemplo, se o valor de next for 5, após execução deste comando, o valor de
nums(1,5) será 5. Note que, no programa acima, isso significa que nums é estendido,
colocando-se mais um valor no final desse vetor. Em Scilab, pode também ser usada a
seguinte forma alternativa, que pode ser entendida como "estenda o vetor nums, incluindo
o valor next no final deste vetor".
nums =
[nums next]
2. A função disp pode ser usada para exibir um valor na tela, de maneira semelhante à
função printf. A função disp recebe como argumento apenas os valores a serem exibidos na tela, não permitindo especificar como esses valores devem ser formatados, o que
significa que os valores são exibidos em uma formatação padrão adotada pelo Scilab.
2.2
Exemplo 2 - Validando um dado de entrada
Uma tarefa comum em programas consiste em testar se um dado fornecido pelo usuário é
válido, isto é, se corresponde a um valor esperado. Quando um usuário digita um valor inválido,
em geral queremos permitir que ele possa corrigir seu erro, digitando um novo valor. Para isso,
devemos solicitar ao usuário uma nova entrada, repetidas vezes, até que o valor digitado seja
válido. O exemplo a seguir ilustra a implementação desse tipo de tarefa, onde se considera a
entrada válida somente se ela for um número inteiro positivo:
// Verifica se o valor digitado é um inteiro positivo
n = input("Digite um valor inteiro positivo: ");
while n <> int(n) || n <= 0
printf("Valor inválido.")
n = input("Digite um valor inteiro positivo: ");
end
O corpo do comando while será repetido enquanto o usuário insistir em digitar um número
que não seja inteiro, ou que seja negativo ou nulo. Portanto, garante-se que, ao final do while,
2
o valor de n será um número inteiro positivo. Note que, se o usuário digitar um valor válido
inicialmente, o corpo do comando while não será executado nenhuma vez.
2.3
Exemplo 3 - Controle de Qualidade
Uma indústria de tubos de aço possui, em sua linha de produção, uma máquina para cortar
tubos. A máquina de corte é controlada por um programa, que verifica se os comprimentos dos
tubos cortados estão dentro de uma determinada margem de erro, em relação ao comprimento
desejado. Os tubos com comprimento inadequado são rejeitados.
No início da operação da máquina, são especificados o comprimento desejado para os tubos, a margem de erro aceitável e a quantidade de tubos necessária. A operação da máquina
deve parar quando tiver sido obtido o número de tubos desejados, com comprimentos dentro da
margem de erro especificada. Ao final da operação da máquina, o programa imprime o total de
tubos cortados e o número de tubos rejeitados, tal como mostrado no exemplo de execução do
programa, a seguir.
Exemplo de execução da aplicação
Controle de Qualidade de Corte de Tubos
--------------------------------------Comprimento de corte dos tubos: 10
Erro aceitável: .2
Número de tubos desejados: 4
--------------------------------------Comprimento do tubo cortado: 10.1
Comprimento do tubo cortado: 9.7
Comprimento do tubo cortado: 9.9
Comprimento do tubo cortado: 10.3
Comprimento do tubo cortado: 10
Comprimento do tubo cortado: 10.2
--------------------------------------Desligue a máquina.
Total de tubos cortados = 6
Total de tubos rejeitados = 2
Como poderia ser implementado esse programa? A idéia é usar um loop, que deverá terminar
quando for obtido o número de tubos desejados. No corpo do loop, devemos contar o número de
tubos com comprimento válido, isto é, com comprimento dentro da margem de erro aceitável,
em relação ao comprimento desejado. Essa idéia é implementada pelo programa a seguir.
3
clear; clc;
// Controle de Qualidade de corte de tubos
printf("Controle de Qualidade de Corte de Tubos\n")
printf("---------------------------------------\n")
lenP = input("Comprimento de corte dos tubos: ")
errP = input("Erro aceitável: ")
nTubos = input("Número de tubos desejados: ")
printf("---------------------------------------\n")
tubosOk = 0
// quantidade de tubos com comprimento aceitável
totTubos = 0 // quantidade total de tubos cortados
while tubosOk < nTubos
len = input("Comprimento do tubo cortado: ")
err = abs(len - lenP)
if err <= errP then
tubosOk = tubosOk + 1
end
totTubos = totTubos + 1
end
printf("---------------------------------------\n")
printf("Desligue a máquina.\n")
printf("Total de tubos cortados = %g\n", totTubos)
printf("Total de tubos rejeitados = %g\n", totTubos-nTubos)
4
3 Resolvendo problemas
Tarefa 1: Adivinhe! - 1
Qual é o menor número inteiro par que é divisível por 7 e cujo cubo é maior do que
4.000?
Escreva um programa para calcular e imprimir esse número.
Exemplo de execução da aplicação
O menor número par que é múltiplo de 7
e cujo cubo é maior do que 4.000 é 28
Dica:
A idéia é usar um loop, que seja repetido enquanto o número procurado – n – não for múltiplo
de 2, ou não for múltiplo de 7, ou seu cubo for menor que 4.000. Em cada passo, ou iteração do
loop, o valor de n deve ser incrementado. É claro que, antes iniciar o loop, deve ser atribuído a
n um valor apropriado. Existem quatro possíveis alternativas para implementar a solução:
1. Atribuir inicialmente a n o valor 1, e incrementar n de 1 em cada passo do loop. Neste
caso, qual deve ser a condição de teste do loop?
2. Atribuir inicialmente a n o valor 2, e incrementar n de 2 emcada passo do loop. Neste
caso, qual deve ser a condição de teste do loop? Note que essa solução é mais eficiente
do que a soluçãoanterior, pois o número de iterações do loop é a metade que na solução
anterior. Além disso, a condição de teste do loop envolve um teste a menos.
3. Atribuir inicialmente a n o valor 7, e incrementar n de 7 em cada passo do loop. Neste
caso, qual deve ser a condição de teste do loop? Essa solução é mais eficiente do que as
duas anteriores. Porque?
4. Existe uma alternativa ainda mais eficiente do que as 3 anteriores. Qual é ela? Qual deve
ser o valor inicial de n? De quanto n deve ser incrementado, em cada passo do loop? Qual
deve sera condição de teste? Quão mais eficiente é esta solução, em relação à primeira?
Veja que mesmo um programa bastante simples como este admite diversas soluções alternativas, com diferentes tempos de execução. É claro sempre almejamos a solução mais eficiente
possível. Portanto, pense bem sobre a solução de cada problema, antes de implementá-lo.
Tarefa 2: Adivinhe! - 2
Vamos agora generalizar o programa da tarefa anterior. Escreva um programa que
leia 4 valores inteiros positivos – a, b, c e k e encontre o menor número inteiro n que seja
divisível por a e por b e tal que nk > c.
Exemplo de execução da aplicação
Cálculo do menor n tal que n|a, n|b e n^k > c
--------------------------------------------a = 2
b = 7
c = 4000
k = 3
n = 28
5
Dica:
Qual seria o valor apropriado para inicialização de n, antes do loop? De quanto n deve ser
incrementado em cada passo do loop?
Lembre-se que o máximo divisor comum de dois números inteiros a e b – mdc(a, b) – pode
ser calculado pelo algoritmo de Euclides. O mínimo múltiplo comum de a e b – mmc(a, b) –
pode ser calculado como:
mmc(a, b) =
a ḃ
mdc(a, b)
Muitas vezes, um problema específico, tal como o do exemplo ??, pode ser generalizado. A
solução do problema mais geral nos permite obter resposta para vários problemas particulares,
que são instâncias do problema mais geral. Essa capacidade de generalização, ou abstração, é
um dos conceitos mais fundamentais em computação e na ciência em geral. Então, ao resolver
um problema, pense sempre se ele pode ser generalizado, pois a solução do problema mais geral
possivelmente poderá ser útil como parte da solução de outros problemas.
6
Tarefa 3: Collatz
A conjectura de Collatz, também conhecida como conjectura 3n+1, foi proposta pelo
matemático Lothar Collatz, em 1937. Para explicar essa conjectura, considere o seguinte
processo que descreve como obter a Sequência de Collatz para um número inteiro n > 0:
Se n for par, divida n por 2, obtendo n/2; se n for ímpar, multiplique n por 3
e some 1, obtendo 3n + 1. Repita esse processo para o valor obtido, e assim
sucessivamente, até que o valor obtido seja 1.
Exemplos:
n
5
11
12
sequência de Collatz para n
5, 16, 8, 4, 2, 1
11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
12, 6, 3, 10, 5, 16, 8, 4, 2, 1
A conjectura é que esse processo de cálculo sempre termina: sempre se obtém, eventualmente, o valor 1, para qualquer inteiro n > 0 dado inicialmente. Tal conjectura nunca
foi provada, mas também nunca se encontrou um exemplo em contrário.
Escreva um programa que leia um valor inteiro n > 0 e imprima a sequência de
Collatz para n, assim como o comprimento dessa sequência. O programa deve verificar
se o valor de entrada é válido, solicitando um novo valor caso não o seja.
Exemplo de execução da aplicação
Sequência de Collatz
--------------------Digite um número inteiro > 0: 11
Collatz: 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
Comprimento da sequência = 15
Dicas:
1. Uma maneira de implementar o programa é usar um vetor para armazenar a sequência
de Collatz. Esse vetor deve conter, inicialmente, apenas o número digitado. Cada novo
número da sequência é incluído nesse vetor, tal como mostrado no exemplo ??.
2. Para imprimir a sequência no formato acima, use os comandos a seguir, onde seq é o
vetor que contém a sequência gerada e i é o número de elementos dessa sequência:
printf("\nCollatz: ")
printf(strcat(repmat("%g ",1,i)),seq)
O significado das funções repmat e strcat é explicado a seguir (veja mais detalhes no
Help do Scilab):
função
repmat(A,m,n)
strcat(S)
descrição
retorna uma matriz que
consiste de m × n cópias
da matriz A
concatena todos os strings
na matriz de strings S
7
exemplo
repmat([1 2], 2, 3) =
[1 2 1 2 1 2; 1 2 1 2 1 2]
strcat(["ab" "cd"] = "abcd"
strcat(["ab" "cd"; "ef" "gh"]) =
"abefcdgh"
Tarefa 4: Controle de Qualidade
Sua tarefa agora é modificar o programa apresentado no exemplo ?? de modo que, ao
final do programa, sejam também impressos os seguintes dados:
1. o comprimento de cada um dos tubos aceitos,
2. o erro médio de corte de todos os tubos, e
3. o maior erro de corte dos tubos.
Exemplo de execução da aplicação
Controle de Qualidade de Corte de Tubos
--------------------------------------Comprimento de corte dos tubos: 10
Erro aceitável: .2
Número de tubos desejados: 4
--------------------------------------Comprimento do tubo cortado: 10.1
Comprimento do tubo cortado: 9.7
Comprimento do tubo cortado: 10.3
Comprimento do tubo cortado: 10
Comprimento do tubo cortado: 10.2
Comprimento do tubo cortado: 9.9
--------------------------------------Desligue a máquina.
Total de tubos cortados = 6
Total de tubos rejeitados = 2
Tubos aceitos: 10.1 10 10.2 9.9
Erro médio = 0.166667
Maior erro = 0.3
8
Download

P6. Comandos de repetição: while - Decom