Algorithme efficace pour obtenir des nombres premiers entre deux grands nombres
Je suis un débutant en C#, je suis en train d'écrire une application pour obtenir les nombres premiers entre deux nombres entrés par l'utilisateur. Le problème est: les grands nombres (les nombres valides sont dans la gamme de 1 à 1000000000) obtenir les nombres premiers prend beaucoup de temps et selon le problème, je vais résoudre, l'ensemble de l'opération doit être effectuée dans un petit intervalle de temps. C'est le problème le lien pour plus d'explication:
SPOJ-Premier
Et voici la partie de mon code qui est responsable de l'obtention de nombres premiers:
public void GetPrime()
{
int L1 = int.Parse(Limits[0]);
int L2 = int.Parse(Limits[1]);
if (L1 == 1)
{
L1++;
}
for (int i = L1; i <= L2; i++)
{
for (int k = L1; k <= L2; k++)
{
if (i == k)
{
continue;
}
else if (i % k == 0)
{
flag = false;
break;
}
else
{
flag = true;
}
}
if (flag)
{
Console.WriteLine(i);
}
}
}
Est-il un algorithme plus rapide?
Merci à l'avance.
source d'informationauteur rafael
Vous devez vous connecter pour publier un commentaire.
Je me souviens de résoudre le problème comme ceci:
sqrt(1000000000) = ~32 000
dans un tableauprimes
.x
entrem
etn
seul test si c'est le premier en tests de divisibilité contre numéros<= sqrt(x)
à partir de la matrice deprimes
. Donc, pourx = 29
vous permettra de tester si c'est divisibles par2, 3 and 5
.Il n'y a aucun point dans la vérification de la divisibilité à l'égard des non-nombres premiers, car si
x divisible by non-prime y
alors il existe un premierp < y
tels quex divisible by p
puisque l'on peut écrirey
comme un produit de nombres premiers. Par exemple,12
est divisible par6
mais6 = 2 * 3
ce qui signifie que12
est aussi divisible par2
ou3
. En générant toutes les focales fixes à l'avance (il y en a très peu dans ce cas), vous réduire considérablement le temps requis pour le test de primalité.Cela va être accepté et ne nécessite pas d'optimisation ou de la modification d'un tamis, et c'est assez propre mise en œuvre.
Vous pouvez le faire plus rapidement en généralisant le tamis pour générer des nombres premiers dans un intervalle
[left, right]
pas[2, right]
comme il est généralement présenté dans les tutoriels et manuels scolaires. Cela peut devenir assez laid cependant, et il n'est pas nécessaire. Mais si quelqu'un est intéressé, voir:http://pastie.org/9199654 et lié répondre.
Vous faites beaucoup de divisions qui ne sont pas nécessaire - si vous savez qu'un nombre n'est pas divisible par 3, il est inutile de vérifier si elle est divisible par 9, 27, etc. Vous devriez essayer de diviser que par le potentiel de facteurs premiers d'un nombre. Cache de l'ensemble des nombres premiers de la production et ne vérifiez la division par le précédent nombres premiers. Notez que vous avez besoin pour produire la première série de nombres premiers en dessous de L1.
Rappelez-vous que pas de numéro avoir un premier facteur qui est plus grand que sa propre racine carrée, de sorte que vous pouvez arrêter vos divisions à ce point. Par exemple, vous pouvez arrêter la vérification des facteurs potentiels de la numéro 29 après 5.
Vous aussi vous ne pouvez incrémenter par 2 de sorte que vous pouvez ne pas tenir compte de vérifier si un nombre est premier au total (revêtement spécial, le numéro 2, bien sûr.)
J'ai l'habitude de poser cette question au cours des entretiens comme un test, j'ai comparé une mise en œuvre similaire à la vôtre avec l'algorithme que j'ai décrit. Avec l'algorithme optimisé, j'ai pu générer des centaines de milliers de nombres premiers très rapide - je n'ai jamais dérangé d'attente autour de la lenteur, de la mise en œuvre directe.
Vous pouvez essayer de le Crible d'Eratosthène. La principale différence serait que vous commencez à
L1
au lieu de partir de2
.Nous allons un peu changer ma question: Combien de temps pouvez-vous générer les nombres premiers entre m et n et il suffit d'écrire dans la mémoire? (Ou, éventuellement, à un disque RAM.) D'autre part, souvenez-vous de la gamme de paramètres comme décrit sur la page: m et n peuvent être aussi élevé que un milliard de dollars, tandis que les n-m est à plus d'un million de dollars.
IVlad et Brian plus d'une solution compétitive, même si il est vrai qu'un ralentissement de la solution pourrait être assez bon. Tout d'abord, générer ou même précalculer les nombres premiers inférieurs à sqrt(milliards de dollars); il n'y a pas très nombreuses. Puis faire un tronquée Crible d'Eratosthène: Faire un tableau de longueur n-m+1 pour garder une trace de l'état de chaque nombre dans l'intervalle [m,n], avec initialement une telle marqué comme nombre premier (1). Ensuite, pour chaque précalculées premier p, de faire une boucle qui ressemble à ceci:
Cette boucle marques de tous les numéros de la plage de m <= x <= n composite (0) si elle est multiple de p. Si c'est ce que IVlad entend par "assez laid", je ne suis pas d'accord; je ne pense pas que c'est mauvais.
En fait, près de 40% de ce travail est juste pour les nombres premiers 2, 3, et 5. Il existe une astuce pour combiner les tamis pour quelques nombres premiers avec initialisation du tableau de statut. À savoir, le modèle de divisibilité par 2, 3, et 5 répétitions mod 30. Au lieu de l'initialisation de la matrice de tous les 1, vous pouvez initialiser un motif répétitif de 010000010001010001010001000001. Si vous voulez être encore plus tranchant, vous pouvez avancer k par 30*p au lieu de p, et seulement marquer des multiples dans la même tendance.
Après cela, réaliste gains de performance impliquerait des mesures comme l'utilisation d'un vecteur de bits plutôt qu'un char tableau de garder le tamis de données en cache sur processeur. Et initialisation du vecteur de bits par mot plutôt que peu à peu. Cela ne se salissant, et aussi hypothétique puisque vous pouvez arriver au point de générer des nombres premiers plus vite que vous pouvez utiliser. La base du tamis est déjà très rapide et pas très compliqué.
Une chose que personne n'a mentionné, c'est que c'est plutôt rapide pour tester un numéro unique pour de primalité. Ainsi, si la plage est peu élevé, mais le nombre est important (ex. générer tous les nombres premiers entre 1 000 000 000 d', et 1,000,100,000), il serait plus rapide de simplement vérifier le numéro de tous de primalité individuellement.
Il existe de nombreux algorithmes de trouver des nombres premiers. Certains sont plus rapides, d'autres sont plus faciles.
Vous pouvez commencer par le plus facile de faire quelques optimisations. Par exemple,
pourquoi êtes-vous à la recherche si chaque nombre est premier? En d'autres termes, êtes-vous sûr que, compte tenu de toute une gamme de 411 à 418, il est nécessaire de rechercher si le nombre de 412, 414, 416 et 418 premier? Les numéros de diviser par 2 et 3 peuvent être ignorées très simples modifications du code.
si le nombre n'est pas 5, mais qui se termine par un chiffre '5' (1405, 335), il n'est pas le premiermauvaise idée: il va rendre la recherche plus lent.que sur la mise en cache des résultats? Vous pouvez ensuite diviser par des nombres premiers plutôt par chaque nombre. Par ailleurs, seuls les nombres premiers inférieur à la racine carrée du nombre de votre recherche sont concernés.
Si vous avez besoin de quelque chose de vraiment rapide et optimisé, en prenant un algorithme existant plutôt que de réinventer la roue peut être une alternative. Vous pouvez également essayer de trouver des articles scientifiques expliquant comment le faire rapidement, mais il peut être difficile à comprendre et à traduire en code.
}
Je pense que j'ai un très rapide et efficace(générer tous les le premier, même si l'aide de type BigInteger) l'algorithme pour obtenir le premier numéro,il est beaucoup plus rapide et plus simple que toutes les autres, et je l'utilise pour résoudre la quasi-problème lié à un nombre premier dans le Projet Euler avec seulement quelques secondes pour l'ensemble de la solution(brute force)
Voici le code java: