素数を法とする階乗を計算する最も効率的な方法は何ですか?


20

係数の後の階乗を効率的に計算するアルゴリズムを知っていますか?

たとえば、私はプログラムしたい:

for(i=0; i<5; i++)
  sum += factorial(p-i) % p;

しかし、p階乗を直接適用するための大きな数(素数)です。(p108)

Pythonでは、このタスクは本当に簡単ですが、最適化の方法を知りたいのです。


6
問題がウィルソンの定理を使用することを望んでいるようです。プライム場合、。したがって、プログラミング言語を使用しなくても、答えはです。おそらくあなたはあなたの問題を一般化したいですか?p100(p1)!=1modp100
アルヤバタ

5
問題をより明確に説明できますか?計算します(X!) (mod (X+1))か、それとももっと一般的(X!) (mod Y)ですか?そして、それfactorial(100!)は、階乗関数を2回適用したいという意味ではないと思います。
キーストンプソン

1
ウィルソンの定理がなくても、があります。これにより、少なくともオーバーフローの問題を回避できます。(mn)modp=(mmodp)(nmodp)
デイブクラーク

8
ウィルソンの定理は、pが素数の場合にのみ適用されることに注意してください。あなたの質問は、pが素数であると述べていないので、あなたが書いたものは正しくありません。
デイブクラーク

回答:


11

(この回答は、質問内のasker jonaprietoによって最初に投稿されました。)

ウィルソンの定理を覚えていますが、ささいなことに気付きました。

上記のプログラムでは、と書いた方が良いです

(p1)!1(modp)(p2)!(p1)!(p1)11(modp)(p3)!(p2)!(p2)1(p2)1(modp)(p4)!(p3)!(p3)1(p2)1(p3)1(modp) (p5)!(p4)!(p4)1(p2)1(p3)1(p4)1(modp)

そして、あなたは見つけることができますなぜなら、そうで拡張ユークリッドの互除法あなたがの値を見つけることができますされ、逆モジュラス。(pi)1gcd(p,pi)=1(pi)1

ように、同じ一致を表示することもできます したがって、合計は等しくなります: そして、階乗を最初に因数分解すると、 そして、逆モジュラスは階乗よりも効率的です。

(p5)!(p24)1(modp)(p4)!(p+6)1(modp)(p3)!(p2)1(modp)(p2)!1(modp)(p1)!1(modp)
(24)1+(6)1+(2)1
8(24)1(modp)

基本的に。きちんとした!(pk)!(p+(k1)!(1)k)1(modp)
トーマスエール

申し訳ありませんが、を分解すると、(24)1+61+(2)1
9(24)1=38

1

投稿している例は、オイラー問題#381と非常に密接に関連しています。オイラー問題を解決しない答えを投稿します。素数を法とする階乗を計算する方法を投稿します。

だから:nを計算する方法!モジュロp?

迅速な観察:n≥pの場合、n!係数pがあるため、結果は0です。非常に高速です。そして、pが素数であるという要件を無視する場合、qをpの最小素因数とし、n!n≥qの場合、モジュロpは0です。pがあなたの質問に答える素数であることを要求する理由はあまりありません。

あなたの例では(n-i)!1≤i≤5が登場しました。5つの階乗を計算する必要はありません:(n-5)!を計算し、(n-4)を乗算してget(n-4)を取得し、(n-3)を乗算して(n-3)を取得します!これにより、作業がほぼ5分の1に削減されます。問題を文字通り解決しないでください。

問題は、nの計算方法です。モジュロm 明らかな方法は、おおよそn log nの10進数を持つ数値n!を計算し、pを法とする剰余を計算することです。それは大変な仕事です。質問:どうすればこの結果をより早く取得できますか?明らかなことをしないことによって。

((a * b * c)modulo p =((((a * b)modulo p)* c)modulo p。

n!を計算するには、通常x = 1から始め、xに1、2、3、... nを掛けます。モジュロ式を使用して、n!を計算します。n!を計算せずにpを法として、x = 1から始めて、i = 1、2、3、..、nの場合、xを(x * i)を法とするpで置き換えます。

常にx <pおよびi <nであるため、x!pを計算するのに十分な精度のみが必要であり、n!を計算するのにそれほど高い精度は必要ありません。だからnを計算する!p≥2のpを法として、次の手順を実行します。

Step 1: Find the smallest prime factor q of p. If n ≥ q then the result is 0.
Step 2: Let x = 1, then for 1 ≤ i ≤ n replace x with (x * i) modulo p, and x is the result. 

(いくつかの答えはウィルソンの定理に言及しており、これは与えられた例の非常に特別な場合にのみ質問に答え、オイラー問題#381を解決するのに非常に有用ですが、一般に尋ねられた質問を解決するのには有用ではありません)


-1

これは、ウィルソンの定理の私の実装の使用です:

factMOD関数は、MOD-nがnに対してほとんどない場合に(n!)%MODを計算するために呼び出す関数です。

それ以外の場合、誰かが他の効率的なアプローチを知っていますか(例:n = 1e6およびMOD = 1e9 + 7)?

ll powmod(ll a, ll b){//a^b % MOD
  ll x=1,y=a;
  while(b){
    if(b&1){
      x*=y; if(x>=MOD)x%=MOD;
    }
    y*=y; if(y>=MOD)y%=MOD;
    b>>=1;
  }
  return x;
} 
ll InverseEuler(ll n){//modular inverse of n
  return powmod(n,MOD-2);
}
ll factMOD(ll n){ //n! % MOD efficient when MOD-n<n
   ll res=1,i;
   for(i=1; i<MOD-n; i++){
     res*=i;
     if(res>=MOD)res%=MOD;
   }
   res=InverseEuler(res);   
    if(!(n&1))
      res= -res +MOD;
  }
  return res%MOD;
}

1
ここでは、コードはあまり話題になりません。アルゴリズムの説明は、コードを書くことに決めた言語を理解する必要がないため、実際の実装は理解しにくい方法で最適化されることが多いため、非常に便利です。また、回答ではなく個別の質問として質問してください。Stack Exchangeはディスカッション掲示板ではなく質疑応答サイトであり、質問に答えが隠されているかどうかを見つけるのは困難です。ありがとう!
デビッドリチャービー14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.