/* CALCULO DEL FACTORIAL DE NUMEROS GRANDES
- SI LA MEMORIA LO PERMITE -
SE UTILIZA UN DIGITO POR CELDA
( LISTAS LIGADAS )
*/
#include <stdio.h>
#include <stdlib.h>
struct Nodo
{
int Digito;
struct Nodo *Sig;
struct Nodo *Ant;
};
struct Nodo *Numero_Entrada; // NUmero al que se le calcularA el factorial
struct Nodo *Factorial; // Resultado al calcular el factorial de Numero_Entrada
void Solicita_Dato(char*);
struct Nodo *Crea_Nodo(int);
struct Nodo *Crea_Lista(char*);
void Muestra_Lista(struct Nodo*);
int Compara(struct Nodo*, struct Nodo*);
struct Nodo *Suma_Lista_Escalar(struct Nodo *, int);
void Calcula_Factorial();
struct Nodo *Producto_Lista_Escalar(struct Nodo*, int, struct Nodo*, int);
struct Nodo *Producto_Lista_Lista(struct Nodo*, struct Nodo*);
struct Nodo *Crea_Nodo(int Numero)
{
struct Nodo *Temporal = (struct Nodo *)malloc(sizeof(struct Nodo *));
Temporal->Digito = Numero;
Temporal->Ant = Temporal->Sig = NULL;
return Temporal;
}
// (FACTOR_1, ESCALAR, SUMA_PARCIAL, posiciOn_de_corrimiento) SUMA = RESP * ESC
struct Nodo *Producto_Lista_Escalar(struct Nodo *RESP, int ESC, struct Nodo *SUMA, int POS)
{
int TEMP = 0; // Entero para guardar el producto parcial de ESCALAR * ESCALAR
int LLEVO = 0; // Se almacena el acarreo si lo hay
struct Nodo *Nuevo = NULL; // CreaciOn de nuevos nodos
while (RESP->Sig != NULL) RESP = RESP->Sig; // Se posiciona el apuntador en el dIgito menos significativo
while (SUMA->Sig != NULL) SUMA = SUMA->Sig; // Se posiciona el apuntador en el dIgito menos significativo
while ( POS ) { SUMA = SUMA->Ant; --POS; } // Se recorre el apuntador hacia atrAs POS posiciones
while ( RESP != NULL ) // Mientras existan dIgitos en RESP
{
TEMP = ESC * RESP->Digito + SUMA->Digito + LLEVO;
if (TEMP > 9) { SUMA->Digito = TEMP % 10; LLEVO = (TEMP - SUMA->Digito) / 10; }
else { SUMA->Digito = TEMP; LLEVO = 0; }
if (SUMA->Ant != NULL) SUMA = SUMA->Ant;
else
{
Nuevo = Crea_Nodo(0);
Nuevo->Sig = SUMA; SUMA->Ant = Nuevo; SUMA = Nuevo;
}
RESP = RESP->Ant;
}
if ( LLEVO ) SUMA->Digito = LLEVO;
else // Se elimina el nodo mas significativo con contenido de cero
{ Nuevo = SUMA; SUMA = SUMA->Sig; SUMA->Ant = NULL; free(Nuevo); }
while (SUMA->Ant != NULL) SUMA = SUMA->Ant; // Se regresa al dIgito mas significativo
return SUMA;
}
struct Nodo *Producto_Lista_Lista(struct Nodo *Factorial, struct Nodo *Factor)
{
struct Nodo *Suma_Acumulada = Crea_Nodo(0);
int Inicio = 0; // Cantidad de dIgitos que se corren para realizar la suma acumulada
while(Factor->Sig != NULL) Factor = Factor->Sig; // Se posiciona el apuntador en el dIgito menos significativo
while ( 1 ) // Ciclo infinito hasta la cantidad de dIgitos de Factor
{
Suma_Acumulada = Producto_Lista_Escalar(Factorial, Factor->Digito, Suma_Acumulada, Inicio);
if ( Factor->Ant != NULL ) { Factor = Factor->Ant; Inicio++; } // Se hace un corrimiento a la izquierda
else break;
}
while (Suma_Acumulada->Ant != NULL) Suma_Acumulada = Suma_Acumulada->Ant;
return Suma_Acumulada;
}
void Calcula_Factorial()
{
struct Nodo *Factor = Crea_Nodo(1); // Inicializa el caso base
Factorial = Crea_Nodo(1); // Inicializa el caso base
int Detectar = 0; // Bandera cuando se iguala el Factor con el Numero_Entrada
while (!Detectar) // Mientras Factor sea menor que Numero_Entrada
{
Detectar = Compara(Factor, Numero_Entrada); // Ya se llegO al nUmero deseado pero aUn asI se multiplica
Factorial = Producto_Lista_Lista(Factorial, Factor);
Factor = Suma_Lista_Escalar(Factor, 1);
}
}
struct Nodo *Suma_Lista_Escalar(struct Nodo *Lista, int ESCALAR)
{
struct Nodo *Nuevo = NULL;
while(Lista->Sig != NULL) Lista = Lista->Sig; // Se posiciona el apuntador en el dIgito menos significativo
while ( 1 ) // Ciclo infinito por si hay corrimientos
{
Lista->Digito += ESCALAR;
if (Lista->Digito < 10) break; // No hay corrimiento. No tiene caso continuar
ESCALAR = (Lista->Digito - Lista->Digito % 10) / 10;
Lista->Digito = Lista->Digito - ESCALAR*10;
if ( Lista->Ant != NULL ) Lista = Lista->Ant;
else // Significa que ya llegO al principio de la lista y se efectUa un corrimiento
{
Nuevo = Crea_Nodo(ESCALAR); // Por consiguiente se agrega un nodo al principio (dIgito mas significativo)
Nuevo->Sig = Lista;
Lista->Ant = Nuevo;
Lista = Nuevo;
break;
}
}
while(Lista->Ant != NULL) Lista = Lista->Ant; // Se posiciona el apuntador en el dIgito mas significativo
return Lista;
}
int Compara(struct Nodo *N1, struct Nodo *N2)
{
while(N1)
{
if (N1->Digito != N2->Digito) return 0; // Con un digito que sea diferente, todo es diferente.
if (N1->Sig != NULL && N2->Sig != NULL) { N1 = N1->Sig; N2 = N2->Sig; } // Existe un prOximo Digito
else if (N1->Sig == NULL && N2->Sig == NULL) return 1; // Ambas llegaron al final al mismo tiempo
else return 0; // Al menos una llegO al final y la otra no
}
return 1;
}
void Muestra_Lista(struct Nodo *Lista) { while(Lista) { printf("%d ", Lista->Digito); Lista = Lista->Sig; } printf("\nOK\n"); }
void Solicita_Dato(char *Numero) { printf("Introduce el nUmero al que se le calcularA el factorial: "); gets(Numero); }
struct Nodo *Crea_Lista(char *CAD)
{
int Indice = 0;
struct Nodo *Nuevo=NULL, *Aux=NULL, *Lista=NULL;
while( CAD[Indice] != '\0')
{
Nuevo = Crea_Nodo(CAD[Indice] - 48); // (Ascii - 48 = N) Convierte a decimal
if (!Lista) Lista = Aux = Nuevo;
else
{
Aux->Sig = Nuevo;
Nuevo->Ant = Aux;
Aux = Nuevo;
}
Indice++;
}
return Lista;
}
int main()
{
char *Numero = (char*)malloc(sizeof(char*)*100);
Numero_Entrada = Factorial = NULL; // Se inicializan como listas vacIas
Solicita_Dato(Numero);
Numero_Entrada = Crea_Lista(Numero);
Calcula_Factorial();
Muestra_Lista(Factorial);
}