Les règles sont simples:
- Les premiers n nombres premiers (pas les nombres premiers inférieurs à n ) doivent être imprimés sur la sortie standard séparés par des retours à la ligne (les nombres premiers doivent être générés dans le code)
- les nombres premiers ne peuvent pas être générés par une fonction intégrée ou par le biais d'une bibliothèque , c'est-à-dire que l'utilisation d'une fonction intégrée ou d'une bibliothèque telle que prime = get_nth_prime (n), is_a_prime (nombre) ou factorlist = list_all_factors (nombre) ne sera pas très créative.
Scoring - Disons que nous définissons Score = f ([nombre de caractères dans le code]), O ( f (n)) étant la complexité de votre algorithme où n est le nombre de nombres premiers qu'il trouve. Ainsi, par exemple, si vous avez un code de 300 caractères avec une complexité O (n ^ 2), le score est de 300 ^ 2 = 90000 , pour 300 caractères avec O (n * ln (n)), le score devient 300 * 5,7 = 1711,13 ( supposons que tous les journaux soient des journaux naturels pour plus de simplicité)
Utilisez n'importe quel langage de programmation existant, le score le plus bas gagne
Edit: le problème a été changé de trouver 'premiers 1000000 premiers' à 'premiers n premiers' en raison d'une confusion sur ce que 'n' dans O (f (n)) est, n est le nombre de nombres premiers que vous trouvez (trouver des nombres premiers est le problème ici et donc la complexité du problème dépend du nombre de nombres premiers trouvés)
Remarque: pour clarifier certaines confusions sur la complexité, si 'n' est le nombre de nombres premiers que vous trouvez et 'N' est le nième nombre premier trouvé, la complexité en termes de n est et N ne sont pas équivalents, c'est-à-dire O (f (n))! = O (f (N)) as, f (N)! = Constant * f (n) et N! = Constant * n, car nous savons que la nième fonction première n'est pas linéaire, je pensais que puisque nous trouvions 'n' la complexité des nombres premiers devrait être facilement exprimable en termes de «n».
Comme l'a souligné Kibbee, vous pouvez visiter ce site pour vérifier vos solutions ( voici l'ancienne liste de documents Google)
Veuillez les inclure dans votre solution -
la complexité de votre programme (incluez une analyse de base si elle n'est pas anodine)
longueur de caractère du code
le score calculé final
Ceci est ma première question CodeGolf donc, s'il y a une erreur ou une faille dans les règles ci-dessus, veuillez les signaler.
la source
1[\p:i.78498
ma réponse car ce serait1[\p:i.1000000
. Même en supposant que l'algorithme premier interne de J est O (n ^ 2), mon score ne serait toujours que de 196.n
le nombre de nombres premiers ou le nombre maximal premier, et tout le monde ignore le fait que l'ajout de nombres dans la plage0..n
estO(logn)
, et la multiplication et la division sont encore plus coûteuses. Je vous suggère de donner quelques exemples d'algorithmes avec leur complexité correcte.O-tilde(k^6)
. Cela conduit à penser que quiconque réclame un temps de course supérieur à celui quiO-tilde(n ln n (ln(n ln n))^6)
a mal compris une partie du problème; et à la question de savoir comment lesO-tilde
complexités doivent être traitées dans la notation.Réponses:
Python (129 caractères, O (n * log log n), score de 203,948)
Je dirais que le tamis d'Ératosthène est la voie à suivre. Très simple et relativement rapide.
Code amélioré d'avant.
Python (
191 156152 caractères, O (n * log log n) (?), Score de 252.620 (?))Je ne peux pas du tout calculer la complexité, c'est la meilleure approximation que je puisse donner.
n*int(l(n)+l(l(n)))
est la limite supérieure dun
e nombre premier.la source
n
mais pas sur le nombre de nombres premiers. Ainsi, je suppose que le score doit être plus élevé. Voir mon commentaire ci-dessus.n
? Qu'est-ce que c'est?N=15485864
. Pour les calculs de complexité basés surn=1000000
, vous pouvez direN=n*log(n)
(à cause de la densité des nombres premiers).Haskell, taux de croissance empirique n ^ 1,1, 89 caractères, score 139 (?)
Ce qui suit fonctionne à l'invite GHCi lorsque la bibliothèque générale qu'il utilise a été précédemment chargée. Imprimer n -ième prime, basé sur 1:
let s=3:minus[5,7..](unionAll[[p*p,p*p+2*p..]|p<-s])in getLine>>=(print.((0:2:s)!!).read)
C'est le tamis illimité d'Eratosthène, utilisant une bibliothèque à usage général pour les listes ordonnées. Complexité empirique entre 100 000 et 200 000 nombres premiers
O(n^1.1)
. S'adapte àO(n*log(n)*log(log n))
.À propos de l'estimation de la complexité
J'ai mesuré le temps d'exécution pour des nombres premiers de 100k et 200k, puis calculé
logBase 2 (t2/t1)
, ce qui a produitn^1.09
. Définirg n = n*log n*log(log n)
, calculerlogBase 2 (g 200000 / g 100000)
donnen^1.12
.Ensuite
89**1.1 = 139
, bien queg(89) = 600
. --- (?)Il semble que pour la notation, le taux de croissance estimé devrait être utilisé à la place de la fonction de complexité elle-même. Par exemple,
g2 n = n*((log n)**2)*log(log n)
est beaucoup mieux quen**1.5
, mais pour 100 caractères, les deux produisent respectivement le score de3239
et1000
. Ça ne peut pas être vrai. L'estimation sur 200k / 100k donnelogBase 2 (g2 200000 / g2 100000) = 1.2
et donc le score de100**1.2 = 251
.En outre, je ne cherche pas à imprimer tous les nombres premiers, juste le n premier -ème place.
Aucune importation, 240 caractères. n ^ 1,15 taux de croissance empirique, score 546.
la source
Haskell,
7289 caractères, O (n ^ 2), score 7921Le score le plus élevé par nombre de chars gagne, non? Modifié pour le premier N. Aussi, je ne peux apparemment pas utiliser de calculatrice, donc mon score n'est pas aussi mauvais que je le pensais. (en utilisant la complexité de la division d'essai de base telle que trouvée dans la source ci-dessous).
Selon Will Ness, ce qui suit n'est pas un programme Haskell complet (il repose en fait sur le REPL). Ce qui suit est un programme plus complet avec un pseudo-tamis (les importations enregistrent en fait un caractère, mais je n'aime pas les importations dans le code golf).
Cette version est sans aucun doute (n ^ 2). L'algorithme n'est qu'une version golfique du `` tamis '' naïf, comme on le voit ici Old ghci 1 liner
Laissant l'ancienne réponse tricherie parce que la bibliothèque à laquelle elle est liée est plutôt sympa.
Voir ici pour une implémentation et les liens pour la complexité temporelle. Malheureusement, les roues ont un temps de recherche log (n), ce qui nous ralentit d'un facteur.
la source
C #, 447 caractères, octets 452, score?
scriptcs Variant, 381 caractères, 385 octets, score?
Si vous installez des scriptcs, vous pouvez l'exécuter.
PS J'ai écrit ceci dans Vim
:D
la source
=
et<
. De plus, je ne pense pas qu'il y ait une différence d'octets et de caractères pour ce code - c'est 548 caractères et 548 octets.GolfScript (45 caractères, score revendiqué ~ 7708)
Cela fait une division d'essai simple par nombres premiers. Si près de la pointe de Ruby (c'est-à-dire en utilisant 1.9.3.0), l'arithmétique utilise la multiplication Toom-Cook 3, donc une division d'essai est O (n ^ 1,465) et le coût global des divisions est
O((n ln n)^1.5 ln (n ln n)^0.465) = O(n^1.5 (ln n)^1.965)
†. Cependant, dans GolfScript, l'ajout d'un élément à un tableau nécessite de copier le tableau. J'ai optimisé cela pour copier la liste des nombres premiers uniquement lorsqu'il trouve un nouveau nombre premier, donc seulementn
au total. Chaque opération de copie est desO(n)
éléments de tailleO(ln(n ln n)) = O(ln n)
†, ce qui donneO(n^2 ln n)
.Et cela, garçons et filles, est la raison pour laquelle GolfScript est utilisé pour le golf plutôt que pour une programmation sérieuse.
†
O(ln (n ln n)) = O(ln n + ln ln n) = O(ln n)
. J'aurais dû repérer cela avant de commenter divers articles ...la source
C'est tellement facile, même mon éditeur de texte peut le faire!
Vim: 143 frappes (115 actions): O (n ^ 2 * log (n)): Score: 101485.21
Soumission:
Entrée: N doit être sur la première ligne d'un document vierge. Après cela, chaque nombre premier de 2 à N sera une ligne distincte.
Exécution des commandes:
Tout d'abord, notez que toutes les commandes avec un curseur devant elles signifient que vous devez maintenir Ctrl et taper la lettre suivante (par exemple ^ V est Ctrl-vet ^ R est Ctrl-r).
Cela écrasera tout ce qui se trouve dans vos registres @a, @b, @d et @p.
Parce que cela utilise des qcommandes, il ne peut pas simplement être placé dans une macro. Cependant, voici quelques conseils pour l'exécuter.
qpqqdq
efface simplement les registresA^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"dd
va créer une liste de numéros 2 à N + 1. Ceci est une pause entre les deux parties principales, donc une fois cela fait, vous ne devriez plus avoir à le refairempqdmd"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
ne doit être tapé en une seule fois. Essayez d'éviter le retour arrière car cela pourrait gâcher quelque chose.qdqqpq
puis réessayez cette ligne.Pour le grand N, c'est très lent. Il a fallu environ 27 minutes pour exécuter N = 5000; considérez-vous comme prévenu.
Algorithme:
Cela utilise un algorithme récursif de base pour trouver des nombres premiers. Étant donné une liste de tous les nombres premiers compris entre 1 et A, A + 1 est premier s'il n'est divisible par aucun des nombres de la liste des nombres premiers. Commencez par A = 2 et ajoutez des nombres premiers à la liste lorsqu'ils sont trouvés. Après N récursions, la liste contiendra tous les nombres premiers jusqu'à N.
Complexité
Cet algorithme a une complexité de O (nN), où N est le nombre d'entrée et n est le nombre de nombres premiers jusqu'à N. Chaque récursivité teste n nombres, et N récursions sont effectuées, donnant O (nN).
Cependant, N ~ n * log (n), donnant la complexité finale en O (n 2 * log (n)) ( https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number )
Explication
Il n'est pas facile de discerner le flux du programme à partir des commandes vim, donc je l'ai réécrit en Python en suivant le même flux. Comme le code Vim, le code python sortira en erreur lorsqu'il atteindra la fin. Python n'aime pas trop la récursivité; si vous essayez ce code avec N> 150 ou plus, il atteindra la profondeur de récursivité maximale
Maintenant, pour décomposer les frappes réelles!
qpqqdq
Efface les registres @d et @p. Cela garantira que rien ne s'exécute lors de la configuration de ces macros récursives.A^V^Ayyp<Esc>3h"aC@a<Esc>0C1<Esc>@"dd
Transforme l'entrée en une liste de nombres de 2 à N + 1. L'entrée N + 1 est supprimée comme effet secondaire de la configuration de la macro @d.mpqdmd"bywo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>0*w*wyiWdd@0q
écrit la macro @d, qui implémente la fonction d () ci-dessus. Les instructions "If" sont intéressantes à implémenter dans Vim. En utilisant l'opérateur de recherche *, il est possible de choisir un certain chemin à suivre. Briser la commande plus loin, nous obtenonsmpqd
Définissez la marque p ici et commencez à enregistrer la macro @d. La marque p doit être définie, il y a donc un point connu vers lequel sauter lorsque cela s'exécuteo^Ra ^Rb 0 0 `pj@p ^Ra 0 ^R=@a%@b<Enter> `pdd@p 0 `dj@d<Esc>
Écrit le texte de l'instruction if / else0*w*wyiWdd@0
exécute réellement l'instruction if.@a @b 0 0 `pj@p @a 0 (@a%@b) `pdd@p 0 `dj@d
0
déplace le curseur au début de la ligne*w*w
Déplace le curseur sur le code à exécuter ensuite`pj@p
dire qui passe au numéro suivant pour @a et exécute @p dessus.`pdd@p
dire qui supprime le nombre actuel @a, puis exécute @p sur le suivant.`dj@d
dire qui vérifie le nombre suivant pour @b pour voir si c'est un facteur de @ayiWdd@0
met la commande dans le registre 0, supprime la ligne et exécute la commandeq
termine l'enregistrement de la macro @dLors de sa première exécution, la
`pdd@p
commande est exécutée, supprimant la ligne N + 1.qpmp"aywgg@dq
écrit la macro @p, qui enregistre le nombre sous le curseur, puis passe à la première entrée et exécute @d dessus.gg@p
exécute en fait @p pour qu'il itère sur tout le fichier.la source
QBASIC, 98 caractères, Complexité N Sqrt (N), Score 970
la source
IF K=
(donc la durée du programme ne comprendrait pas le chiffre). En l'état, le programme imprime les n premiers nombres premiers non compris 2, qui peuvent être fixés en ajoutant?2
au début et en changeantK=...
enK=...-1
. Le programme peut également être golfed un peu en prenant les espaces surJ=2 TO
,J=0 THEN
,K=...-1 THEN
et en supprimant la mise en retrait. Je crois que cela se traduit par un programme de 96 caractères.Scala 263 caractères
Mis à jour pour s'adapter aux nouvelles exigences. 25% du code traitent de la recherche d'une limite supérieure raisonnable pour calculer les nombres premiers ci-dessous.
J'ai aussi un tamis.
Voici un test empirique des coûts de calcul, non testé pour l'analyse:
conduit aux décomptes suivants:
Je ne sais pas comment calculer le score. Vaut-il la peine d'écrire 5 caractères supplémentaires?
Pour un n plus grand, cela réduit les calculs d'environ 16% dans cette plage, mais afaik pour la formule de score, nous ne considérons pas les facteurs constants?
nouvelles considérations Big-O:
Pour trouver 1 000, 10 000, 100 000 nombres premiers et ainsi de suite, j'utilise une formule sur la densité des nombres premiers x => (math.log (x) * x * 1,3 qui détermine la boucle externe que j'exécute.
Donc pour les valeurs i dans 1 à 6 => NPrimes (10 ^ i) court 9399, 133768 ... fois la boucle externe.
J'ai trouvé cette fonction O de manière itérative avec l'aide du commentaire de Peter Taylor, qui a suggéré une valeur beaucoup plus élevée pour l'exponentiation, au lieu de 1,01, il a suggéré 1,5:
O: (n: Int) Long
ns: List [Long] = List (102, 4152, 91532, 1612894, 25192460, 364664351)
Ce sont les quotients, si j'utilise 1.01 comme exposant. Voici ce que le compteur trouve empiriquement:
Les deux premières valeurs sont aberrantes, car j'ai fait une correction constante pour mon formulaire d'estimation pour les petites valeurs (jusqu'à 1000).
Avec la suggestion de Peter Taylors de 1,5, cela ressemblerait à:
Maintenant, avec ma valeur, j'arrive à:
Mais je ne sais pas, à quel point je peux me rapprocher de ma fonction O des valeurs observées.
la source
O(M^1.5 / ln M)
, et à chaque fois que vousO(ln M)
travaillez (addition), donc globalement c'estO(M^1.5) = O((n ln n)^1.5)
.def O(n:Int) = (math.pow((n * math.log (n)), 1.02)).toLong
je me rapproche beaucoup plus des valeurs, trouvées empiriquement avec mon compteur. J'insère mes conclusions dans mon message.Ruby 66 caractères, O (n ^ 2) Score - 4356
lazy
est disponible depuis Ruby 2.0, et1.0/0
est une astuce intéressante pour obtenir une plage infinie:la source
(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.take(n).to_a
(2..(1.0/0)).lazy.select{|i|(2..i).one?{|j|i%j<1}}.take(n).to_a
. Cela rase deux autres personnages.(2..(1.0/0)).lazy.select{|i|!(2...i).any?{|j|i%j<1}}.first(n)
donnera 61 caractères.Ruby, 84 caractères, 84 octets, score?
Celui-ci est probablement un peu trop novice pour ces parties, mais j'ai eu du plaisir à le faire. Il boucle simplement jusqu'à ce que
f
(nombres premiers trouvés) soit égal aun
nombre souhaité de nombres premiers à trouver.La partie amusante est que pour chaque boucle, il crée un tableau de 2 à un de moins que le nombre inspecté. Ensuite, il mappe chaque élément du tableau pour être le module du nombre d'origine et de l'élément, et vérifie si l'un des résultats est nul.
De plus, je n'ai aucune idée de comment le marquer.
Mise à jour
Code compacté et inclus une valeur (totalement arbitraire) pour
n
Original
Le
i += 1
bit et launtil
boucle me sautent aux yeux comme des domaines à améliorer, mais sur cette piste, je suis en quelque sorte coincé. Quoi qu'il en soit, c'était amusant d'y penser.la source
Scala, 124 caractères
Division d'essai simple jusqu'à la racine carrée. La complexité devrait donc être O (n ^ (1,5 + epsilon))
124 ^ 1,5 <1381, ce serait donc mon score je suppose?
la source
Perl - 94 caractères, O (n log (n)) - Score: 427
Python - 113 caractères
la source
AWK,
9686 octetsSous-titre: Regardez maman! Ajout seulement et un peu de comptabilité!
Fichier
fsoe3.awk
:Courir:
BASH, 133 octets
Fichier
x.bash
:Courir:
Les nombres premiers sont calculés en laissant les nombres premiers déjà trouvés sauter sur la "bande d'entiers positifs". Fondamentalement, c'est un tamis sérialisé d'Eratosthène.
... est le même algorithme en Python et affiche le moment où le
l
-ième nombre premier a été trouvé au lieu du nombre premier lui-même.La sortie tracée avec
gnuplot
donne les résultats suivants:Les sauts ont probablement quelque chose à voir avec les retards d'E / S de fichiers dus à l'écriture de données tamponnées sur le disque ...
L'utilisation d'un plus grand nombre de nombres premiers pour trouver, entraînera des retards supplémentaires dépendants du système dans le jeu, par exemple, le tableau représentant la "bande d'entiers positifs" croît continuellement et tôt ou tard, chaque ordinateur pleurera pour plus de RAM (ou échange ultérieur).
... donc avoir une idée de la complexité en regardant les données expérimentales n'aide pas vraiment beaucoup ... :-(
Maintenant, comptons les ajouts nécessaires pour trouver des
n
nombres premiers:la source
Gnuplot
avecset term xterm
puis capture d'écran dexterm
la fenêtre graphique de (probablement une fonctionnalité presque oubliée). ;-)Scala 121 (99 sans passe-partout de classe principale)
la source
Python 3,
117106 octetsCette solution est légèrement triviale, car elle génère 0 où un nombre n'est pas premier, mais je le publierai quand même:
De plus, je ne sais pas comment calculer la complexité d'un algorithme. S'il vous plaît, ne votez pas à cause de cela. Au lieu de cela, soyez gentil et commentez comment je pourrais le résoudre. Aussi, dites-moi comment je pourrais raccourcir cela.
la source
print(i)
sur la même ligne que la boucle et supprimer les espaces àin [2]
,0 if
,0 in [i%j
et+1,2)] else
.Haskell (52² = 2704)
la source
Perl 6, 152 octets, O (n log n log (n log n) log (log (n log n))) (?), 9594,79 points
Selon cette page , la complexité en bits de trouver tous les nombres premiers jusqu'à n est O (n log n log log n); la complexité ci-dessus utilise le fait que le nième nombre est proportionnel à n log n.
la source
Groovy (50 octets) - O (n * sqrt (n)) - Score 353,553390593
Prend n et sort tous les nombres de 1 à n qui sont premiers.
L'algorithme que j'ai choisi ne produit que des nombres premiers n> 2, il est donc nécessaire d'ajouter 1,2 au début.
Panne
x%it
- Vérité implicite si elle n'est pas divisible, fausse si elle l'est.(2..x**0.5).every{...}
- Pour toutes les valeurs comprises entre 2 et sqrt (x), assurez-vous qu'elles ne sont pas divisibles, pour que cela renvoie true, vous devez renvoyer true pour chaque .(1..it).findAll{x->...}
- Pour toutes les valeurs comprises entre 1 et n, trouvez toutes celles qui correspondent au critère d'être non divisible entre 2 et sqrt (n).{[1,2]+...}
- Ajoutez 1 et 2, car ils sont toujours premiers et ne sont jamais couverts par l'algorithme.la source
Raquette 155 octets
Il conserve une liste des nombres premiers trouvés et vérifie la divisibilité de chaque nombre suivant par les nombres premiers déjà trouvés. De plus, il ne vérifie que jusqu'à la racine carrée du nombre testé car cela suffit.
Non golfé:
Essai:
Sortie:
la source
awk 45 (complexité N ^ 2)
un autre
awk
, pour des nombres premiers jusqu'à 100, utilisez comme cecipartie de code de golf compté est
qui peut être placé dans un fichier script et exécuté en tant que
awk -f prime.awk <(seq 100)
la source
Javascript, 61 caractères
Un peu pire que O (n ^ 2), il manquera d'espace de pile pour les grands n.
la source