Este programa em C17 usa divisão por tentativa para testar números e listar os primos de 1 até um limite superior n, inclusive. Um primo é um inteiro maior ou igual a 2; portanto, limites de 0 ou 1 não produzem primos. Digite um único inteiro decimal entre 0 e INT_MAX.
Código
| |
Compilação e exemplo de execução
Salve como primes.c. Em um ambiente com GCC, execute gcc -std=c17 -Wall -Wextra -O2 primes.c -o primes e depois ./primes. Ao digitar 30, o programa mostra um cabeçalho seguido desta linha:
| |
O limite 2 produz 2; 0 ou 1 produz uma linha vazia. A entrada é uma linha de texto de até 127 bytes, sem contar a quebra de linha. Espaços em branco no início e no fim e um + inicial são permitidos. Valores negativos, linhas vazias, texto que não representa um inteiro, valores fora do intervalo, linhas longas demais e falhas de leitura causam um erro e encerram o programa. Apenas a primeira linha é processada; as seguintes não são usadas.
Como funcionam o teste e o tratamento da entrada
isPrimeretorna falso para valores menores ou iguais a 1 e verdadeiro para 2 e 3. Para os demais múltiplos de 2 ou 3, retorna falso. Depois testaiei + 2parai = 5, 11, 17, .... Os candidatos a divisor têm a forma6k - 1ou6k + 1, e não são múltiplos de 6. Nem todo número dessas formas é primo.- Todo número composto tem um divisor primo menor ou igual à sua raiz quadrada. Assim, basta continuar enquanto
i <= num / i. Para inteiros positivos, essa condição cobre o mesmo intervalo quei * i <= num, evitando o estouro da multiplicação emint. Não é necessário calcular uma raiz quadrada em ponto flutuante. printPrimesimprime apenas uma linha vazia quando o limite é menor que 2. Caso contrário, imprime 2 e testa os candidatos ímpares. Sei > n - 2, sai antes de somar, evitando o estouro do últimoi += 2, mesmo quando o limite éINT_MAX.readLimitlê comfgets, verifica o ponteiro para o fim da conversão eERANGEdestrtol, e confirma o intervalo de 0 aINT_MAXantes de converter paraint. O argumento deisspaceé convertido paraunsigned char. Ignorar o retorno descanf("%d", &n)pode levar ao uso de umnnão inicializado após uma entrada malsucedida. Também não se pode presumir que um resultado fora do intervalo deintseja tratado como uma simples falha de conversão.
Aplicabilidade
INT_MAX depende da implementação. Com um int de 32 bits, vale 2,147,483,647, mas C não exige esse valor em todas as implementações. Poder representar um limite não significa que listar todos os primos até ele será rápido.
Esta implementação serve para aprender divisão por tentativa. O teste de um número usa, no máximo, uma quantidade de divisões proporcional à sua raiz quadrada; para listar todos os candidatos, um limite superior aproximado é O(n sqrt(n)) divisões. Aqui cada divisão conta como uma operação: não se trata de complexidade em bits nem de tempo medido. Para listar primos em intervalos grandes, considere a peneira de Eratóstenes. Este programa não é um gerador de primos criptográficos. Para testar inteiros grandes, consulte o artigo sobre Miller–Rabin.
As regras das funções de entrada e da aritmética inteira de C estão nas seções 6.5, 7.4, 7.21.6.2, 7.21.7.2 e 7.22.1.4 do rascunho de comitê C11 N1570 do WG14.
