Plus grand facteur premier d’un nombre

Quelle est la meilleure approche pour calculer le plus grand facteur premier d’un nombre?

Je pense que le plus efficace serait le suivant:

  1. Trouver le plus petit nombre premier qui divise proprement
  2. Vérifiez si le résultat de la division est premier
  3. Sinon, trouver le plus bas suivant
  4. Allez à 2.

Je base cette hypothèse sur le fait qu’il est plus facile de calculer les petits facteurs premiers. Est-ce que c’est juste? Quelles autres approches devrais-je examiner?

Edit: J’ai maintenant réalisé que mon approche est futile s’il y a plus de 2 facteurs premiers en jeu, puisque l’étape 2 échoue lorsque le résultat est le produit de deux autres nombres premiers, un algorithme récursif est donc nécessaire.

Editer à nouveau: Et maintenant, je me suis rendu compte que cela fonctionne toujours, car le dernier nombre premier trouvé doit être le plus élevé; par conséquent, tout test supplémentaire du résultat non-premier de l’étape 2 entraînerait un nombre premier plus petit.

En fait, il existe plusieurs moyens plus efficaces de trouver des facteurs de grand nombre (pour les plus petits, la division d’essais fonctionne raisonnablement bien).

Une méthode qui est très rapide si le nombre d’entrée a deux facteurs très proches de sa racine carrée est la factorisation de Fermat . Il utilise l’identité N = (a + b) (a – b) = a ^ 2 – b ^ 2 et est facile à comprendre et à mettre en œuvre. Malheureusement, ce n’est pas très rapide en général.

Le tamis quadratique est la méthode la plus connue pour factoriser des nombres allant jusqu’à 100 chiffres. En prime, une partie de l’algorithme se fait facilement avec un parallel processing.

Un autre algorithme dont j’ai entendu parler est l’algorithme Rho de Pollard . Ce n’est pas aussi efficace que le Quadratic Sieve en général, mais semble être plus facile à mettre en œuvre.


Une fois que vous avez décidé de diviser un nombre en deux facteurs, voici l’algorithme le plus rapide auquel je puisse penser pour trouver le facteur premier le plus important d’un nombre:

Créez une queue prioritaire qui stocke initialement le numéro lui-même. À chaque itération, vous supprimez le nombre le plus élevé de la queue et tentez de le diviser en deux facteurs (ne permettant pas à l’un de ces facteurs, bien sûr). Si cette étape échoue, le nombre est premier et vous avez votre réponse! Sinon, vous ajoutez les deux facteurs dans la queue et répétez.

Voici le meilleur algorithme que je connaisse (en Python)

 def prime_factors(n): """Returns all the prime factors of a positive integer""" factors = [] d = 2 while n > 1: while n % d == 0: factors.append(d) n /= d d = d + 1 return factors pfs = prime_factors(1000) largest_prime_factor = max(pfs) # The largest element in the prime factor list 

La méthode ci-dessus s’exécute dans O(n) dans le pire des cas (lorsque l’entrée est un nombre premier).

MODIFIER:
Ci-dessous la version O(sqrt(n)) , comme suggéré dans le commentaire. Voici le code, une fois de plus.

 def prime_factors(n): """Returns all the prime factors of a positive integer""" factors = [] d = 2 while n > 1: while n % d == 0: factors.append(d) n /= d d = d + 1 if d*d > n: if n > 1: factors.append(n) break return factors pfs = prime_factors(1000) largest_prime_factor = max(pfs) # The largest element in the prime factor list 

Ma réponse est basée sur Triptych , mais améliore beaucoup sur elle. Il est basé sur le fait qu’au-delà de 2 et 3, tous les nombres premiers sont de la forme 6n-1 ou 6n + 1.

 var largestPrimeFactor; if(n mod 2 == 0) { largestPrimeFactor = 2; n = n / 2 while(n mod 2 == 0); } if(n mod 3 == 0) { largestPrimeFactor = 3; n = n / 3 while(n mod 3 == 0); } multOfSix = 6; while(multOfSix - 1 <= n) { if(n mod (multOfSix - 1) == 0) { largestPrimeFactor = multOfSix - 1; n = n / largestPrimeFactor while(n mod largestPrimeFactor == 0); } if(n mod (multOfSix + 1) == 0) { largestPrimeFactor = multOfSix + 1; n = n / largestPrimeFactor while(n mod largestPrimeFactor == 0); } multOfSix += 6; } 

J'ai récemment écrit un article de blog expliquant comment cet algorithme fonctionne.

Je m'aventurerais qu'une méthode dans laquelle il n'y aurait pas besoin de test de primalité (et pas de construction de tamis) serait plus rapide que celle qui les utilise. Si tel est le cas, c'est probablement l'algorithme le plus rapide.

Tous les nombres peuvent être exprimés comme le produit des nombres premiers, par exemple:

 102 = 2 x 3 x 17 712 = 2 x 2 x 2 x 89 

Vous pouvez les trouver simplement en commençant à 2 et en continuant simplement à diviser jusqu’à ce que le résultat ne soit pas un multiple de votre numéro:

 712 / 2 = 356 .. 356 / 2 = 178 .. 178 / 2 = 89 .. 89 / 89 = 1 

en utilisant cette méthode, vous n’avez pas besoin de calculer les nombres premiers: ils seront tous des nombres premiers, car vous avez déjà factorisé le nombre autant que possible avec tous les nombres précédents.

 number = 712; currNum = number; // the value we'll actually be working with for (currFactor in 2 .. number) { while (currNum % currFactor == 0) { // keep on dividing by this number until we can divide no more! currNum = currNum / currFactor // reduce the currNum } if (currNum == 1) return currFactor; // once it hits 1, we're done. } 
  //this method skips unnecessary sortingal divisions and makes //sortingal division more feasible for finding large primes public static void main(Ssortingng[] args) { long n= 1000000000039L; //this is a large prime number long i = 2L; int test = 0; while (n > 1) { while (n % i == 0) { n /= i; } i++; if(i*i > n && n > 1) { System.out.println(n); //prints n if it's prime test = 1; break; } } if (test == 0) System.out.println(i-1); //prints n if it's the largest prime factor } 

Code JavaScript:

 'option ssortingct'; function largestPrimeFactor(val, divisor = 2) { let square = (val) => Math.pow(val, 2); while ((val % divisor) != 0 && square(divisor) <= val) { divisor++; } return square(divisor) <= val ? largestPrimeFactor(val / divisor, divisor) : val; } 

Exemple d'utilisation:

 let result = largestPrimeFactor(600851475143); 

Voici un exemple du code :

La solution la plus simple est une paire de fonctions mutuellement récursives .

La première fonction génère tous les nombres premiers:

  1. Commencez par une liste composée de 2 et de tous les nombres impairs supérieurs à 2.
  2. Supprimez tous les nombres qui ne sont pas premiers. C’est-à-dire des nombres qui n’ont pas de facteurs premiers (autres qu’eux-mêmes). Voir ci-dessous.

La deuxième fonction renvoie les facteurs premiers d’un nombre donné n dans l’ordre croissant. La stratégie est d’essayer de diviser n par chaque premier qui pourrait être son diviseur:

  1. Prenez une liste de tous les nombres premiers en ordre croissant (voir ci-dessus).
  2. Soit p un premier dans cette liste, et ps les facteurs premiers de n/p (voir étape 1).
    • Si p carré est supérieur à notre nombre n , alors n est premier. Nous avons fini.
    • Si p divise n , alors p est un facteur premier de n . Les autres facteurs sont ps .
    • Sinon, p n’est pas un facteur premier de n .

Le plus grand facteur premier de n est le dernier nombre donné par la deuxième fonction.

Pour plus de clarté, voici le code de ce qui précède, dans Haskell:

 import Control.Monad -- All the primes primes = 2 : filter (ap (<=) (head . primeFactors)) [3,5..] -- Gives the prime factors of its argument primeFactors = factor primes where factor [] n = [] factor xs@(p:ps) n = if p*p > n then [n] else let (d,r) = divMod np in if r == 0 then p : factor xs d else factor ps n -- Gives the largest prime factor of its argument largestFactor = last . primeFactors 

Semblable à la réponse @Triptych mais aussi différente. Dans cet exemple, la liste ou le dictionnaire n’est pas utilisé. Le code est écrit en Ruby

 def largest_prime_factor(number) i = 2 while number > 1 if number % i == 0 number /= i; i -= 1 end i += 1 end return i end largest_prime_factor(600851475143) # => 6857 
 n = abs(number); result = 1; if (n mod 2 == 0) { result = 2; while (n mod 2 = 0) n /= 2; } for(i=3; i 

Certains tests modulo sont superflous, car n ne peut jamais être divisé par 6 si tous les facteurs 2 et 3 ont été supprimés. Vous ne pouvez autoriser que des nombres premiers pour i, ce qui est montré dans plusieurs autres réponses ici.

Vous pourriez effectivement mêler le tamis d'Eratosthène ici:

  • Commencez par créer la liste des entiers jusqu’à sqrt (n).
  • Dans la boucle for, marquez tous les multiples de i jusqu'au nouveau sqrt (n) comme non premiers et utilisez plutôt une boucle while.
  • mettre i au prochain nombre premier dans la liste.

Voir aussi cette question .

Je suis conscient que ce n’est pas une solution rapide. Poster comme on l’espère plus facile à comprendre la solution lente.

  public static long largestPrimeFactor(long n) { // largest composite factor must be smaller than sqrt long sqrt = (long)Math.ceil(Math.sqrt((double)n)); long largest = -1; for(long i = 2; i <= sqrt; i++) { if(n % i == 0) { long test = largestPrimeFactor(n/i); if(test > largest) { largest = test; } } } if(largest != -1) { return largest; } // number is prime return n; } 

Approche itérative Python en supprimant tous les facteurs premiers du nombre

 def primef(n): if n <= 3: return n if n % 2 == 0: return primef(n/2) elif n % 3 ==0: return primef(n/3) else: for i in range(5, int((n)**0.5) + 1, 6): #print i if n % i == 0: return primef(n/i) if n % (i + 2) == 0: return primef(n/(i+2)) return n 

J’utilise un algorithme qui continue à diviser le nombre par son facteur premier actuel.

Ma solution en python 3:

 def PrimeFactor(n): m = n while n%2==0: n = n//2 if n == 1: # check if only 2 is largest Prime Factor return 2 i = 3 sqrt = int(m**(0.5)) # loop till square root of number last = 0 # to store last prime Factor ie Largest Prime Factor while i <= sqrt : while n%i == 0: n = n//i # reduce the number by dividing it by it's Prime Factor last = i i+=2 if n> last: # the remaining number(n) is also Factor of number return n else: return last print(PrimeFactor(int(input()))) 

Entrée: 10 Sortie: 5

Entrée: 600851475143 Sortie: 6857

Voici mon approche pour calculer rapidement le facteur premier le plus important. Il est basé sur le fait que x modifié ne contient pas de facteurs non premiers. Pour ce faire, nous divisons x dès qu’un facteur est trouvé. Ensuite, il ne rest plus qu’à retourner le facteur le plus important. Ce serait déjà prime.

Le code (Haskell):

 f max' xi | i > x = max' | x `rem` i == 0 = fi (x `div` i) i -- Divide x by its factor | otherwise = f max' x (i + 1) -- Check for the next possible factor gx = f 2 x 2 

L’algorithme C ++ suivant n’est pas le meilleur, mais il fonctionne pour des nombres inférieurs à un milliard et c’est assez rapide.

 #include  using namespace std; // ------ is_prime ------ // Determines if the integer accepted is prime or not bool is_prime(int n){ int i,count=0; if(n==1 || n==2) return true; if(n%2==0) return false; for(i=1;i<=n;i++){ if(n%i==0) count++; } if(count==2) return true; else return false; } // ------ nextPrime ------- // Finds and returns the next prime number int nextPrime(int prime){ bool a = false; while (a == false){ prime++; if (is_prime(prime)) a = true; } return prime; } // ----- MAIN ------ int main(){ int value = 13195; int prime = 2; bool done = false; while (done == false){ if (value%prime == 0){ value = value/prime; if (is_prime(value)){ done = true; } } else { prime = nextPrime(prime); } } cout << "Largest prime factor: " << value << endl; } 

Il me semble que la deuxième étape de l’algorithme ne sera pas très efficace. Vous n’avez aucune attente raisonnable que ce soit premier.

En outre, la réponse précédente suggérant que le crible d’Eratosthène est totalement erronée. Je viens d’écrire deux programmes sur le facteur 123456789. L’un était basé sur le Sieve, l’autre sur les points suivants:

 1) Test = 2 2) Current = Number to test 3) If Current Mod Test = 0 then 3a) Current = Current Div Test 3b) Largest = Test 3c) Goto 3. 4) Inc(Test) 5) If Current < Test goto 4 6) Return Largest 

Cette version était 90 fois plus rapide que le tamis.

Le fait est que, sur les processeurs modernes, le type d'opération est beaucoup moins important que le nombre d'opérations, sans compter que l'algorithme ci-dessus peut fonctionner en cache, ce que le Sieve ne peut pas faire. Le tamis utilise beaucoup d'opérations en supprimant tous les nombres composés.

Notez également que la répartition des facteurs identifiés diminue l’espace à tester.

Calculer une liste stockant d’abord les nombres premiers, par exemple 2 3 5 7 11 13 …

Chaque fois que vous factorisez un nombre, utilisez l’implémentation de Triptych mais en itérant cette liste de nombres premiers plutôt que des entiers naturels.

Voici ma tentative en c #. La dernière impression est le facteur le plus important du nombre. J’ai vérifié et ça marche.

 namespace Problem_Prime { class Program { static void Main(ssortingng[] args) { /* The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143 ? */ long x = 600851475143; long y = 2; while (y < x) { if (x % y == 0) { // y is a factor of x, but is it prime if (IsPrime(y)) { Console.WriteLine(y); } x /= y; } y++; } Console.WriteLine(y); Console.ReadLine(); } static bool IsPrime(long number) { //check for evenness if (number % 2 == 0) { if (number == 2) { return true; } return false; } //don't need to check past the square root long max = (long)Math.Sqrt(number); for (int i = 3; i <= max; i += 2) { if ((number % i) == 0) { return false; } } return true; } } } 

Avec Java:

Pour les valeurs int :

 public static int[] primeFactors(int value) { int[] a = new int[31]; int i = 0, j; int num = value; while (num % 2 == 0) { a[i++] = 2; num /= 2; } j = 3; while (j <= Math.sqrt(num) + 1) { if (num % j == 0) { a[i++] = j; num /= j; } else { j += 2; } } if (num > 1) { a[i++] = num; } int[] b = Arrays.copyOf(a, i); return b; } 

Pour long valeurs long :

 static long[] getFactors(long value) { long[] a = new long[63]; int i = 0; long num = value; while (num % 2 == 0) { a[i++] = 2; num /= 2; } long j = 3; while (j <= Math.sqrt(num) + 1) { if (num % j == 0) { a[i++] = j; num /= j; } else { j += 2; } } if (num > 1) { a[i++] = num; } long[] b = Arrays.copyOf(a, i); return b; } 
 #python implementation import math n = 600851475143 i = 2 factors=set([]) while i 

Calcule le plus grand facteur premier d’un nombre en utilisant la récursivité en C ++. Le fonctionnement du code est expliqué ci-dessous:

 int getLargestPrime(int number) { int factor = number; // assumes that the largest prime factor is the number itself for (int i = 2; (i*i) <= number; i++) { // iterates to the square root of the number till it finds the first(smallest) factor if (number % i == 0) { // checks if the current number(i) is a factor factor = max(i, number / i); // stores the larger number among the factors break; // breaks the loop on when a factor is found } } if (factor == number) // base case of recursion return number; return getLargestPrime(factor); // recursively calls itself } 

J’ai trouvé cette solution sur le web par “James Wang”

 public static int getLargestPrime( int number) { if (number <= 1) return -1; for (int i = number - 1; i > 1; i--) { if (number % i == 0) { number = i; } } return number; } 

Ce n’est probablement pas toujours plus rapide mais plus optimiste quant à la possibilité de trouver un grand diviseur:

  1. N est votre numéro
  2. Si c’est premier, alors return(N)
  3. Calculer les nombres premiers jusqu’à Sqrt(N)
  4. Passer par les nombres premiers dans l’ordre décroissant (premier plus grand)
    • Si N is divisible by Prime alors Return(Prime)

Edit: A l’étape 3, vous pouvez utiliser le tamis d’Eratosthenes ou le tamis d’Atkins ou ce que vous voulez, mais le tamis ne vous apportera pas le facteur principal le plus important. (C’est pourquoi je ne choisirais pas la publication de SQLMenace comme réponse officielle…)

Je pense qu’il serait bon de stocker quelque part tous les nombres premiers possibles plus petits que n et de simplement les parcourir pour trouver le plus grand divisior. Vous pouvez obtenir des nombres premiers à partir de prime-numbers.org .

Bien sûr, je suppose que votre numéro n’est pas trop gros 🙂

Pas le plus rapide mais ça marche!

  static bool IsPrime(long num) { long checkUpTo = (long)Math.Ceiling(Math.Sqrt(num)); for (long i = 2; i <= checkUpTo; i++) { if (num % i == 0) return false; } return true; } 

Voici la même fonction @ Triptych fournie en générateur, qui a également été légèrement simplifiée.

 def primes(n): d = 2 while (n > 1): while (n%d==0): yield d n /= d d += 1 

Le maximum peut alors être trouvé en utilisant:

 n= 373764623 max(primes(n)) 

et une liste de facteurs trouvés en utilisant:

 list(primes(n)) 
 #include #include #include #include  factor(long int n) { long int i,j; while(n>=4) { if(n%2==0) { n=n/2; i=2; } else { i=3; j=0; while(j==0) { if(n%i==0) {j=1; n=n/i; } i=i+2; } i-=2; } } return i; } void main() { clock_t start = clock(); long int n,sp; clrscr(); printf("enter value of n"); scanf("%ld",&n); sp=factor(n); printf("largest prime factor is %ld",sp); printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC); getch(); }