¿Conoces algún algoritmo que calcule el factorial después del módulo de manera eficiente?
Por ejemplo, quiero programar:
for(i=0; i<5; i++)
sum += factorial(p-i) % p;
Pero, p
es un gran número (primo) para aplicar factorial directamente .
En Python, esta tarea es realmente fácil, pero realmente quiero saber cómo optimizar.
algorithms
efficiency
integers
jonaprieto
fuente
fuente
(X!) (mod (X+1))
, o el más general(X!) (mod Y)
? Y supongo quefactorial(100!)
eso realmente no significa que desee aplicar la función factorial dos veces.Respuestas:
(Esta respuesta fue inicialmente publicada por el autor de la pregunta jonaprieto dentro de la pregunta).
Recuerdo el teorema de Wilson y noté pequeñas cosas:
En el programa anterior, es mejor si escribo:
Y puede encontrar porque , por lo que con el algoritmo Euclidiano extendido puede encontrar el valor de , ese es el módulo inverso(p−i)−1 gcd(p,p−i)=1 (p−i)−1
También puede ver las mismas congruencias, como: entonces, la suma es igual: y si factorizas al principio los factoriales obtienes Y, voila, el módulo inverso es más eficiente que los factoriales.
fuente
El ejemplo que está publicando está muy relacionado con el problema # 381 de Euler. Así que publicaré una respuesta que no resuelve el problema de Euler. Publicaré cómo puedes calcular factoriales módulo a primo.
Entonces: ¿Cómo calcular n! módulo p?
Observación rápida: Si n ≥ p, entonces n! tiene un factor p, por lo que el resultado es 0. Muy rápido. Y si ignoramos el requisito de que p debería ser un primo, ¡entonces sea q el factor primo más pequeño de p, yn! módulo p es 0 si n ≥ q. Tampoco hay muchas razones para exigir que p sea primordial para responder a su pregunta.
Ahora en tu ejemplo (n - i)! para 1 ≤ i ≤ 5 surgió. No tiene que calcular cinco factoriales: ¡Calcula (n - 5) !, multiplique por (n - 4) vaya a obtener (n - 4) !, multiplique por (n - 3) para obtener (n - 3)! etc. Esto reduce el trabajo en casi un factor 5. No resuelva el problema literalmente.
La pregunta es cómo calcular n! módulo m. La forma obvia es calcular n !, un número con aproximadamente n log n dígitos decimales, y calcular el módulo restante p. Eso es trabajo duro. Pregunta: ¿Cómo podemos obtener este resultado más rápido? Al no hacer lo obvio.
Sabemos que ((a * b * c) módulo p = (((a * b) módulo p) * c) módulo p.
Para calcular n !, normalmente comenzaríamos con x = 1, luego multiplicaríamos x por 1, 2, 3, ... n. Usando la fórmula del módulo, calculamos n! módulo p sin calcular n !, comenzando con x = 1, y luego para i = 1, 2, 3, .., n reemplazamos x con (x * i) módulo p.
Siempre tenemos x <p e i <n, por lo que solo necesitamos suficiente precisión para calcular x * p, ¡no la precisión mucho más alta para calcular n !. Entonces para calcular n! módulo p para p ≥ 2 tomamos los siguientes pasos:
(Algunas respuestas mencionan el teorema de Wilson, que solo responde la pregunta en el caso muy especial del ejemplo dado, y es muy útil para resolver el problema de Euler # 381, pero en general no es útil para resolver la pregunta que se hizo).
fuente
Este es mi uso de implementación del teorema de wilson:
La función factMOD es la que se debe llamar para calcular (n!)% MOD cuando MOD-n es poco contra n.
¿Alguien conoce otro enfoque eficiente cuando no es el caso (por ejemplo: n = 1e6 y MOD = 1e9 + 7)?
fuente