
(
Fonte da Figura )
É sabido que a Peneira de Eratóstenes (ER) é um dos algoritmos mais antigos que surgiram muito antes da invenção dos computadores. Portanto, você pode pensar que, ao longo dos séculos, esse algoritmo foi estudado de cima para baixo e nada pode ser adicionado a ele. Se você olhar para a Wikipedia, há um mar de referências a fontes autorizadas nas quais você pode se afogar facilmente. Portanto, fiquei surpreso quando descobri acidentalmente outro dia que a
opção apresentada como ideal na Wikipedia pode ser significativamente otimizada.
Foi assim. Em uma discussão de um artigo sobre programação funcional (FP), ele fez uma
pergunta : como escrever RE neste paradigma. Possuindo um conhecimento mais do que escasso da FA, não me atrevo a julgar as respostas, mas outros participantes da discussão rejeitaram algumas das soluções propostas imediatamente, indicando que, em vez de complexidade teórica
O(n log logn) (1)a implementação proposta terá complexidade computacional
O(n2/ logn) 2)e que com tanta complexidade você não pode esperar quando, por exemplo, 10 milhões de números são analisados. Fiquei interessado e tentei implementar a versão ideal de acordo com a Wikipedia, usando a programação processual usual. No Delphi-7, obtive o seguinte código:
Listagem 1program EratosthenesSieve;
RE é representado pela matriz booleana da peneira com valores inversos - se o número for primo, é indicado como falso, o que reduz o número de operações de negação (não) durante a peneiração. Existem três procedimentos no programa: inicialização do RE - init, cálculos (peneiração e tacada de números no RE) - calc e impressão dos números primos encontrados como resultado - print e o número de números encontrados é contado. Vou chamar especialmente a atenção para a saída comentada de números primos no procedimento de impressão: para testes em N = 1000, o comentário é removido.
Aqui no procedimento de cálculo, uso a recomendação da Wikipedia: para o próximo número primo i, exclua os números do RE
i2,i2+i,i2+2i,...
Esse programa analisou um bilhão de números em 17,6 segundos. no meu PC (CPU Intel Core i7 de 3,4 GHz).
Tendo criado este programa, de repente me lembrei das propriedades conhecidas dos
números pares e ímpares .
Lema 1. 1) ímpar + ímpar = par; 2) ímpar + par = ímpar; 3) par + par = par.Prova1)
(2n+1)+(2m+1)=2n+2m+2 divisível por 2. TCD.
2)
(2n+1)+(2m)=2n+2m+1 não divisível por 2 sem restante. Chtd.
3)
(2n)+(2m)=2n+2m divisível por 2. TCD.
Lema 2. O quadrado de um número ímpar é um número ímpar.Prova. (2n+1)2=4n2+4n+1 não divisível por 2 sem restante. Chtd.
Observação. Um número primo maior que 2 é ímpar.Portanto, você pode excluir apenas números ímpares:
i2,i2+2i,i2+4i,... (3)Mas primeiro você precisa cruzar todos os números pares. Isso é feito por um procedimento de inicialização init modificado.
Listagem 2 program EratosthenesSieve;
Este programa funcionou por 9,9 segundos. - quase o dobro da velocidade.
Para avaliar a correspondência da operação em tempo real do programa com a teórica, sugeri que
dt=C∗O,
onde
dt - tempo de operação medido;
C - constante com a dimensão do tempo;
O - avaliação teórica.
Calculado a partir daqui
C avaliar (1) e (2). Para
N=106 e menos
dt perto de zero. Por isso, trago os dados do primeiro programa para grandes
N.Como vemos, a estimativa (1) está muito mais próxima dos resultados reais. Para o segundo programa, uma imagem semelhante é observada. Duvido muito que tenha descoberto a América usando a sequência (3) e ficarei muito grato pelo link para o trabalho em que essa abordagem foi aplicada. Provavelmente, os próprios autores da Wikipedia se afogaram em um mar de informações sobre a guerra eletrônica e perderam esse trabalho.
PS Para o algoritmo da Wikipedia com "tempo de execução linear",
consulte