Encontre o maior primo cujo comprimento, soma e produto sejam primos

37

O número 113é o primeiro primo cujo comprimento 3é primo, a soma digital 5 = 1 + 1 + 3é primo e o produto digital 3 = 1 * 1 * 3é primo.

Um primo que possui essas três propriedades será chamado de primo primordial . Os primos 11117e 1111151são outros exemplos.

Objetivo

Escreva um programa que encontre o maior número supremamente possível em menos de uma hora em um computador pessoal moderno decente (como a especificação preferida aqui ).

Você não deve simplesmente nos dar um grande supremo supremo. Você precisa nos mostrar seu processo de pesquisa com o código que realmente funciona. Você pode criar soluções suas ou de outras pessoas, mas não se esqueça de dar crédito a elas. Estamos meio que tentando encontrar o maior primo supremo possível de realizar em um computador normal em uma hora.

Pontuação

A finalização que encontra as maiores vitórias supremas. Se houver finitos numeros primos supremos, então a primeira submissão que gera as vitórias supremos mais altas.

(Se você puder provar matematicamente que existem ou não infinitos primos supremos, darei a você 200 representantes de recompensa só porque. :))

Detalhes

  • Você pode usar qualquer fonte para gerar seus números primos (por exemplo, internet).
  • Você pode usar métodos probabilísticos de teste principal.
  • Tudo está na base 10.
  • Zero e um NÃO são considerados primos.
  • Primes que contêm 0têm um produto digital 0tão obviamente que não podem ser supremos.
  • Para manter a página menos confusa, coloque números primos supremos grandes (mais de 100 dígitos) no formato:

    {[number of 1's before the prime digit]}[prime digit]{[number of 1's after the prime digit]}
    

    Então, 1111151pode ser expresso como {5}5{1}.

Passatempos de Calvin
fonte
Podemos começar com uma lista de números primos ou buscar uma lista na Internet e passar a hora fazendo verificações de supremacia?
Sparr
2
Se você pode começar com o primo supremo mais alto conhecido, isso se torna um desafio para quem pode escrever um programa que passa exatamente uma hora abrangendo a maior lacuna possível entre dois primos supremos. :(
Sparr
8
Além de não conter um 0, qualquer primo supremo em potencial deve obviamente ter a forma 1 ^ n [3 | 5 | 7] 1 ^ m, ou seja, alguns 1s, qualquer primo abaixo de 10 e outros 1s. Você pode colocar mais restrições imediatamente.
Ingo Bürk
3
Ryan iniciou uma pergunta relacionada no MSE sobre a existência de infinitos primos supremos. Se você tiver alguma idéia para essa pergunta, pesa!
Semiclassical
11
Posso mostrar facilmente que atualmente não há uma prova de um número infinito de primos supremos (e que uma quantidade substancial de trabalho foi direcionada a isso). De acordo com michaelnielsen.org/polymath1/… , sabemos que os números primos aparecem infinitamente com intervalos tão pequenos quanto 246, mas para uma prova de números primos supremos infinitos, precisamos de um intervalo de 2, 4 ou 6 (correspondendo aos números primos com 3, 5 ou 7 em algum lugar neles).
Tim S.

Respostas:

9

Perl, 15101 dígitos, {83} 7 {15017}, 8 minutos. Máximo encontrado: 72227 dígitos

Usando meu módulo Math :: Prime :: Util e seu back-end GMP . Possui vários testes de composição, incluindo is_prob_prime () com um teste ES BPSW ( um pouco mais rigoroso que o ispseudoprime de Pari), is_prime () que adiciona um MR de base aleatória e is_provable_prime () que executará o BLS75 T5 ou o ECPP. Nesses tamanhos e tipos, fazer uma prova vai demorar muito tempo. Joguei outro teste de RM no submarino pedante. Vezes em um Core2 E7500 que definitivamente não é o meu computador mais rápido (leva 2,5 minutos no meu i7-4770K).

Como Tim S. ressalta, podemos continuar procurando valores maiores, até o ponto em que um único teste leva uma hora. Com ~ 15.000 dígitos neste E7500, são necessários cerca de 26s para um teste de RM e 2 minutos para o is_prime completo (divisão de teste mais MR de base 2 mais ES Lucas mais um MR de base aleatória). Meu i7-4770K é 3x mais rápido. Tentei alguns tamanhos, principalmente vendo como funcionava nos resultados de outras pessoas. Eu tentei 8k, 20k e 16k, matando cada um após ~ 5 minutos. Eu tentei 15k em progressão por ~ 10m cada e tive sorte no quarto.

Os testes de PRP do OpenPFGW são certamente mais rápidos, depois dos 4000 ou mais dígitos, e muito mais rápidos na faixa de 50k +. No entanto, seu teste possui uma quantidade razoável de falsos positivos, o que o torna um ótimo pré-teste, mas ainda assim gostaria de verificar os resultados com outra coisa.

Isso pode ser paralelo com threads perl ou usando o MCE semelhante aos exemplos paralelos de busca de Fibonacci no módulo.

Tempo e resultados em um i7-4770K inativo usando o núcleo único:

  • entrada 3000, 16 segundos, 3019 dígitos, {318} 5 {2700}
  • entrada 4000, 47 segundos, 4001 dígitos, {393} 7 {3607}
  • entrada 4100, 5 segundos, 4127 dígitos, {29} 7 {4097}
  • entrada 6217, 5 segundos, 6217 dígitos, {23} 5 {6193}
  • entrada 6500, 5 minutos, 6547 dígitos, {598} 5 {5948}
  • entrada 7000, 15 minutos, 7013 dígitos, {2411} 7 {4601}
  • entrada 9000, 11 minutos, 9001 dígitos, {952} 7 {8048}
  • entrada 12000, 10 minutos, 1.2007 dígitos, {652} 5 {11354}
  • entrada 15100, 2,5 minutos, 15101 dígitos, {83} 7 {15017}
  • entrada 24600, 47 minutos, 24671 dígitos, {621} 7 {24049}
  • entrada 32060, 18 minutos, 32063 dígitos, {83} 7 {31979}
  • 57000, 39 minutos, 57037 dígitos, {112} 5 {56924}
  • entrada 72225, 42 minutos, 72227 dígitos, {16} 3 {72210}

Para o resultado de 32k dígitos, iniciei 6 scripts em execução ao mesmo tempo, cada um com argumentos sucessivos começando em 32000. Após 26,5 minutos, um terminou com o resultado de 32063 dígitos mostrado. Para 57k, permiti que scripts sucessivos executassem 6 por vez, durante uma hora, em incrementos de entrada de 500 até que o resultado de 57k retornasse em 57 minutos. O resultado de 72k dígitos foi encontrado com primos sucessivos de 70k em diante, portanto, definitivamente não foi encontrado em uma hora (embora depois que você saiba por onde começar, é).

O script:

#!/usr/bin/env perl
use warnings;
use strict;
use Math::Prime::Util qw/:all/;
use Math::Prime::Util::GMP;  # Just to ensure it is used.

my $l = shift || 1000;  $l--;

while (1) {
  $l = next_prime($l);
  my @D = grep { is_prime($l-1 + $_) } (3,5,7);
  next unless scalar @D > 0;
  for my $s (0 .. $l-1) {
    my $e = $l-$s-1;
    warn "   checking $l $s\n" unless $s % 100;
    for my $d (@D) {
      my $n = "1"x$s . $d . "1"x$e;
      die unless length($n) == $l;
      verify_supreme($n,$s,$d,$e) if is_prime($n);  # ES BPSW + 1 rand-base M-R
    }
  }
}
sub verify_supreme {  # Be pedantic and verify the result
  my($n,$s,$d,$e) = @_;
  die "Incorrect length" unless is_prime(length($n));
  die "Incorrect sum" unless is_prime(vecsum(split(//,$n)));
  my $prod = 1; $prod *= $_ for split(//,$n);
  die "Incorrect product" unless is_prime($prod);
  die "n is not a prime!" unless miller_rabin_random($n,1);  # One more M-R test
  die "{$s} $d {$e}\n";
}
DanaJ
fonte
+1 por me apresentar a esta biblioteca! Horários na minha máquina para fazer uma iteração primos menos de 10 ^ 7 (em comparação com CPython com gmpy2e PyPy com my_math): codepad.org/aSzc0esT
primo
Estou feliz por ter gostado! Existem outras maneiras, incluindo o forprimes { ...do stuff... } 1e7;que é 10x ou mais rápido (parabéns ao Pari / GP por muitas ótimas idéias). Eu sempre aprecio o feedback, então, deixe-me saber se algo não está funcionando da maneira que você deseja.
DanaJ
21

Python 2.7 no PyPy, {2404} 3 {1596} (~ 10 ^ 4000)

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111113111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Encontrei este cerca de 50 minutos após o início de 4000. Portanto, eu estimaria que esse é o limite superior dessa abordagem de código.

Alteração: notei que alguns comprimentos parecem ser mais proveitosos para gerar esse tipo de primo do que outros, então decidi verificar apenas 50 locais aleatórios do dígito que não é 1, em vez de todos os locais possíveis, antes de mudar em. Não tenho certeza absoluta de que isso melhore o desempenho ou que 50 esteja correto, mas veremos.

A lista de possibilidades é gerada com base no fato de que, para que o requisito de produtos seja atendido, o número deve ser todos, exceto um primo. Além disso, o número primo não pode ser 2 por causa da relação soma e comprimento, e a soma digital não deve ser divisível por três, fornecendo os requisitos de% 3.

is_prime extraído de http://codepad.org/KtXsydxK , escrito por @primo

Nota: essa função is_prime é na verdade um teste de pseudoprime Baillie-PSW, mas não há contra-exemplos conhecidos, portanto, não vou me preocupar com a distinção.

#http://codepad.org/KtXsydxK
from my_math import is_prime
import time,random
LLIMIT=2748
time.clock()
start_time=time.time()
checked=0
while time.time()-start_time<3600:
    small_primes = [a for a in range(LLIMIT,2*LLIMIT) if is_prime(a)]
    leng,dig=(0,0)
    for a in small_primes:
        if a+2 in small_primes:
            leng,dig=(a,3)
            break
        if a+4 in small_primes:
            leng,dig=(a,5)
            break
        if a+6 in small_primes:
            leng,dig=(a,7)
            break
    start=time.clock()
    print leng,dig,time.clock(),checked
    for loc in random.sample(range(leng),50):
        checked+=1
        if is_prime(int('1'*loc+str(dig)+'1'*(leng-loc-1))):
            print leng-1,loc,dig,time.clock(),time.clock()-start, \
                  int('1'*loc+str(dig)+'1'*(leng-loc-1))
            break
    LLIMIT=leng+1
isaacg
fonte
Não sei nada além do link, infelizmente. Encontrei o link aqui: codegolf.stackexchange.com/questions/10739/… Primeira resposta
isaacg
Bem então. Eu credito você.
Isaacg
10
É como um ASCII onde está wally ...
Trichoplax
5
Talvez você deve renomear a função is_very_very_very_very_very_very_very_probably_prime()...
Trichoplax
2
Mathmatica e Maple usam o mesmo método, por isso não pode ser tão ruim assim.
primo
13

PARI / GP, 4127 dígitos

(10 4127 -1) / 9 + 2 * 10 515

Essa é uma pesquisa bastante direta: verifique apenas os comprimentos dos dígitos primos, depois calcule os números primos possíveis de usar e, em seguida, repita todas as possibilidades. Eu casei especialmente os casos comuns em que existem 0 ou 1 dígitos primos adequados para usar.

supreme(lim,startAt=3)={
    forprime(d=startAt,lim,
        my(N=10^d\9, P=select(p->isprime(d+p),[1,2,4,6]), D, n=1);
        if(#P==0, next);
        if(#P==1,
            for(i=0,d-1,
                if (ispseudoprime(D=N+n*P[1]), print(D));
                n*=10
            );
            next
        );
        D=vector(#P-1,i,P[i+1]-P[i]);
        for(i=0,d-1,
            forstep(k=N+n*P[1],N+n*P[#P],n*D,
                if (ispseudoprime(k), print(k))
            );
            n*=10
        )
    )
};
supreme(4200, 4100)

Demorou 36 minutos para calcular em um núcleo de uma máquina bastante antiga. Não seria difícil encontrar um número tão alto de mais de 5000 dígitos em uma hora, tenho certeza, mas também estou impaciente.

Uma solução melhor seria usar qualquer linguagem razoável para fazer tudo, exceto o loop mais interno, e então construir um arquivo abc para o primeform, otimizado para esse tipo específico de cálculo. Isso deve poder empurrar o cálculo para pelo menos 10.000 dígitos.

Edit : Eu implementei a solução híbrida descrita acima, mas na minha máquina antiga não consigo encontrar o primeiro termo com> = 10.000 dígitos em menos de uma hora. A menos que eu execute algo mais rápido, terei que mudar para um alvo menos elevado.

Charles
fonte
Como você soube começar no 4100?
Isaacg
@isaacg: Eu estava apenas tentando ser maior do que a solução (incorreta) do Mathematica, que tinha pouco mais de 4000. Acabei de passar para o próximo múltiplo de 100 como um número 'nada-da-minha-manga'. Na verdade, parece que esse foi um ponto de partida infeliz, pois eu tive que ir mais do que eu esperava (e mais do que o Mathematica!) Para encontrar o melhor.
Charles
Não, na verdade, você teve uma sorte incrível. (4127,3) é o primeiro par depois de 4100 e, por puro acaso, ele tem um primo. Muitos pares não têm primo.
Isaacg
@isaacg: Talvez sim. Minhas heurísticas estão claramente erradas, já que eu esperava uma probabilidade de ~ 80% encontrar um primo em um determinado par: 1 - exp (-15 / (4 * log 10)), mas elas parecem ser mais raras do que isso, portanto não aja como números suaves de seu tamanho {2, 3, 5} - suaves (a menos que eu tenha ignorado o cálculo).
Charles Charles
@isaacg: De qualquer forma, estou trabalhando na "melhor solução" que mencionei agora: forçando o trabalho duro para o pfgw. Ele pesquisou os primeiros 20 pares acima de 10 ^ 10000 sem encontrar nada, mas isso levou apenas 15 minutos.
Charles
7

Dígitos do Mathematica 3181

Atualização: houve alguns erros graves na minha primeira submissão. Consegui dedicar algum tempo para verificar os resultados deste. A saída é formatada como uma lista de dígitos. Isso facilita a verificação de cada uma das condições.

f[primeDigitLength_]:=
Module[{id=ConstantArray[1,primeDigitLength-1]},
permutations=Reverse@Sort@Flatten[Table[Insert[id,#,pos],{pos,primeDigitLength}]&/@{3,5,7},1];
Flatten[Select[permutations,PrimeQ[FromDigits[#]]\[And]PrimeQ[Plus@@#]&,1],1]]

Exemplo

Este foi o meu primeiro teste, uma busca por uma solução com 3181 dígitos. Encontrou o primeiro caso em 26 segundos.

Vamos analisar o raciocínio. Então entraremos no programa em si.

Vamos começar, como eu fiz, "Qual é o 450º primo?" Podemos encontrar uma solução com tantos dígitos (3181)?

primeDigits = Prime[450]

3181


O número é encontrado juntando os dígitos.

number = FromDigits[digits];

Mas, em vez de exibi-lo, podemos perguntar quais são os dígitos e onde estão.

DigitCount[number]

{3180, 0, 0, 0, 0, 0, 1, 0, 0, 0}

Isso significa que havia 3180 instâncias do dígito 1 e uma única instância do dígito 7.

Em que posição está o dígito 7?

Position[digits, 7][[1, 1]]

142

Portanto, o dígito 7 é o 142º dígito. Todos os outros são 1's.


Obviamente, o produto dos dígitos deve ser primo, ou seja, 7.

digitProduct = Times @@ digits

7


E a soma dos dígitos também é primordial.

digitSum = Plus @@ digits
PrimeQ[digitSum]

3187
True


E sabemos que o número de dígitos é primo. Lembre-se, selecionamos o 450º primo, ou seja, 3118.

Então, todas as condições foram cumpridas.

DavidC
fonte
3
Se não me engano, sua soma é 4009, o que não é primo.
gerw 31/07
Uma coisa: não deveria ser a soma de todos os dígitos primos e não o número de dígitos? No seu caso, você precisaria testar 4002 * 1 + 7 = 4009e não o 4003, de acordo com as especificações.
31414 Johnride
2
@ Johnride: Ambos devem ser primos.
gerw 31/07
@gerw está certo. O número de dígitos E a soma dos dígitos E o produto dos dígitos devem ser primos.
Calvin's Hobbies
Vocês todos estavam corretos. Na minha submissão anterior, esqueci de verificar a soma dos dígitos quanto à primalidade. Isso é feito agora, verificando se um dos seguintes (não importa qual) é primo: comprimento do dígito + 2, comprimento do dígito _4 ou Comprimento do dígito +6.
DavidC
7

Python 2.7, 6217 dígitos: {23} 5 {6193} 6 minutos 51 segundos

Eu estava trabalhando em minha própria versão e fiquei desapontado ao ver que @issacg havia me superado com uma abordagem muito semelhante, embora com is_ (very_probably) _prime (). No entanto, vejo que tenho algumas diferenças significativas que resultam em uma resposta melhor em menos tempo (quando eu também uso is_prime). Para deixar isso claro, quando também a partir de 4000, chego a uma resposta melhor de 4001 dígitos ({393} 7 {3607}) em apenas 26 minutos, 37 segundos usando o interpretador Python padrão (também na versão 2.7), não o PyPy versão. Além disso, não estou 'verificando' os números. Todos os candidatos são verificados.

Aqui estão as principais melhorias:

  1. Use um gerador principal ( https://stackoverflow.com/questions/567222/simple-prime-generator-in-python/568618#568618 ) para criar uma lista de números primos a serem verificados (e sua versão de "números primos pequenos") e para gerar comprimentos de número elegíveis.

  2. Queremos gastar nosso tempo procurando o maior número primo supremo de um determinado comprimento, não o menor; portanto, construo os maiores números possíveis primeiro para verificação, não o menor. Então, uma vez encontrado, podemos passar imediatamente para o próximo comprimento.

EDIT: Agora com multiprocessamento

Esta é uma alteração significativa para as versões anteriores. Antes, notei que minha máquina com 8 núcleos mal estava funcionando, então decidi tentar o multiprocessamento em Python (primeira vez). Os resultados são muito bons!

Nesta versão, são gerados 7 processos filhos, que retiram uma 'tarefa' de uma fila de possibilidades em potencial (num_length + dígitos elegíveis). Eles agitam tentando diferentes [7,5,3] posições até encontrar uma. Se assim for, informa o processo mestre do novo comprimento mais longo que foi encontrado. Se as crianças estiverem trabalhando em um num_length menor, elas apenas pagam a fiança e vão para a próxima.

Comecei esta corrida com 6000, e ela ainda está em execução, mas até agora estou muito satisfeito com os resultados.

O programa ainda não para corretamente, mas não é um grande negócio para mim.

Agora o código:

#!/usr/bin/env python
from __future__ import print_function

import sys
from multiprocessing import Pool, cpu_count, Value
from datetime import datetime, timedelta

# is_prime() et al from: http://codepad.org/KtXsydxK - omitted for brevity
# gen_primes() from: https://stackoverflow.com/questions/567222/simple-prime-generator-in-python/568618#568618 - ommitted for brevity
from external_sources import is_prime, gen_primes


def gen_tasks(start_length):
    """
    A generator that produces a stream of eligible number lengths and digits
    """
    for num_length in gen_primes():
        if num_length < start_length:
            continue

        ns = [ n for n in [7,5,3] if num_length + n - 1 in prime_list ]
        if ns:
            yield (num_length, ns)


def hunt(num_length, ns):
    """
    Given the num_length and list of eligible digits to try, build combinations
    to try, and try them.
    """

    if datetime.now() > end_time or num_length <= largest.value:
        return

    print('Tasked with: {0}, {1}'.format(num_length, ns))
    sys.stdout.flush()
    template = list('1' * num_length)
    for offset in range(num_length):
        for n in ns:
            if datetime.now() > end_time or num_length <= largest.value:
                return

            num_list = template[:]
            num_list[offset] = str(n)
            num = int(''.join(num_list))

            if is_prime(num):
                elapsed = datetime.now() - start_time
                largest.value = num_length
                print('\n{0} - "{1}"\a'.format(elapsed, num))


if __name__ == '__main__':
    start_time = datetime.now()
    end_time = start_time + timedelta(seconds=3600)

    print('Starting @ {0}, will stop @ {1}'.format(start_time, end_time))

    start_length = int(sys.argv[1])

    #
    # Just create a list of primes for checking. Up to 20006 will cover the first
    # 20,000 digits of solutions
    #
    prime_list = []
    for prime in gen_primes():
        prime_list.append(prime)
        if prime > 20006:
            break;
    print('prime_list is primed.')

    largest = Value('d', 0)

    task_generator = gen_tasks(start_length)

    cores = cpu_count()
    print('Number of cores: {0}'.format(cores))


    #
    # We reduce the number of cores by 1 because __main__ is another process
    #
    pool = Pool(processes=cores - 1)

    while datetime.now() < end_time:
        pool.apply_async(hunt, next(task_generator))
mkoistinen
fonte
ele iria ler mais limpa se você representa o link do Controlador Remoto como um [quebrado, se necessário] importação
Sparr
Eu acho que seria confuso, pois o código do outro lado não é realmente importável assim.
Mkoistinen
use a sintaxe de isaacg. comentar o URL, em seguida, importar a partir de um pacote inexistente (my_math, no seu caso)
Sparr
11
Na verdade, eu também gero os números do maior para o menor. Não acho que nossas diferenças de código sejam muito significativas. Eu esperava que a diferença estivesse mais em nossos computadores do que em nosso código. No entanto, bem feito, e bem-vindo ao site.
Isaacg
my_mathtambém pode ser usado para gerar uma lista de números primos, à la while prime < 20006: prime = next_prime(prime). Parece ser cerca de três vezes mais rápido gen_primese muito mais eficiente em termos de memória.
primo
6

C, GMP - {7224} 5 {564} = 7789

Parabéns a @issacg e a todos vocês pelas inspirações e truques.
E também a pergunta magistral solicitada @ Calvin's Hobbies para esta pergunta.

Compilar: gcc -I/usr/local/include -o p_out p.c -pthread -L/usr/local/lib -lgmp

Se você deseja doar seu poder computacional ou curioso pelo desempenho, copie o código e compile. ;) Você precisará do GMP instalado.

#include<stdio.h>
#include<stdlib.h>
#include<sys/time.h>
#include<gmp.h>
#include<pthread.h>

#define THREAD_COUNT 1
#define MAX_DIGITS   7800
#define MIN_DIGITS   1000

static void huntSupremePrime(int startIndex) {

    char digits[MAX_DIGITS + 1];

    for (int i = 0; i < MAX_DIGITS; digits[i++] = '1');

    digits[MAX_DIGITS] = '\0';
    mpz_t testPrime, digitSum, digitCount, increment;

    for (int j = 0; j < MAX_DIGITS - startIndex; digits[j++] = '0');

    int step = THREAD_COUNT * 2;

    for (int i = startIndex, l = MAX_DIGITS - startIndex; i > MIN_DIGITS - 1; 
        i -= step, l += step) {
        fprintf(stderr, "Testing for %d digits.\n", i);
        mpz_init_set_ui(digitCount, i);
        if (mpz_millerrabin(digitCount, 10)) {
            for (int j = 3; j < 8; j += 2) {
                mpz_init_set_ui(digitSum, i - 1 + j);
                if (mpz_millerrabin(digitSum, 10)) {
                    gmp_printf("%Zd \n", digitSum);
                    digits[MAX_DIGITS - 1] = j + 48;
                    mpz_init_set_str(testPrime, digits, 10);
                    mpz_init_set_ui(increment, (j - 1) * 99);
                    for (int k = 0; k < i/20; ++k) {
                        if (mpz_millerrabin(testPrime, 25)) {
                            i = 0;
                            j = 9;
                            k = l;
                            gmp_printf("%Zd\n", testPrime);
                            break;
                        }
                        mpz_add(testPrime, testPrime, increment);
                        mpz_mul_ui(increment, increment, 100);
                        fprintf(stderr, "TICK %d\n", k);
                    }

                }
            }
        }
        for (int j = 0; j < step; digits[l + j++] = '0');

    }
}

static void *huntSupremePrimeThread(void *p) {
    int* startIndex = (int*) p;
    huntSupremePrime(*startIndex);
    pthread_exit(NULL);
}

int main(int argc, char *argv[]) {

    int  startIndexes[THREAD_COUNT];
    pthread_t threads[THREAD_COUNT];

    int startIndex = MAX_DIGITS;
    for (int i = 0; i < THREAD_COUNT; ++i) {
        for (;startIndex % 2 == 0; --startIndex);
        startIndexes[i] = startIndex;
        int rc = pthread_create(&threads[i], NULL, huntSupremePrimeThread, (void*)&startIndexes[i]); 
        if (rc) { 
            printf("ERROR; return code from pthread_create() is %d\n", rc);
            exit(-1);
        }
        --startIndex;
    }

    for (int i = 0; i < THREAD_COUNT; ++i) {
        void * status;
        int rc = pthread_join(threads[i], &status);
        if (rc) {
            printf("ERROR: return code from pthread_join() is %d\n", rc);
            exit(-1);
        }
    }

    pthread_exit(NULL);
    return 0;
}
Vetorizado
fonte
5

PFGW, 6067 dígitos, {5956} 7 {110}

Execute PFGW com o seguinte arquivo de entrada e -f100para pré-fatorar os números. Em cerca de 2-3 minutos de CPU no meu computador (i5 Haswell), ele encontra o PRP (10 ^ (6073-6) -1) / 9 + 6 * 10 ^ 110 ou {5956} 7 {110} . Eu escolhi 6000 dígitos como ponto de partida como um número do tipo "nada na minha manga", que é um pouco maior do que todos os envios anteriores.

ABC2 $a-$b & (10^($a-$b)-1)/9+$b*10^$c
a: primes from 6000 to 6200
b: in { 2 4 6 }
c: from 0 to 5990

Com base na rapidez com que consegui encontrar esse, pude facilmente aumentar o número de dígitos e ainda encontrar um PRP em uma hora. Com a forma como as regras são escritas, posso até encontrar o tamanho em que minha CPU, rodando nos quatro núcleos, pode concluir um teste de PRP em uma hora, demorar muito tempo para encontrar um PRP e fazer com que minha "pesquisa" seja apenas de um PRP.

PS Em alguns sentidos, essa não é uma solução de "código" porque eu não escrevi nada além do arquivo de entrada ... mas, em seguida, muitas soluções Mathematica de uma linha para problemas matemáticos poderiam ser descritas da mesma maneira, como poderiam usando uma biblioteca que faz o trabalho duro para você. Na realidade, acho difícil traçar uma boa linha entre os dois. Se você preferir, eu poderia escrever um script que crie o arquivo de entrada PFGW e chame PFGW. O script pode até pesquisar em paralelo, para usar todos os 4 núcleos e acelerar a pesquisa em ~ 4 vezes (na minha CPU).

PPS Acho que o LLR pode fazer os testes de PRP para esses números, e espero que seja muito mais rápido que o PFGW . Um programa dedicado de peneiração também poderia ser melhor para fatorar esses números do que o PFGW, um de cada vez. Se você combinou isso, tenho certeza de que poderia aumentar os limites muito mais do que as soluções atuais.

Tim S.
fonte
4

Python 2.7, 17-19 dígitos

11111111171111111

Encontrado 5111111111111 (13 dígitos) em 3 segundos e esse supremo supremo de 17 dígitos em 3 minutos. Suponho que a máquina alvo possa executar isso e obter um primo supremo de 19 dígitos em menos de uma hora. Essa abordagem não é bem dimensionada porque mantém primos até a metade do número de dígitos de destino na memória. A pesquisa de 17 dígitos requer o armazenamento de uma matriz de 100 milhões de booleanos. 19 dígitos exigiriam uma matriz de elementos 1B e a memória se esgotaria antes de chegar a 23 dígitos. O tempo de execução provavelmente também seria.

As abordagens de teste de primazia que não envolvem uma variedade ridiculamente grande de números primos divisores serão muito melhores.

#!/usr/bin/env python
import math
import numpy as np
import sys

max_digits = int(sys.argv[1])
max_num = 10**max_digits

print "largest supreme prime of " + str(max_digits) + " or fewer digits"

def sum_product_digits(num):
    add = 0
    mul = 1
    while num:
         add, mul, num = add + num % 10, mul * (num % 10), num / 10
    return add, mul

def primesfrom2to(n):
    # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Input n>=6, Returns a array of primes, 2 <= p < n """
    sieve = np.ones(n/3 + (n%6==2), dtype=np.bool)
    sieve[0] = False
    for i in xrange(int(n**0.5)/3+1):
        if sieve[i]:
            k=3*i+1|1
            sieve[      ((k*k)/3)      ::2*k] = False
            sieve[(k*k+4*k-2*k*(i&1))/3::2*k] = False
    return np.r_[2,3,((3*np.nonzero(sieve)[0]+1)|1)]

def checkprime(n):
    for divisor in primes:
        if (divisor>math.sqrt(n)):
            break
        if n%divisor==0:
            return False
    return True

# make an array of all primes we need to check as divisors of our max_num
primes = primesfrom2to(math.sqrt(max_num))
# only consider digit counts that are prime
for num_digits in primes:
    if num_digits > max_digits:
        break
    for ones_on_right in range(0,num_digits):
        for mid_prime in ['3','5','7']:
            # assemble a number of the form /1*[357]1*/
            candidate = int('1'*(num_digits-ones_on_right-1)+mid_prime+'1'*ones_on_right)
            # check for primeness of digit sum first digit product first
            add, mul = sum_product_digits(candidate)
            if add in primes and mul in primes:
                # check for primality next
                if checkprime(candidate):
                    # supreme prime!
                    print candidate
Sparr
fonte
3

Mathematica 4211 4259 dígitos

Com o número: {1042} 7 {3168} {388} 3 {3870}

Que foi gerado pelo seguinte código:

TimeConstrained[
 Do[
  p = Prime[n];
  curlargest = Catch[
    If[PrimeQ[p + 6],
     list = ConstantArray[1, p];
     Do[
      temp = FromDigits[ReplacePart[list, i -> 7]];
      If[PrimeQ[temp],
       Throw[temp]
       ], {i, p}]
     ];

    If[PrimeQ[p + 4],
     list = ConstantArray[1, p];
     Do[
      temp = FromDigits[ReplacePart[list, i -> 5]];
      If[PrimeQ[temp],
       Throw[temp]
       ], {i, p}]
     ];
    If[PrimeQ[p + 2],
     list = ConstantArray[1, p];
     Do[
      temp = FromDigits[ReplacePart[list, i -> 3]];
      If[PrimeQ[temp],
       Throw[temp]
       ], {i, p}]
     ];
    Throw[curlargest];
    ]

  , {n, 565, 10000}]
 , 60*60]

Os lançamentos fazem com que ele pare de testar outros números com os mesmos dígitos que o encontrado atualmente. como começa o teste no dígito mais significativo, isso significa que ele sempre retorna o maior número, a menos que o número de dígitos seja um membro de um trigêmeo primo.

Simplesmente comecei a testar logo abaixo do valor de uma das respostas anteriores :)

Quando termina, o número é armazenado na variável mais baixa

Tally
fonte
2

JavaScript, 3019 dígitos, {2.273} 5 {745}

Isso usa o teste MillerRabin incluído no BigInteger.js por Tom Wu.

A partir de 0 => 2.046 dígitos = {1799} 7 {263} em uma hora .

A partir de 3000 => 3.019 dígitos = {2.273} 5 {745} em uma hora, menos 3 segundos .

Quando começou a partir de 0, o programa avançou e começou a procurar novamente a uma extensão de 1,5X a duração do último s-prime encontrado. Então, quando eu vi o quão rápido ele estava rodando, imaginei que encontraria um começando em 3000 em uma hora - o que aconteceu com apenas 3 segundos de sobra.

Você pode experimentá-lo aqui: http://goo.gl/t3TmTk
(Defina para calcular todos os primos s ou pule adiante).

insira a descrição da imagem aqui insira a descrição da imagem aqui
insira a descrição da imagem aqui

O programa funciona construindo sequências de todos os "1" s, mas com um "3", "5" ou "7". Eu adicionei uma verificação rápida na função IsStrPrime para rejeitar os números que terminam em "5".

if (IsIntPrime(length)) {

    var do3s = IsIntPrime(length + 2);
    var do5s = IsIntPrime(length + 4);
    var do7s = IsIntPrime(length + 6);

    if (do3s || do5s || do7s) {

        // loop through length of number
        var before, digit, after;

        for (var after = 0; after <= length - 1; after++) {

            before = length - after - 1;
            beforeStr = Ones(before);
            afterStr = Ones(after);

            if (do3s && IsStrPrime(beforeStr + (digit = "3") + afterStr)) { RecordAnswer(); if (brk) break; }
            if (AreDone()) break;

            if (do5s && IsStrPrime(beforeStr + (digit = "5") + afterStr)) { RecordAnswer(); if (brk) break; }
            if (AreDone()) break;

            if (do7s && IsStrPrime(beforeStr + (digit = "7") + afterStr)) { RecordAnswer(); if (brk) break; }
            if (AreDone()) break;

            if (after % 10 == 0) document.title = "b=" + bestLength + ", testing=" + length + "-" + after;
        }
    }
}

Isso foi bem divertido. Lembra-me de um quebra-cabeça que fiz há muitos anos para calcular o que é chamado de dígito removido primo . Este é um número primo que, se você remover qualquer dígito, o número restante ainda será primo. Por exemplo 1037 é um número primo removido porque 1037, 037, 137, 107 e 103 são números primos. Encontrei 84 dígitos, e o mais longo que conheço tem 332 dígitos. Tenho certeza de que poderíamos encontrar um muito mais tempo com as técnicas usadas para este quebra-cabeça. (Mas escolher os números dos testes é um pouco mais complicado - talvez?)

JeffSB
fonte
RE: dígito removido primo, tivemos esse aqui . 332 dígitos também teriam vencido.
Primo
0

Axioma, 3019 dígitos {318} 5 {2700}

)time on

-- Return true if n is pseudo prime else return false
-- **Can Fail**
prime1(n:PI):Boolean==
     n=1=>false
     n<4=>true
     i:=5;sq:=sqrt(1.*n)
     repeat
       if i>sq or i>50000 then break
       if n rem i=0       then return false
       i:=i+2
     if i~=50001        then return true
     --output("i")
     if powmod(3,n,n)=3 then return true
     --output("e")
     false

-- input  'n': must be n>1 prime
-- output [0] if not find any number, else return 
-- [n,a,b,c,z] 'n' digits of solution, 
-- 'a' number of '1', 'b' central digit, 'b' number of final digit '1'
-- 'z' the number found
g(n:PI):List NNI==
    x:=b:=z:=1
    for i in 1..n-1 repeat
        z:=z*10+1
        b:=b*10
    repeat
       --output b
       k:=0    -- 3 5 7 <-> 2 4 6
       for i in [2,4,6] repeat
           ~prime?(n+i)=>0 --somma
           k:=k+1
           t:=z+b*i
           if prime1(t) then return [n,x-1,i+1,n-x,t]
       --if x=1 then output ["k=", k] 
       if k=0  then break
       x:=x+1
       b:=b quo 10
       if b<=0 then break
    [0]

-- start from number of digits n
-- and return g(i) with i prime i>=n 
find(n:PI):List NNI==
    i:=n
    if i rem 2=0 then i:=i+1 
    repeat
        if prime?(i) then --solo le lunghezze prime sono accettate
             output i 
             a:=g(i)
             if a~=[0] then return a
        i:=i+2

resultado do valor inicial 3000 em 529 seg

(4) -> find(3000)
   3001
   3011
   3019

   (4)
   [3019, 318, 5, 2700, Omissis]
                                            Type: List NonNegativeInteger
       Time: 0.02 (IN) + 525.50 (EV) + 0.02 (OT) + 3.53 (GC) = 529.07 sec
RosLuP
fonte