Quel est l'algorithme le plus rapide pour trouver des nombres premiers en C++? J'ai utilisé l'algorithme de tamis mais je veux quand même qu'il soit plus rapide!
Une implémentation très rapide du Sieve of Atkin est le primegen de Dan Bernstein. Ce tamis est plus efficace que le tamis d'Eratosthène . Sa page contient des informations de référence.
Si cela doit être très rapide, vous pouvez inclure une liste de nombres premiers:
http://www.bigprimes.net/archive/prime/
Si vous devez simplement savoir si un certain nombre est un nombre premier, il existe divers premiers tests répertoriés sur wikipedia . Ils sont probablement la méthode la plus rapide pour déterminer si un grand nombre est un nombre premier, en particulier parce qu'ils peuvent vous dire si un nombre est pas un nombre premier.
Je sais que je suis un nécromancien de questions répondant à de vieilles questions, mais je viens de trouver cette question en cherchant sur le net des moyens de mettre en œuvre des tests efficaces des nombres premiers.
Jusqu'à présent, j'estime que l'algorithme de test du nombre premier le plus rapide est le protocole Strong Probable Prime (SPRP). Je cite les forums Nvidia CUDA:
Un des problèmes de niche les plus pratiques de la théorie des nombres doit être résolu avec identification des nombres premiers. Étant donné N, comment pouvez-vous efficacement déterminer s'il est premier ou pas? Ce n’est pas simplement une théorie problème, c’est peut-être un réel nécessaire dans le code, peut-être lorsque vous en aurez besoin trouver dynamiquement une taille de table de hachage optimale dans certaines plages. Si N est quelque chose de l’ordre de 2 ^ 30, voulez-vous vraiment faire 30000 tests de division pour rechercher des facteurs? Évidemment pas.
La solution pratique commune à ce problème est un test simple appelé un premier test probable d'Euler et une généralisation plus puissante appelé un fort probable fort (SPRP). Ceci est un test qui pour un le nombre entier N peut le classer de manière probabiliste comme étant premier ou non, et des tests répétés peuvent augmenter la probabilité de correction. La partie lente du test lui-même implique principalement le calcul d’une valeur similaire à A ^ (N-1) modulo N. Toute personne implémentant le chiffrement RSA à clé publique les variantes ont utilisé cet algorithme. C'est utile à la fois pour les entiers énormes (comme 512 bits) ainsi que les ints 32 ou 64 bits normaux.
Le test peut être changé d’un rejet probabiliste en un preuve définitive de primalité en précalculant certaines entrées de test paramètres connus pour toujours réussir pour des plages de N . Malheureusement, la découverte de ces "tests les plus connus" est effectivement une recherche d'un domaine énorme (en fait infini). En 1980, une première liste de Des tests utiles ont été créés par Carl Pomerance (célèbre pour être celui à factoriser RSA-129 avec son algorithme Quadratic Seive.) Plus tard Jaeschke amélioré considérablement les résultats en 1993. En 2004, Zhang et Tang amélioré la théorie et les limites du domaine de recherche. Greathouse et Livingstone a publié les résultats les plus modernes jusqu’à présent sur le Web, à http://math.crg4.com/primes.html , les meilleurs résultats d’un énorme domaine de recherche.
Voir ici pour plus d’informations: http://primes.utm.edu/prove/prove2_3.html et http://forums.nvidia.com/index.php?showtopic=70483
Si vous avez simplement besoin d'un moyen de générer de très grands nombres premiers et que vous ne souhaitez pas générer tous les nombres premiers <un entier n, vous pouvez utiliser le test de Lucas-Lehmer pour vérifier les nombres premiers de Mersenne. Un nombre premier de Mersenne est sous la forme de 2 ^ p -1. Je pense que le test de Lucas-Lehmer est l'algorithme le plus rapide découvert pour les nombres premiers de Mersenne.
Et si vous souhaitez non seulement utiliser l'algorithme le plus rapide, mais également le matériel le plus rapide, essayez de l'implémenter avec Nvidia CUDA, écrivez un noyau pour CUDA et exécutez-le sur un processeur graphique.
Vous pouvez même gagner de l’argent si vous découvrez des nombres premiers assez importants. EFF offre des prix allant de 50 000 $ à 250 000 $: https://www.eff.org/awards/coop
Il existe un test mathématique à 100% qui vérifie si un nombre P
est premier ou composite, appelé Test de primalité AKS .
Le concept est simple: étant donné un nombre P
, si tous les coefficients de (x-1)^P - (x^P-1)
sont divisibles par P
, alors P
est un nombre premier, sinon c'est un nombre composé.
Par exemple, étant donné P = 3
, donnerait le polynôme:
(x-1)^3 - (x^3 - 1)
= x^3 + 3x^2 - 3x - 1 - (x^3 - 1)
= 3x^2 - 3x
Et les coefficients sont tous deux divisibles par 3
, le nombre est donc premier.
Et par exemple, où P = 4
, qui n'est PAS un nombre premier, donnerait:
(x-1)^4 - (x^4-1)
= x^4 - 4x^3 + 6x^2 - 4x + 1 - (x^4 - 1)
= -4x^3 + 6x^2 - 4x
Et ici, nous pouvons voir que les coefficients 6
ne sont pas divisibles par 4
, par conséquent, il n’est PAS premier.
Le polynôme (x-1)^P
sera P+1
termes et peut être trouvé à l'aide d'une combinaison. Donc, ce test s'exécutera dans le runtime O(n)
, donc je ne sais pas à quel point ce serait utile puisque vous pouvez simplement parcourir i
de 0 à p
et tester le reste.
Votre problème est de décider si un nombre particulier est premier? Ensuite, vous avez besoin d'un test de primalité (facile). Ou avez-vous besoin de tous les nombres premiers jusqu'à un nombre donné? Dans ce cas, les premiers tamis sont bons (faciles, mais nécessitent de la mémoire). Ou avez-vous besoin des facteurs premiers d'un nombre? Cela nécessiterait une factorisation (difficile pour les grands nombres si vous voulez vraiment les méthodes les plus efficaces). Quelle est la taille des chiffres que vous regardez? 16 bits? 32 bits? plus gros?
Un moyen intelligent et efficace consiste à pré-calculer des tables de nombres premiers et à les conserver dans un fichier en utilisant un codage au niveau du bit. Le fichier est considéré comme un vecteur de bits long alors que le bit n représente l'entier n. Si n est premier, son bit est mis à un et à zéro sinon. La recherche est très rapide (vous calculez le décalage d'octet et un masque de bits) et ne nécessite pas le chargement du fichier en mémoire.
Cela dépend de votre application. Il y a quelques considérations:
Les tests de Miller-Rabin et analogues ne sont plus rapides qu’un tamis pour des nombres supérieurs à une certaine taille (quelques millions, je crois). En dessous, utiliser une division d’essai (si vous n’avez que quelques chiffres) ou un tamis est plus rapide.
Rabin-Miller est un test de primalité probabiliste standard. (vous l'exécutez K fois et le numéro d'entrée est soit définitivement composite, soit probablement premier avec une probabilité d'erreur 4-K. (quelques centaines d'itérations et c'est presque certainement la vérité)
Il existe une variante non probabiliste (déterministe) de Rabin Miller .
Le Great Internet Mersenne Prime Search (GIMPS) qui a enregistré le record du monde du plus grand nombre de transactions74 207 281 - 1 à compter de juin 2017), utilise plusieurs algorithmes , mais il s'agit de nombres premiers sous des formes spéciales. Cependant, la page GIMPS ci-dessus inclut certains tests de primalité déterministes généraux. Ils semblent indiquer que l'algorithme le plus rapide dépend de la taille du nombre à tester. Si votre numéro correspond à 64 bits, vous ne devriez probablement pas utiliser une méthode destinée à traiter des nombres premiers de plusieurs millions de chiffres.
Je vous laisse décider si c'est le plus rapide ou pas.
using System;
namespace PrimeNumbers
{
public static class Program
{
static int primesCount = 0;
public static void Main()
{
DateTime startingTime = DateTime.Now;
RangePrime(1,1000000);
DateTime endingTime = DateTime.Now;
TimeSpan span = endingTime - startingTime;
Console.WriteLine("span = {0}", span.TotalSeconds);
}
public static void RangePrime(int start, int end)
{
for (int i = start; i != end+1; i++)
{
bool isPrime = IsPrime(i);
if(isPrime)
{
primesCount++;
Console.WriteLine("number = {0}", i);
}
}
Console.WriteLine("primes count = {0}",primesCount);
}
public static bool IsPrime(int ToCheck)
{
if (ToCheck == 2) return true;
if (ToCheck < 2) return false;
if (IsOdd(ToCheck))
{
for (int i = 3; i <= (ToCheck / 3); i += 2)
{
if (ToCheck % i == 0) return false;
}
return true;
}
else return false; // even numbers(excluding 2) are composite
}
public static bool IsOdd(int ToCheck)
{
return ((ToCheck % 2 != 0) ? true : false);
}
}
}
Il faut environ 82 secondes pour rechercher et imprimer des nombres premiers dans une plage allant de 1 à 1 000 000 sur mon ordinateur portable Core 2 Duo doté d’un processeur à 2,40 GHz. Et il a trouvé 78 498 nombres premiers.