Elenco dei primi n numeri primi in modo più efficiente e nel codice più breve [chiuso]


27

Le regole sono semplici:

  • I primi n numeri primi (non i numeri primi al di sotto di n ), devono essere stampati sullo standard output separati da newline (i numeri primi devono essere generati nel codice)
  • i numeri primi non possono essere generati da una funzione integrata o tramite una libreria , ovvero l'uso di una funzione integrata o di libreria come, prime = get_nth_prime (n), is_a_prime (numero) o factorlist = list_all_factors (numero) non sarà molto creativo.
  • Punteggio: supponiamo che definiamo Score = f ([numero di caratteri nel codice]), O ( f (n)) è la complessità dell'algoritmo in cui n è il numero di numeri primi che trova. Ad esempio, se hai un codice di 300 caratteri con complessità O (n ^ 2), il punteggio è 300 ^ 2 = 90000 , per 300 caratteri con O (n * ln (n)), il punteggio diventa 300 * 5.7 = 1711.13 ( supponiamo che tutti i log siano log naturali per semplicità)

  • Utilizza qualsiasi linguaggio di programmazione esistente, il punteggio più basso vince

Modifica: il problema è stato cambiato dal trovare "primi 1000000 numeri primi" in "primi n numeri primi" a causa di una confusione su ciò che è "n" in O (f (n)), n è il numero di numeri primi che trovi (trovare i numeri primi è il problema qui e quindi la complessità del problema dipende dal numero di numeri primi trovati)

Nota: per chiarire alcune confusioni sulla complessità, se 'n' è il numero di numeri primi che trovi e 'N' è l'ennesimo numero primo trovato, la complessità in termini di n è e N non sono equivalenti, cioè O (f (n))! = O (f (N)) as, f (N)! = Costante * f (n) e N! = Costante * n, perché sappiamo che l'ennesima funzione primo non è lineare, anche se da quando abbiamo trovato 'n' la complessità dei numeri primi dovrebbe essere facilmente esprimibile in termini di "n".

Come sottolineato da Kibbee, puoi visitare questo sito per verificare le tue soluzioni ( qui è il vecchio elenco di documenti di Google)

Includi questi nella tua soluzione -

  • quale complessità ha il tuo programma (includi l'analisi di base se non banale)

  • lunghezza del carattere del codice

  • il punteggio finale calcolato

Questa è la mia prima domanda su CodeGolf, quindi, se c'è un errore o una lacuna nelle regole di cui sopra, ti preghiamo di segnalarle.



2
La mia risposta per quella era la 1[\p:i.78498mia risposta per questo sarebbe 1[\p:i.1000000. Anche supponendo che l'algoritmo primo interno di J sia O (n ^ 2) il mio punteggio sarebbe comunque solo 196.
Gareth

2
Nessuno sembra riuscire a calcolare correttamente la loro complessità. C'è confusione sul fatto che nsia il numero di numeri primi o il massimo primo, e tutti ignorano il fatto che l'aggiunta di numeri nell'intervallo 0..nè O(logn), e la moltiplicazione e la divisione sono ancora più costose. Ti suggerisco di fornire alcuni algoritmi di esempio insieme alla loro corretta complessità.
ugoren,

3
L'attuale test di primalità più noto per un numero k-bit è O-tilde(k^6). Ciò porta all'implicazione che chiunque rivendichi un tempo di esecuzione migliore di quanto O-tilde(n ln n (ln(n ln n))^6)abbia frainteso una parte del problema; e alla domanda su come gestire le O-tildecomplessità nel punteggio.
Peter Taylor,

2
Nessuno ha sottolineato che O (n) equivale a O (kn) (per costante k) in termini di complessità, ma non in termini di punteggio. Ad esempio, supponiamo che la mia complessità sia O (n ^ 10). Ciò equivale a O (n ^ 10 * 1E-308), e potrei ancora vincere la sfida con un enorme programma con una terribile complessità.
JDL

Risposte:


10

Python (129 caratteri, O (n * log log n), punteggio di 203.948)

Direi che il setaccio di Eratostene è la strada da percorrere. Molto semplice e relativamente veloce.

N=15485864
a=[1]*N
x=xrange
for i in x(2,3936):
 if a[i]:
  for j in x(i*i,N,i):a[j]=0
print [i for i in x(len(a))if a[i]==1][2:]

Codice migliorato da prima.

Python ( 191 156 152 caratteri, O (n * log log n) (?), Punteggio di 252.620 (?))

Non riesco affatto a calcolare la complessità, questa è la migliore approssimazione che posso dare.

from math import log as l
n=input()
N=n*int(l(n)+l(l(n)))
a=range(2,N)
for i in range(int(n**.5)+1):
 a=filter(lambda x:x%a[i] or x==a[i],a)
print a[:n]

n*int(l(n)+l(l(n)))è il limite superiore del nprimo numero primo.


1
Il calcolo della complessità (e quindi del punteggio) si basa sul limite superiore nma non sul numero di numeri primi. Quindi, presumo che il punteggio debba essere più alto. Vedi il mio commento sopra.
Howard l'

Limite superiore n? Cos'è quello?
beary605,

Il limite superiore qui è N=15485864. Per i calcoli della complessità basati su n=1000000, puoi dire N=n*log(n)(a causa della densità dei numeri primi).
ugoren,

Se il mio punteggio deve essere corretto, correggilo per me, non ho ancora una buona comprensione del sistema di punteggio.
beary605

@ beary605 sarebbe ok se modificassi i problemi per trovare i primi n numeri primi? ciò risolverebbe molta confusione sulla complessità e ciò che n è in O (f (n))
Optimus,

7

Haskell, n ^ 1,1 tasso di crescita empirica, 89 caratteri, punteggio 139 (?)

Quanto segue funziona al prompt di GHCi quando la libreria generale che utilizza è stata precedentemente caricata. Stampa n -esimo primo, basato su 1:

let s=3:minus[5,7..](unionAll[[p*p,p*p+2*p..]|p<-s])in getLine>>=(print.((0:2:s)!!).read)

Questo è un setaccio illimitato di Eratostene, che utilizza una libreria di uso generale per gli elenchi ordinati. Complessità empirica tra 100.000 e 200.000 numeri primi O(n^1.1). Adatto a O(n*log(n)*log(log n)).

Informazioni sulla stima della complessità

Ho misurato il tempo di esecuzione per i primi 100k e 200k, quindi ho calcolato logBase 2 (t2/t1), che ha prodotto n^1.09. Definizione g n = n*log n*log(log n), calcolo logBase 2 (g 200000 / g 100000)n^1.12.

Quindi 89**1.1 = 139, sebbene g(89) = 600. --- (?)

Sembra che per il punteggio si debba usare il tasso di crescita stimato invece della funzione di complessità stessa. Ad esempio, g2 n = n*((log n)**2)*log(log n)è molto meglio di n**1.5, ma per 100 caratteri i due producono il punteggio di 3239e 1000, rispettivamente. Questo non può essere giusto. La stima sulla gamma 200k / 100k fornisce logBase 2 (g2 200000 / g2 100000) = 1.2e quindi un punteggio di 100**1.2 = 251.

Inoltre, non tentare di stampare tutti i numeri primi, solo il n primo esimo posto.

Nessuna importazione, 240 caratteri. n ^ 1,15 tasso di crescita empirica, punteggio 546.

main=getLine>>=(print.s.read)
s n=let s=3:g 5(a[[p*p,p*p+2*p..]|p<-s])in(0:2:s)!!n
a((x:s):t)=x:u s(a$p t)
p((x:s):r:t)=(x:u s r):p t
g k s@(x:t)|k<x=k:g(k+2)s|True=g(k+2)t
u a@(x:r)b@(y:t)=case(compare x y)of LT->x:u r b;EQ->x:u r t;GT->y:u a t

5

Haskell, 72 89 caratteri, O (n ^ 2), Punteggio 7921

Il punteggio più alto per numero di caratteri vince, giusto? Modificato per il primo N. Anche apparentemente non riesco a usare una calcolatrice, quindi il mio punteggio non è terribilmente cattivo come pensavo. (usando la complessità per la divisione di prova di base come trovata nella fonte seguente).

Secondo Will Ness, il seguito non è un programma Haskell completo (in realtà si basa sul REPL). Quello che segue è un programma più completo con uno pseudo-setaccio (le importazioni in realtà salvano un carattere, ma non mi piacciono le importazioni nel codice golf).

main=getLine>>= \x->print.take(read x).(let s(x:y)=x:s(filter((>0).(`mod`x))y)in s)$[2..]

Questa versione è senza dubbio (n ^ 2). L'algoritmo è solo una versione da golf dell'ingenuo `` setaccio '', come visto qui Old liner ghci 1

getLine>>= \x->print.take(read x)$Data.List.nubBy(\x y->x`mod`y==0)[2..]

Lasciare la vecchia, imbroglione risposta perché la biblioteca a cui si collega è piuttosto carina.

print$take(10^6)Data.Numbers.Primes.primes

Vedi qui per un'implementazione e i collegamenti per la complessità temporale. Sfortunatamente le ruote hanno un tempo di ricerca log (n), che ci rallenta di un fattore.


• i numeri primi non possono essere generati da una funzione incorporata o attraverso una libreria
beary605

@walpen Mi dispiace di aver modificato le regole senza preavviso, ti preghiamo di apportare le modifiche che ritieni opportune
Optimus

La complessità non sarebbe simile a O ((n ln n) ^ 1,5 ln (n ln n) ^ 0,585)? (O O ((n ln n) ^ 1,5 ln (n ln n)) se Haskell usa una divisione ingenua piuttosto che, come ho ipotizzato, Karatsuba)
Peter Taylor,

No, perché questo mi dà un punteggio orrendo: /. Ma sono sicuro che tu abbia ragione. Sembrava solo una divisione di prova, e questa è la complessità temporale della divisione di prova (forse, secondo la mia scarsa comprensione della lettura di una fonte forse sbagliata), quindi l'ho scelto. Per ora chiamerò il mio punteggio NaN, sembra sicuro.
Walpen

Sto assumendo (il mio Haskell è trascurabile, ma so come sarebbe naturale farlo in SML ...) che stai facendo solo una divisione di prova con numeri primi più piccoli, nel qual caso la divisione di prova su una P non fa O ( P ^ 0,5 / ln P) divisioni. Ma se P ha k bit, una divisione prende O (k ^ 1.585) (Karatsuba) o O (k ^ 2) (naïve) tempo, e devi passare attraverso O (n lg n) numeri di lunghezza O (ln ( n lg n)) bit.
Peter Taylor,

5

C #, 447 caratteri, byte 452, punteggio?

using System;namespace PrimeNumbers{class C{static void GN(ulong n){ulong primes=0;for (ulong i=0;i<(n*3);i++){if(IP(i)==true){primes++;if(primes==n){Console.WriteLine(i);}}}}static bool IP(ulong n){if(n<=3){return n>1;}else if (n%2==0||n%3==0){return false;}for(ulong i=5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}static void Main(string[] args){ulong n=Convert.ToUInt64(Console.ReadLine());for(ulong i=0;i<n;i++){GN(i);}}}}

scriptcs Variant, 381 caratteri, 385 byte, punteggio?

using System;static void GetN(ulong n){ulong primes=0;for (ulong i=0;i<(n*500);i++){if(IsPrime(i)==true){primes++;if(primes==n){Console.WriteLine(i);}}}}public static bool IsPrime(ulong n){if(n<=3){return n>1;}else if (n%2==0||n%3==0){return false;}for(ulong i=5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}ulong n=Convert.ToUInt64(Console.ReadLine());for(ulong i=0;i<n;i++){GetN(i);}

Se installi scriptcs, puoi eseguirlo.

PS L'ho scritto su Vim :D


2
Puoi salvare alcuni personaggi rimuovendo alcuni spazi bianchi non necessari. Ad esempio, non è necessario mettere spazi bianchi attorno a =e <segno. Inoltre, non penso che ci sia una differenza in byte e caratteri per questo codice: sono 548 caratteri e 548 byte.
Programma FOX

2
Oh grazie, questo è il mio primo CodeGolf!
XiKuuKy

4

GolfScript (45 caratteri, punteggio richiesto ~ 7708)

~[]2{..3${1$\%!}?={.@\+\}{;}if)1$,3$<}do;\;n*

Questo fa una semplice divisione di prova per numeri primi. Se vicino al limite di Ruby (ovvero usando 1.9.3.0) l'aritmetica usa la moltiplicazione Toom-Cook 3, quindi una divisione di prova è O (n ^ 1.465) e il costo complessivo delle divisioni è O((n ln n)^1.5 ln (n ln n)^0.465) = O(n^1.5 (ln n)^1.965)†. Tuttavia, in GolfScript l'aggiunta di un elemento a un array richiede la copia dell'array. Ho ottimizzato questo per copiare l'elenco dei numeri primi solo quando trova un nuovo numero primo, quindi solo nvolte in totale. Ogni operazione di copia è O(n)di dimensioni O(ln(n ln n)) = O(ln n)†, dando O(n^2 ln n).

E questo, ragazzi e ragazze, è il motivo per cui GolfScript viene utilizzato per il golf piuttosto che per una programmazione seria.

O(ln (n ln n)) = O(ln n + ln ln n) = O(ln n). Avrei dovuto individuarlo prima di commentare vari post ...


4

È così facile anche il mio editor di testo può farlo!

Vim: 143 sequenze di tasti (115 azioni): O (n ^ 2 * log (n)): Punteggio: 101485.21

Presentazione:

qpqqdqA^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddmpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qqpmp"aywgg@dqgg@p

Input: N dovrebbe essere sulla prima riga di un documento vuoto. Al termine, ogni numero primo da 2 a N sarà una linea separata.

Esecuzione dei comandi:

Innanzitutto, nota che qualsiasi comando con un cursore davanti a loro significa che devi tenere premuto Ctrl e digitare la lettera successiva (ad esempio ^ V è Ctrl-ve ^ R è Ctrl-r).

Ciò sovrascriverà qualsiasi cosa nei tuoi registri @a, @b, @d e @p.

Poiché utilizza qcomandi, non può essere semplicemente inserito in una macro. Tuttavia, ecco alcuni suggerimenti per eseguirlo.

  • qpqqdq cancella semplicemente i registri
  • A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddcreerà un elenco di numeri da 2 a N + 1. Questa è una pausa tra le due parti principali, quindi una volta fatto, non dovresti aver bisogno di farlo di nuovo
  • mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qqpmp"aywgg@dqgg@pdeve essere digitato in una volta sola. Cerca di evitare il backspace in quanto potrebbe rovinare qualcosa.
    • Se commetti un errore, digita qdqqpqquindi riprova questa riga.

Per N grande, questo è molto lento. Ci sono voluti circa 27 minuti per eseguire N = 5000; considerati avvertito.

Algoritmo:

Questo utilizza un algoritmo ricorsivo di base per trovare i numeri primi. Dato un elenco di tutti i numeri primi tra 1 e A, A + 1 è primo se non è divisibile per nessuno dei numeri nell'elenco dei numeri primi. Inizia da A = 2 e aggiungi i numeri primi all'elenco man mano che vengono trovati. Dopo N ricorsioni, l'elenco conterrà tutti i numeri primi fino a N.

Complessità

Questo algoritmo ha una complessità di O (nN), dove N è il numero di input e n è il numero di numeri primi fino a N. Ogni test di ricorsione n numeri e vengono eseguite N ricorsioni, dando O (nN).

Tuttavia, N ~ n * log (n), che fornisce la complessità finale come O (n 2 * log (n)) ( https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number )

Spiegazione

Non è facile discernere il flusso del programma dai comandi vim, quindi lo riscrivo in Python seguendo lo stesso flusso. Come il codice Vim, il codice Python si spegnerà quando raggiunge la fine. A Python non piace troppa ricorsione; se provi questo codice con N> 150 o giù di lì, raggiungerà la profondità massima di ricorsione

N = 20
primes = range(2, N+1)

# Python needs these defined.
mark_p = b = a = -1

# Check new number for factors. 
# This macro could be wrapped up in @d, but it saves space to leave it separate.
def p():
    global mark_d, mark_p, primes, a
    mark_d = 0
    print(primes)
    a = primes[mark_p]
    d()      

# Checks factor and determine what to do next
def d():
    global mark_d, mark_p, a, b, primes
    b = primes[mark_d]
    if(a == b): # Number is prime, check the next number
        mark_p += 1
        p()
    else:
        if(a%b == 0): # Number is not prime, delete it and check next number
            del(primes[mark_p])
            p()
        else: # Number might be prime, try next possible factor
            mark_d += 1
            d()

mark_p = 0 #Start at first number         
p()

Ora, per abbattere i tasti premuti!

  • qpqqdqCancella i registri @d e @p. Ciò garantirà che nulla venga eseguito durante l'impostazione di queste macro ricorsive.

  • A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"ddTrasforma l'input in un elenco di numeri da 2 a N + 1. La voce N + 1 viene eliminata come effetto collaterale della configurazione della macro @d.

    • In particolare, scrive una macro che incrementa un numero, quindi lo copia sulla riga successiva, quindi scrive un 1 ed esegue questa macro N volte.
  • mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0qscrive la macro @d, che implementa la funzione d () sopra. Le dichiarazioni "If" sono interessanti da implementare in Vim. Utilizzando l'operatore di ricerca *, è possibile scegliere un determinato percorso da seguire. Abbattendo ulteriormente il comando otteniamo

    • mpqdImpostare qui il segno p e iniziare a registrare la macro @d. Il segno p deve essere impostato in modo che vi sia un punto noto su cui saltare mentre questo corre
    • o^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc> Scrive il testo dell'istruzione if / else
    • 0*w*wyiWdd@0 esegue effettivamente l'istruzione if.
    • Prima di eseguire questo comando, la riga conterrà @a @b 0 0 `pj@p @a 0 (@a%@b) `pdd@p 0 `dj@d
    • 0 sposta il cursore all'inizio della riga
    • *w*w Sposta il cursore sul codice per eseguire successivamente

      1. se @a == @b, ovvero `pj@p, che passa al numero successivo per @a e vi esegue @p.
      2. se @a! = @b e @ a% @ b == 0, ovvero `pdd@pelimina il numero corrente @a, quindi esegue @p su quello successivo.
      3. if @a! = @b e @ a %% b! = 0, ovvero `dj@dverifica il numero successivo per @b per vedere se si tratta di un fattore di @a
    • yiWdd@0 trascina il comando nel registro 0, cancella la riga ed esegue il comando

    • q termina la registrazione della macro @d
  • Al primo avvio, il `pdd@pcomando viene eseguito, eliminando la riga N + 1.

  • qpmp"aywgg@dq scrive la macro @p, che salva il numero sotto il cursore, quindi passa alla prima voce ed esegue @d su quello.

  • gg@p esegue effettivamente @p in modo che itererà sull'intero file.


3

QBASIC, 98 caratteri, complessità N Sqrt (N), punteggio 970

I=1
A:I=I+2
FOR J=2 TO I^.5
    IF I MOD J=0 THEN GOTO A
NEXT
?I
K=K+1
IF K=1e6 THEN GOTO B
GOTO A
B:

Ho modificato un po 'la dichiarazione del problema, ora trova i primi' n 'primi, mi dispiace per nessuna notifica
Optimus

Suppongo che possiamo assumere input "in-source" per questo programma; cioè, l'input è il numero subito dopo il IF K=(quindi la lunghezza del programma non includerebbe il numero). Allo stato attuale, il programma stampa i primi n numeri primi non inclusi 2, che possono essere corretti aggiungendo ?2all'inizio e cambiando K=...in K=...-1. Il programma può anche essere giocato a golf un po 'prendendo gli spazi su J=2 TO, J=0 THEN, K=...-1 THEN, e rimuovendo il rientro. Credo che ciò si traduca in un programma di 96 caratteri.
ris.

3

Scala 263 caratteri

Aggiornato per adattarsi ai nuovi requisiti. Il 25% del codice si occupa di trovare un limite superiore ragionevole per calcolare i numeri primi di seguito.

object P extends App{
def c(M:Int)={
val p=collection.mutable.BitSet(M+1)
p(2)=true
(3 to M+1 by 2).map(p(_)=true)
for(i<-p){
var j=2*i;
while(j<M){
if(p(j))p(j)=false
j+=i}
}
p
}
val i=args(0).toInt
println(c(((math.log(i)*i*1.3)toInt)).take(i).mkString("\n"))
}

Anch'io ho un setaccio.

Ecco un test empirico dei costi di calcolo, non approvato per l'analisi:

object PrimesTo extends App{
    var cnt=0
    def c(M:Int)={
        val p=(false::false::true::List.range(3,M+1).map(_%2!=0)).toArray
        for (i <- List.range (3, M, 2)
            if (p (i))) {
                var j=2*i;
                while (j < M) {
                    cnt+=1
                    if (p (j)) 
                        p(j)=false
                    j+=i}
            }
        (1 to M).filter (x => p (x))
    }
    val i = args(0).toInt
    /*
        To get the number x with i primes below, it is nearly ln(x)*x. For small numbers 
        we need a correction factor 1.13, and to avoid a bigger factor for very small 
        numbers we add 666 as an upper bound.
    */
    val x = (math.log(i)*i*1.13).toInt+666
    println (c(x).take (i).mkString("\n"))
    System.err.println (x + "\tcount: " + cnt)
}
for n in {1..5} ; do i=$((10**$n)); scala -J-Xmx768M P $i ; done 

porta ai seguenti conteggi:

List (960, 1766, 15127, 217099, 2988966)

Non sono sicuro di come calcolare il punteggio. Vale la pena di scrivere altri 5 personaggi?

scala> List(4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534).map(x=>(math.log(x)*x*1.13).toInt+666) 
res42: List[Int] = List(672, 756, 1638, 10545, 100045, 1000419, 10068909, 101346800, 1019549994)

scala> List(4, 25, 168, 1229, 9592, 78498, 664579, 5761455, 50847534).map(x=>(math.log(x)*x*1.3)toInt) 
res43: List[Int] = List(7, 104, 1119, 11365, 114329, 1150158, 11582935, 116592898, 1172932855)

Per n maggiore riduce i calcoli di circa il 16% in quell'intervallo, ma per quanto riguarda la formula del punteggio, non consideriamo i fattori costanti?

nuove considerazioni su Big-O:

Per trovare 1 000, 10 000, 100000 numeri primi e così via, utilizzo una formula sulla densità dei numeri primi x => (math.log (x) * x * 1.3 che determina il ciclo esterno che sto eseguendo.

Quindi per i valori da 1 a 6 => NPrimes (10 ^ i) viene eseguito 9399, 133768 ... volte il ciclo esterno.

Ho trovato questa O-funzione in modo iterativo con l'aiuto del commento di Peter Taylor, che ha suggerito un valore molto più alto per l'espiazione, invece di 1,01 ha suggerito 1.5:

def O(n:Int) = (math.pow((n * math.log (n)), 1.01)).toLong

O: (n: Int) Lungo

val ns = List(10, 100, 1000, 10000, 100000, 1000*1000).map(x=>(math.log(x)*x*1.3)toInt).map(O) 

ns: List [Long] = List (102, 4152, 91532, 1612894, 25192460, 364664351)

 That's the list of upper values, to find primes below (since my algorithm has to know this value before it has to estimate it), send through the O-function, to find similar quotients for moving from 100 to 1000 to 10000 primes and so on: 

(ns.head /: ns.tail)((a, b) => {println (b*1.0/a); b})
40.705882352941174
22.045279383429673
17.62109426211598
15.619414543051187
14.47513863274964
13.73425213148954

Questi sono i quozienti, se uso 1.01 come esponente. Ecco cosa trova empiricamente il contatore:

ns: Array[Int] = Array(1628, 2929, 23583, 321898, 4291625, 54289190, 660847317)

(ns.head /: ns.tail)((a, b) => {println (b*1.0/a); b})
1.799140049140049
8.051553431205189
13.649578085909342
13.332251210010625
12.65003116535112
12.172723833234572

I primi due valori sono anomali, perché ho fatto una correzione costante per la mia stima formulare per valori piccoli (fino a 1000).

Con il suggerimento di Peter Taylors di 1.5 sembrerebbe:

245.2396265560166
98.8566987153728
70.8831374743478
59.26104390040363
52.92941829568069
48.956394784317816

Ora con il mio valore arrivo a:

O(263)
res85: Long = 1576

Ma non sono sicuro di quanto possa essere vicino con la mia funzione O ai valori osservati.


Mi dispiace di aver apportato alcune modifiche alla dichiarazione del problema per ridurre alcune ambiguità legate alla complessità, (sono sicuro che la tua soluzione non cambierebbe molto)
Optimus,

Questa è effettivamente una divisione di prova per numeri primi. Il numero di volte attraverso il ciclo interno è O(M^1.5 / ln M), e ogni volta attraverso di te O(ln M)funziona (aggiunta), quindi nel complesso lo è O(M^1.5) = O((n ln n)^1.5).
Peter Taylor,

Con ^ 1.02 invece di ^ 1.5 def O(n:Int) = (math.pow((n * math.log (n)), 1.02)).toLongmi avvicino molto di più ai valori, trovati empiricamente con il mio contatore. Inserisco i miei risultati nel mio post.
utente sconosciuto

3

Ruby 66 caratteri, O (n ^ 2) Punteggio - 4356

lazyè disponibile da Ruby 2.0 ed 1.0/0è un bel trucco per ottenere una gamma infinita:

(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j==0}}.take(n).to_a

1
Puoi radere un carattere modificandolo in(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.take(n).to_a
Qqwy

O addirittura: (Questo rende la soluzione meno efficiente, ma non modifica il limite O superiore (n²)) (2..(1.0/0)).lazy.select{|i|(2..i).one?{|j|i%j<1}}.take(n).to_a. Questo fa radere altri due personaggi.
Qqwy,

Anche cambiarlo in (2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.first(n)comporterà 61 caratteri.
Richie,

2

Rubino, 84 caratteri, 84 byte, punteggio?

Questo è probabilmente un po 'troppo alle prime armi per queste parti, ma mi sono divertito a farlo. Fa semplicemente un giro fino a quando f(numeri primi trovati) è uguale n, il numero desiderato di numeri primi da trovare.

La parte divertente è che per ogni loop crea un array da 2 a uno in meno rispetto al numero da ispezionare. Quindi mappa ogni elemento dell'array in modo che sia il modulo del numero originale e dell'elemento e verifica se uno qualsiasi dei risultati è zero.

Inoltre, non ho idea di come segnarlo.

Aggiornare

Codice compattato e incluso un valore (totalmente arbitrario) per n

n,f,i=5**5,0,2
until f==n;f+=1;p i if !(2...i).to_a.map{|j|i%j}.include?(0);i+=1;end

Originale

f, i = 0, 2
until f == n
  (f += 1; p i) if !(2...i).to_a.map{|j| i % j}.include?(0)
  i += 1
end

I i += 1bit and untilloop mi saltano addosso come aree di miglioramento, ma su questa pista sono un po 'bloccato. Ad ogni modo, è stato divertente pensarci.


2

Scala, 124 caratteri

object Q extends App{Stream.from(2).filter(p=>(2 to p)takeWhile(i=>i*i<=p)forall{p%_!= 0})take(args(0)toInt)foreach println}

Semplice divisione di prova fino a radice quadrata. La complessità quindi dovrebbe essere O (n ^ (1.5 + epsilon))

124 ^ 1,5 <1381, quindi sarebbe il mio punteggio immagino?


1

Perl - 94 caratteri, O (n log (n)) - Punteggio: 427

perl -wle '$n=1;$t=1;while($n<$ARGV[0]){$t++;if((1x$t)!~/^1?$|^(11+?)\1+$/){print $t;$n++;}}'

Python - 113 caratteri

import re
z = int(input())
n=1
t=1
while n<z:
    t+=1
    if not re.match(r'^1?$|^(11+?)\1+$',"1"*t):
        print t
        n+=1

1

AWK, 96 86 byte

Sottotitolo: guarda mamma! Solo aggiungendo e un po 'di contabilità!

File fsoe3.awk:

{for(n=2;l<$1;){if(n in L)p=L[n]
else{print p=n;l++}
for(N=p+n++;N in L;)N+=p
L[N]=p}}

Correre:

$ awk -f fsoe3.awk <<< 5
2
3
5
7
11
$ awk -f fsoe3.awk <<< 1000 | wc -l
1000

BASH, 133 byte

File x.bash:

a=2
while((l<$1));do if((b[a]))
then((c=b[a]));else((c=a,l++));echo $a;fi;((d=a+c))
while((b[d]));do((d+=c));done
((b[d]=c,a++));done

Correre:

$ bash x.bash 5
2
3
5
7
11
$ bash x.bash 1000 | wc -l
1000

I primi vengono calcolati lasciando che i numeri primi già trovati saltino sul "nastro di numeri interi positivi". Fondamentalmente è un setaccio serializzato di eratostene.

from time import time as t

L = {}
n = 2
l = 0

t0=t()

while l<1000000:

        if n in L:
                P = L[n]
        else:
                P = n
                l += 1
                print t()-t0

        m = n+P
        while m in L:
                m += P
        L[m] = P

        n += 1

... è lo stesso algoritmo in Python e stampa il tempo in cui è lstato trovato il -th prime anziché il primo stesso.

L'output tracciato con gnuplotproduce quanto segue:

inserisci qui la descrizione dell'immagine

I salti probabilmente hanno qualcosa a che fare con i ritardi di I / O dei file dovuti alla scrittura di dati bufferizzati su disco ...

L'uso di un numero molto maggiore di numeri primi da trovare porterà ulteriori ritardi dipendenti dal sistema, ad esempio l'array che rappresenta il "nastro di numeri interi positivi" cresce continuamente e prima o poi farà piangere ogni computer per più RAM (o scambio successivo).

... quindi avere un'idea della complessità guardando i dati sperimentali non aiuta molto ... :-(


Ora contando le aggiunte necessarie per trovare i nnumeri primi:

cells = {}
current = 2
found = 0

additons = 0

while found < 10000000:

        if current in cells:
                candidate = cells[current]
                del cells[current] # the seen part is irrelevant
        else:
                candidate = current
                found += 1 ; additons += 1
                print additons

        destination = current + candidate ; additons += 1
        while destination in cells:
                destination += candidate ; additons += 1
        cells[destination] = candidate

        current += 1 ; additons += 1

inserisci qui la descrizione dell'immagine


Come hai fatto a creare quei grafici?
gatto,

1
Gnuplotcon set term xterme poi screenshot della xtermfinestra grafica (probabilmente una funzionalità quasi dimenticata). ;-)

0

Scala 121 (99 senza piastra della classe principale)

object Q extends App{Stream.from(2).filter{a=>Range(2,a).filter(a%_==0).isEmpty}.take(readLine().toInt).foreach(println)}

0

Python 3, 117 106 byte

Questa soluzione è leggermente banale, poiché genera 0 dove un numero non è primo, ma lo posterò comunque:

r=range
for i in[2]+[i*(not 0 in[i%j for j in r(3,int(i**0.5)+1,2)])for i in r(3,int(input()),2)]:print(i)

Inoltre, non sono sicuro di come elaborare la complessità di un algoritmo. Per favore, non sottovalutare per questo. Invece, sii gentile e commenta come ho potuto risolverlo. Inoltre, dimmi come ho potuto accorciare questo.


Penso che si possa mettere la print(i)sulla stessa linea, come il ciclo for e rimuovere gli spazi a in [2], 0 if, 0 in [i%je +1,2)] else.
acrolith,

@daHugLenny Wow, grazie mille! Modificherò il mio post tra un secondo. :-D
0WJYxW9FMN

@daHugLenny Sapresti calcolare l'efficienza per caso?
0WJYxL9FMN,

No scusa. (I commenti devono essere lunghi almeno 15 caratteri)
acrolith,

Grazie comunque. Hai reso il mio programma il più breve qui!
0WJYxL9FMN,


0

Perl 6, 152 byte, O (n registro n registro (n registro n) registro (registro (n registro n))) (?), 9594,79 punti

Secondo questa pagina , la complessità dei bit nel trovare tutti i numeri primi fino a n è O (n log n log log n); la complessità di cui sopra utilizza il fatto che l'ennesimo primo è proporzionale a n log n.

my \N=+slurp;my \P=N*(N.log+N.log.log);my @a=1 xx P;for 2..P.sqrt ->$i {if @a[$i] {@a[$_*$i]=0 for $i..P/$i}};say $_[1] for (@a Z ^P).grep(*[0])[2..N+1]

non si qualifica, fallo a Wentel per qualificarsi
noɥʇʎԀʎzɐɹƆ

Perdonate, ma cosa intendete?
bb94,

per la generosità (fiiiiiiiiilerrrrr)
noɥʇʎԀʎzɐɹƆ

0

Groovy (50 byte) - O (n * sqrt (n)) - Punteggio 353.553390593

{[1,2]+(1..it).findAll{x->(2..x**0.5).every{x%it}}​}​

Accetta n e genera tutti i numeri da 1 a n che sono primi.

L'algoritmo che ho scelto produce solo numeri primi n> 2, quindi è necessario aggiungere 1,2 all'inizio.

Abbattersi

x%it - Verità implicita se non è divisibile, falsa se lo è.

(2..x**0.5).every{...}- Poiché tutti i valori compresi tra 2 e sqrt (x) assicurano che non siano divisibili, affinché ciò restituisca true, deve restituire true per ogni .

(1..it).findAll{x->...} - Per tutti i valori compresi tra 1 e n, trova tutto ciò che soddisfa i criteri di non divisibilità tra 2 e sqrt (n).

{[1,2]+...}​ - Aggiungi 1 e 2, perché sono sempre primi e mai coperti dall'algoritmo.


0

Racchetta 155 byte

(let p((o'(2))(c 3))(cond[(>=(length o)n)(reverse o)][(ormap(λ(x)(= 0(modulo c x)))
(filter(λ(x)(<= x(sqrt c)))o))(p o(add1 c))][(p(cons c o)(add1 c))]))

Mantiene un elenco di numeri primi trovati e controlla la divisibilità di ogni numero successivo per numeri primi già trovati. Inoltre, controlla solo fino alla radice quadrata del numero in fase di test poiché è sufficiente.

Ungolfed:

(define(nprimes n)
  (let loop ((outl '(2))                   ; outlist having primes being created
             (current 3))                  ; current number being tested
  (cond
    [(>= (length outl) n) (reverse outl)]  ; if n primes found, print outlist.
    [(ormap (λ(x) (= 0 (modulo current x))) ; test if divisible by any previously found prime
            (filter                         ; filter outlist till sqrt of current number
             (λ(x) (<= x (sqrt current)))
             outl))
     (loop outl (add1 current)) ]           ; goto next number without adding to prime list
    [else (loop (cons current outl) (add1 current))] ; add to prime list and go to next number
    )))

test:

(nprimes 35)

Produzione:

'(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149)

0

awk 45 (complessità N ^ 2)

un altro awk, per numeri primi fino a 100 utilizzare in questo modo

awk '{for(i=2;i<=sqrt(NR);i++) if(!(NR%i)) next} NR>1' <(seq 100)

codice parte contata golf è

{for(i=2;i<=sqrt(NR);i++)if(!(NR%i))next}NR>1

che può essere inserito in un file di script ed eseguito come awk -f prime.awk <(seq 100)


0

Javascript, 61 caratteri

f=(n,p=2,i=2)=>p%i?f(n,p,++i):i==p&&n--&alert(p)||n&&f(n,++p)

Un po 'peggio di O (n ^ 2), esaurirà lo spazio dello stack per n grande.

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.