Ayuda - Funcion factorial de un numero

Iniciado por Miky Gonzalez, 30 Junio 2012, 01:12 AM

0 Miembros y 1 Visitante están viendo este tema.

Miky Gonzalez

Hola, buenas... soy Mike Gonzalez. Estoy haciendo una calculadora por consola, mas bien el modulo de calcular y despues hare la GUI en VB6.
Tengo una funcion hecha que me permite calcular el factorial de un numero:

unsigned long int factorial(short int numero) {
   int pred = 0;
   unsigned long int tmp = numero;
   for (pred = --numero; pred > 1; --pred)
       tmp *= pred;
   return tmp;
}


Las declaraciones son unsigned porque se supone que asi gano mas memoria de calculo (en el almacenamiento de variables). Mi pregunta es que solo me permite calcular hasta el factorial de 25 (a partir de ahi da resultados negativos :S).
Alguna solucion de mejorar el codigo y/o permitirme calcular numeros mas elevados (las calculadoras normales llegan al 69).

Gracias de antemano.
Mi blog personal, con información acerca de programación, seguridad, desarrollo y electrónica:

EN CONSTRUCCIÓN

durasno

Hola! este tema se planteo varias veces en la mayoria la respuesta final es buscar alguna libreria externa para poder operar con numero mas grandes

Saludos
Ahorrate una pregunta, lee el man

Miky Gonzalez

Bueno, sera eso lo que tenga que hacer, muchas gracias por la ayuda, aunque se me ocurrio ahora mismo otra manera:

Hacer la funcion como ld (long double) y las variables al estilo:
unsigned long double factorial(short int numero) {
    int pred = 0;
    unsigned long double tmp = numero;
    for (pred = --numero; pred > 1; --pred)
        tmp *= pred;
    return tmp;
}

Despues se me ocurre llamarlas/almacenarlas directamente como uld (unsigned long double) o escribirlas en pantalla: printf("%lld", factorial(x));
Mi blog personal, con información acerca de programación, seguridad, desarrollo y electrónica:

EN CONSTRUCCIÓN

$Edu$

Hacelo recursivamente, busca sobre funciones recursivas con ejemplos de factorial de un numero.

Factorial(n) {
if (n = 1) return 1;

return Factorial(n) * Factorial(n - 1);
}

Algo asi seria, cuando busques entenderas mejor.

BlackZeroX

The Dark Shadow is my passion.

do-while

#5
XD, vaya idiotez que habia puesto. Eso me pasa por no leer bien las cosas.

Lo que pasa es que el factorial crece muy rapido, y los enteros en C, ocupan una cantidad finita de bytes (supongo que con los procesadores actuales cuatro u ocho bytes). En cuanto te pasas de esa cantidad supongo que almacenara los bytes de menor peso del resultado (aunque no puedo asegurarlo, solo lo supongo), es por eso que te aparecen numeros extraños.

Tienes dos opciones. Utilizar una libreria para manejar enteros arbitrariamente grandes (huge int, creo que se llaman...), o crearte tu tu propio tipo de dato entero para que no tenga limites, por ejemplo, utilizando vectores.

¡Saludos!
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!

Miky Gonzalez

#6
Muchas gracias por la respuesta a todos, me sirvieron para fomentar el estudio de C. Creo que tengo un mente una solucion, cuando termine posteare la funcion para calcular factorial de numeros mas grandes.


Cita de: $Edu$ en 30 Junio 2012, 01:59 AM
Hacelo recursivamente, busca sobre funciones recursivas con ejemplos de factorial de un numero.

Factorial(n) {
if (n = 1) return 1;

return Factorial(n) * Factorial(n - 1);
}

Algo asi seria, cuando busques entenderas mejor.

Si, se lo que es hacer una funcion recursiva y demas pero el tamaño al que llega es el mismo. Por si acaso no sabia algo lo probe y sigue siendo lo mismo, pero gracias por la respuesta.

Cita de: BlackZeroX (Astaroth) en 30 Junio 2012, 03:31 AM

unsigned long long


Ya lo probe, y sigue igual pero gracias de todas formas.

Cita de: do-while en 30 Junio 2012, 09:24 AM

Tienes dos opciones. Utilizar una libreria para manejar enteros arbitrariamente grandes (huge int, creo que se llaman...), o crearte tu tu propio tipo de dato entero para que no tenga limites, por ejemplo, utilizando vectores.


No se exactamente como hacer que no tenga limites utilizando vectores... un nuevo tipo de datos se declara como typedef, en que me puede ayudar? :S
Mi blog personal, con información acerca de programación, seguridad, desarrollo y electrónica:

EN CONSTRUCCIÓN

do-while

#7
Por ejemplo, creas un struct con un vector de unsigned char (0 - 255) para almacenar el valor del numero, y oto campo char (-128, 127) con valores -1 y 1 para el signo. Y defines por tu cuenta la suma, resta, multiplicacion y division de elementos de este tipo. Tendrias que fijar una base para representar los numeros de forma interna, y despues de cada operacion asegurarte de que el resultado se traduce a dicha base... por ejemplo, poniendo entre parentesis el signo y entre corchetes, del byte menos significativo al mas significativo, en base 16, podrias hacer:

(1)[12][15] + (1)[10] = (1)[22][15] = (1)[6 + 16][15] = (1) [6][16] = (1)[6][0][1]

Y asi con el resto de las operaciones...

¡Saludos!

Le estoy echando un ojo de forma algebraica al asunto, y el echo de pasar de base 16 a base 10 sin pasar por multiplicar las cifras por las correspondientes potencias de 16 es (parece) algo que no resulta trivial. Aunque malgastes espacio, lo mejor seria utilizar base 10 para almacenar de forma interna los datos... Esto ultimo es por dar salida a los datos. Sigo trabajando a ver si he pasado algo por alto o puedo simplificar cosas. Aunque aparecen por ahi factoriales y potencias muy feos...
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!

Miky Gonzalez

Cita de: do-while en 30 Junio 2012, 13:19 PM
Por ejemplo, creas un struct con un vector de unsigned char (0 - 255) para almacenar el valor del numero, y oto campo char (-128, 127) con valores -1 y 1 para el signo. Y defines por tu cuenta la suma, resta, multiplicacion y division de elementos de este tipo. Tendrias que fijar una base para representar los numeros de forma interna, y despues de cada operacion asegurarte de que el resultado se traduce a dicha base... por ejemplo, poniendo entre parentesis el signo y entre corchetes, del byte menos significativo al mas significativo, en base 16, podrias hacer:

(1)[12][15] + (1)[10] = (1)[22][15] = (1)[6 + 16][15] = (1) [6][16] = (1)[6][0][1]


Entendi ya un poco, creo que me costara implementarlo porque no quiero tirar de librerias externas, pero es una solucion bastante buena pero complicada de hacer; Muchas gracias. Mientras, solucion temporal:

double factorial(short int numero) {
    int pred = 0;
    double tmp = numero;
    for (pred = --numero; pred > 1; --pred)
        tmp *= pred;
    return tmp;
}


Y llamarlo: printf("Factorial de 87: %.20lg", factorial(87));
Dandonos como salida: Factorial de 87: 2.1077572983795269087e+132

La exactitud viene marcada por el numero de decimales que coja (en este caso 20).
Mi blog personal, con información acerca de programación, seguridad, desarrollo y electrónica:

EN CONSTRUCCIÓN

leogtz

Lo mejor sería que usaras la librería gmp para esto, pero si es para un factorial, podrías checar el siguiente enlace:

http://mailman.linuxchix.org/pipermail/courses/2002-November/001043.html
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com