Você conhece algum algoritmo que calcula o fatorial após o módulo de maneira eficiente?
Por exemplo, eu quero programar:
for(i=0; i<5; i++)
sum += factorial(p-i) % p;
Mas, p
é um grande número (primo) para a aplicação fatorial diretamente .
Em Python, essa tarefa é realmente fácil, mas eu realmente quero saber como otimizar.
algorithms
efficiency
integers
jonaprieto
fonte
fonte
(X!) (mod (X+1))
, ou o mais geral(X!) (mod Y)
? E presumo quefactorial(100!)
isso realmente não significa que você queira aplicar a função fatorial duas vezes.Respostas:
(Esta resposta foi inicialmente postada pelo autor (a) jonaprieto dentro da pergunta.)
Lembro-me do teorema de Wilson e notei pequenas coisas:
No programa acima, é melhor se eu escrever:
E você pode encontrar porque , portanto, com o algoritmo euclidiano estendido, você pode encontrar o valor de , que é o módulo inverso.( p - i )- 1 ( p - i ) - 1gcd(p,p−i)=1 (p−i)−1
Você também pode ver as mesmas congruências, como: portanto, a soma é igual: e se você fatorar no início os fatoriais, obtém E, voila, o módulo inverso é mais eficiente que os fatoriais. (-24)-1+(6)-1+(
fonte
O exemplo que você está postando está muito relacionado ao problema de Euler # 381. Então, vou postar uma resposta que não resolve o problema de Euler. Vou postar como você pode calcular fatoriais modulo um primo.
Então: Como calcular n! módulo p?
Observação rápida: Se n ≥ p, então n! tem um fator p, então o resultado é 0. Muito rápido. E se ignorarmos o requisito de que p deve ser um primo, então deixe q ser o menor fator primo de p, e n! módulo p é 0 se n ≥ q. Também não há muitas razões para exigir que p seja o principal para responder à sua pergunta.
Agora no seu exemplo (n - i)! para 1 ≤ i ≤ 5 surgiu. Você não precisa calcular cinco fatoriais: você calcula (n - 5) !, multiplica por (n - 4) vai buscar (n - 4) !, multiplica por (n - 3) para obter (n - 3)! etc. Isso reduz o trabalho em quase um fator 5. Não resolva o problema literalmente.
A questão é como calcular n! módulo m. A maneira óbvia é calcular n !, um número com aproximadamente n log n dígitos decimais e calcular o restante módulo p. Isso é trabalho duro. Pergunta: Como podemos obter esse resultado mais rapidamente? Por não fazer a coisa óbvia.
Sabemos que ((a * b * c) módulo p = (((a * b) módulo p) * c) módulo p.
Para calcular n !, normalmente começamos com x = 1 e depois multiplicamos x por 1, 2, 3, ... n. Usando a fórmula do módulo, calculamos n! módulo p sem calcular n !, começando com x = 1 e, em seguida, para i = 1, 2, 3, .., n substituímos x por (x * i) módulo p.
Sempre temos x <pe i <n; portanto, precisamos apenas de precisão suficiente para calcular x * p, e não de uma precisão muito maior para calcular n !. Então, para calcular n! módulo p para p ≥ 2, seguimos os seguintes passos:
(Algumas respostas mencionam o teorema de Wilson, que apenas responde à pergunta no caso muito especial do exemplo dado, e é muito útil para resolver o problema de Euler # 381, mas em geral não é útil para resolver a pergunta que foi feita).
fonte
Este é meu uso de implementação do teorema de wilson:
A função factMOD é a única a chamar para calcular (n!)% MOD quando MOD-n é pouco contra n.
Alguém conhece outra abordagem eficiente quando não é o caso (por exemplo: n = 1e6 e MOD = 1e9 + 7)?
fonte