O que você realmente precisa saber sobre números primos
Eu já fiz script depois de script pra listar números primos e nunca me dei bem com soluções genéricas. A maioria dos tutoriais começa explicando o conceito, mas o problema real é que quando você precisa encontrar todos os numeros primos num range grande, a diferença entre um algoritmo que funciona e um que trava sua máquina é ridícula. Vou direto ao que importa. Número primo é aquele divisível apenas por 1 e por ele mesmo. Ok, isso todo mundo sabe. O que ninguém conta é que testar divisibilidade um por um até a raiz quadrada do número é aceitável só pra listas curtas. Quando você tem que entregar uma lista completa, como em criptografia ou exercícios acadêmicos pesados, a criva de Eratóstenes é o mínimo que você deve usar. E mesmo assim, tem armadilha.
Como gerar todos os numeros primos até um limite N
A criva funciona assim: você cria um array booleano de 0 a N, marca tudo como possível primo, depois vai cruzando os múltiplos de cada primo encontrado a partir de 2. Começa em 2, marca todos os múltiplos de 2 como não primo, depois vai pro próximo não marcado, que é 3, e repete. Quando chega na raiz quadrada de N, o que sobra são os primos. Em Python, uma implementação mínima seria:
def criva_eratostenes(n):
primos = [True] * (n + 1)
primos[0] = primos[1] = False
for i in range(2, int(n0.5) + 1):
if primos[i]:
for j in range(i*i, n + 1, i):
primos[j] = False
return [i for i, x in enumerate(primos) if x] Isso gera todos os primos até N em tempo O(N log log N). Pra N=1 milhão, roda em menos de meio segundo num laptop comum. Pra N=100 milhões, leva uns 8 segundos. Tudo depende da memória disponível, porque o array booleano ocupa espaço proporcional a N.
👉 Clique no botão abaixo para saber mais sobre o assunto!
O erro que eu cometi e como resolvi
Num projeto meu, precisei listar todos os primos até 500 milhões pra um teste de densidade. A solução ingênua acima estourou memória — o array de booleanos ficou com cerca de 500MB, e o GC do Python começou a sofrer. A solução foi usar uma criva segmentada: dividi o intervalo em blocos de 10 milhões, processei cada bloco separadamente e fui acumulando os primos encontrados. Assim, a memória ficou estável em torno de 10-15MB e o tempo total não aumentou muito, talvez 30% a mais. Se você precisa de todos os numeros primos em ranges maiores que 100 milhões, a criva segmentada é o caminho. Se o range for menor, a versão simples basta.
Limitações reais que os tutoriais escondem
A criva de Eratóstenes é eficiente, mas não é mágica. Dois problemas sérios: memória e paralelização. A versão padrão é sequencial e não aproveita múltiplos núcleos de CPU. Existem variantes paralelas, mas elas complicam muito a implementação e só valem a pena em ranges enormes. Além disso, se seu objetivo é só verificar se um número é primo, não use a criva. Use o teste de Miller-Rabin, que é probabilístico mas extremamente rápido e usa memória constante. Outro ponto: números primos gigantes, como os usados em RSA de 2048 bits, não são gerados por criva. Eles são gerados por algoritmos que testam candidatos aleatórios com testes de primalidade. Não adianta tentar crivar até 2^2048 — é fisicamente impossível.
Quando usar o quê
Até 10 milhões: criva simples. Até 100 milhões: criva segmentada. Mais que isso: depende do que você precisa. Se quer a lista completa, criva segmentada com blocos maiores e salvando em disco. Se só precisa verificar primalidade de números específicos, Miller-Rabin. Se precisa de primos para criptografia, geradores especializados que combinam probabilidade com testes de Lucas-Lehmer-Riesel. A escolha errada do algoritmo é o motivo principal pelo qual gente novata tenta rodar código e ele nunca termina. Não é o computador lento. É o algoritmo inadequado pro tamanho do problema.
Recursos úteis
Se quer baixar listas prontas, o site primepages.org tem listas de até bilhões de primos. Pra rodar localmente, bibliotecas como sympy em Python já implementam criva otimizada. Em linguagens como C ou Rust, escrever sua própria criva segmentada é simples e ganha performance considerável. O importante é entender que todos os numeros primos num intervalo não são só um exercício teórico. Tem consequência prática direta na escolha do algoritmo, e errar isso custa tempo e recursos que poderiam ser economizados com um estudo mínimo antes de codar.