Introdução
Considere o processo de pegar um número inteiro positivo n em alguma base be substituir cada dígito por sua representação na base do dígito à direita.
- Se o dígito à direita for 0, use a base b .
- Se o dígito à direita for 1, use unário com zeros como marcas de contagem.
- Se não houver um dígito à direita (ou seja, você está no local certo), faça um loop até o dígito mais significativo.
Como exemplo, deixe n = 160 eb = 10. A execução do processo é semelhante a esta:
The first digit is 1, the digit to the right is 6, 1 in base 6 is 1.
The next digit is 6, the digit to the right is 0, 0 is not a base so use b, 6 in base b is 6.
The last digit is 0, the digit to the right (looping around) is 1, 0 in base 1 is the empty string (but that's ok).
Concatenating '1', '6', and '' together gives 16, which is read in the original base b = 10.
O mesmo procedimento exato, mas mover para a esquerda em vez da direita também pode ser feito:
The first digit is 1, the digit to the left (looping around) is 0, 0 is not a base so use b, 1 in base b is 1.
The next digit is 6, the digit to the left is 1, 6 in base 1 is 000000.
The last digit is 0, the digit to the left is 6, 0 in base 6 is 0.
Concatenating '1', '000000', and '0' together gives 10000000, which is read in the original base b = 10.
Assim, criamos dois números relacionados a 160 (para b = 10): 16 e 10000000.
Definiremos n como um número astuto se ele dividir uniformemente pelo menos um dos dois números gerados nesse processo em 2 ou mais partes
No exemplo n é astuto porque 160 divide 10000000 exatamente 62500 vezes.
203 NÃO é astuto porque os números resultantes são 2011 e o próprio 203, que 203 não pode se ajustar uniformemente em 2 ou mais vezes.
Desafio
(Para o resto do problema, consideraremos apenas b = 10.)
O desafio é escrever um programa que encontre o maior número astuto que também seja primo.
Os primeiros 7 primos astutos (e tudo o que encontrei até agora) são:
2
5
3449
6287
7589
9397
93557 <-- highest so far (I've searched to 100,000,000+)
Não tenho oficialmente certeza se existem mais, mas espero que sim. Se você puder provar que existem (ou não) muitos, eu darei a você +200 representantes de recompensa.
O vencedor será a pessoa que poderá fornecer o mais alto astuto, desde que seja aparente que eles foram ativos na busca e não estão intencionalmente se gloriando dos outros.
Regras
- Você pode usar as ferramentas principais de busca que desejar.
- Você pode usar testadores probabilísticos primos.
- Você pode reutilizar o código de outras pessoas com atribuição . Este é um esforço comunitário. Táticas cruéis não serão toleradas.
- Seu programa deve procurar ativamente o principal. Você pode iniciar sua pesquisa no ponto mais alto conhecido.
- Seu programa deve poder calcular todos os primos espertos conhecidos dentro de 4 horas das instâncias do Amazon EC2 t2.medium (quatro de uma vez ou uma por quatro horas ou algo intermediário). Na verdade, não vou testá-lo e você certamente não precisa. Esta é apenas uma referência.
Aqui está o meu código Python 3 que eu usei para gerar a tabela acima: (roda em um ou dois segundos)
import pyprimes
def toBase(base, digit):
a = [
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
['', '0', '00', '000', '0000', '00000', '000000', '0000000', '00000000', '000000000' ],
['0', '1', '10', '11', '100', '101', '110', '111', '1000', '1001'],
['0', '1', '2', '10', '11', '12', '20', '21', '22', '100'],
['0', '1', '2', '3', '10', '11', '12', '13', '20', '21'],
['0', '1', '2', '3', '4', '10', '11', '12', '13', '14'],
['0', '1', '2', '3', '4', '5', '10', '11', '12', '13'],
['0', '1', '2', '3', '4', '5', '6', '10', '11', '12'],
['0', '1', '2', '3', '4', '5', '6', '7', '10', '11'],
['0', '1', '2', '3', '4', '5', '6', '7', '8', '10']
]
return a[base][digit]
def getCrafty(start=1, stop=100000):
for p in pyprimes.primes_above(start):
s = str(p)
left = right = ''
for i in range(len(s)):
digit = int(s[i])
left += toBase(int(s[i - 1]), digit)
right += toBase(int(s[0 if i + 1 == len(s) else i + 1]), digit)
left = int(left)
right = int(right)
if (left % p == 0 and left // p >= 2) or (right % p == 0 and right // p >= 2):
print(p, left, right)
if p >= stop:
break
print('DONE')
getCrafty()
fonte
Respostas:
Mathematica, encontra 93.557 em 0,3s (não há primos astutos abaixo de 2 * 10 10 )
Esta é apenas uma pesquisa exaustiva ingênua por todos os números primos. Para começar, ele verifica cerca de 1.000.000 de números primos a cada 55 segundos (que tendem a ficar mais lentos à medida que os números primos ficam maiores).
Estou usando várias funções auxiliares:
E então esse loop faz a pesquisa real:
Continuarei atualizando a postagem, se encontrar primos ou pensar em otimizações.
Atualmente, ele verifica todos os números primos até 100.000.000 em cerca de 5,5 minutos.
Edit: Decidi seguir o exemplo do OP e mudei para uma tabela de pesquisa para conversão de base. Isso deu aproximadamente 30% de aceleração.
Números espertos em geral
Estou interrompendo minha busca por números primos astutos agora, já que eu precisaria de vários dias apenas para acompanhar onde a resposta Perl já chegou. Em vez disso, comecei a procurar todos os números espertos. Talvez sua distribuição ajude a encontrar uma prova de que o número de números primos astutos é finito ou infinito.
Defino números habilidosos à direita aqueles que dividem o número relacionado obtido pela interpretação do dígito à direita como a nova base, e números habilidosos à esquerda de acordo. Provavelmente ajudará a resolvê-los individualmente para uma prova.
Aqui estão todos os números de esquerda espertos até 2.210.000.000:
E aqui estão todos os números espertos nesse intervalo:
Observe que há um número infinito de números astutos à esquerda e astutos à direita, porque existem várias maneiras de gerá-los a partir dos existentes:
0
s a qualquer número habilidoso à esquerda cujo dígito menos significativo seja maior que o dígito mais significativo para obter outro número habilidoso à esquerda.0
s a qualquer número habilidoso cujo dígito menos significativo seja menor que o dígito mais significativo. Isso (e a declaração anterior) ocorre porque o0
será anexado ao número astuto e ao número relacionado, multiplicando efetivamente os dois por 10.2
s ou5
s é astuto.777
s é astuto.28
unidos por0
s, como28028028
é sempre deixado astuto.Outras coisas a serem observadas:
125
. Pode valer a pena investigar aqueles para encontrar outra regra de produção.Suponho que essa lista seria mais interessante se eu omitisse aqueles cuja existência é implícita por um número menor de espertos, especialmente porque esses nunca são primos pelas regras de construção descobertas até agora. Então, aqui estão todos os números primos astutos que não podem ser construídos com uma das regras acima:
Observe também que existem alguns números duplamente espertos (aqueles que aparecem nas duas listas e, portanto, dividem os dois números relacionados):
Existem infinitamente muitos deles também.
Mas como você pode ver, exceto paraEncontrei o contra-exemplo16
,28
,68
todos estes consistir apenas de um único dígito (repetido). Também seria interessante provar se um número maior pode ser duplamente esperto sem ter essa propriedade, mas isso pode ser considerado um corolário de uma prova de números individualmente espertos.1944919449
.fonte
100540625, 100540625
na sua lista de artesãos certas?Perl (1e5 em 0,03s, 1e8 em 21s). Max 93557 a 1e11.
Muito parecido com o original. As mudanças incluem:
O primeiro 1e8 inicia em 21 segundos na minha máquina rápida, 3,5 minutos para 1e9, 34 minutos para 1e10. Estou um pouco surpreso que seja mais rápido que o código Python para pequenas entradas. Poderíamos paralelizar (o novo Pari / GP
parforprime
seria bom para isso). Como é uma pesquisa, podemos paralelizar à mão, suponho (forprimes
pode levar dois argumentos).forprimes
é basicamente como o Pari / GPforprime
- ele peneira segmentada internamente e chama o bloco com cada resultado. É conveniente, mas para esse problema, não acho que seja uma área de atuação.fonte
C ++ 11, com threads e GMP
Tempo (no MacBook Air):
Requisitos:
g++ crafty.cpp -o crafty --std=c++11 -ffast-math -lprimesieve -O3 -lgmpxx -lgmp -Wall -Wextra
Resultado:
fonte
C, com GMP, multithread (1e8 em 17s para 1 thread)
De conceito semelhante ao resto, provavelmente com algumas otimizações aqui e ali.
Compilar:
gcc -I/usr/local/include -Ofast crafty.c -pthread -L/usr/local/lib -lgmp && ./a.out
Por favor, doe sua energia da CPU. Eu não tenho um computador rápido.
1e8 em 17 segundos com 1 thread no meu macbook air.
fonte
Python, encontra 93557 em 0,28s
Muito semelhante ao código do OP, pois ele também usa
pyprimes
. Eu escrevi isso sozinho xDTambém imprime o tempo desde o início em que encontra um número.
Resultado:
O formato é
number left right time
. Como comparação, o código do OP encontra 93557 por aí0.37
.fonte