Le premier numéro de calcul de plaisir
Que nous allons avoir un peu de plaisir ici à l'œuvre. Tout a commencé avec l'un des gars de la configuration d'un Hackintosh et nous nous demandions si elle était plus rapide que Windows Boîte de (presque) les mêmes caractéristiques que nous avons. Nous avons donc décidé d'écrire un petit test pour elle. Juste un simple nombre Premier de la calculatrice. Il est écrit en Java et nous dit que le temps qu'il faut pour calculer les n premiers nombres premiers.
Version optimisée ci-dessous - prend maintenant ~6.6 secondes
public class Primes {
public static void main(String[] args) {
int topPrime = 150000;
int current = 2;
int count = 0;
int lastPrime = 2;
long start = System.currentTimeMillis();
while (count < topPrime) {
boolean prime = true;
int top = (int)Math.sqrt(current) + 1;
for (int i = 2; i < top; i++) {
if (current % i == 0) {
prime = false;
break;
}
}
if (prime) {
count++;
lastPrime = current;
}
if (current == 2) {
current++;
} else {
current = current + 2;
}
}
System.out.println("Last prime = " + lastPrime);
System.out.println("Total time = " + (double)(System.currentTimeMillis() - start) / 1000);
}
}
Nous ai vraiment perdu le fil de l'ensemble de la Hackintosh vs PC chose et sont simplement avoir du plaisir avec l'optimisation. Première tentative avec aucun des optimisations (le code ci-dessus a un couple) a couru autour de 52,6 min pour trouver la première 150000 nombres premiers. Cette optimisation est en cours d'exécution autour de 47,2 minutes.
Si vous voulez avoir un aller poster vos résultats, puis stick em up.
Les spécifications pour le PC je suis en cours d'exécution sur Pentium D 2.8 GHz, 2 go de RAM, Ubuntu 8.04.
Meilleure Optimisation jusqu'à présent a été la racine carrée du courant, d'abord mentionné par Jason Z.
C'est une optimisation plutôt que d'une erreur? Merci, je vais essayer.
Parfois, d'autre blocs de ralentir beaucoup pour essayer de se débarrasser de ce trop et voir si ça aide. Évidemment, le courant est augmenté de 1 à chaque tour de boucle, donc au lieu de if..else je l'avais mis if(courant!=2) { courant++; } courant++; à sa place.
L'écriture d'un très algorithmique pour tester des OS de la performance est un peu comme écrire un poème pour tester les différentes couvertures. Au mieux, vous trouverez une différence dans la VM implémentations.
Peut-être que Java n'est pas le candidat idéal pour passer le test, mais je pense que vous pouvez comprendre l'essentiel de ce que nous essayions de faire. Peut-être un langage de plus bas niveau aurait été un meilleur choix.
OriginalL'auteur Feet | 2008-11-13
Vous devez vous connecter pour publier un commentaire.
Et bien je vois quelques optimisations qui peut être fait.
D'abord, vous n'avez pas à essayer chaque numéro jusqu'à la moitié du nombre actuel.
Au lieu de cela vous avez seulement jusqu'à la racine carrée du nombre actuel.
Et l'autre optimisation est ce que BP a dit avec un twist:
Au lieu de
utilisation
Ce qui devrait accélérer les choses beaucoup.
EDIT:
Optimisation plus aimable autorisation de Joe Pineda:
Supprimer la variable "top".
Si cette optimisation, en effet, augmente la vitesse est jusqu'à java.
Calcul de la racine carrée prend beaucoup de temps par rapport à la multiplication de deux nombres. Cependant, puisque nous passons de la multiplication dans la boucle de ce qui est fait à chaque boucle. Donc, cela POURRAIT ralentir les choses en fonction de la vitesse de la racine carrée de l'algorithme en java.
Pour intégrer l'optimisation de l'utilisation de la place au lieu de la moitié, mais en évitant les erreurs d'arrondi: for (int i = 3; i*i < courant; i += 2) et ensuite vous pouvez prendre le "top" de la variable
Désolé, il convient de for (int i = 3; i*i <=; i += 2) d'autre vous acceptez 9 comme un nombre premier :$
à peine une optimisation: la racine carrée est calculé une fois, mais vous calculer le carré sur chaque boucle.
Bon point! Probablement, il serait préférable d'utiliser un Newton-Raphson, ou probablement le coût du temps de l'appel de la méthode sqrt peuvent être en vaut la peine...
OriginalL'auteur
C'est un peu pire que mon tamis fait sur un 8 Mhz 8088 en turbo pascal en 1986. Mais c'était après optimisations 🙂
OriginalL'auteur
Puisque vous êtes à la recherche pour eux dans l'ordre croissant, vous pouvez garder une liste des nombres premiers vous avez déjà trouvé et seulement de vérifier pour la divisibilité contre eux, puisque tous les non-nombres premiers peut être réduite à une liste de moindre facteurs premiers. Combinez cela avec l'astuce précédente au sujet de ne pas vérifier les facteurs au cours de la racine carrée du nombre actuel, et vous aurez vous-même une sacrément efficace de mise en œuvre.
D'accord. J'ai un code C++ (ne peut pas afficher) qui fait cela, et le temps sur mon ordinateur portable a été 0.45 sec. Pas sûr de savoir comment beaucoup de qui est le C++ vs Java vitesse & combien est l'algorithme, mais il semble clair que vous avez besoin pour tirer parti des travaux déjà réalisés. Memoization est votre ami!
OriginalL'auteur
Ici est une solution rapide et simple:
Trouver les nombres premiers de moins de 1000000000; 50847534 ont été trouvés dans 23839 ms
Deux choses que j'ai remarqué en comparant @voidlogic code pour Wikipedia pseudo-code. 1. Je voudrais modifier la première boucle for pour
for(int i = 2; i < sqrt(n); i++)
. Et 2. Je voudrais modifier la 2ème boucle for pourfor(int j = i * i; j < n; j += i)
. S'il vous plaît corrigez-moi si je me trompe.OriginalL'auteur
Il nous faut moins d'une seconde (2.4 GHz) pour générer le premier 150000 nombres premiers en Python en utilisant le Crible d'Eratosthène:
Exemple:
OriginalL'auteur
En C#:
De sortie:
Temps Total: 2.087 secondes
Prend 2.281 secondes en Java. AMD 3200+ 2 go de RAM, fonctionnant XP.
Est-ce à dire que C# peut faire les choses plus vite que Java? Ou est le C# en cours d'exécution sur une supériorité de la machine?
Eh bien, si nous l'avons fait en C# 3.5, ne pourrions-nous pas également utiliser des techniques de Programmation Parallèle pour tirer parti des processeurs multicœurs machines.
Ne pourriez-vous aussi de ré-écrire le Java pour rendre l'utilisation de plusieurs threads?
OriginalL'auteur
En gardant à l'esprit qu'il existe de meilleures façons de chercher les nombres premiers...
Je pense que vous pouvez profiter de cette boucle:
et de faire en sorte que votre variable de compteur, je passe de 3 et le seul qui essaye de faire de la mod sur les nombres impairs, puisque tous les nombres premiers autres que les 2 ne sont jamais divisible par aucun des nombres pairs.
On devrait être à partir de 1 suivant ma logique ci-dessus.
OK, si vous souhaitez commencer avec 1 semblant de ne rien connaître les nombres premiers... je déteste perdre mais bon, vous êtes seulement à perdre quelques millisecondes. Essayez ceci: for (int i = 1; i*i <=; i++) Qui est le côté sympa de la propriété de rejet de 1 un nombre premier 😀
OriginalL'auteur
La déclaration de la variable premier
dans la boucle de la rendre inefficace? (Je suppose qu'il n'a pas d'importance, car je pense que Java serait d'optimiser ce)
Je doute qu'il aurait, si elle le faisait, il pourrait être une couple de cycles.
Il ne fait pas de différence.
Devrait probablement être optimisé par le compilateur, suggère d'essayer -serveur -J-Xms48m Remarque: Pour J2SE 5.0, la définition d'un serveur de classe de la machine est un avec au moins 2 Processeurs et au moins 2 go de mémoire physique, donc si quelqu'un a des pièces de rechange 64 temps ...
OriginalL'auteur
C#
Amélioration de Aistina du code:
Cela rend l'utilisation du fait que tous les nombres premiers de plus de 3 sont de la forme 6n + 1 ou 6n - 1.
C'était environ 4-5% d'augmentation de vitesse de plus de incrémenter de 1 à chaque passage dans la boucle.
Vous êtes encore en test trop de chiffres dans le IsPrime boucle. (i = 3; i <= s; i += 2)
primes.utm.edu/notes/faq/six.html explique les 6n +- 1 propriété
OriginalL'auteur
Mon prendre à l'optimisation, en évitant de trop cryptique astuces. J'utilise l'astuce donnée par I-DONNER-TERRIBLE-des CONSEILS, je le savais, et j'ai oublié... 🙂
Oui, j'ai utilisé une étiquette de poursuivre, première fois que j'ai essayer en Java...
Je sais que je peux sauter le calcul des premiers nombres premiers, mais ils sont bien connus, pas de point de recalculer. 🙂 Je peux coder en dur de leur sortie en cas de besoin! En outre, il ne donne pas un avantage décisif de toute façon.
Résultats:
-- La première
Dernier premier = 2015201
Temps Total = 4.281
-- Deuxième
Dernier premier = 2015201
Temps Total = 0.953
Pas mal. Pourrait être amélioré un peu, je suppose, mais trop d'optimisation peut tuer le code de bonne.
OriginalL'auteur
Vous devriez être en mesure de faire la boucle interne deux fois plus rapide que par l'évaluation de l'nombres impairs. Vous ne savez pas si c'est valable Java, j'ai l'habitude de C++, mais je suis sûr qu'il peut être adapté.
ce qui se passe lorsque le courant = 2?
grâce fixe. @Pieds, cette modification n'est pas faire des hypothèses sur les propriétés des nombres premiers, seulement de reconnaître que même les chiffres n'ont pas besoin d'être vérifiée, car ils sont automatiquement divisible par 2.
Oh, et désolé de ne pas reconnaître que cela avait déjà été proposé mais je n'ai chair avec le code réel.
OriginalL'auteur
J'ai décidé d'essayer ce en F#, mon décent première tentative. En utilisant le Crible d'Eratosthène sur mon 2.2 Ghz Core 2 Duo, il fonctionne grâce à 2..150 000 environ 200 millisecondes. Chaque fois qu'elle appelle de l'auto, il est éliminé au courant des multiples de la liste, de sorte qu'il devient juste plus rapide au fur et à mesure. C'est un de mes premiers essais en F#, de sorte que toute les remarques constructives seront les bienvenues.
OriginalL'auteur
Je parie Miller-Rabin serait plus rapide. Si le test est assez numéros contigus, il devient déterministe, mais je n'aurais même pas pris la peine. Une fois une étude randomisée algorithme atteint le point de son taux d'échec est égale à la probabilité qu'un CPU hoquet va provoquer un mauvais résultat, il n'a tout simplement pas plus d'importance.
OriginalL'auteur
Voici ma solution... c'est assez rapide... il calcule les nombres premiers entre 1 et 10 000 000 de 3 secondes sur ma machine (core i7 @ 2.93 Ghz) sur Vista64.
Ma solution est en C, mais je ne suis pas un professionnel de la C programmeur. Hésitez pas à critiquer l'algorithme et le code lui-même 🙂
OriginalL'auteur
Voici mon prendre sur elle. Le programme est writtern en C et 50 millisecondes sur mon portable(Core 2 Duo, 1 GO de Ram). Je suis maintenant tout le calcul sur les nombres premiers dans un tableau et en essayant de divisibilité seulement jusqu'à la racine carrée de nombre. Bien sûr, cela ne fonctionne pas lorsque nous avons besoin d'un très grand nombre de nombres premiers(essayé avec 100000000) tableau devient trop grand et donne seg fault.
OriginalL'auteur
@ Marque de la Rançon ne sais pas si c'est du code java
Ils vont gémir éventuellement mais j'ai voulu réécrire à l'aide de paradigme j'ai appris à avoir confiance en Java, et ils ont dit que pour avoir du plaisir, assurez-vous qu'ils comprennent que spec ne dit rien que les effets de la commande sur l'ensemble de résultats renvoyés, vous jetterait le jeu de résultats dot valeurs() pour une liste de type de donnée de mon one-off dans le bloc-notes avant de prendre une courte course
=============== commencer le code non testé ===============
=============== fin du code non testé ===============
À l'aide de Jeux de Hachage permet de rechercher les résultats que les B-Arbres, ainsi que les résultats pourraient être empilés jusqu'à ce que la machine commence à manquer alors que le point de départ pourrait être utilisé pour un autre bloc de test == la fin d'un terme utilisé en tant que Constructeur de la valeur pour une autre course, la persistance de disque travail déjà accompli et permettant aux différentiels de feed-forward dessins. Brûlé à droite maintenant, boucle logique de l'analyse des besoins.
patch (plus ajouter sqrt) :
OriginalL'auteur
J'ai trouvé ce code quelque part sur ma machine quand j'ai commencé la lecture de ce billet de blog à propos des nombres premiers.
Le code est en C# et l'algorithme que j'ai utilisé vient de ma tête même si elle est probablement quelque part sur Wikipédia. 😉
De toute façon, il peut aller chercher la première 150000 nombres premiers dans environ 300ms. J'ai découvert que la somme des n premiers nombres impairs est égale à n^2. Encore une fois, il y a probablement une preuve de cela quelque part sur wikipédia. Donc, sachant cela, je peux écrire un algorithme qui wil ne jamais avoir à calculer une racine carrée, mais je dois calculer de façon incrémentielle pour trouver les nombres premiers. Donc, si vous voulez le n-ième nombre premier, ce algo aurez à trouver le (N-1) qui précède nombres premiers avant de! C'est donc là. Profitez-en!
OriginalL'auteur
Voici ma contribution:
Machine: 2.4 GHz Quad-Core i7 w/8 go de RAM @ 1600MHz
Compilateur:
clang++ main.cpp -O3
De référence:
Source:
Il utilise le Tamis de Erastothenes approche, j'ai optimisé autant que je peux avec mes connaissances. Des améliorations bienvenues.
OriginalL'auteur