Lógica de Programação I Gilson de Souza Carvalho [email protected] Produzindo conhecimento, transformando vidas www.posse.ueg.br 1 Lógica de Programação I Comandos de Repetição Comandos de repetição comandos de condição combinados com A utilização de comandos de repetição combinados com comandos de condição permite resolver problemas bem mais complexos que os vistos até agora. Na realidade, o ferramental já apresentado é a base para toda a sequência de algoritmos, e sua compreensão é absolutamente fundamental para o desenvolvimento de algoritmos mais sofisticados. Produzindo conhecimento, transformando vidas www.posse.ueg.br 2 Lógica de Programação I Comandos de Repetição Os comandos de condição podem fazer parte de blocos pertencentes a comandos de repetição e vice-versa. Ou seja, estruturas como as descritas a seguir podem ocorrer intercaladas quantas vezes forem necessárias. Produzindo conhecimento, transformando vidas www.posse.ueg.br 3 Lógica de Programação I Comandos de Repetição ... if <valor boolean> { ... while <valor boolean> { ... } ... } //} do bloco if ... Produzindo conhecimento, transformando vidas www.posse.ueg.br 4 Lógica de Programação I Comandos de Repetição ... else { ... while <valor boolean> { ... if <valor boolean> { ... } else { ... } } } <continuação do algoritmo> //} do bloco while //} do bloco else} } Produzindo conhecimento, transformando vidas www.posse.ueg.br 5 Lógica de Programação I Comandos de Repetição Na estrutura anterior temos comandos de decisão aninhados a comandos de repetição e vice-versa. Esse tipo de estrutura é extremamente útil para resolver problemas em diversas situações. Vejamos a seguir alguns exemplos. Produzindo conhecimento, transformando vidas www.posse.ueg.br 6 Lógica de Programação I Comandos de Repetição Calcular a soma dos números ímpares de um intervalo Faça um algoritmo que calcule a soma de todos os números ímpares dentro de uma faixa de valores determinada pelo usuário. Um numero é ímpar quando sua divisão por 2 não é exata, ou seja, o mod(%) resultante da divisão inteira do numero por 2 tem valor 1.Vejamos como fica o código: Produzindo conhecimento, transformando vidas www.posse.ueg.br 7 Lógica de Programação I Comandos de Repetição if ((numero % 2) != 0) <código para numero impar> else <código para numero par> Como o algoritmo solicita a soma dos valores ímpares dentro de uma faixa, teremos que fazer o acúmulo do resultado apenas quando a condição ímpar for atendida. Essa condição será testada para todos os números dentro da faixa, por meio de um laço. Produzindo conhecimento, transformando vidas www.posse.ueg.br 8 Lógica de Programação I Comandos de Repetição #include <stdio.h> #include <stdlib.h> #include <locale.h> int main() { setlocale(LC_ALL,"portuguese"); unsigned short int n_inf, n_sup, s_impar; n_inf = n_sup = s_impar = 0; printf("Informe 2 numeros referente ao intervalo: \n"); scanf("%d %d", &n_inf, &n_sup); ... Produzindo conhecimento, transformando vidas www.posse.ueg.br 9 Lógica de Programação I Comandos de Repetição ... while (n_inf <= n_sup) { if ((n_inf % 2) != 0) s_impar += n_inf; n_inf++; } printf("Soma dos Impares: %d\n", s_impar); return 0; } Produzindo conhecimento, transformando vidas www.posse.ueg.br 10 Lógica de Programação I Comandos de Repetição Produzindo conhecimento, transformando vidas www.posse.ueg.br 11 Lógica de Programação I Comandos de Repetição 1. do o teste de mesa com intervalo definido entre 1 e 5. 2. Adapte o algoritmo Soma_Ímpares, para obrigar o usuário a entrar com um valor para o limite inferior menor que o valor definido para o limite superior. Para isto, faça um laço que garanta a entrada de um intervalo válido (inferior > superior). Produzindo conhecimento, transformando vidas www.posse.ueg.br 12 Lógica de Programação I Comandos de Repetição Determinar if um numero é primo Faça um algoritmo que escaneie um numero inteiro positivo e determine if este é primo ou não. Por definição, um numero é primo quando é divisível somente por si próprio e por 1, Portanto, para determinar if um numero é primo, temos de definir por quais números é divisível. A aproximação mais simples, e que podemos dizer ser uma aproximação de 'força bruta', poderia ser testar a divisibilidade do numero avaliado por todos os números menores que ele, Vejamos a implementação deste algoritmo. Produzindo conhecimento, transformando vidas www.posse.ueg.br 13 Lógica de Programação I Comandos de Repetição #include <stdio.h> #include <stdlib.h> #include <locale.h> #include <stdbool.h> int main() { setlocale(LC_ALL,"portuguese"); unsigned short int n1 = 0, divisor = 0; bool booleano = false; printf("Informe o numero a ser testado: "); scanf("%d", &n1); ... Produzindo conhecimento, transformando vidas www.posse.ueg.br 14 Lógica de Programação I Comandos de Repetição ... divisor = n1 - 1; while (divisor > 1 && booleano == false) { if (n1 % divisor == 0) booleano = true; else divisor = divisor - 1; } if (booleano == false) printf("Número é primo!"); else printf("Número não é primo!"); return 0; } Produzindo conhecimento, transformando vidas www.posse.ueg.br 15 Lógica de Programação I Comandos de Repetição Produzindo conhecimento, transformando vidas www.posse.ueg.br 16 Lógica de Programação I Comandos de Repetição #include <stdio.h> #include <stdlib.h> #include <locale.h> int main() { setlocale(LC_ALL,"portuguese"); unsigned short int n1 = 0, divisor = 0; printf("Informe o numero a ser testado: "); scanf("%d", &n1); ... Produzindo conhecimento, transformando vidas www.posse.ueg.br 17 Lógica de Programação I Comandos de Repetição ... divisor = n1 - 1; while (divisor > 1) { if (n1 % divisor == 0) { printf("Número não é primo! \n"); exit(0); } else divisor -= 1; } printf("Número é primo! \n"); return 0; } Produzindo conhecimento, transformando vidas www.posse.ueg.br 18 Lógica de Programação I Comandos de Repetição Produzindo conhecimento, transformando vidas www.posse.ueg.br 19 Lógica de Programação I Comandos de Repetição Apesar de o algoritmo Primo_Versão1 ser eficaz, visto que resolve o problema para o qual foi projetado, não if pode dizer que seja propriamente eficiente. Basta que analisemos com um pouco mais de profundidade que perceberemos que várias otimizações podem ser aplicadas ao raciocínio utilizado nesse algoritmo. Vejamos: Produzindo conhecimento, transformando vidas www.posse.ueg.br 20 Lógica de Programação I Comandos de Repetição *Números pares (com exceção do 2) não podem ser primos, visto que são divisíveis por 2, if um numero não for divisível por 2, não será divisível por nenhum outro numero par. Portanto, com exceção do numero 2, só precisaremos testar números ímpares. **É mais fácil que um numero seja divisível por um numero pequeno do que por um numero maior, Portanto, if iniciarmos a procura do divisor de baixo para cima, ao invés de cima para baixo, como foi implementado, teremos chance de encontrar o numero muito antes. Produzindo conhecimento, transformando vidas www.posse.ueg.br 21 Lógica de Programação I Comandos de Repetição ***Nenhum numero pode ser divisível por outro numero maior que a metade dele. Portanto, não precisamos testar a divisibilidade dos numero na faixa entre a metade e o próprio numero. if levarmos em conta tais considerações, teremos um algoritmo muito mais eficiente que o anterior, pois executará muito menos instruções para responder a mesma questão. Produzindo conhecimento, transformando vidas www.posse.ueg.br 22 Lógica de Programação I Comandos de Repetição LP1_16 Produzindo conhecimento, transformando vidas www.posse.ueg.br 23 Lógica de Programação I Comandos de Repetição LP1_16 Produzindo conhecimento, transformando vidas www.posse.ueg.br 24 Lógica de Programação I Comandos de Repetição Um raciocínio mais sofisticado pode ainda nos dar uma otimização final. Vejamos alguns exemplos para facilitar a compreensão deste ponto: • 15 é divisível pelos números 1,3,5 e 15(1*15,3*5, 5*3 e 15*1). • 16 é divisível pelos números 1, 2, 4, 8 e 16 (1*16,2*8,4*4,8*2 e 16*1). • 17 é divisível pelos números 1 e 17(1*17 e 17*1). • 20 é divisível pelos números 1, 2, 4, 5, 10 e 20 (1*20,2*10,4*5, 5*4,10 *2 e 20*1). • 25 é divisível pelo números 1, 5 e 25 (1*25,5*5 e 25*1). • 36 é divisível pelo números 1, 2, 3,4,6,9, 12, 18 e 36 (1*36, 2*18, 3* 12,4*9, 6*6,9*4, 12*3, 18*2 e 36*1). Produzindo conhecimento, transformando vidas www.posse.ueg.br 25 Lógica de Programação I Comandos de Repetição Os exemplos anteriores são para ilustrar a seguinte propriedade da divisibilidade de um numero: qualquer numero que seja divisível por outro terá como divisores dois números ou fatores, e um será maior que o outro, a não ser que tais números sejam iguais (quando o numero tem uma raiz quadrada exata). No caso de divisores diferentes, o numero menor sempre será menor que a raiz quadrada do resultado da multiplicação e o numero maior, maior que a raiz quadrada do numero em questão. Produzindo conhecimento, transformando vidas www.posse.ueg.br 26 Lógica de Programação I Comandos de Repetição Podemos perceber que quanto maior um dos fatores, menor o outro. A relação if inverte após a linha da raiz quadrada, quando os números if repetem em ordem inversa. Podemos, então, concluir que if um numero não for divisível por um numero menor ou igual à sua raiz quadrada, não terá outro divisor que não ele próprio ou o 1. ou seja, será um numero primo.****Portanto, só precisamos testar a divisibilidade de um numero por valores iguais ou inferiores à sua raiz quadrada. Adaptando o algoritmo, teremos o que if vê no exemplo a seguir. Produzindo conhecimento, transformando vidas www.posse.ueg.br 27 Lógica de Programação I Comandos de Repetição LP1_17 Produzindo conhecimento, transformando vidas www.posse.ueg.br 28 Lógica de Programação I Comandos de Repetição LP1_17 Produzindo conhecimento, transformando vidas www.posse.ueg.br 29 Lógica de Programação I Produzindo conhecimento, transformando vidas www.posse.ueg.br 30