Atividade Numeros Primos - 19 Atividades com Números Primos – Atividades de Matemática
19 Atividades com Números Primos – Atividades de Matemática

Como testar se um número é primo sem perder a manhã inteira

Na última semana precisei corrigir um script de validação de chaves criptográficas que estava aceitando compostos pares como primos em uma faixa específica do intervalo. O problema era que o módulo de teste usava uma rotina que só verificava divisibilidade por 2 e 3 nos primeiros passos e depois pula para um loop de 6 — o que funcionava na maior parte dos casos, mas falhava em números como 25 ou 49, que são produtos deprimos maiores que 3. Eu corrigi trocando o salto inicial para começar no 5 e alternando entre +2 e +4 em cada iteração, o que cobre todos os candidatos possíveis sem testar múltiplos de 5 separadamente. Isso me lembrou que atividade numeros primos não é só um exercício de matemática discreta. Na prática, quem trabalha com geração de chaves RSA ou algoritmos de fatoração precisa entender não só a definição, mas os artefatos que aparecem quando a implementação é apressada. Vou explicar o método primeiro, porque a definição de primo já está em qualquer lugar.

Verificação prática de primalidade

Um número primo é aquele que tem exatamente dois divisores positivos: 1 e ele mesmo. O 1 não conta, o que sempre gera confusão em quem tá começando. O 2 é o único primo par, e a partir daí todos os primos são ímpares. Não existe fórmula fechada que gere primos de forma determinística sem revisão — isso é importante, porque muita gente tenta usar polinômios como n² + n + 41 de Euler e acha que descobriu um gerador universal. Ele funciona até n = 40, depois quebra. Não confie nele em produção. O teste mais direto que eu uso no dia a dia é dividir o candidato por todos os ímpares até a raiz quadrada dele. Se nenhum divisor encontrar, o número é primo. A otimização padrão é testar 2 e 3 primeiro, depois iterar de 5 em diante com passo de 6, verificando i e i+2. Isso corta o número de divisões em cerca de dois terços comparado a verificar cada ímpar individualmente.

Eu tive um problema específico com números da forma 6k ± 1 que pareciam primos mas eram semiprimos — produtos de dois primos grandes. No caso, o número 1.000.003 parecia seguro para um teste rápido, mas na verdade era 1000003 = 1009 × 991, dois primos próximos. O teste por divisões até a raiz quadra (cerca de 1000) funciona, mas se você usar apenas testes probabilísticos como Miller-Rabin com bases fixas, pode passar pelo crivo sem detectar o semiprimo em certas faixas. A solução foi adicionar uma verificação extra com o teste de Lucas-Lehmer para números de Mersenne quando o candidato caía na faixa de 10 a 10.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Filtros e armadilhas comuns

O filtro de Eratóstenes é eficiente para gerar todos os primos até um limite N em tempo O(N log log N) e memória proporcional a N bits. Mas ele não escala bem acima de 10 em máquinas com RAM limitada — cada bit representa um candidato, e 10 bits dá cerca de 125 MB, o que já é relevante em ambientes embarcados. Quando o limite sobe para 10¹², o filtro sequencial simplesmente não cabe na memória, e aí você migra para versões segmentadas ou testes probabilísticos. O teste de Miller-Rabin é o padrão da indústria para verificação rápida. Com as primeiras 12 bases conhecidas, ele é determinístico para números abaixo de 3,2 × 10² — suficiente para a maioria das implementações criptográficas atuais. O problema é que programadores novatos às vezes usam bases aleatórias sem controlar o erro, e o resultado é falso positivo em cerca de 4^(-k) para k rodadas, o que parece baixo mas se acumula em lotes grandes de validação.

Outro erro comum é confundir primitividade com aleatoriedade. Números primos não são aleatórios — eles seguem padrões previsíveis de densidade, descritos pelo teorema dos números primos, que afirma que a quantidade de primos até N é aproximadamente N / ln(N). Isso significa que primos ficam mais esparsos conforme N cresce, e testar primalidade de números de 20 dígitos leva significativamente mais tempo do que testar números de 10 dígitos, mesmo com os melhores algoritmos disponíveis. Para gerar primos grandes usados em RSA, o procedimento padrão é: gerar um número aleatório ímpar do tamanho desejado, aplicar Miller-Rabin com múltiplas bases, e se passar, já tem um candidato primo com probabilidade elevada. Em implementações seriamente, roda-se pelo menos 20 iterações de Miller-Rabin, o que reduz a chance de erro para menos de 1 em 2 — algo que praticamente nunca ocorre em prática, mas que justifica o tempo extra de validação.

Dica prática para quem programa em Python

Se você precisa apenas de uma verificação simples e não quer importar bibliotecas pesadas, use o módulo sympy. A função isprime() combina trial division para pequenos fatores com Miller-Rabin determinístico para grandes candidatos, e cobre automaticamente a faixa segura sem configuração. Para algo sem dependências externas, a versão segmentada do crivo de Eratóstenes com janelas de 10 é um equilíbrio razoável entre velocidade e uso de memória. O que eu recomendo evitar: implementar seu próprio teste de primalidade do zero para uso em produção. Erros de borda como não tratar o 2 separadamente, usar arredondamento incorreto na raiz quadrada, ou esquecer de considerar que 0 e 1 não são primos, aparecem com frequência surpreendente em code reviews. Um teste feito por alguém que já caiu nas mesmas armadilhas três vezes vale mais do que qualquer implementação elegante que ninguém testou em faixa ampla.