Trovare numeri primi senza usare "caratteri primi"


21

Il tuo compito, se scegli di accettarlo, è scrivere un programma / funzione che accetta un numero intero N come input. Il programma / funzione dovrebbe generare / restituire un elenco dei primi N numeri primi. Ma ecco il trucco: non ti è permesso usare i caratteri primi nel tuo codice. Un carattere primo è un carattere il cui punto di codice Unicode è un numero primo. Nell'intervallo ASCII stampabile, questi sono:

%)+/5;=CGIOSYaegkmq

Ma la regola si applica anche ai caratteri non ASCII se il codice li utilizza.

  • Un input valido è un numero intero N dove 0 <N <= T , in cui è possibile scegliere T , ma deve essere maggiore o uguale a 10000. T non deve essere finito.
  • Per input non validi (non numeri interi, numeri interi non compresi nell'intervallo), generare un'eccezione o generare / restituire nulla / null.
  • Un numero intero con spazi bianchi iniziali / finali come input è considerato non valido.
  • Un numero intero con un +carattere come segno come input è considerato non valido.
  • Un numero intero con zeri iniziali come input è considerato valido.
  • Se la tua lingua ti consente di passare un intero già analizzato come input, le regole di analisi sopra (tranne quella di intervallo) non si applicano, perché int è già analizzato.
  • L'input è sempre base-10.
  • Non è consentito l'uso di generatori primi e tester di primalità incorporati (questo include le funzioni di fattorizzazione primaria).
  • La restrizione di origine è imposta ai caratteri Unicode, ma il conteggio dei byte per il punteggio può essere in un'altra codifica, se lo si desidera.
  • L'output può contenere una nuova riga finale, ma ciò non è necessario.
  • Se si genera / restituisce l'elenco di numeri primi come stringa, allora ogni numero primo deve essere delimitato da uno o più caratteri non numerici. Puoi scegliere quale delimitatore utilizzare.
  • Questa è una sfida di , vince il codice più corto in byte.

Stack Snippet per verificare il tuo codice

Puoi utilizzare il frammento di stack seguente per verificare che il codice non contenga caratteri primi:

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>


10
È piuttosto crudele che ;sembra essere bandito ...
ɐɔıʇǝɥʇuʎs

Se i tester di primalità non sono ammessi, che dire delle funzioni di scomposizione in fattori primi.
Maltysen,

@Maltysen Dalle funzioni di scomposizione in fattori primi, puoi vedere rapidamente se un numero è un numero primo o no, quindi temo che non sia consentito. Lo chiarirò.
Programma FOX il

Siamo obbligati a eliminare alcuni di questi input non validi? Ad esempio, se la funzione string-> int del nostro linguaggio consente un +comando, sembra deludente essere obbligato a buttarli via manualmente.
Runer112,

11
Mi sono emozionato per questo e ho iniziato una soluzione, poi ho capito che i genitori chiusi non sono ammessi. Bene, sono fuori.
Alex A.

Risposte:


10

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

Provalo online.

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

Questo è probabilmente uno degli algoritmi più orribilmente inefficienti che io abbia mai implementato. Ma l'ho fatto per le dimensioni!

La mia risposta consiste in un blocco di codice, che agisce come una funzione anonima in CJam. Eseguilo con un numero intero immediatamente precedente allo stack e l'elenco risultante viene scaricato nello stack. Considero il limite superiore sull'input infinito, quindi non devo controllare quel limite.

Il mio algoritmo inizia aumentando 3 alla inputth potenza, che è garantita per dare un numero maggiore del input-th primo se l'input è valido. Quindi viene generato un elenco di numeri interi da 2 a questo numero meno uno, che è un'andana abbastanza grande da contenere tutti i numeri primi che vogliamo. Per sbarazzarci dei numeri compositi ... sospiro ... creiamo un elenco di ogni prodotto a coppie, che dovrebbe generare tutti i numeri compositi da 4 a un valore stupidamente grande, abbastanza grande per i nostri scopi. Quindi è solo una questione di rimuovere ogni elemento dall'elenco originale che si trova in questo elenco composito, ridimensionandolo fino ai primi inputelementi e unendo gli elementi con il carattere di nuova riga.

L'algoritmo dovrebbe funzionare per qualsiasi input. Tuttavia, se l'interprete / il computer disponga o meno di memoria o tempo sufficienti è un'altra questione, poiché i requisiti di tempo e spazio sono esponenziali rispetto all'input. Quindi, se l'input è maggiore di circa 5 per l'interprete online o di circa 8 per quello offline, probabilmente la risposta a questa domanda è no.


3
eh, a 17 anni hai un numero primo di byte nella tua risposta.
Corey Ogburn,

Perché hai bisogno di un S*?
jimmy23013,

@ user23013 Gli input non validi meno di 1 continuano ad alimentare l'algoritmo, producono solo un elenco vuoto. Ma questo non è un output legale per loro, quindi mi unisco agli elementi dell'elenco con spazi per produrre un output vuoto per questi input non validi.
Runer112,

1
L'ho notato, non è Sun personaggio principale?
Zacharý,

È un personaggio principale. Io so che sono più di 2 anni di ritardo a dire questo, ma questa risposta dovrebbe essere valida
Zachary

8

Giava. 474 byte

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}

Accetta input tramite argomento di funzione, output tramite eccezione generata.

rientrato:

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
}

Personaggi fuggiti rimossi:

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);
}

Spiegazione:

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.

La mia soluzione originale utilizzava una returndichiarazione. Dopo aver posto questa domanda su StackOverflow, regettman è stato così gentile da fornire un modo per produrre / restituire senza usare le lettere primi.

Come al solito, i suggerimenti sono benvenuti :)


3
+1. Doveva essere davvero difficile da capire per te e per rgettman. Molto impressionante. :)
TNT,

5

Ruby, 74

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

Spiegazione:

*oinizializza un array di output vuoto. fino a quando non ha nelementi, troviamo il numero più piccolo> = 2 che non divide nessun elemento attualmente in o, quindi lo aggiungiamo a o. Per verificare la divisione, yikes. A tutti i buoni operatori è vietato, e non posso nemmeno usarli divmod. Il migliore che potessi vedere era usare x.div y, che prende x diviso per y e arrotondato per difetto, quindi moltiplicalo di nuovo per y. Se è uguale a x, non c'è stato arrotondamento, quindi y divide x. 1.>x.^è un test di uguaglianza, verificando se il risultato di xor è 0. Il .prima di ogni operatore è perché non è possibile combinare .chiamate operatore prive di parentesi e chiamate metodo libere.

Modifica: le specifiche di controllo della portata sono state aggiunte dopo che ho pubblicato questo, credo. Per essere conforme richiede 79 caratteri:

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

4

CJam, 38 37 30 byte

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

Provalo qui

Penso che questo dovrebbe rispettare tutte le regole e funziona per qualsiasi N non negativa (cioè T è infinito). È orribilmente inefficiente, quindi non provarlo per grandi numeri.

Questo è un blocco - la cosa più vicina a una funzione (senza nome) - che si aspetta un numero intero nello stack, stampa tutti i numeri primi e lascia lo stack senza il suo input. Per tutti gli input non validi genererà un errore o non stampa nulla.

La maggior parte del codice è la convalida dell'input, seguita dal setaccio di Eratostene. Avevo solo bisogno di aggirare la restrizione di input in 3 posti:

  • )è l'incremento in CJam. Ne avevo bisogno una volta, ma potevo sostituirlo con ~(complemento bit per bit) perché stavo comunque quadrando i numeri.
  • %è modulo. Sto usando 37c~invece, che prima crea il personaggio %e poi lo valuta. Questo rende il codice molto più lento.
  • ;apre e scarta un elemento dallo stack. Devo farlo alla fine. Invece sto usando ciò '<(~che spinge il personaggio <, lo decrementa e lo valuta.

Ho pensato che, date tutte le regole di analisi dell'input, non ci fosse permesso di prendere un intero già analizzato.
Runer112,

@ Runer112 Siamo autorizzati a scrivere "una funzione che accetta un numero intero". Non "una funzione che accetta la rappresentazione in forma di stringa di un numero intero".
Martin Ender,

3

Bash + coreutils, 227 byte

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

Questo è stato piuttosto complicato. Alcune cose in cui mi sono imbattuto:

  • La maggior parte dei loop ( whilee until) sono inutilizzabili perché si avvicinano maggiormente a doneuna parola chiave della shell e non possono essere il risultato di un'espansione variabile (a meno che non evalvenga utilizzata, ma anche quella non è disponibile). L'unico loop utilizzabile è for/ inche consente {/ }anziché do/ done. for (( ; ; ))inoltre non è utilizzabile.
  • =è uscito, quindi abbiamo bisogno di un altro modo per assegnare variabili. printf -vè buono per questo.
  • Sappiamo che p (10000) è 104729, quindi per il loop esterno per potenziali numeri primi possiamo semplicemente passare da 2 a 104729 e rompere una volta che abbiamo abbastanza numeri primi
  • jotgenera l'elenco di potenziali fattori nel ciclo interno. Se un fattore potenziale divide un potenziale primo, allora non è primo e scoppiamo presto
  • Fortunatamente breakè una shell integrata e non una parola chiave, quindi può essere generata a seguito di un'espansione. dcconverte un numero di base 13 in bytestream eak.
  • Per verificare se un potenziale fattore divide un potenziale primo, non possiamo usare gli operatori aritmetici usuali /o %shell. Quindi questo è affidato in outsourcing all'operatore dcs ~, che spinge quoziente e resto nello stack.
  • -lt - less-than - è l'unico operatore di confronto shell utilizzabile.
  • echonon serve per l'output. printffunziona anche se evitiamo%

Ottenere la corretta convalida dell'input è un po 'un problema. Questo non restituisce nulla in caso di input non valido.

Produzione:

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

3

Haskell, 90 byte

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

Questa è una funzione anonima che accetta un numero intero ncome input.

Come funziona: [p|p<-[2..],not$or[b>p-1&&b-1<p|b<-[u*v|u<-[2..p-1],v<-[2..p-1]]]](primo esempio di numeri primi di una riga nella wiki di Haskell ma con la elemfunzione sostituita) crea un elenco infinito di numeri primi. zipcon i numeri da 1a nper creare un elenco di (prime, seq. number)coppie. Rimuovi seq. numero, di nuovo. Il risultato è un elenco di numeri primi di lunghezza n.


1

Ruggine, 64897 byte

|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 ...}

(codice estratto a causa del limite di caratteri, soluzione completa qui )

Le seguenti caratteristiche di ruggine non sono disponibili a causa della restrizione principale:

  • chiamate di funzione, in quanto richiedono ')'
  • attacchi regolari, poiché richiedono let (e)
  • definizioni macro, richiedono regole macro! (A, e, m)
  • istruzioni match, richiedono match (a, m) e => (=)
  • mutabilità, poiché viene sempre introdotto con la parola chiave mut (m).
  • return (e), break (a, e), continue (e)
  • altro (e)

Cosa puoi tecnicamente usare:

  • Se. Ma senza altro, sono inutili nei contesti di espressione, quindi buoni solo per gli effetti collaterali.
  • macro. Macro standard come la stampa! di solito sono seguiti da (), ma in realtà è legale usare {} o [] invece. Senza questo, il compito sarebbe impossibile.
  • chiusure, nel senso più stretto. Non è possibile chiamarli (richiede ()) o associarli (richiede let), ma è possibile definirne uno singolo non ricorsivo. Senza questo, il compito sarebbe ovviamente impossibile.
  • struct.
  • per i loop. Questi sono promettenti, poiché in realtà consentono l'associazione variabile e prendono un iteratore, che può ancora essere definito con la sintassi dell'intervallo. L'iteratore può anche essere un'espressione.
  • Operatori incorporati, tranne +,% e /. Gli operatori logici in corto circuito sembrano promettenti.

Semplicemente non riuscivo a fare nulla di Turing completo con questi strumenti. Mi dispiace. Non restava che includere i primi 10000 numeri primi, puliti da 5. Almeno puoi tagliarlo e avere una soluzione valida, nel senso più stretto possibile.

Vorrei davvero che gli esperti delle immersioni sul Tarpit (o su Rust!) Mi dicessero se avrei potuto fare qualcosa di meglio!


1

GNU APL, 75 68 67 65 59 56 55 caratteri

⎕IOdeve essere 1.

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

Sono tornato su questi mesi dopo rendendomi conto che avevo uno spazio extra!


È nella codifica APL o UTF-8? Se lo converti in codifica APL (ed è valido) sarebbe molto più breve in byte.
NoOneIsHere

UTF-8. Sì, ma in quei punti bassi del personaggio, ci saranno più numeri primi.
Zacharý,

Per l'esattezza, ora è conteggiato byte in APL, ma la sua restrizione sull'origine è Unicode. (Mi sono reso conto che la sfida consentiva conteggi di byte non Unicode)
Zacharý

0

Pyth - 12 byte

Utilizza la funzione di fattorizzazione primaria di pyth per vedere se # è primo. Il !tPTtrucco degli usi mi è stato suggerito nella mia risposta per numeri primi con milioni di problemi.

<f!tPTr2^T6Q

Dato che il filtro funziona solo con i numeri primi sotto n e non con il primo n, ho appena cercato l'inverso di pi (x) per 10.000 e ho ottenuto 104.000, quindi uso i numeri primi sotto 10⁶ e ottengo il primo n. Questo in realtà non eseguito, così si dovrebbe provare sostituendo ^T6con ^T3e limitare n a meno di 1000. Ingresso da stdin e output sullo standard output.

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

5
Dalle regole: "Non è consentito l'uso di generatori primi e tester di primalità integrati".
Runer112,

@ Runer112 Sì, ma questo non è un tester di primalità, è la scomposizione in fattori primi, è al limite delle regole. Probabilmente dovrei chiedere se questo è permesso.
Maltysen,

@Maltysen "Non è consentito l' uso di generatori primi e tester di primalità integrati (questo include le funzioni di fattorizzazione in fattori primi)" - mi sembra abbastanza chiaro.
Trauma digitale

4
@DigitalTrauma è stato aggiunto il chiarimento "(questo include le funzioni di scomposizione in fattori primi)" dopo che questa risposta è stata pubblicata.
Martin Ender,

MartinBüttner True. Immagino che spetti a discrezione di @ ProgramFOX.
Trauma digitale
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.