Vérifier si un entier est premier plus efficacement
J'ai récemment été en partie d'un petit langage de programmation java de la concurrence à mon école. Mon partenaire et moi venons de terminer notre premier pure de la programmation orientée objet classe et la plupart des questions étaient hors de notre ligue nous nous sommes donc installées sur celui-ci (et je paraphrase un peu): "compte tenu de l'entrée n entier revenir le lendemain int qui est le premier et son inverse est également le premier par exemple, si n = 18 votre programme doit imprimer 31" parce que le 31 et 13 sont premiers. Votre .fichier de classe serait alors un cas de test de tous les nombres de 1 à 2,000,000,000 passé et il a dû retourner la bonne réponse dans les 10 secondes pour être considéré comme valide.
Nous avons trouvé une solution mais avec un plus grand cas de test, il faudrait plus de 10 secondes. Je suis assez certain qu'il y est un moyen pour déplacer la plage de la boucle de n,..2,000,000,000 bas que le capot probable de devoir en boucle que la loin où n est un faible nombre est petit, mais de toute façon, nous avons cassé la boucle quand un nombre est premier dans les deux conditions est trouvé. Au départ, nous étions en boucle de 2,..n, peu importe comment grand il a été ensuite je me suis souvenu de la règle de la " seulement en boucle à la racine carrée de n. Toutes les suggestions sur la façon de faire mon programme le plus efficace? J'ai eu pas de cours traitant de l'analyse de la complexité des algorithmes. Voici notre tentative.
public class P3
{
public static void main(String[] args){
long loop = 2000000000;
long n = Integer.parseInt(args[0]);
for(long i = n; i<loop; i++)
{
String s = i +"";
String r = "";
for(int j = s.length()-1; j>=0; j--)
r = r + s.charAt(j);
if(prime(i) && prime(Long.parseLong(r)))
{
System.out.println(i);
break;
}
}
System.out.println("#");
}
public static boolean prime(long p){
for(int i = 2; i<(int)Math.sqrt(p); i++)
{
if(p%i==0)
return false;
}
return true;
}
}
ps désolé si j'ai fait la mise en forme de code de mal c'est ma première fois de poster ici. Également la sortie devait avoir un '#' après chaque ligne c'est ce que la ligne après la boucle est d'environ Merci pour toute aide que vous les gars!!!
Cette question semble être hors-sujet, car il est à propos de la théorie des nombres. Essayez math.stackexchange.com.
OriginalL'auteur SipSop | 2010-05-05
Vous devez vous connecter pour publier un commentaire.
D'abord, vous devez précalculer tous les nombres premiers jusqu'à 2,000,000,000 en utilisant quelque chose comme la Crible d'Eratosthène. Vous pouvez stocker si chaque nombre est premier dans un tableau de bits.
C'est assez rapide, et puis la vérification de chaque numéro de primalité est une recherche simple.
Si vous ne pouvez pas faire cela parce que vous avez besoin pour exécuter une nouvelle instance de votre programme pour chaque cas de test, utiliser un rapide test de primalité de l'algorithme comme De Miller-Rabin.
Je me demande si precomputing réponses serait considéré comme de la triche-- après tout, s'ils connaissent les nombres premiers de 1 à 2 milliards de dollars à l'avance, de trouver l'ensemble de ce groupe qui est aussi "renverser le premier" pourrait également être fait. Ensuite, c'est juste une simple question de " qui, au nombre de dans ma précalculées ensemble est l'entrée la plus proche?'
À l'aide d'un meilleur algorithme n'est pas de la triche, juste être intelligent et à l'aide de toutes les informations reçues, afin d'optimiser votre programme.
Vraiment? Dans mes livres de tamisage d'une table de est un des premiers trucs dans l'optimisation d'un premier problème lié à l'. S'il était mon élève, je serais impressionné par l'ingéniosité!
vraiment? Un étudiant qui calcule les réponses à un temps de problème à l'avance, et ensuite fait référence à une table de la réponse est dans l'esprit de la compétition? @Lucero points, que c'est stupide, parce que c'est " idiot mais rapide, et en tant que professeur, oui, je disqualifier. Peut-être que votre style d'enseignement est pourquoi j'ai un moment difficile de trouver des formés, des gens compétents qui peuvent écrire décent code, mais vraiment un temps facile de trouver des perroquets qui ne peut pas réfléchir sur leurs pieds.
OriginalL'auteur David
Votre premier chèque est très inefficace. En fait, vous n'avez pas besoin de re-vérifier les multiples de déjà vérifié les numéros. Ainsi, lorsque vous vérifiez %2, vous n'avez pas besoin de vérifier pour %4.
Pour savoir si un nombre est un nombre premier, vous n'avez qu'à essayer de le diviser par tous les nombres premiers connus jusqu'à atteindre la racine carrée du nombre à être vérifié. En faisant cela réduit le nombre de divisions largement: si votre application dispose d'une liste des nombres premiers de 2..~44721 (par exemple calculé comme étape de préparation), vous pouvez vérifier tous les nombres jusqu'à 2000000000 assez rapidement.
Aussi, assurez-vous de vérifier le plus petit des deux permutations première (par exemple, dans l'échantillon de la première case 13, 31).
Edit:
Voici un exemple, j'ai rapidement mis en C# (vous aurez besoin de faire quelques petits changements syntaxiques de le faire tourner sur Java, mais j'ai juste eu un compilateur C# à la main):
Sur mon ordinateur et avec le
loop
etn
dans la source, le résultat s'affiche instantanément.merci pour vos commentaires. Notez que dans mon cas, mon nom est emprunté à l'un de mes chevaux, l'un sur l'avatar c'est. Il est un de 9 ans étalon pure race espagnole (PRE: en.wikipedia.org/wiki/Andalusian_horse ). 😉
OriginalL'auteur Lucero
À l'aide de
BigInteger.isProbablePrime(certitude)
etBigInteger.nextProbablePrime()
peut de manière significative réduire le nombre de cas, vous devez vérifier très efficacementOriginalL'auteur Stephen Denne
Il semble que vous êtes en augmentant de 1, mais vous devriez être en augmentant de 2. Pas de même le nombre est premier, mais 2.
OriginalL'auteur Mantas Vidutis
La grande inefficacité ici est votre premier essai méthode
prime
. Prendre un pensez au nombre de fois qu'il faudra tester le même nombre, et de se concentrer sur la façon dont on pourrait tirer parti des structures de la mémoire afin d'éviter la répétition des calculs.OriginalL'auteur spender
Je n'ai pas fait cela avant, mais voici quelques choses qui viennent à mon esprit.
si votre racine carrée est un entier, le nombre n'est pas premier
si le nombre se termine par un 0,2,4,5,6, ou 8 il n'est pas premier, à l'exception des 2 lui-même
Nombre est divisible par 3 si la somme ofdigits est divisible par 3
et par 9 si la somme est 9.
Je ne sais pas si les tests pour ce genre de choses vous aider, au moins le test de la racine carrée devrait aider parce que vous avez à calculer de toute façon et vous avez peut-être déjà fait.
Oh, et bien sûr votre efficence augmente beaucoup si vous faites quelque chose comme de Miller–Rabin test de primalité http://en.wikipedia.org/wiki/Miller-Rabin_primality_test.
Votre test ne doit être effectué dans les cas qui ne coûtent pas certain.
OriginalL'auteur HansDampf
Une autre amélioration de la vitesse que vous pouvez faire dans
main
est de changer votre boucle de pré-filtre à certains numéros composés, en déroulant quelques itérations dans une séquence de tests. Le plus simple est de tester les 2 en dehors de la boucle, puis de tester les nombres impairs (2*i+1
). Un peu plus complexe est de tester les 2, 3, puis6*i ± 1
. Vous pouvez conserver l'extension de cette approche, les tests les n premiers nombres premiers, puis en boucle fourpn# * i+j
, où pn# est le premier primordiale (le produit des n premiers nombres premiers) et j est un entier positif inférieur et le premier a ' pn#.Pour accélérer le
prime
méthode, vous pouvez commencer avec un rapide probabiliste premier test et de test à l'aide d'un ralentissement de la déterministe test seulement pour les cas les probabiliste de test ne peut pas déterminer.il ignore les multiples de n premiers nombres premiers. Notez comment
2*i+1
ignore même nombre, et6*i±1
ignore les multiples de 2 et de 3. La page de Wikipedia sur les tests de primalité (en.wikipedia.org/wiki/Primality_test) a des exemples.OriginalL'auteur outis
@outis...je vois ce que vous dites c'est un petit truc utile que je dois dire. je vous remercie pour cela.
@Graham...aussi cool j'ai lu un article sur le test que vous avez mentionné parce que même si je crois que j'ai compris l'essentiel à partir des commentaires que vous faites Python a toujours l'air comme le grec pour moi. Je sais tout le monde dit que c'est l'un des plus simple des langues à ramasser, mais pour quelque raison que ce soit java et c++ toujours regarder plus lisible pour moi. De toute façon, oui, qui wouldve été une bien meilleure façon de le faire. Merci encore à vous tous, qui m'a donné des conseils, j'ai appris beaucoup de cette commission. Peut pas pour mes structures de données et algorithmes de la classe à l'automne!!!
OriginalL'auteur SipSop
L'option la plus simple serait d'utiliser utiliser un grand nombre entier de la bibliothèque. Il n'aura pas de bugs, et de disposer de toutes les fonctions de support.
Si vous écrivez votre propre mise en œuvre (c'est à dire pour une cession), je vous recommande de travailler à partir d'un pseudo code de l'algorithme dans un livre, afin que vous compreniez ce que vous faites.
Cela étant dit, l'une des méthodes les plus simples est d'utiliser de Jacobi et de Legendre, et de les comparer pour l'égalité. Je viens d'envoyer une mission pour le chiffrement RSA. Voici ce que j'ai fait pour la simple précision, cependant, les algorithmes sont générales et de travailler pour de multiples précision des nombres entiers.
La Performance est très bonne, même avec un grand nombre.
OriginalL'auteur ioquatix
@David obtenir la racine carrée d'un nombre, puis en boucle jusqu'à la racine carrée d'éliminer les même nombres et de voir si il n'est pas divisble
OriginalL'auteur Dead Programmer
Encore plus vite que tout cela est à l'aide de la De Miller-Rabin test. C'est un test probabiliste, et a donc un certain niveau d'erreur; toutefois, le test s'exécute plusieurs fois ce qui réduit cette erreur aussi petite que nécessaire (50 suffit souvent pour des applications commerciales).
Pas en Java, mais voici une mise en œuvre rapide en Python que j'ai cuisiné.
OriginalL'auteur Graham