Czy znasz jakiś algorytm, który skutecznie oblicza silnię po module?
Na przykład chcę zaprogramować:
for(i=0; i<5; i++)
sum += factorial(p-i) % p;
Ale p
jest duża liczba (prime) stosowania bezpośrednio silnia .
W Pythonie to zadanie jest naprawdę łatwe, ale naprawdę chcę wiedzieć, jak zoptymalizować.
algorithms
efficiency
integers
jonaprieto
źródło
źródło
(X!) (mod (X+1))
, czy bardziej ogólnie(X!) (mod Y)
? Zakładam, żefactorial(100!)
tak naprawdę nie oznacza to, że chcesz dwukrotnie zastosować funkcję silni.Odpowiedzi:
(Ta odpowiedź została pierwotnie zamieszczona przez pytającego jonaprieto wewnątrz pytania).
Pamiętam twierdzenie Wilsona i zauważyłem małe rzeczy:
W powyższym programie lepiej jest napisać:
I możesz znaleźć ponieważ nazwa , więc dzięki rozszerzonemu algorytmowi euklidesowemu możesz znaleźć wartość , czyli moduł odwrotny.(p−i)−1 gcd(p,p−i)=1 (p−i)−1
Możesz także zobaczyć te same przystawki, na przykład: więc suma jest równa: i jeśli na początku rozłożymy czynniki na czynniki, otrzymamy I, voila, moduł odwrotności jest bardziej wydajny niż silnia.
źródło
Przykład, który publikujesz, jest bardzo blisko związany z problemem Eulera # 381. Więc opublikuję odpowiedź, która nie rozwiąże problemu Eulera. Napiszę, jak możesz obliczyć silnię modulo liczbę pierwszą.
Więc: Jak obliczyć n! modulo p?
Szybka obserwacja: Jeśli n ≥ p, to n! ma współczynnik p, więc wynik wynosi 0. Bardzo szybko. A jeśli zignorujemy wymóg, aby p było liczbą pierwszą, niech q będzie najmniejszym współczynnikiem liczby pierwszej p, a n! moduł p wynosi 0, jeżeli n ≥ q. Nie ma również wielu powodów, aby wymagać, aby p było liczbą pierwszą, aby odpowiedzieć na twoje pytanie.
Teraz w twoim przykładzie (n - i)! dla 1 ≤ i ≤ 5 pojawiły się. Nie musisz obliczać pięciu silni: obliczasz (n - 5) !, mnożymy przez (n - 4) idź zdobądź (n - 4) !, mnoż przez (n - 3), aby uzyskać (n - 3)! itp. Zmniejsza to pracę prawie 5-krotnie. Nie rozwiązuj problemu dosłownie.
Pytanie brzmi: jak obliczyć n! modulo m. Oczywistym sposobem jest obliczenie n !, liczby z grubsza n log n cyfr dziesiętnych i obliczenie reszty modułu p. To ciężka praca. Pytanie: Jak możemy szybciej uzyskać ten wynik? Nie robiąc rzeczy oczywistych.
Wiemy, że ((a * b * c) modulo p = (((a * b) modulo p) * c) modulo p.
Aby obliczyć n !, zwykle zaczynamy od x = 1, a następnie mnożymy x przez 1, 2, 3, ... n. Korzystając ze wzoru modulo, obliczamy n! modulo p bez obliczania n !, zaczynając od x = 1, a następnie dla i = 1, 2, 3, .., n zamieniamy x na (x * i) modulo p.
Zawsze mamy x <p i i <n, więc potrzebujemy tylko wystarczającej precyzji, aby obliczyć x * p, a nie dużo większej precyzji, aby obliczyć n !. Więc obliczyć n! modulo p dla p ≥ 2 wykonujemy następujące kroki:
(Niektóre odpowiedzi wspominają twierdzenie Wilsona, które odpowiada tylko na pytanie w bardzo szczególnym przypadku podanego przykładu i jest bardzo przydatne do rozwiązania problemu Eulera # 381, ale ogólnie nie jest przydatne do rozwiązania zadanego pytania).
źródło
Oto moje zastosowanie implementacyjne twierdzenia Wilsona:
Funkcję factMOD można wywołać w celu obliczenia (n!)% MOD, gdy MOD-n jest małe w stosunku do n.
Czy ktoś zna inne skuteczne podejście, gdy tak nie jest (np .: n = 1e6 i MOD = 1e9 + 7)?
źródło