Faktörleri modulo prime hesaplamanın en etkili yolu nedir?


20

Modülü sonra faktöriyel etkili bir şekilde hesaplayan bir algoritma biliyor musunuz?

Örneğin, programlamak istiyorum:

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

Ancak, pfaktöriyeli doğrudan uygulamak için büyük bir sayıdır (asal) (p108) .

Python'da bu görev gerçekten kolay, ama gerçekten nasıl optimize edileceğini bilmek istiyorum.


6
Sorun, Wilson teoremini kullanmanızı istiyor gibi görünüyor. Başbakan p , (p1)!=1modp . Yani herhangi bir programlama dili kullanmadan: cevap 100 . Belki probleminizi genelleştirmek istersiniz?
Aryabhata

5
Sorunu daha açık bir şekilde ifade edebilir misiniz? Hesaplamak mı yoksa (X!) (mod (X+1))daha genel (X!) (mod Y)mi? Ve factorial(100!)bunun faktöriyel fonksiyonu iki kez uygulamak istediğiniz anlamına gelmediğini düşünüyorum.
Keith Thompson

1
Wilson teoreminiz olmasa bile , en azından taşma sorunlarından kaçınmaya yardımcı olacak (mn)modp=(mmodp)(nmodp) .
Dave Clarke

8
Wilson Teoreminin sadece p asal olduğu zaman geçerli olduğunu unutmayın . Sorunuz p asal olduğunu belirtmiyor , bu yüzden yazdıklarınız doğru değil.
Dave Clarke

Yanıtlar:


11

(Bu cevap başlangıçta sorunun içinde asker jonaprieto tarafından yayınlanmıştır .)

Wilson teoremini hatırlıyorum ve küçük şeyler fark ettim:

Yukarıdaki programda şöyle yazarsam daha iyi olur:

(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)

Ve çünkü , bu nedenle genişletilmiş Öklid algoritması ile değerini bulabilirsiniz . ters modül.(pi)1gcd(p,pi)=1(pi)1

Aynı kongrüasyonları da görüntüleyebilirsiniz: , toplam eşittir: ve başlangıçta faktöriyelleri çarpanlarına ayırırsanız, alırsınız. Ve tersine, ters modül faktöriyellerden daha verimlidir.

(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)

Yani temelde . Temiz! (pk)!(p+(k1)!(1)k)1(modp)
Thomas Ahle

Üzgünüm ama çarpanlarına ayırdığımda , şunu alıyorum:(24)1+61+(2)1
9(24)1=38

1

Gönderdiğiniz örnek 388 numaralı Euler sorunu ile çok yakından ilgilidir. Bu yüzden Euler sorununu çözmeyen bir cevap göndereceğim. Bir faktöriyel modulo nasıl hesaplayabileceğinizi yazacağım.

Yani: n nasıl hesaplanır! modulo p?

Hızlı gözlem: n ≥ p ise n! bir p faktörüne sahiptir, dolayısıyla sonuç 0 olur. Çok hızlı. Ve p'nin asal olması şartı göz ardı edilirse, q'nun p'nin en küçük asal faktörü olmasına izin verin ve n! n ≥ q ise modulo p 0'dır. Ayrıca, p'nin sorunuzu cevaplamak için bir ana olmasını gerektirecek çok fazla neden yoktur.

Şimdi örneğinizde (n - i)! 1 ≤ i ≤ 5 geldi. Beş faktöriyeli hesaplamak zorunda değilsiniz: (n - 5)! Bu, işi neredeyse bir faktör 5 azaltır. Sorunu tam anlamıyla çözmeyin.

Soru n'nin nasıl hesaplanacağı! modulo m. Açık olan yol, kabaca n log n ondalık basamağı olan bir sayı olan n! 'Yı hesaplamak ve kalan modulo p'yi hesaplamaktır. Bu zor bir iş. Soru: Bu sonucu nasıl daha çabuk alabiliriz? Bariz olanı yapmayarak.

((A * b * c) modulo p = ((((a * b) modulo p) * c) modulo p olduğunu biliyoruz.

N! 'Yi hesaplamak için normalde x = 1 ile başlayıp, x'i 1, 2, 3, ... n ile çarparız. Modulo formülünü kullanarak n'yi hesaplıyoruz! n! 'yi hesaplamaksızın modulo p, x = 1 ile başlayıp i = 1, 2, 3, .. için, n yerine x'i (x * i) modulo p ile değiştiriyoruz.

Her zaman x <p ve i <n'ye sahibiz, bu nedenle x * p'yi hesaplamak için yeterli hassasiyete ihtiyacımız var, n'yi hesaplamak için çok daha yüksek hassasiyete değil! N hesaplamak için! p ≥ 2 için modulo p aşağıdaki adımları atıyoruz:

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. 

(Bazı cevaplar, yalnızca verilen örneğin çok özel durumunda soruyu cevaplayan Wilson'ın teoreminden bahseder ve Euler problemi # 381'i çözmek için çok yararlıdır, ancak genel olarak sorulan soruyu çözmek için yararlı değildir).


-1

Wilson teoremini benim uygulamamda kullanıyorum:

FactMOD işlevi, MOD-n, n'ye karşı çok küçük olduğunda, (n!)% MOD'u hesaplamak için çağrılacak işlevdir.

Biri durum böyle olmadığında başka etkili bir yaklaşım biliyor mu (örn: n = 1e6 ve 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
Kod burada gerçekten konuyla ilgili değil. Algoritmanın açıklaması çok daha kullanışlıdır, çünkü insanların kodunuzu yazmaya karar verdiğiniz dili anlamalarını gerektirmez ve gerçek uygulamalar genellikle anlaşılmasını zorlaştıracak şekilde optimize edilmiştir. Ve lütfen sorularınızı cevabınızdan ziyade ayrı sorular olarak sorun. Stack Exchange bir tartışma panosu değil, bir soru ve cevap sitesidir ve soruların cevaplar arasında gizli olup olmadıklarını bulmak zordur. Teşekkürler!
David Richerby
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.