7
votes

Problèmes de nombres premiers

J'essaie d'écrire un programme pour trouver le principal facteur premier d'un très grand nombre et j'ai essayé plusieurs méthodes avec un succès varié. Tous ceux que j'ai trouvés jusqu'à présent ont été incroyablement lents. J'avais pensé et je me demandais s'il s'agit d'une approche valide: xxx

Cette approche prendrait une entrée et ferait ce qui suit:

200 -> 100 -> 50 -> 25 -> 5 (retour)

90 -> 45 -> 15 -> 5 (retour)

Il divise à plusieurs reprises par le plus petit nombre divisible (la plupart souvent 2, ou 3) jusqu'à ce que CurrentNum soit prime (il n'y a pas de numéro de premier rang divisible inférieur au Squareroot de CurrentNum), et suppose qu'il s'agit du principal facteur premier de l'entrée d'origine.

cela fonctionnera-t-il toujours ? Sinon, quelqu'un peut-il me donner un contre-exemple?

-

Modifier: par très grand, je veux dire environ 2 ^ 40, ou 10 ^ 11.


4 commentaires

J'aimerais voir la mise en œuvre de votre Magique Notprime () Fonction. :)


heh, c'est facile: Notprime (n) = (getlowestdivisiblePrimenumber (n) == n).


Pour être honnête, j'utilise alors que (vrai) là-bas, il était tout simplement plus facile d'expliquer de cette façon. Ma méthode GetLowestDivisiblePrime fait référence à une arrayliste PRIMELIST; S'il n'y a pas de numéro de premier ordre divisible dans PRIMELIST, il trouve le prochain numéro principal à ajouter à Premelist et continue à le faire jusqu'à ce qu'il soit primordial que le «numéro» est divisible (et se référera ultérieurement à une plus grande liste de nombres premiers). , ou jusqu'à ce que le plus grand prime dans le priméliste soit supérieur au SQAURREROOT de «nombre». Pas de magie là-bas, même si j'espère que cela sera assez efficace. = P


21: 10 5 2 Attendu que 7 devraient être cédés. Malchance.


6 Réponses :


17
votes

Ceci fonctionnera toujours à cause de la Théorème de factorisation unique unique .


1 commentaires

Pour les cas d'angle, 0 et 1 ne sont ni premiers ni composites, et étant donné que longtemps sont signés, vous devez déterminer comment vous souhaitez gérer des nombres négatifs.



2
votes

Vous essayez de trouver le Facteurs principaux d'un numéro. Ce que vous proposez travaillera, mais sera toujours lent pour les grands nombres ... vous devriez être reconnaissant pour cela, car la sécurité la plus moderne repose sur cet étant un problème difficile.


0 commentaires

3
votes

Certainement, cela fonctionnera (voir Réponse de Mark Byers 'Réponse ), mais Pour les entrées «très grandes», cela peut prendre beaucoup trop de temps. Vous devez noter que votre appel à getlowestdivisibleprimenumber () dissimule une autre boucle, de sorte que cela fonctionne à O (n ^ 2) et que, selon ce que vous entendez par "très grand", il peut avoir à travailler sur Bignums qui sera lent.

Vous pourriez accélérer un peu, en notant que votre algorithme n'a besoin de ne jamais vérifier les facteurs plus petits que le dernier trouvé.


2 commentaires

Bien que d'être difficile, cela dit «long» et utilise «Java» dans la balise de questions, ce n'est donc que 2 ** 63 et non un problème de Bignum. D'autre part, la documentation réside. :)


@dalke: ack. Voir les mots «très gros» Kinda m'a coincé dans une ornière. Et je pense que la version améliorée peut fonctionner dans (un peu lent) du temps linéaire, bien que la méthode suggère que l'op utilise beaucoup d'espace ...



25
votes

La méthode fonctionnera, mais sera lente. "Quelle est la taille de vos chiffres?" Détermine la méthode à utiliser:


6 commentaires

Je suis impressionné par vos références aux algorithmes que je n'ai jamais entendu parler de, mais: ne sont pas ces algorithmes bien mieux adaptés à la recherche de tous de nombres premiers à une limite donnée, que d'affecter un seul numéro?


Je suis d'accord avec Carl. Bien que je ne puisse pas l'énoncer comme un fait (je n'ai pas étudié sur les méthodes mentionnées ci-dessus), je pense que cela constitue une méthode très efficace pour trouver le plus grand facteur premier. Comment puis-je implémenter Notprime () -OR plutôt,! Prime () - est une autre question entièrement.


@Jonathan: Quelle est la taille "très grande"?


Cela tombe sous "assez petit" - facile à facteur en millisecondes. Allez avec l'algorithme de Richard Brent.


Des algorithmes énumérés, seul le tamis des eratosthènes et un tamis d'Atkin tente effectivement de calculer de grandes listes de nombres premiers. Le Pollard's Rho, l'ECM de Lenstra, les tamis quadratiques et les tarifs de champs généraux sont tous exclusivement en personnalisation d'algorithmes. Et ils sont tous asymptotiquement "lents". Bien qu'aucun n'est presque si grave que la division d'essai (algorithme du questionneur)


@ 280z28 belle table, mais 10 ^ 20 <2 ^ 70.



1
votes

Dans une recherche rapide, je viens de faire, le moyen le plus rapide de faire correspondre un nombre consiste à utiliser la méthode de la courbe elliptique.

Vous pouvez essayer de jeter votre numéro à cette démo: http://www.alpertron.com .ar / ecm.htm .

Si cela vous convaincu, vous pouvez essayer de voler le code (ce n'est pas amusant, ils vous offrent un lien!) Ou lire la théorie de celui-ci ailleurs. Il y a un article Wikipedia à ce sujet ici: http://fr.wikipedia.org/wiki/lenstra_elliptic_curve_factorization Mais je suis trop stupide pour le comprendre. Heureusement, c'est votre problème, pas le mien! :)


0 commentaires

0
votes

La chose avec le projet Euler est qu'il ya généralement une méthode de force brute évidente à faire le problème, qui prendra à peu près jamais. Comme les questions deviennent plus difficiles, vous aurez besoin de mettre en œuvre des solutions intelligentes.

Une façon de résoudre ce problème est d'utiliser une boucle qui trouve toujours le facteur d'un plus petit nombre (entier positif). Lorsque le plus petit facteur d'un nombre est ce nombre, alors vous avez trouvé le plus grand facteur premier p>

Description détaillée Algorithme: p>

Vous pouvez le faire en gardant trois variables: p>

Le nombre que vous essayez de facteur (A) Un magasin courant de diviseur (B) Un plus grand magasin diviseur (C) p>

Dans un premier temps, que (A) le nombre qui vous intéresse - dans ce cas, il est 600851475143. Ensuite nous (B) soit 2. Avoir un test qui examine si (A) est divisible par (B). Si elle est divisible, diviser (A) (B), remise à zéro (B) à 2, et revenir à vérifier si (A) est divisible par (B). Sinon, si (A) est non divisible par (B), incrément (B) par +1, puis vérifier si (A) est divisible par (B). Exécutez la boucle jusqu'à ce que (A) est 1. Le (3) vous revenez sera le plus grand diviseur premier de 600.851.475.143 p>

Il existe de nombreuses façons, vous pouvez le rendre plus efficace -. Au lieu de incrémenter à l'entier , vous pouvez augmenter le nombre entier suivant nécessairement le premier, et au lieu de garder un plus grand magasin de diviseur, vous pouvez simplement retourner le nombre actuel lorsque son seul diviseur est lui-même. Cependant, l'algorithme I décrit ci-dessus fonctionne en quelques secondes quel que soit p>

La mise en œuvre en Python est comme suit: -. P>

def lpf(x):
        lpf = 2;
        while (x > lpf):
                if (x%lpf==0):
                        x = x/lpf
                        lpf = 2
                else:
                        lpf+=1;
        print("Largest Prime Factor: %d" % (lpf));

def main():
        x = long(raw_input("Input long int:"))
        lpf(x);
        return 0;

if __name__ == '__main__':
    main()


0 commentaires