[C con Clase] Errores de aprendiz

Steven Davidson srd4121 en njit.edu
Lun Mayo 12 21:19:10 CEST 2008


Hola Ariel,

Ariel Tarifeño wrote:
> Gracias Steven. Me ayudo mucho. Sii, del N° 13 en adelante daba
> siempre error. Lo cambie y funciona aunque sigue siendo de
> principiante.
>  

Bueno, lo que podemos hacer es modificar tu algoritmo original para no 
introducir errores. Como realmente no quieres calcular el factorial de 
'N-1', sino que es un paso para el problema de verdad: determinar si 'N' 
es primo o no, entonces podemos realizar los cálculos con operaciones de 
módulo. De esta forma, podemos hacer el cálculo del módulo en tu fórmula 
por "piezas" o por términos; o sea, de una manera discreta en lugar de 
hacer todo de golpe.

Algunas propiedades de operaciones de módulo son las siguientes:

1. (x+y) mod n = (x mod n + y mod n) mod n
2. (x*y) mod n = ((x mod n) * (y mod n)) mod n

Por ejemplo,

15 mod 4 = 3

1. (10+5) mod 4 = (10 mod 4 + 5 mod 4) mod 4 = (2+1) mod 4 = 3
2. (5*3) mod 4 = ((5 mod 4) * (3 mod 4)) mod 4 = (1*3) mod 4 = 3

Con estas dos propiedades, podemos separar las operaciones de tu 
algoritmo para no tener que calcular el factorial total, sino su 
contribución al cálculo final de 'mod N'. Esto sería,

((N-1)! + 1) mod N = 0 ?

pasa a ser,

((N-1)! mod N + 1) mod N = 0 ?  Ten presente que 1 mod N = 1

Como el factorial es una serie de multiplicaciones, entonces podemos 
aplicar la propiedad #2 en un bucle 'for'. Sin embargo, podemos 
optimizar un poco esto, ya que los factores de '(N-1)! mod N' siempre 
serán menores que 'N'. Es decir,

(N-1)! mod N;
((N-1) mod N) * ((N-2)! mod N)) mod N;
((N-1) * ((N-2)! mod N)) mod N
...

O sea,
N-1 < N  =>  (N-1) mod N < N
N-2 < N  =>  (N-2) mod N < N
N-3 < N  =>  (N-3) mod N < N
...

Por lo tanto, no tenemos que calcular el módulo de cada factor, pero sí 
tenemos que hacerlo para cada pareja de factores. Con esto, podemos 
sacar una relación recurrente:

res[2] = ((N-1) * (N-2)) mod N  (caso base o inicial)
res[3] = (res[2] * (N-3)) mod N
res[4] = (res[3] * (N-4)) mod N
...
res[n] = (res[n-1] * (N-n)) mod N, donde n=3,4,...,N-1

No recomiendo implementar este algoritmo como una función recursiva, 
sino iterativamente; o sea, usa un bucle 'for'.

Al final, agregaríamos 1 al valor final de 'res', por lo que tendríamos 
aplicar nuevamente el cálculo del módulo:

res_final = (res+1) mod N

Lo último  que queda por hacer es comprobar si 'res_final' es 0 (cero) o 
no, para determinar si 'N' es primo o no.


Huelga decir que las limitaciones de 'int' siguen siendo las mismas que 
en el algoritmo anterior, pero al no tener que hacer multiplicaciones 
con números grandes, podemos alcanzar un valor de 'N' mayor al que 
podíamos antes. Si 'int' es de 32 bits, entonces podemos usar valores de 
N <= 65536; con 'int' de 64 bits, el alcance es de N <= 9223372036854775808.

Espero que todo esto te sirva.

Steven







Más información sobre la lista de distribución Cconclase