Каков самый быстрый алгоритм факторизации?

Я написал программу, которая пытается найти Amicable Pairs. Это требует нахождения сумм собственных делителей чисел.

Вот мой текущий метод sumOfDivisors():

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;
}

Поэтому мне нужно сделать много факторизации, и это начинает становиться настоящим узким местом в моем приложении. Я набрал огромное количество в MAPLE, и он произвел безумно быстро.

Что является одним из быстрых алгоритмов факторизации?

Ответ 1

Вытащил прямо из моего ответа на этот другой вопрос.

Метод будет работать, но будет медленным. "Насколько велики ваши цифры?" определяет способ использования:

Ответ 2

Вопрос в заголовке (и в последней строке), похоже, имеет мало общего с фактическим телом вопроса. Если вы пытаетесь найти дружественные пары или вычислять сумму делителей для многих чисел, то раздельно факторизуя каждое число (даже с самым быстрым возможным алгоритмом), это абсолютно неэффективный способ сделать это.

Функция сумма-делителей, σ(n) = (sum of divisors of n), является мультипликативная функция: для относительно простых m и n имеем σ(mn) = σ(m)σ(n), поэтому

σ (р <суб > 1суб > к <суб > 1суб > ... р <суб > тсуб > к <югу > т) = [(p 1 k 1 +1 -1)/(p 1 -1)]... [(р <суб > тсуб > к <югу > тсуб > + 1 -1)/(р <суб > тсуб > - 1)].

Итак, вы использовали бы любое простое сито (например, расширенную версию Sieve of Eratosthenes), чтобы найти простые числа до n, и при этом факторизация всех чисел до n. (Например, как вы делаете свое сито, храните наименьший первичный коэффициент для каждого n. Затем вы можете разложить количество чисел n путем повторения.) Это было бы быстрее (в целом), чем использование какого-либо отдельного алгоритма факторизации несколько раз.

Кстати: несколько известных списков дружественных пар уже существуют (см. например здесь и ссылки на MathWorld) - так вы пытаетесь продлить запись или делать это просто для удовольствия?

Ответ 4

Я бы предложил начать с того же алгоритма, который использовался в Maple, Quadratic Sieve.

  • Выберите нечетное число n для факторизации,
  • Выберите натуральное число k,
  • Найти все p &lt = k так, чтобы k ^ 2 не соответствовало (n mod p), чтобы получить фактор-базу B = p1, p2,..., pt,
  • Начиная с r > floor (n) найдите не менее t + 1 значений, так что y ^ 2 = r ^ 2 - n имеют только факторы в B,
  • Для каждого вычисленного y1, y2,..., y (t + 1) вы создаете вектор v (yi) = (e1, e2,..., et), где ei вычисляется путем уменьшения по модулю 2 показатель pi в yi,
  • Используйте Gaussian Elimination, чтобы найти некоторые из добавленных вместе векторов, дают нулевой вектор
  • Зададим x как произведение ri, связанное с yi, найденным на предыдущем шаге, и установим y как p1 ^ a * p2 ^ b * p3 ^ c *.. * pt ^ z, где показатели - половина экспонентов, найденная в факторизация yi
  • Вычислите d = mcd (x-y, n), если 1 < d < n, то d является нетривиальным фактором n, иначе начните с шага 2, выбирая большее k.

Проблема этих алгоритмов заключается в том, что они действительно подразумевают много теории в численном исчислении.

Ответ 5

Это документ факторизации целых чисел в клене.

"Начиная с некоторых очень простых инструкций -" ускорить целочисленную факторизацию в Maple "- мы реализовали алгоритм факторизации квадратичного сита в сочетание Maple и C... "

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

Ответ 6

Зависит от того, насколько велики ваши номера. Если вы ищете дружественные пары, вы делаете много факторизаций, поэтому ключ может не быть как можно быстрее, а делиться как можно большей работой между различными вызовами. Чтобы ускорить пробное деление, вы можете посмотреть меморандум и/или предварительное вычисление простых чисел до квадратного корня из самого большого числа, о котором вы заботитесь. Это быстрее, чтобы получить основную факторизацию, а затем вычислить сумму всех факторов из этого, чем для того, чтобы все петли вплоть до sqrt (n) для каждого числа.

Если вы ищете действительно большие дружественные пары, скажем больше, чем 2 ^ 64, то на небольшом количестве машин вы не сможете это сделать, разложив каждое число независимо от того, насколько быстро ваша факторизация. Сокращения, которые вы используете для поиска кандидатов, могут помочь вам их определить.

Ответ 7

Более 2015 С++ версия 2 27 реализация таблицы поиска для 1 ГБ памяти:

#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;
}

Обновление: или принести в жертву некоторую простоту для немного большего диапазона всего за 2 28

#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;
}