Algorithme pour trouver le plus grand facteur premier d'un nombre

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

"151900920 je pense que le plus efficace serait le suivant:

  1. trouver le nombre premier Le plus bas qui divise proprement
  2. vérifier si le résultat de la division est premier
  3. si ce n'est pas le cas, trouver le plus bas suivant
  4. passez à 2.

je fonde cette hypothèse sur le fait que c'est plus facile pour calculer les petits facteurs premiers. Est-ce vrai? 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 principaux en jeu, puisque l'étape 2 échoue lorsque le résultat est un produit de deux autres nombres premiers, donc un algorithme récursif est nécessaire.

éditer à nouveau: et maintenant j'ai réalisé que cela fonctionne toujours, parce que le dernier nombre premier trouvé doit être le plus élevé, par conséquent, tout autre test du résultat de non-prime de l'étape 2 se traduirait par une prime plus petite.

165
demandé sur smci 2008-08-22 23:35:50

27 réponses

en fait, il existe plusieurs façons plus efficaces de trouver les facteurs des grands nombres (pour les plus petits, la section de première instance fonctionne assez 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 connue comme FERMAT factorisation . Il rend l'utilisation de l'identité N = (a + b)(a - b) = a^2 - b^2 et est facile à comprendre et à mettre en œuvre. Malheureusement, il n'est pas très rapide en général.

la méthode la plus connue pour factoriser des nombres jusqu'à 100 chiffres de long est le tamis quadratique . En bonus, une partie de l'algorithme est facilement traitée en parallèle.

encore un autre algorithme dont j'ai entendu parler est algorithme Rho de Pollard . Ce N'est pas aussi efficace que le tamis quadratique en général, mais il semble plus facile à mettre en œuvre.


une fois que vous avez décidé sur la façon de diviser un nombre en deux facteurs, voici l'algorithme le plus rapide que je peux penser pour trouver le plus grand facteur premier d'un nombre:

crée une file d'attente prioritaire qui stocke initialement le numéro lui-même. À chaque itération, vous retirez le nombre le plus élevé de la file d'attente, et tentez de le diviser en deux facteurs (ne permettant pas à 1 d'être 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 file d'attente et répéter.

126
répondu Artelius 2014-06-12 08:23:46

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 fonctionne en O(n) dans le pire des cas (lorsque l'entrée est un nombre premier).

EDIT:

Voici 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
126
répondu Triptych 2014-02-21 03:35:11

ma réponse est basée sur Triptyque 's, mais améliore beaucoup sur elle. Il est basé sur le fait qu'au-delà de 2 et 3, tous les nombres premiers 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 risquerais qu'une méthode dans laquelle il n'y a pas besoin d'un test pour la primalité (et aucune construction de tamis) fonctionnerait plus vite qu'un ce qui ne les utiliser. Si c'est le cas, c'est probablement l'algorithme le plus rapide ici.

17
répondu sundar 2017-05-23 12:34:54

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

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

vous pouvez les trouver en commençant simplement à 2 et en continuant simplement à diviser jusqu'à ce que le résultat n'est pas un multiple de votre nombre:

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

en utilisant cette méthode, vous n'avez pas à calculer réellement des nombres premiers: ils seront tous des nombres premiers, basé sur le fait que 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.
}
4
répondu nickf 2008-10-28 05:06:53
    //this method skips unnecessary trial divisions and makes 
    //trial division more feasible for finding large primes

    public static void main(String[] 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
    }
4
répondu the_prole 2014-09-22 16:50:45

code JavaScript:

'option strict';

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 :

4
répondu Vlad Bezden 2016-04-01 15:54:37

similaire à @Triptych réponse, mais aussi différent. 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
4
répondu Ugnius Malūkas 2018-02-19 08:53:03

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. commence par une liste qui se compose de 2 et de tous les nombres impairs supérieurs à 2.
  2. supprimer tous les nombres qui ne sont pas premiers. Qui est, des chiffres qui n'ont pas de facteurs premiers (autres qu'eux-mêmes). Voir ci-dessous.

La seconde fonction retourne 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 éventuellement être son diviseur:

  1. prenez une liste de tous les nombres premiers dans l'ordre croissant (voir ci-dessus).
  2. soit p soit un nombre premier dans cette liste, et ps soit les facteurs premiers de n/p (voir étape 1).
    • si p au carré est plus grand que notre nombre n , puis n est premier. Nous avons terminé.
    • si p divise n , alors p est un facteur principal de n . Les autres facteurs sont ps .
    • autrement p n'est pas un facteur principal de n .

le facteur principal le plus important de n est le dernier nombre donné par la deuxième fonction.

pour plus de précision, 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 n p in
            if r == 0 then p : factor xs d
            else factor ps n

-- Gives the largest prime factor of its argument
largestFactor = last . primeFactors
3
répondu Apocalisp 2015-03-24 18:38:06
n = abs(number);
result = 1;
if (n mod 2 == 0) {
  result = 2;
  while (n mod 2 = 0) n /= 2;
}
for(i=3; i<sqrt(n); i+=2) {
  if (n mod i == 0) {
    result = i;
    while (n mod i = 0)  n /= i;
  }
}
return max(n,result)

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

vous pourriez en fait entrelacer le tamis D'Eratosthène ici:

  • créez D'abord la liste des entiers à sqrt(n).
  • dans le marqueur de boucle for tous les multiples de i jusqu'à la nouvelle sqrt(n) ne pas le premier, et d'utiliser une boucle while à la place.
  • fixe i au prochain nombre premier dans liste.

Voir aussi cette question .

2
répondu Ralph M. Rickenbach 2017-05-23 10:31:37

je suis conscient que ce n'est pas une solution rapide. Affichage comme, espérons plus facile à comprendre 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;
    } 
2
répondu thejosh 2012-02-27 22:41:54

Python approche Itérative par la suppression de 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
1
répondu Jyothir Aditya Singh 2015-11-09 12:55:37

j'utilise un algorithme qui continue à diviser le nombre par son facteur principal 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 i.e. 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

1
répondu Kalpesh Dusane 2016-09-01 06:26:10

voici ma tentative dans c#. La dernière impression est le facteur principal le plus important du nombre. J'ai vérifié et il fonctionne.

namespace Problem_Prime
{
  class Program
  {
    static void Main(string[] 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;
    }

  }
}
0
répondu Seamus Barrett 2014-01-20 15:54:25
#python implementation
import math
n = 600851475143
i = 2
factors=set([])
while i<math.sqrt(n):
   while n%i==0:
       n=n/i
       factors.add(i)
   i+=1
factors.add(n)
largest=max(factors)
print factors
print largest
0
répondu Rishabh Prasad 2014-05-31 20:57:01

calcule le plus grand facteur premier d'un nombre en utilisant la récursion 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
}
0
répondu 4aRk Kn1gh7 2014-12-12 05:08:30

Voici mon approche pour calculer rapidement le plus grand facteur principal. Il est basé sur le fait que modifié x ne contient pas de facteurs non-prime. Pour y parvenir, nous diviser x dès qu'un facteur est trouvé. La seule chose qui reste est de rendre le plus grand facteur. Il serait déjà premier.

le code (Haskell):

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

g x = f 2 x 2
0
répondu penkovsky 2015-11-22 12:33:21

l'algorithme C++ suivant n'est pas le meilleur, mais il fonctionne pour les nombres de moins d'un milliard et son assez rapide

#include <iostream>
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;
 }
 // ----- M A I N ------
 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;
 }
0
répondu s.n 2016-06-15 16:09:44

a 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;
}
0
répondu Babar Baig 2018-07-18 20:57:03

le Premier facteur à l'aide de tamis :

#include <bits/stdc++.h>
using namespace std;
#define N 10001  
typedef long long ll;
bool visit[N];
vector<int> prime;

void sieve()
{
            memset( visit , 0 , sizeof(visit));
            for( int i=2;i<N;i++ )
            {
                if( visit[i] == 0)
                {
                    prime.push_back(i);
                    for( int j=i*2; j<N; j=j+i )
                    {
                        visit[j] = 1;
                    }
                }
            }   
}
void sol(long long n, vector<int>&prime)
{
            ll ans = n;
            for(int i=0; i<prime.size() || prime[i]>n; i++)
            {
                while(n%prime[i]==0)
                {
                    n=n/prime[i];
                    ans = prime[i];
                }
            }
            ans = max(ans, n);
            cout<<ans<<endl;
}
int main() 
{
           ll tc, n;
           sieve();

           cin>>n;
           sol(n, prime);

           return 0;
}
0
répondu rashedcs 2018-09-13 10:41:37

Il me semble que l'étape 2 de l'algorithme donné ne va pas du tout être efficace, une approche. Vous n'avez aucune attente raisonnable qu'il soit premier.

aussi, la réponse précédente suggérant le tamis D'Eratosthène est tout à fait fausse. Je viens d'écrire deux programmes de facteur 123456789. L'une était basée sur le tamis, l'autre était basée sur ce qui suit:

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 90x plus rapide que le tamis.

Le fait est que, sur les processeurs modernes, le type d'opération importe beaucoup moins que le nombre d'opérations, sans mentionner que l'algorithme ci-dessus peut fonctionner en cache, le tamis ne peut pas. Le tamis utilise beaucoup d'opérations de suppression de tous les numéros composés.

Notez aussi que ma division des facteurs au fur et à mesure qu'ils sont identifiés réduit l'espace qui doit être testé.

-1
répondu Loren Pechtel 2008-10-28 05:40:45

calculer une liste stockant les nombres premiers en premier, par exemple 2 3 5 7 11 13 ...

chaque fois que vous prime factorisez un nombre, utilisez l'implémentation par Triptyque mais en itérant cette liste de nombres premiers plutôt que des entiers naturels.

-1
répondu guoger 2013-11-07 23:09:49

Avec Java:

pour int valeurs:

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:

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;
}
-1
répondu Paul Vargas 2014-04-11 19:26:54

ce n'est probablement pas toujours plus rapide mais plus optimiste à propos de ce que vous trouvez un grand diviseur prime:

  1. N est votre numéro
  2. si elle est prime puis return(N)
  3. calculer les primes jusqu'à Sqrt(N)
  4. passer par les nombres premiers dans l'ordre décroissant (le plus grand premier)
    • si N is divisible by Prime puis Return(Prime)

Edit: dans l'étape 3, vous pouvez utiliser le tamis D'Eratosthène ou le tamis D'Atkins ou ce que vous voulez, mais par lui-même le tamis ne vous trouvera pas le plus grand facteur principal. (Thats pourquoi je ne choisirais pas le poste de SQLMenace comme une réponse officielle...)

-2
répondu palotasb 2008-08-27 20:45:14

je pense qu'il serait bon de stocker quelque part tous les nombres premiers possibles plus petits que n et de les itérer pour trouver le plus grand diviseur. Vous pouvez obtenir des nombres premiers de prime-numbers.org .

bien sûr, je suppose que votre nombre n'est pas trop grand:)

-3
répondu Klesk 2008-08-22 19:57:15

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;
    }
-3
répondu Nick 2008-08-27 20:48:47

Voici la même fonction@Triptych fournie comme 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 Max prime peut alors être trouvé en utilisant:

n= 373764623
max(primes(n))

et une liste des facteurs trouvés en utilisant:

list(primes(n))
-3
répondu pedram 2013-05-16 18:56:12
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include <time.h>

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();
 }
-6
répondu Chitransh 2011-10-08 17:23:59