Encuentra el primo más grande cuya longitud, suma y producto es primo


37

El número 113es el primer primo cuya longitud 3es primo, la suma digital 5 = 1 + 1 + 3es primo y el producto digital3 = 1 * 1 * 3 es primo.

Un primo que tiene estas 3 propiedades se llamará supremamente primo . Los primos 11117y 1111151son otros ejemplos.

Gol

Escriba un programa que pueda encontrar el número primo supremo más grande posible en menos de una hora en una computadora personal moderna decente (como la especificación preferida aquí ).

No deberías simplemente darnos una gran prima suprema. Debe mostrarnos su proceso de búsqueda con el código que realmente funciona. Puede aprovechar sus soluciones o las de otras personas, pero asegúrese de darles crédito. Estamos intentando comunalmente encontrar el mayor prime supremo realizable en una computadora normal en una hora.

Tanteo

La sumisión que encuentra el mayor premio supremo gana. Si resulta que hay muchos primos supremos finitos, entonces la primera sumisión que genera el primo supremo más alto gana.

(Si puedes demostrar matemáticamente que hay o no hay infinitos números primos supremos, te daré 200 repeticiones por recompensa solo porque :))

Detalles

  • Puede usar cualquier fuente para generar sus primos (por ejemplo, internet).
  • Puede usar métodos de prueba primarios probabilísticos.
  • Todo está en la base 10.
  • Cero y uno NO se consideran primos.
  • Los premios que contienen 0tienen un producto digital de 0modo que obviamente no pueden ser supremos.
  • Para mantener la página menos abarrotada, ponga primos supremos grandes (más de 100 dígitos) en la forma:

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

    Entonces 1111151podría expresarse como {5}5{1}.


¿Podemos comenzar con una lista de números primos, o buscar una lista de Internet y pasar la hora haciendo controles de supremacía?
Sparr

2
Si puede comenzar con el primo supremo más alto conocido, entonces esto se convierte en un desafío para quién puede escribir un programa que pase exactamente una hora que abarque la brecha más grande posible entre dos primos supremos. :(
Sparr

8
Además de no contener un 0, cualquier primo supremo potencial obviamente debe tener la forma 1 ^ n [3 | 5 | 7] 1 ^ m, es decir, algunos 1s, cualquier primo por debajo de 10 y algunos más 1s. Hay más restricciones que puede aplicar de inmediato.
Ingo Bürk

3
Ryan ha comenzado una pregunta relacionada sobre MSE en cuanto a la existencia de infinitos primos supremos. Si tiene alguna idea para esa pregunta, ¡por favor evalúe!
Semiclásico

1
Puedo demostrar fácilmente que actualmente no hay una prueba de un número infinito de números primos supremos (y que se ha invertido una gran cantidad de trabajo). De acuerdo con michaelnielsen.org/polymath1/… , sabemos que los números primos vienen infinitamente con espacios tan pequeños como 246, pero para una prueba de números primos supremos infinitos, necesitamos un espacio de 2, 4 o 6 (correspondiente a los números primos con un 3, 5 o 7 en algún lugar de ellos).
Tim S.

Respuestas:


9

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

Usando mi módulo Math :: Prime :: Util y su back end GMP . Tiene una serie de pruebas de composición que incluyen is_prob_prime () con una prueba ES BPSW (un poco más estricta que la ispseudoprime de Pari), is_prime () que agrega un MR de base aleatoria y is_provable_prime () que ejecutará BLS75 T5 o ECPP. En estos tamaños y tipos, hacer una prueba llevará mucho tiempo. Lancé otra prueba de MR en el sub verificador pedante. Veces en un Core2 E7500 que definitivamente no es mi computadora más rápida (toma 2.5 minutos en mi i7-4770K).

Como señala Tim S., podríamos seguir buscando valores más grandes, hasta el punto en que una sola prueba tome una hora. Con ~ 15000 dígitos en este E7500, toma alrededor de 26 segundos para una prueba de MR y 2 minutos para el is_prime completo (división de prueba más MR de base-2 más ES Lucas más un MR de base aleatoria). Mi i7-4770K es más de 3 veces más rápido. Probé algunos tamaños, principalmente viendo cómo le fue en los resultados de otras personas. Intenté 8k, 20k y 16k, matando cada uno después de ~ 5 minutos. Luego probé 15k en progresión durante ~ 10m cada uno y tuve suerte en el 4to.

Las pruebas de PRP de OpenPFGW son ciertamente más rápidas una vez que pasan más de 4000 dígitos, y mucho más rápido en el rango de 50k +. Sin embargo, su prueba tiene una buena cantidad de falsos positivos, lo que lo convierte en una excelente prueba previa, pero a uno todavía le gustaría verificar los resultados con otra cosa.

Esto podría ser paralelizado con hilos perl o usando MCE similar a los ejemplos paralelos de buscador de Fibonacci en el módulo.

Tiempo y resultados en un i7-4770K inactivo con un solo núcleo:

  • 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, 12007 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}
  • entrada 57000, 39 minutos, 57037 dígitos, {112} 5 {56924}
  • entrada 72225, 42 minutos, 72227 dígitos, {16} 3 {72210}

Para el resultado de 32k dígitos, comencé a ejecutar 6 scripts al mismo tiempo, cada uno con argumentos sucesivos a partir de 32000. Después de 26.5 minutos, uno terminó con el resultado de 32063 dígitos mostrado. Por 57k, dejé que las secuencias de comandos sucesivas se ejecutaran 6 a la vez durante una hora en incrementos de entrada de 500 hasta que el resultado de 57k regresó en 57 minutos. El resultado de 72k dígitos se encontró haciendo primos sucesivos desde 70k en adelante, por lo que definitivamente no se encuentra en una hora (aunque una vez que sabe por dónde empezar, lo es).

La secuencia de comandos:

#!/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";
}

¡+1 por presentarme a esta biblioteca! Tiempos en mi máquina para iterar números primos de menos de 10 ^ 7 (en comparación con CPython con gmpy2y PyPy con my_math): codepad.org/aSzc0esT
primo

Me alegro de que te guste! Hay otras formas, forprimes { ...do stuff... } 1e7;que incluyen 10 veces o más rápido (felicitaciones a Pari / GP por muchas buenas ideas). Siempre agradezco los comentarios, así que avíseme si algo no funciona de la manera deseada.
DanaJ

21

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

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111113111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Encontré este aproximadamente 50 minutos después de comenzar desde 4000. Por lo tanto, estimaría que este es el límite superior de este enfoque de código.

Cambio: He notado que algunas longitudes parecen ser más fructíferas para generar este tipo de primo que otras, por lo que he decidido verificar solo 50 ubicaciones aleatorias del dígito que no es 1 en lugar de todas las ubicaciones posibles, antes de mover en. No estoy completamente seguro de que esto mejore el rendimiento, o que 50 sea correcto, pero ya veremos.

La lista de posibilidades se genera en función del hecho de que para que se cumplan los requisitos de los productos, el número debe ser todos excepto un primo. Además, el primo no puede ser 2 debido a la relación de suma y longitud, y la suma digital no debe ser divisible por tres, dando los requisitos de% 3.

is_prime tomado de http://codepad.org/KtXsydxK , escrito por @primo

Nota: esta función is_prime es en realidad una prueba de pseudoprime Baillie-PSW, pero no hay contraejemplos conocidos, por lo que no me preocuparé por la distinción.

#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

No sé nada más que el enlace, desafortunadamente. Encontré el enlace aquí: codegolf.stackexchange.com/questions/10739/… Primera respuesta
isaacg

Bien entonces. Te daré crédito.
isaacg

10
Es como un ASCII donde está wally ...
trichoplax

55
Quizás debería cambiar el nombre de la función is_very_very_very_very_very_very_very_probably_prime()...
trichoplax

2
Mathmatica y Maple usan el mismo método, por lo que no puede ser tan malo.
primo

13

PARI / GP, 4127 dígitos

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

Esta es una búsqueda bastante sencilla: verifique solo las longitudes de los dígitos primos, luego calcule los posibles números primos para usar, luego repita todas las posibilidades. Encerré en especial los casos comunes donde hay 0 o 1 dígitos primos adecuados 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)

Esto tomó 36 minutos para calcular en un núcleo de una máquina bastante vieja. Estoy seguro de que no tendría problemas para encontrar un número primo de más de 5000 dígitos en una hora, pero también soy impaciente.

Una mejor solución sería usar cualquier lenguaje razonable para hacer todo menos el bucle más interno, luego construir un archivo abc para primeform que esté optimizado para ese tipo particular de cálculo. Esto debería ser capaz de llevar el cálculo hasta al menos 10,000 dígitos.

Editar : Implementé la solución híbrida descrita anteriormente, pero en mi máquina anterior no puedo encontrar el primer término con> = 10,000 dígitos en menos de una hora. A menos que lo ejecute en algo más rápido, tendré que cambiar a un objetivo menos elevado.


¿Cómo supiste comenzar en 4100?
isaacg

@isaacg: solo estaba tratando de ser más grande que la solución (incorrecta) de Mathematica, que tenía poco más de 4000. Simplemente fui al siguiente múltiplo de 100 como un número 'nada en la manga'. En realidad, parece que este fue un punto de partida desafortunado, ya que tuve que ir más de lo esperado (¡y más que Mathematica!) Para encontrar un mejor momento.
Charles

No, en realidad, fuiste increíblemente afortunado. (4127,3) es el primer par después de 4100, y por pura casualidad tiene un primo. Muchos pares no tienen primos en absoluto.
isaacg

@isaacg: Quizás sí. Mis heurísticas están claramente desactivadas, ya que hubiera esperado una probabilidad de ~ 80% para encontrar un primo en un par dado: 1 - exp (-15 / (4 * log 10)), pero parecen ser más raras que eso, por lo que no actúes como números aleatorios {2, 3, 5} suaves de su tamaño (a menos que haya engañado el cálculo).
Charles

@isaacg: En cualquier caso, estoy trabajando en la "mejor solución" que mencioné ahora: empujar el arduo trabajo a pfgw. Se buscaron los primeros 20 pares por encima de 10 ^ 10000 sin encontrar nada, pero eso solo tardó ~ 15 minutos.
Charles

7

Mathematica 3181 dígitos

Actualización: Hubo algunos errores graves en mi primera presentación. Pude dedicar algo de tiempo a verificar los resultados de este. La salida está formateada como una lista de dígitos. Eso facilita la comprobación de cada una de las condiciones.

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]]

Ejemplo

Esta fue mi primera prueba, una búsqueda de una solución con 3181 dígitos. Encontró el primer caso en 26 segundos.

Veamos el razonamiento. Luego entraremos en el programa en sí.

Comencemos, como lo hice, "¿Cuál es el número 450?" ¿Podemos encontrar una solución con tantos dígitos (3181)?

primeDigits = Prime[450]

3181


El número se encuentra uniendo los dígitos.

number = FromDigits[digits];

Pero en lugar de mostrarlo, podemos preguntar cuáles son los dígitos y dónde se encuentran.

DigitCount[number]

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

Esto significa que hubo 3180 instancias del dígito 1 y una sola instancia del dígito 7.

¿En qué posición está el dígito 7?

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

142

Entonces el dígito 7 es el dígito 142. Todos los demás son de 1.


Por supuesto, el producto de los dígitos debe ser primo, es decir, 7.

digitProduct = Times @@ digits

7 7


Y la suma de los dígitos también es primo.

digitSum = Plus @@ digits
PrimeQ[digitSum]

3187
verdadero


Y sabemos que el número de dígitos es primo. Recuerde, seleccionamos el número 450, es decir, 3118.

Entonces se han cumplido todas las condiciones.


3
Si no me equivoco, su suma es 4009, que no es primo.
gerw

Una cosa: ¿no debería ser la suma de todos los dígitos primos y no la cantidad de dígitos? En su caso, tendría que probar 4002 * 1 + 7 = 4009y no 4003 de acuerdo con las especificaciones.
Johnride

2
@Johnride: Ambos deberían ser primos.
gerw

@gerw tiene razón. El número de dígitos Y la suma de los dígitos Y el producto de los dígitos tienen que ser primos.
Calvin's Hobbies

Todos ustedes estaban en lo correcto. En mi presentación anterior, olvidé verificar la suma de dígitos para primalidad. Esto se hace ahora al ver si uno de los siguientes (no importa cuál) es primo: longitud de dígito + 2, longitud de dígito _4 o longitud de dígito +6.
DavidC

7

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

Estaba trabajando en mi propia versión y me decepcionó ver que @issacg me había golpeado con un enfoque muy similar, aunque con is_ (muy_probablemente) _prime (). Sin embargo, veo que tengo algunas diferencias significativas que resultan en una mejor respuesta en menos tiempo (cuando también uso is_prime). Para aclarar esto, cuando también empiezo desde 4000, llego a una mejor respuesta de 4001 dígitos ({393} 7 {3607}) en solo 26 minutos, 37 segundos usando el intérprete estándar de Python (también en la versión 2.7), no el PyPy versión. Además, no estoy revisando los números. Todos los candidatos son verificados.

Aquí están las mejoras principales:

  1. Use un generador principal ( https://stackoverflow.com/questions/567222/simple-prime-generator-in-python/568618#568618 ) para crear una lista de primos para verificar y (su versión de "primos pequeños") y para generar longitudes de número elegibles.

  2. Queremos pasar nuestro tiempo buscando el primo supremo más grande de una longitud determinada, no el más pequeño, por lo tanto, primero construyo los números más grandes posibles para verificar, no el más pequeño. Luego, una vez que se encuentra uno, podemos pasar inmediatamente a la siguiente longitud.

EDITAR: ahora con multiprocesamiento

Este es un cambio significativo a las versiones anteriores. Antes, noté que mi máquina de 8 núcleos apenas funcionaba, así que decidí probar suerte en el multiprocesamiento en Python (primera vez). ¡Los resultados son muy buenos!

En esta versión, se generan 7 procesos hijos, que toman una 'tarea' de una lista de posibles posibilidades (num_length + dígitos elegibles). Agitan intentando diferentes posiciones [7,5,3] hasta encontrar una. Si lo hace, informa al proceso maestro de la nueva longitud más larga que se ha encontrado. Si los niños están trabajando en una longitud num_ que es más corta, simplemente salen bajo fianza y obtienen la siguiente longitud.

Comencé esta ejecución con 6000, y todavía se está ejecutando, pero hasta ahora, estoy muy satisfecho con los resultados.

El programa aún no se detiene correctamente, pero no es un gran problema para mí.

Ahora el 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))

sería más claro si representas el enlace del teclado como una importación [rota, si es necesario]
Sparr

Creo que sería confuso, ya que el código en el otro extremo no es realmente importante como ese.
mkoistinen

usa la sintaxis de isaacg. comente la URL, luego importe desde un paquete inexistente (my_math, en su caso)
Sparr

1
En realidad, también genero los números de mayor a menor. No creo que nuestras diferencias de código sean muy significativas. Esperaría que la diferencia radique más en nuestras computadoras que en nuestro código. Sin embargo, bien hecho y bienvenido al sitio.
isaacg

my_mathtambién se puede usar para generar una lista de primos, a la while prime < 20006: prime = next_prime(prime). Parece ser aproximadamente 3 veces más rápido gen_primesy mucho más eficiente en memoria.
primo

6

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

Felicitaciones a @issacg y a todos ustedes por las inspiraciones y trucos.
Y también el autor de la pregunta magistral @ Calvin's Hobbies para esta pregunta.

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

Si tiene ganas de donar su capacidad de cálculo o tiene curiosidad por el rendimiento, no dude en copiar el código y compilarlo. ;) Necesitará 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;
}

5

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

Ejecute PFGW con el siguiente archivo de entrada y -f100prefactorice los números. En aproximadamente 2-3 minutos de CPU en mi computadora (i5 Haswell), encuentra el PRP (10 ^ (6073-6) -1) / 9 + 6 * 10 ^ 110, o {5956} 7 {110} . Elegí 6000 dígitos como punto de partida como un número nada bajo la manga que es un poco más alto que todas las presentaciones 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

Según lo rápido que pude encontrar este, pude aumentar fácilmente la cantidad de dígitos y aún así encontrar un PRP en una hora. Con la forma en que se escriben las reglas, incluso podría encontrar el tamaño en el que mi CPU, que se ejecuta en los 4 núcleos, puede terminar una prueba de PRP en una hora, tomar mucho tiempo para encontrar un PRP y hacer que mi "búsqueda" consista únicamente del único PRP.

PD: En algunos sentidos, esta no es una solución de "código" porque no escribí nada más que el archivo de entrada ... pero entonces, muchas soluciones de Mathematica de una línea para problemas matemáticos podrían describirse de la misma manera, como podría usando una biblioteca que hace el trabajo duro por ti. En realidad, creo que es difícil trazar una buena línea entre los dos. Si lo desea, podría escribir un script que cree el archivo de entrada PFGW y llame a PFGW. El script incluso podría buscar en paralelo, para usar los 4 núcleos y acelerar la búsqueda ~ 4 veces (en mi CPU).

PPS Creo que LLR puede hacer las pruebas de PRP para estos números, y espero que sea mucho más rápido que PFGW . Un programa de tamizado dedicado también podría ser mejor para factorizar estos números que el PFGW de uno en uno. Si combina estos, estoy seguro de que podría superar los límites mucho más que las soluciones actuales.


4

Python 2.7, 17-19 dígitos

11111111171111111

Encontrado 5111111111111 (13 dígitos) en 3 segundos y este primo supremo de 17 dígitos en 3 minutos. Supongo que la máquina de destino podría ejecutar esto y obtener un primo supremo de 19 dígitos en menos de una hora. Este enfoque no escala bien porque mantiene primos de hasta la mitad del número de dígitos objetivo en la memoria. La búsqueda de 17 dígitos requiere el almacenamiento de una matriz de 100M booleanos. 19 dígitos requerirían una matriz de elementos 1B, y la memoria se agotaría antes de llegar a 23 dígitos. El tiempo de ejecución probablemente también lo sería.

Los enfoques de prueba de primalidad que no involucren una variedad ridículamente grande de primos divisores funcionarán mucho mejor.

#!/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

3

Mathematica 4211 4259 dígitos

Con el número: {1042} 7 {3168} {388} 3 {3870}

El cual fue generado por el siguiente 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]

Los lanzamientos hacen que deje de probar otros números con los mismos dígitos que el que se encuentra actualmente. Dado que comienza a probar en el dígito más significativo, esto significa que siempre devuelve el número más grande a menos que el número de dígitos sea miembro de un triplete primo.

Simplemente comenzó a probar justo debajo del valor de una de las respuestas anteriores :)

Una vez que finaliza, el número se almacena en la variable curlargest


2

JavaScript, 3019 dígitos, {2,273} 5 {745}

Esto utiliza la prueba MillerRabin incluida en BigInteger.js por Tom Wu.

A partir de 0 => 2,046 dígitos = {1799} 7 {263} en una hora .

A partir de 3000 => 3,019 dígitos = {2,273} 5 {745} en una hora, menos 3 segundos .

Cuando comenzó desde 0, el programa saltó hacia adelante y comenzó a buscar nuevamente a una longitud de 1.5X la longitud del último s-prime encontrado. Luego, cuando vi lo rápido que estaba funcionando, supuse que encontraría uno a partir de 3000 en una hora, lo que hizo con solo 3 segundos de sobra.

Puede probarlo aquí: http://goo.gl/t3TmTk
(configurado para calcular todos los primos-s, o salte adelante).

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí
ingrese la descripción de la imagen aquí

El programa funciona construyendo cadenas de todos los "1", pero con un "3", "5" o "7". Agregué una verificación rápida en la función IsStrPrime para rechazar los números que terminan en "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;
        }
    }
}

Esto fue muy divertido. Me recuerda a un rompecabezas que hice hace muchos años para calcular lo que se llama un dígito eliminado primo . Este es un número primo que si elimina cualquier dígito, el número restante sigue siendo primo. Por ejemplo, 1037 es un dígito eliminado primo porque 1037, 037, 137, 107 y 103 son primos. Encontré uno de 84 dígitos de largo, y el más largo que conozco es de 332 dígitos. Estoy seguro de que podríamos encontrar uno mucho más largo con las técnicas utilizadas para este rompecabezas. (Pero elegir los números de prueba es un poco más complicado, ¿tal vez?)


RE: dígito eliminado primo, hemos tenido ese aquí . 332 dígitos también habrían ganado.
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 del valor inicial 3000 en 529 segundos

(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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.