Encontrar números primos sin usar "caracteres primos"

21

Su tarea, si elige aceptarla, es escribir un programa / función que acepte un entero N como entrada. El programa / función debería generar / devolver una lista de los primeros N números primos. Pero aquí está el truco: no puedes usar caracteres primos en tu código. Un carácter primo es un carácter cuyo punto de código Unicode es un número primo. En el rango ASCII imprimible, estos son:

%)+/5;=CGIOSYaegkmq

Pero la regla también se aplica a caracteres no ASCII si su código los usa.

  • Una entrada válida es un número entero N donde 0 <N <= T , donde puede elegir T , pero tiene que ser mayor o igual que 10000. T no tiene que ser finito.
  • Para entradas no válidas (no enteros, enteros fuera de rango), arroje una excepción o envíe / devuelva nada / nulo.
  • Un número entero con espacios en blanco iniciales / finales como entrada se considera inválido.
  • Un entero con un +carácter de signo como entrada se considera inválido.
  • Un entero con ceros a la izquierda como entrada se considera válido.
  • Si su idioma le permite pasar un entero ya analizado como entrada, las reglas de análisis anteriores (excepto el rango uno) no se aplican, porque el int ya está analizado.
  • La entrada siempre es base-10.
  • No se permite el uso de generadores primarios integrados y probadores de primalidades (esto incluye funciones de factorización prima).
  • La restricción de origen se impone a los caracteres Unicode, pero el conteo de bytes para la puntuación puede estar en otra codificación si lo desea.
  • La salida puede contener una nueva línea final, pero esto no es obligatorio.
  • Si genera / devuelve la lista de números primos como una cadena, entonces cada número primo debe estar delimitado por uno o varios caracteres que no sean dígitos. Puede elegir qué delimitador usar.
  • Este es un desafío de , gana el código más corto en bytes.

Fragmento de pila para verificar tu código

Puede usar el siguiente fragmento de pila para verificar que su código no contenga caracteres principales:

var primes=[],max=10000;for(var i=2;i<=max;i++){primes.push(i);}for(var N=2;N<Math.sqrt(max);N++){if(primes.indexOf(N)===-1){continue;}primes=primes.filter(function (x){return x===N||x%N!==0;});}function setText(elem,text){var z=('innerText' in elem)? 'innerText' : 'textContent';elem[z]=text;}function verify(inputCode,resultSpan){var invalidChars=[];var success=true;for(var i=0;i<inputCode.length;i++){var cc = inputCode.charCodeAt(i);if (cc>max){setText(resultSpan,"Uh oh! The char code was bigger than the max. prime number calculated by the snippet.");success = false;break;}if (primes.indexOf(cc)!==-1){invalidChars.push(inputCode[i]);}}if (invalidChars.length===0&&success){setText(resultSpan, "Valid code!");}else if(success) {  var uniqueInvalidChars = invalidChars.filter(function (x, i, self){return self.indexOf(x)===i;});setText(resultSpan, "Invalid code! Invalid chars: " + uniqueInvalidChars.join(""));    }}document.getElementById("verifyBtn").onclick=function(e){e=e||window.event;e.preventDefault();var code=document.getElementById("codeTxt").value;verify(code,document.getElementById("result"));};
Enter your code snippet here:<br /><textarea id="codeTxt" rows="5" cols="70"></textarea><br /><button id="verifyBtn">Verify</button><br /><span id="result"></span>

ProgramFOX
fuente
10
Es bastante cruel que ;esté prohibido ...
20ıʇǝɥʇuʎs
Si los probadores de primalidad no están permitidos, ¿qué pasa con las funciones de factorización prima?
Maltysen
@Maltysen Desde las funciones de factorización prima, puedes ver muy rápidamente si un número es primo o no, así que me temo que no está permitido. Lo aclararé.
ProgramFOX
¿Estamos obligados a tirar algunas de estas entradas no válidas? Por ejemplo, si la función string-> int de nuestro lenguaje permite un inicio +, parece decepcionante que se requiera desecharlos manualmente.
Runer112
11
Me entusiasmé mucho con esto y comencé a buscar una solución, luego me di cuenta de que los padres cerrados no están permitidos. Bueno, ya estoy fuera.
Alex A.

Respuestas:

10

CJam, 19 18 30 34 33 19 17 21 20 bytes

Pruébalo en línea.

{_3\#,2>__ff*:~-<N*}

Este es probablemente uno de los algoritmos más terriblemente ineficientes que he implementado. ¡Pero lo hice por el tamaño!

Mi respuesta consiste en un bloque de código, que actúa como una función anónima en CJam. Ejecútelo con un número entero inmediatamente anterior a la pila, y la lista resultante se volcará en la pila. Trato el límite superior en la entrada como infinito, así que no tengo que verificar ese límite.

Mi algoritmo comienza elevando 3 a la inputpotencia th, lo que garantiza un número mayor que el input-th prime si la entrada es válida. Luego se genera una lista de los enteros de 2 a este número menos uno, que es una franja lo suficientemente grande como para contener todos los números primos que queremos. Para deshacernos de los números compuestos ... suspiro ... creamos una lista de cada producto por pares, que debería generar todos los números compuestos desde 4 hasta algún valor estúpidamente grande, lo suficientemente grande para nuestros propósitos. Entonces es solo cuestión de eliminar cada elemento de la lista original que está en esta lista compuesta, recortarlo a los primeros inputelementos y unir los elementos con el carácter de nueva línea.

El algoritmo debería funcionar para cualquier entrada. Sin embargo, si el intérprete / computadora tiene suficiente memoria o tiempo es otra cuestión, porque los requisitos de tiempo y espacio son exponenciales con respecto a la entrada. Entonces, si la entrada es mayor que aproximadamente 5 para el intérprete en línea o aproximadamente 8 para el intérprete fuera de línea, entonces la respuesta a esa pregunta es probablemente no.

Runer112
fuente
3
je, a los 17 tienes un número primo de bytes en tu respuesta.
Corey Ogburn
¿Por qué necesitas un S*?
jimmy23013
@ user23013 Las entradas no válidas de menos de 1 todavía se alimentan a través del algoritmo, solo producen una lista vacía. Pero esa no es una salida legal para ellos, por lo que unir los elementos de la lista con espacios para producir una salida vacía para estas entradas no válidas.
Runer112
1
Me di cuenta de esto, ¿no es Sun personaje principal?
Zacharý
Es un personaje principal. Yo que soy más de 2 años de retraso en decir esto, pero esta respuesta debería ser no válida
Zachary
8

Java. 474 bytes

i\u006dport j\u0061v\u0061.util.*\u003bvoid b(int b\u0029{Lon\u0067 c\u003d2L,d,f[]\u003d{}\u003bfor(f\u003dArr\u0061ys.copy\u004ff(f,b\u0029,Arr\u0061ys.fill(f,0L\u0029\u003bb-->0\u003b\u0029for(d\u003d0L\u003bf[b]<1\u003bf[b]\u003dd<1?c:f[b],d\u003d0L,c\u002b\u002b\u0029for(lon\u0067 h:f\u0029d\u003dh>0&&c\u002fh*h\u003d\u003dc?1:d\u003bj\u0061v\u0061x.x\u006dl.bind.JAXB.un\u006d\u0061rsh\u0061l(""\u002bArr\u0061ys.\u0061sList(f\u0029,Lon\u0067.cl\u0061ss\u0029\u003b}

Toma entrada a través del argumento de función, salidas a través de una excepción lanzada.

Sangrado:

i\u006dport j\u0061v\u0061.util.*\u003b
void b(int b\u0029{
    Lon\u0067 c\u003d2L,d,f[]\u003d{}\u003b
    for(f\u003dArr\u0061ys.copy\u004ff(f,b\u0029,Arr\u0061ys.fill(f,0L\u0029\u003bb-->0\u003b\u0029
        for(d\u003d0L\u003bf[b]<1\u003bf[b]\u003dd<1?c:f[b],d\u003d0L,c\u002b\u002b\u0029
            for(lon\u0067 h:f\u0029
                d\u003dh>0&&c\u002fh*h\u003d\u003dc?1:d\u003b
    j\u0061v\u0061x.x\u006dl.bind.JAXB.un\u006d\u0061rsh\u0061l(""\u002bArr\u0061ys.\u0061sList(f\u0029,Lon\u0067.cl\u0061ss\u0029\u003b
}

Caracteres escapados eliminados:

import java.util.*;
void b(int b){
    Long c=2L,d,f[]={};
    for(f=Arrays.copyOf(f,b),Arrays.fill(f,0L);b-->0;)
        for(d=0L;f[b]<1;f[b]=d<1?c:0,d=0L,c++)
            for(long h:f)
                d=h>0&&c/h*h==c?1:d;
    javax.xml.bind.JAXB.unmarshal(""+Arrays.asList(f),Long.class);
}

Explicación:

Long c,d,f[]={};                                                //Initialize variables.

for(f=java.util.Arrays.copyOf(f,b),Arrays.fill(f,0L);b-->0;)
    f=java.util.Arrays.copyOf(f,b),Arrays.fill(f,0L)            //Initialize f to an array of 0's.
                                                     b-->0      //Iterate over the first b primes.

for(d=0L;f[b]<1;f[b]=d<1?c:0,d=0L,c++)
    d=0L                        d=0L                            //Initialize d to 0.
         f[b]<1                      c++                        //Increment c while the b'th prime is 0.
                f[b]=d<1?c:0                                    //If d = 0, the b'th prime = c, else continue.

for(long h:f)                                                   //Iterate over all found primes.

d=h>0&&c/h*h==c?1:d;
  h>0                                                           //Ignore non-found primes.
       c/h*h==c                                                 //Equivalent to c%h==0
               ?1:d                                             //If h is prime and c is divisible by h, d = 1. Otherwise d stays unchanged.

javax.xml.bind.JAXB.unmarshal(""+Arrays.asList(f),Long.class)   //Print solution to stderr
javax.xml.bind.JAXB.unmarshal(                   ,Long.class)   //Prints what's contained to stderr.
                                 Arrays.asList(f)               //Convert f to list.
                              ""+                               //Convert to string.

Mi solución original usó una returndeclaración. Después de hacer esta pregunta en StackOverflow, regettman tuvo la amabilidad de proporcionar una forma de salida / retorno sin usar letras primas.

Como de costumbre, las sugerencias son bienvenidas :)

El numero uno
fuente
3
+1. Eso tuvo que ser realmente difícil para ti y para Rgettman. Muy impresionante. :)
TNT
5

Rubí, 74

->n,*o{o<<[2..n*n][0].find{|x|!o.find{|y|1.>x.^y.*x.div y}}until o[n-1]
o}

Explicación:

*oInicializa una matriz de salida vacía. hasta que tenga nelementos, encontramos el número más pequeño> = 2 que no divide ningún elemento actualmente o, luego lo agregamos o. Para probar la división, yikes. Todos los buenos operadores no están permitidos, y ni siquiera puedo usarlos divmod. Lo mejor que pude ver fue usar x.div y, que toma x dividido por y y redondea hacia abajo, luego multiplica eso por y nuevamente. Si es igual a x, no hubo redondeo, por lo que y divide x. 1.>x.^es una prueba de igualdad, que verifica si el resultado de xor es 0. El .antes de cada operador es porque no se pueden mezclar .llamadas de operador libres y llamadas de método sin paréntesis.

Editar: las especificaciones de verificación de rango se agregaron después de publicar esto, creo. Para cumplir requiere 79 caracteres:

->n,*o{o<<[*2..-~n*n].find{|x|!o.find{|y|1.>x.^y.*x.div y}}until o[n-1]||n<1
o}
histocrat
fuente
4

CJam, 38 37 30 bytes

{_~2#,2>\{(\{1$37c~},\p}*'<(~}

Pruébalo aquí

Creo que esto debería cumplir con todas las reglas y funciona para cualquier N no negativo (es decir, T es infinito). Sin embargo, es terriblemente ineficiente, así que no lo intentes con grandes cantidades.

Este es un bloque, lo más parecido a una función (sin nombre), que espera un número entero en la pila, imprime todos los números primos y deja la pila sin su entrada. Para todas las entradas no válidas, arrojará un error o no imprimirá nada.

La mayor parte del código es validación de entrada, seguido del tamiz de Eratóstenes. Solo necesitaba evitar la restricción de entrada en 3 lugares:

  • )es incremento en CJam. Lo necesitaba una vez, pero podría reemplazarlo con ~(complemento bit a bit) porque estaba cuadrando los números después de todos modos.
  • %es modulo. Estoy usando en su 37c~lugar, lo que primero crea el personaje %y luego evalúa eso. Esto hace que el código sea mucho más lento.
  • ;hace estallar y descarta un elemento de la pila. Necesito hacer esto al final. En cambio, estoy usando lo '<(~que empuja al personaje <, lo disminuye y evalúa eso.
Martin Ender
fuente
Pensé que, dadas todas las reglas de análisis de entrada, no se nos permite simplemente tomar un número entero ya analizado.
Runer112
@ Runer112 Se nos permite escribir "una función que acepta un número entero". No "una función que acepta la representación de cadena de un entero".
Martin Ender
3

Bash + coreutils, 227 bytes

printf -vb br`dc<<<Di14B8209P`
printf -vc -- $[$1-0]
[ "${1#$c}" -o $c -lt 1 ]||{
for i in {2..104729}
{
for f in `jot $[i-1] $[i-1] 1`
{
[ 0 -lt `dc<<<"$i $f~p"` ]||$b
}
[ $f -lt 2 ]&&printf $i\ &&: $[c--]
[ $c -lt 1 ]&&$b
}
}

Esto fue bastante complicado. Algunas cosas con las que me encontré:

  • La mayoría de los bucles ( whiley until) no se pueden usar porque están más cerca de lo doneque es una palabra clave de shell y no pueden ser el resultado de una expansión variable (a menos que evalse use, pero eso también está fuera). El único bucle utilizable es for/ inque permite {/ en }lugar de do/ done. for (( ; ; ))Tampoco es utilizable.
  • =está fuera, por lo que necesitamos otra forma de asignar variables. printf -ves bueno para esto
  • Sabemos que p (10000) es 104729, por lo que para el bucle externo para primos potenciales simplemente podemos bucle de 2 a 104729 y romper una vez que tengamos suficientes primos
  • jotgenera la lista de factores potenciales en el bucle interno. Si un factor potencial divide un primo potencial, entonces no es primo y salimos temprano
  • Afortunadamente, breakes un shell integrado y no una palabra clave, por lo que puede generarse como resultado de una expansión. dcconvierte un número base 13 en bytestream eak.
  • Para verificar si un factor potencial divide un primo potencial, no podemos usar los operadores aritméticos habituales /o de %shell. Entonces esto se subcontrata al operador dcs ~, que empuja el cociente y el resto a la pila.
  • -lt - less-than - es el único operador de comparación de shell utilizable.
  • echoNo sirve de nada para la salida. printffunciona siempre y cuando evitemos%

Obtener la validación de entrada correcta es un poco difícil. Esto no devuelve nada en el caso de una entrada no válida.

Salida:

$ ./primenoprime.sh 10
2 3 5 7 11 13 17 19 23 29 $ 
Trauma digital
fuente
3

Haskell, 90 bytes

\n->[fst c|c<-zip[p|p<-[2..],not$or[b>p-1&&b-1<p|b<-[u*v|u<-[2..p-1],v<-[2..p-1]]]][1..n]]

Esta es una función anónima que toma un entero ncomo entrada.

Cómo funciona: [p|p<-[2..],not$or[b>p-1&&b-1<p|b<-[u*v|u<-[2..p-1],v<-[2..p-1]]]](primer ejemplo de un número primos en la wiki de Haskell pero con la elemfunción reemplazada) crea una lista infinita de números primos. zipcon los números de 1a npara hacer una lista de (prime, seq. number)pares. Eliminar seq. número, de nuevo. El resultado es una lista de números primos de longitud n.

nimi
fuente
1

Óxido, 64897 bytes

|n|println!{"{:?}",&[2,3,6-1,7,11,13,17,19,23,29,31,37,41,43,47,60-7,0x3b,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,0x97,0x9d,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,0xfb,0x101 ...}

(código cortado debido al límite de caracteres, solución completa aquí )

Las siguientes características de óxido no están disponibles debido a la restricción principal:

  • llamadas a funciones, ya que requieren ')'
  • enlaces regulares, ya que requieren let (e)
  • definiciones de macro, requieren macro-reglas! (a, e, m)
  • declaraciones de coincidencia, requieren coincidencia (a, m) y => (=)
  • mutabilidad, ya que siempre se introduce con la palabra clave mut (m).
  • volver (e), romper (a, e), continuar (e)
  • más (e)

Lo que técnicamente puedes usar:

  • Si. Pero sin más, son inútiles en contextos de expresión, por lo que solo son buenos para los efectos secundarios.
  • macros ¡Las macros estándar les gusta imprimir! generalmente van seguidos de (), pero en realidad es legal usar {} o [] en su lugar. Sin esto, la tarea sería imposible.
  • cierres, en el sentido más estricto. No puede llamarlos (requiere ()) ni vincularlos (requiere dejar), pero puede definir uno único no recursivo. Sin esto, la tarea obviamente se volvería imposible.
  • estructuras.
  • para bucles Estos son prometedores, ya que en realidad permiten el enlace variable, y toman un iterador, que aún se puede definir con la sintaxis de rango. El iterador puede incluso ser una expresión.
  • Operadores incorporados, excepto +,% y /. Los operadores lógicos de cortocircuito parecen prometedores.

Simplemente no pude hacer nada de Turing completo con estas herramientas. Lo siento. Todo lo que quedaba era incluir los primeros 10000 primos completos, limpiados de 5. Al menos puedes cortarlo y tener una solución válida, en el sentido más estricto posible.

¡Me gustaría mucho que los expertos en el buceo en tarpit de Turing (o en Rust!) Me dijeran si podría haber hecho algo mejor!

Harald Korneliussen
fuente
1

GNU APL, 75 68 67 65 59 56 55 caracteres

⎕IOdebe ser 1.

∇z←p n
z←2,j←3
j←j--2
→2×⍳∨⌿1>z|j
z←z,j
→2×⍳n>⍴z
z←n↑z∇

Regresé este mes más tarde dándome cuenta de que tenía un espacio extra.

Zacharý
fuente
¿Está esto en la codificación APL o UTF-8? Si lo convierte a codificación APL (y es válido), sería mucho más corto en bytes.
NoOneIsHere
UTF-8. Sí, pero en esos puntos de carácter bajos, habrá más números primos.
Zacharý
Para ser exactos, ahora es byte contado en APL, pero su restricción en la fuente es Unicode. (Me di cuenta de que el desafío permitía recuentos de bytes no Unicode)
Zacharý
0

Pyth - 12 bytes

Utiliza la función de factorización prima de pyth para ver si # es primo. Utiliza el !tPTtruco que me sugirieron en mi respuesta para primos con menos de un millón de problemas.

<f!tPTr2^T6Q

Dado que el filtro solo funciona para primos debajo de n y no primero n, solo busqué el inverso de pi (x) para 10,000 y obtuve 104,000, así que uso primos debajo de 10⁶ y obtengo el primer n. En realidad, esto no se ejecuta, por lo que debe probar reemplazando ^T6con ^T3y restringir n por debajo de 1000. Entrada de stdin y salida a stdout.

<          Q     Slice first n
f     r2^T6      filter on range 2->10⁶
 !               Logical not (gives true if tail is empty)
  t              Tail (all but first, so gives empty if prime fact is len 1)
   PT            Prime factorization of filter var (len 1 if num is prime)
Maltysen
fuente
55
De las reglas: "No se permite el uso de generadores primarios y probadores de primalidad integrados".
Runer112
@ Runer112 Sí, pero esto no es un probador de primalidades, es factorización principal, está al borde de las reglas. Probablemente debería preguntar si esto está permitido.
Maltysen
@Maltysen "El uso de generadores primarios integrados y probadores de primalidad (esto incluye funciones de factorización primaria) no está permitido" - me parece bastante claro.
Trauma digital
44
@DigitalTrauma se agregó la aclaración "(esto incluye funciones de factorización prima)" después de que se publicara esta respuesta.
Martin Ender
MartinBüttner True. Supongo que depende de la discreción de @ ProgramFOX.
Trauma digital