web-dev-qa-db-fra.com

Quel est l'algorithme de factorisation le plus rapide?

J'ai écrit un programme qui tente de trouver des paires amiables. Cela nécessite de trouver les sommes des diviseurs de nombres appropriés.

Voici ma méthode sumOfDivisors() actuelle:

int sumOfDivisors(int n)
{  
    int sum = 1;
    int bound = (int) sqrt(n);
    for(int i = 2; i <= 1 + bound; i++)
    {
        if (n % i == 0)
            sum = sum + i + n / i;
    } 
    return sum;
}

Je dois donc faire beaucoup de factorisation et cela commence à devenir le véritable goulot d'étranglement dans mon application. J'ai tapé un nombre énorme dans MAPLE et il l'a rendu incroyablement rapide.

Quel est l'un des algorithmes de factorisation les plus rapides?

54
Mithrax

Tiré directement de ma réponse à cette autre question .

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

86
Sam Harwell

La question dans le titre (et la dernière ligne) semble avoir peu à voir avec le corps même de la question. Si vous essayez de trouver des paires amiables, ou de calculer la somme des diviseurs pour de nombreux nombres, alors factoriser séparément chaque nombre (même avec l'algorithme le plus rapide possible) est absolument un moyen inefficace de le faire.

La fonction somme des diviseurs , σ(n) = (sum of divisors of n), est une fonction multiplicative : pour m et n relativement premiers, nous avons σ(mn) = σ(m)σ(n), donc

σ (p1k1… Prkr) = [(p1k1+1-1)/(p1-1)]… [(prkr+1-1)/(pr-1)].

Donc, vous utiliseriez n'importe quel tamis simple (par exemple une version augmentée du Tamis d'Eratosthène ) pour trouver les nombres premiers jusqu'à n, et, ce faisant, la factorisation de tous les nombres jusqu'à n. (Par exemple, comme vous le faites pour votre tamis, stockez le plus petit facteur premier de chaque n. Ensuite, vous pouvez plus tard factoriser n'importe quel nombre n par itération.) Ce serait plus rapide (global) que d'utiliser plusieurs fois un algorithme de factorisation séparé.

BTW: plusieurs listes connues de paires amiables existent déjà (voir par exemple ici et les liens à MathWorld ) - alors essayez-vous d'étendre l'enregistrement, ou faites-le juste pour le plaisir ?

21
ShreevatsaR

Algorithme de Shor: http://en.wikipedia.org/wiki/Shor%27s_algorithm

Bien sûr, vous avez besoin d'un ordinateur quantique: D

15
Thomas Eding

Je suggérerais de partir du même algorithme utilisé dans Maple, le tamis quadratique .

  1. Choisissez votre nombre impair n pour factoriser,
  2. Choisissez un nombre naturel k,
  3. Rechercher tout p <= k pour que k ^ 2 ne soit pas congru avec (n mod p ) pour obtenir une base factorielle B = p1, p2, ..., pt,
  4. À partir de r> floor (n) recherchez au moins t + 1 valeurs de sorte que y ^ 2 = r ^ 2 - n ont tous juste des facteurs en B,
  5. Pour chaque y1, y2, ..., y (t + 1) juste calculé vous générez un vecteur = v (yi) = (e1, e2, ..., et) ei est calculé en réduisant sur modulo 2 l'exposant pi in yi,
  6. Utilisez Élimination gaussienne pour trouver certains des vecteurs qui, ajoutés ensemble, donnent un vecteur nul
  7. Définissez x comme le produit de ri lié à yi trouvé à l'étape précédente et définissez y comme p1 ^ a * p2 ^ b * p3 ^ c * .. * pt ^ z où les exposants sont la moitié des exposants trouvés dans la factorisation de yi
  8. Calculer d = mcd (xy, n), si 1 <d <n alors d est un non-trivial facteur n, sinon commencez à l'étape 2 en choisissant un k plus grand.

Le problème de ces algorithmes est qu'ils impliquent vraiment beaucoup de théorie dans le calcul numérique.

12
Jack

Ceci est un document de la factorisation entière à Maple.

"En partant de quelques instructions très simples -" accélérez la factorisation des nombres entiers dans Maple "- nous avons implémenté l'algorithme de factorisation Quadratic Sieve dans une combinaison de Maple et C ..."

http://www.cecm.sfu.ca/~pborwein/MITACS/papers/percival.pdf

6
Irwin M. Fletcher

Cela dépend de la taille de vos chiffres. Si vous recherchez des paires amicales, vous faites beaucoup de factorisations, donc la clé n'est peut-être pas de factoriser le plus rapidement possible, mais de partager le plus de travail possible entre les différents appels. Pour accélérer la division d'essai, vous pouvez examiner la mémorisation et/ou le calcul préalable des nombres premiers jusqu'à la racine carrée du plus grand nombre qui vous intéresse. Il est plus rapide d'obtenir la factorisation principale, puis de calculer la somme de tous les facteurs à partir de cela, que de faire une boucle jusqu'à sqrt (n) pour chaque nombre.

Si vous cherchez de très grosses paires amicales, disons plus grandes que 2 ^ 64, alors sur un petit nombre de machines, vous ne pouvez pas le faire en factorisant chaque nombre, quelle que soit la rapidité de votre factorisation. Les raccourcis que vous utilisez pour trouver des candidats peuvent vous aider à les prendre en compte.

4
Steve Jessop

Une version plus C++ 2015 227 implémentation de la table de recherche pour 1 Go de mémoire:

#include <iostream.h> // cerr, cout, and NULL
#include <string.h>   // memcpy()
#define uint unsigned __int32
uint *factors;
const uint MAX_F=134217728; // 2^27

void buildFactors(){
   factors=new (nothrow) uint [(MAX_F+1)*2]; // 4 * 2 * 2^27 = 2^30 = 1GB
   if(factors==NULL)return; // not able to allocate enough free memory
   int i;
   for(i=0;i<(MAX_F+1)*2;i++)factors[i]=0;

   //Sieve of Eratosthenese
   factors[1*2]=1;
   factors[1*2+1]=1;
   for(i=2;i*i<=MAX_F;i++){
      for(;factors[i*2] && i*i<=MAX_F;i++);
      factors[i*2]=1;
      factors[i*2+1]=i;
      for(int j=2;i*j<=MAX_F;j++){
         factors[i*j*2]=i;
         factors[i*j*2+1]=j;
      }
   }
   for(;i<=MAX_F;i++){
      for(;i<=MAX_F && factors[i*2];i++);
      if(i>MAX_F)return;
      factors[i*2]=1;
      factors[i*2+1]=i;
   }
}

uint * factor(uint x, int &factorCount){
   if(x > MAX_F){factorCount=-1;return NULL;}
   uint tmp[70], at=x; int i=0;
   while(factors[at*2]>1){
      tmp[i++]=factors[at*2];
      cout<<"at:"<<at<<" tmp:"<<tmp[i-1]<<endl;
      at=factors[at*2+1];
   }
   if(i==0){
      cout<<"at:"<<x<<" tmp:1"<<endl;
      tmp[i++]=1;
      tmp[i++]=x;
   }else{
      cout<<"at:"<<at<<" tmp:1"<<endl;
      tmp[i++]=at;
   }
   factorCount=i;
   uint *ret=new (nothrow) uint [factorCount];
   if(ret!=NULL)
      memcpy(ret, tmp, sizeof(uint)*factorCount);
   return ret;
}

void main(){
   cout<<"Loading factors lookup table"<<endl;
   buildFactors(); if(factors==NULL){cerr<<"Need 1GB block of free memory"<<endl;return;}
   int size;
   uint x=30030;
   cout<<"\nFactoring: "<<x<<endl;
   uint *f=factor(x,size);
   if(size<0){cerr<<x<<" is too big to factor. Choose a number between 1 and "<<MAX_F<<endl;return;}
   else if(f==NULL){cerr<<"ran out of memory trying to factor "<<x<<endl;return;}

   cout<<"\nThe factors of: "<<x<<" {"<<f[0];
   for(int i=1;i<size;i++)
      cout<<", "<<f[i];
   cout<<"}"<<endl;
   delete [] f;

   x=30637;
   cout<<"\nFactoring: "<<x<<endl;
   f=factor(x,size);
   cout<<"\nThe factors of: "<<x<<" {"<<f[0];
   for(int i=1;i<size;i++)
      cout<<", "<<f[i];
   cout<<"}"<<endl;
   delete [] f;
   delete [] factors;
}

Mise à jour: ou sacrifier un peu de simplicité pour un peu plus de portée juste après 228

#include <iostream.h> // cerr, cout, and NULL
#include <string.h>   // memcpy(), memset()

//#define dbg(A) A
#ifndef dbg
#define dbg(A)
#endif

#define uint   unsigned __int32
#define uint8  unsigned __int8
#define uint16 unsigned __int16

uint * factors;
uint8  *factors08;
uint16 *factors16;
uint   *factors32;

const uint LIMIT_16   = 514; // First 16-bit factor, 514 = 2*257
const uint LIMIT_32   = 131074;// First 32-bit factor, 131074 = 2*65537
const uint MAX_FACTOR = 268501119;
//const uint64 LIMIT_64 = 8,589,934,594; // First 64-bit factor, 2^33+1

const uint TABLE_SIZE = 268435456; // 2^28 => 4 * 2^28 = 2^30 = 1GB 32-bit table
const uint o08=1, o16=257 ,o32=65665; //o64=4294934465
// TableSize = 2^37 => 8 * 2^37 = 2^40 1TB 64-bit table
//   => MaxFactor = 141,733,953,600

/* Layout of factors[] array
*  Indicies(32-bit)              i                 Value Size  AFactorOf(i)
*  ----------------           ------               ----------  ----------------
*  factors[0..128]            [1..513]             8-bit       factors08[i-o08]
*  factors[129..65408]        [514..131073]        16-bit      factors16[i-o16]
*  factors[65409..268435455]  [131074..268501119]  32-bit      factors32[i-o32]
*
* Note: stopping at i*i causes AFactorOf(i) to not always be LargestFactor(i)
*/
void buildFactors(){
dbg(cout<<"Allocating RAM"<<endl;)
   factors=new (nothrow) uint [TABLE_SIZE]; // 4 * 2^28 = 2^30 = 1GB
   if(factors==NULL)return; // not able to allocate enough free memory
   uint i,j;
   factors08 = (uint8 *)factors;
   factors16 = (uint16 *)factors;
   factors32 = factors;
dbg(cout<<"Zeroing RAM"<<endl;)
   memset(factors,0,sizeof(uint)*TABLE_SIZE);
   //for(i=0;i<TABLE_SIZE;i++)factors[i]=0;

//Sieve of Eratosthenese
     //8-bit values
dbg(cout<<"Setting: 8-Bit Values"<<endl;)
   factors08[1-o08]=1;
   for(i=2;i*i<LIMIT_16;i++){
      for(;factors08[i-o08] && i*i<LIMIT_16;i++);
dbg(cout<<"Filtering: "<<i<<endl;)
      factors08[i-o08]=1;
      for(j=2;i*j<LIMIT_16;j++)factors08[i*j-o08]=i;
      for(;i*j<LIMIT_32;j++)factors16[i*j-o16]=i;
      for(;i*j<=MAX_FACTOR;j++)factors32[i*j-o32]=i;
   }
   for(;i<LIMIT_16;i++){
      for(;i<LIMIT_16 && factors08[i-o08];i++);
dbg(cout<<"Filtering: "<<i<<endl;)
      if(i<LIMIT_16){
         factors08[i-o08]=1;
         j=LIMIT_16/i+(LIMIT_16%i>0);
         for(;i*j<LIMIT_32;j++)factors16[i*j-o16]=i;
         for(;i*j<=MAX_FACTOR;j++)factors32[i*j-o32]=i;
      }
   }i--;

dbg(cout<<"Setting: 16-Bit Values"<<endl;)
     //16-bit values
   for(;i*i<LIMIT_32;i++){
      for(;factors16[i-o16] && i*i<LIMIT_32;i++);
      factors16[i-o16]=1;
      for(j=2;i*j<LIMIT_32;j++)factors16[i*j-o16]=i;
      for(;i*j<=MAX_FACTOR;j++)factors32[i*j-o32]=i;
   }
   for(;i<LIMIT_32;i++){
      for(;i<LIMIT_32 && factors16[i-o16];i++);
      if(i<LIMIT_32){
         factors16[i-o16]=1;
         j=LIMIT_32/i+(LIMIT_32%i>0);
         for(;i*j<=MAX_FACTOR;j++)factors32[i*j-o32]=i;
      }
   }i--;

dbg(cout<<"Setting: 32-Bit Values"<<endl;)
     //32-bit values
   for(;i*i<=MAX_FACTOR;i++){
      for(;factors32[i-o32] && i*i<=MAX_FACTOR;i++);
      factors32[i-o32]=1;
      for(j=2;i*j<=MAX_FACTOR;j++)factors32[i*j-o32]=i;
   }
   for(;i<=MAX_FACTOR;i++){
      for(;i<=MAX_FACTOR && factors32[i-o32];i++);
      if(i>MAX_FACTOR)return;
      factors32[i-o32]=1;
   }
}

uint * factor(uint x, int &factorCount){
   if(x > MAX_FACTOR){factorCount=-1;return NULL;}
   uint tmp[70], at=x; int i=0;
   while(at>=LIMIT_32 && factors32[at-o32]>1){
      tmp[i++]=factors32[at-o32];
dbg(cout<<"at32:"<<at<<" tmp:"<<tmp[i-1]<<endl;)
      at/=tmp[i-1];
   }
   if(at<LIMIT_32){
      while(at>=LIMIT_16 && factors16[at-o16]>1){
         tmp[i++]=factors16[at-o16];
dbg(cout<<"at16:"<<at<<" tmp:"<<tmp[i-1]<<endl;)
         at/=tmp[i-1];
      }
      if(at<LIMIT_16){
         while(factors08[at-o08]>1){
            tmp[i++]=factors08[at-o08];
dbg(cout<<"at08:"<<at<<" tmp:"<<tmp[i-1]<<endl;)
            at/=tmp[i-1];
         }
      }
   }
   if(i==0){
dbg(cout<<"at:"<<x<<" tmp:1"<<endl;)
      tmp[i++]=1;
      tmp[i++]=x;
   }else{
dbg(cout<<"at:"<<at<<" tmp:1"<<endl;)
      tmp[i++]=at;
   }
   factorCount=i;
   uint *ret=new (nothrow) uint [factorCount];
   if(ret!=NULL)
      memcpy(ret, tmp, sizeof(uint)*factorCount);
   return ret;
}
uint AFactorOf(uint x){
   if(x > MAX_FACTOR)return -1;
   if(x < LIMIT_16) return factors08[x-o08];
   if(x < LIMIT_32) return factors16[x-o16];
                    return factors32[x-o32];
}

void main(){
   cout<<"Loading factors lookup table"<<endl;
   buildFactors(); if(factors==NULL){cerr<<"Need 1GB block of free memory"<<endl;return;}
   int size;
   uint x=13855127;//25255230;//30030;
   cout<<"\nFactoring: "<<x<<endl;
   uint *f=factor(x,size);
   if(size<0){cerr<<x<<" is too big to factor. Choose a number between 1 and "<<MAX_FACTOR<<endl;return;}
   else if(f==NULL){cerr<<"ran out of memory trying to factor "<<x<<endl;return;}

   cout<<"\nThe factors of: "<<x<<" {"<<f[0];
   for(int i=1;i<size;i++)
      cout<<", "<<f[i];
   cout<<"}"<<endl;
   delete [] f;

   x=30637;
   cout<<"\nFactoring: "<<x<<endl;
   f=factor(x,size);
   cout<<"\nThe factors of: "<<x<<" {"<<f[0];
   for(int i=1;i<size;i++)
      cout<<", "<<f[i];
   cout<<"}"<<endl;
   delete [] f;
   delete [] factors;
}
4
Gregor y