Você sabe o que são os tais números perfeitos?
Se não sabe, não se preocupe, a matemática parece mesmo infinita quando se trata de conceitos e definições.
Vamos por parte. Todos os números possuem sua lista de divisores. O número 6 por exemplo possui os seguintes divisores positivos: 1, 2, 3, 6. Isso significa que o número 6 é divisível de forma exata apenas por esses números.
Agora, vamos somar os divisores do número 6 exceto o próprio 6. Perceba que o resultado dessa soma curiosamente é 6 = (1 + 2 + 3).
Assim, dizemos que um número n é um número perfeito se a soma de seus divisores positivos próprios (exceto o próprio n), for igual a n.
Será que é possível escrever um algoritmo para determinar se um número n é um número perfeito? Pode ter certeza que sim. Apresentaremos aqui uma solução possível e, acredito, a mais intuitiva.
A ideia básica para a construção deste algoritmo é, partido do número 1, descobrir quais números são divisores de n, exceto o próprio n claro.
Somando estes divisores, ao final saberes se n é um número perfeito ou não.
Apresentamos a seguir uma possível implementação desta função que retorna 1 se n for perfeito e 0 caso contrário.
int ehPerfeito(int n){// 500 250 500 int i, soma = 0; for(i = 1; i <= n/2; i++){ if(n % i == 0) soma += i; } if(soma == n) return 1;// é perfeito else return 0;// não é perfeito }
Com a finalidade de poder conferir os resultados, também implementamos um procedimento que recebe um número n e imprime todos os seus divisores. como apresentado a seguir.
void imprimeDivisores(int n){ int i; printf("%d = ", n); for(i = 1; i < n; i++){ if(n % i == 0) printf("%d, ", i); } printf("\n"); }
Por fim, na função principal de nosso programa, perguntamos ao usuário quantos números perfeitos ele deseja descobrir.
É realizada uma repetição, iniciando em 1, na tentativa de descobrir a quantidade de números perfeitos solicitada. A cada número perfeito descoberto, com a primeira função apresentada, seus divisores são impressos no terminal.
int main() { int n, quantidade = 0, perfeito, i = 1; printf("Quantos numeros perfeitos deseja?: "); scanf("%d", &n); while(quantidade < n){ perfeito = ehPerfeito(i); if(perfeito){ quantidade++; printf("%d: ", quantidade); imprimeDivisores(i); } i++; if(i % 50000 == 0) printf("%d\n", i); } return 0; }
Apesar de simples, não se anime muito. A sequência dos números perfeitos cresce assustadoramente rápido, de tal forma que você terá que esperar muito tempo até ver o quinto valor (se você viver tanto claro rsrs).
1º – 6
2º – 28
3º – 496
4º – 8128
5º – 33550336
A seguir apresentamos o código completo.
#include <stdio.h> #include <stdlib.h> // 6 = 1 + 2 + 3 = 6 /* 28 496 8128 33550336 */ int ehPerfeito(int n){// 500 250 500 int i, soma = 0; for(i = 1; i <= n/2; i++){ if(n % i == 0) soma += i; } if(soma == n) return 1;// é perfeito else return 0;// não é perfeito } void imprimeDivisores(int n){ int i; printf("%d = ", n); for(i = 1; i < n; i++){ if(n % i == 0) printf("%d, ", i); } printf("\n"); } int main() { int n, quantidade = 0, perfeito, i = 1; printf("Quantos numeros perfeitos deseja?: "); scanf("%d", &n); while(quantidade < n){ perfeito = ehPerfeito(i); if(perfeito){ quantidade++; printf("%d: ", quantidade); imprimeDivisores(i); } i++; if(i % 50000 == 0) printf("%d\n", i); } return 0; }
Se ficou alguma dúvida, compartilhe nos comentários que faremos o possível para esclarecer.
Não entendi o que as linhas 15 e 50 fazem, poderia explicar a lógica dessa parte do programa?
Olá Jorge.
A linha 15 for(i = 1; i <= n/2; i++) está dentro da função ehPerfeito. Esta função recebe um número n e seu retorno diz se n é um número perfeito (retorna 1) ou não (retorna 0). Agora, imagine n = 100. A lógica mais simples para descobrir se n é um número perfeito é procurar seus divisores de 1 até n - 1 (1 até 99 para n = 100), assim: for(i = 1; i <= n - 1; i++) Contudo, isso pode ser melhorado. Perceba o seguinte: 100 / 50 = 2 e 100 / 100 = 1 Isso nos faz chegar a conclusão que não existe nenhum outro valor entre 51 e 99 que, ao dividir 100, produzirá um resultado inteiro. Dizendo em outras palavras, 100 dividido por qualquer valor inteiro entre 51 e 99 terá como resultado um número real maior que 1 e menor que 2. Dessa forma, não precisamos procurar por divisores até n - 1, mas apenas até a metade de n, por isso o for termina em n/2. Sobre a linha 50: if(i % 50000 == 0) O código apresentado aqui pede ao usuário quantos número perfeitos ele deseja descobrir. Assim, se o usuário digitar por exemplo 4, o programa logo imprimir os 4 primeiros número perfeitos que são: 6, 28, 496 e 8128. Contudo, se o usuário digitar 5, o programa logo imprimirá os 4 primeiros números perfeitos e, aparentemente, não fará mais nada, como se tivesse travado. Isso acontece porque o quinto número perfeitos é o 33.550.336. Perceba que é um número muito grande, bem distante do quarto. A linha 50 está aí apenas para imprimir o valor da variável i na tela a cada 50 mil testes, indicando para o usuário que ele continua procurando o quinto número perfeito. Se você deixar seu programa rodando por alguns dias, talvez semanas, em algum momento ele vai chagar ao quinto valor. Se ainda não ficou claro diga aí que tento explicar de outra forma. Abraços e bons estudos.