web-dev-qa-db-ja.com

最速の因数分解アルゴリズムとは何ですか?

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つは何ですか?

54
Mithrax

この他の質問 への私の答えから直接引き出しました。

メソッドは機能しますが、時間がかかります。 「数字はどれくらいですか?」使用する方法を決定します。

86
Sam Harwell

タイトルの質問(および最後の行)は、質問の実際の本文とはほとんど関係がないようです。友好的なペアを見つけようとしている場合、または多くの数値の除数の合計を計算している場合、各数値を個別に因数分解することは(可能な限り最速のアルゴリズムであっても)絶対に非効率的な方法です。

除数の合計関数σ(n) = (sum of divisors of n)は、 乗算関数 :比較的素数のmとnの場合、σ(mn) = σ(m)σ(n)、そう

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

したがって、単純なふるい(たとえば、拡張バージョンの エラトステネスのふるい )を使用して、findnまでの素数を使用します。 、およびその過程で、nまでのすべての数値の因数分解。 (たとえば、ふるいをするときに、各nのsmallest素因数を保存します。その後、繰り返して任意の数nを因数分解できます。)これ個別の因数分解アルゴリズムを数回使用するよりも(全体的に)高速です。

ところで:友好的なペアのいくつかの既知のリストがすでに存在します(たとえば、 ここ および MathWorld のリンクを参照してください)–あなたはレコードを拡張しようとしていますか? ?

21
ShreevatsaR

Shorのアルゴリズム: http://en.wikipedia.org/wiki/Shor%27s_algorithm

もちろん、量子コンピューターが必要です:D

15
Thomas Eding

Mapleで使用されている同じアルゴリズム、Quadratic Sieveから始めることをお勧めします。

  1. 奇数を選択してくださいn
  2. 自然数を選択してくださいk
  3. すべてを検索p <= kk ^ 2(n mod p)と一致しない因子ベースB = p1、p2、...、pt
  4. r> floor(n)から始まる-t + 1値を少なくとも検索して、y ^ 2 = r ^ 2- nはすべてBに因子のみを持ち、
  5. y1y2、...、y(t + 1)が計算されるたびに、ベクトルを生成しますv(yi )=(e1、e2、...、et)eiは、2を法とする指数を減らすことで計算されますpi in yi =、
  6. Gaussian Elimination を使用して、一緒に加算されたいくつかのベクトルを見つけ、nullベクトルを与える
  7. 前のステップで見つかったyiに関連するriの積としてxを設定し、p1 ^ aとしてyを設定します* p2 ^ b * p3 ^ c * .. * pt ^ zここで、指数はyiの因数分解で見つかった指数の半分です。
  8. 計算d = mcd(xy、n)、if 1 <d <n then dは、n、それ以外の場合はステップ2から開始して、より大きいkを選択します。

これらのアルゴリズムに関する問題は、数値計算の理論の多くを本当に暗示していることです。

12
Jack

これは、Mapleの整数因子分解の論文です。

「いくつかの非常に簡単な指示から開始します-「Mapleで整数因数分解を高速化する」-Quadleatic Sieve因数分解アルゴリズムをMapleとCの組み合わせで実装しました...」

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

6

数字の大きさに依存します。友好的なペアを検索している場合、多くの因数分解を行っているため、キーはできるだけ早く因数分解することではなく、異なる呼び出し間で可能な限り多くの作業を共有することです。試行分割を高速化するために、メモ化、および/または気になる最大数の平方根までの素数の事前計算を見ることができます。素因数分解を取得し、それからすべての因子の合計を計算する方が、すべての数に対してsqrt(n)までループするよりも高速です。

2 ^ 64を超える非常に大きな友好的なペアを探している場合、少数のマシンでは、因数分解の速度に関係なく、すべての数値を因数分解することではできません。候補を見つけるために使用しているショートカットは、それらをファクタリングするのに役立つ場合があります。

4
Steve Jessop

より多くの2015 C++バージョン227 1GBメモリのルックアップテーブル実装:

#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;
}
4
Gregor y