1. Esta comunidad utiliza cookies. Si continuas utilizando nuestra comunidad estás aceptando la utilización de nuestras cookies. Más información.
  2. ¡Bienvenid@ a AyudaExcel! El foro más visitado sobre Excel en habla hispana.

    Si esta es tu primera visita, asegúrate de revisar los temas de la sección Utilización y Funcionamiento para familiarizarte con las funciones del foro. Si deseas publicar mensajes, será necesario que te Registres para que puedas dejar respuestas y crear tus propios mensajes, recuerda que es gratuito.

Factorial de un numero!

Tema publicado en 'Macros y programación VBA' iniciado por digitalboy, 3 Abr 2010.

  1. digitalboy

    digitalboy Usuario Activo

    Reg:
    28 Jul 2008
    Mensajes:
    500
    Me Gusta recibidos:
    90
    Género:
    Masculino
    Hola a todos....

    Hace tiempo que no posteaba por aqui... y ahora regreso con una curiosidad y un reto en el que estoy trabajando.... resulta ser que un compañero de escuela me ha retado a tratar de igual un programa que el realizo, el cual es capaz de calcular el factorial de un numero sin hacer uso de notacion cientifica.

    Como sabran Excel cuenta con la funcion factorial, pero si se le pasa como argumento el numero 171 o superior la funcion no duvuelve nada y segun mi compañero su programa era capaz de obtener el factorial del numero 800 aun eso si, me comento que tardaba mas de tres horas y es que lo hizo hace varios años en Basic!

    Y ese es el reto que me puso mi cimpañero de clase, me dijo que usase el lenguaje que yo quisiese para lograra el reto y pues quiero realizarlo en Lenguaje C, Ruby y VBA. VBA me parece sencillo y mas facil, pero C es mas rapido y ruby maneja numeros muy grandes.

    ¿Como ven esto? a simple vista no tiene ningun sentido practico, pero como reto es muy bueno.

    Ojo! no pido que me lo resuelvean ya que yo estoy trabajando en la solucion, espero no tardar mas de una semana y poderlo subir y si no, pues ya pedire su ayuda.

    Hasta pronto!
     
  2. Ajedrez

    Ajedrez Usuario

    Reg:
    4 Jul 2009
    Mensajes:
    382
    Me Gusta recibidos:
    10
    Género:
    Masculino
    Hola, pues suerte, aqui un ejemplo de codigo de como deberia ir mas o menos, aunque calcular el factorial de 800 sin notacion cientifica va a estar cañon, de todos modos te dejo este codigo a manera de ejemplo de como deberia ser, logicamente es solo un ejemplo y dista mucho de lo que buscas, es solo una guia.

    Se me ocurre tal vez ir convirtiendo los numeros a texto y tal vez por ahi sea la solucion.
    Saludos.
     
    Última edición: 3 Abr 2010
  3. digitalboy

    digitalboy Usuario Activo

    Reg:
    28 Jul 2008
    Mensajes:
    500
    Me Gusta recibidos:
    90
    Género:
    Masculino
    Primero que nada, gracias por el interes en mi post! En cuanto al codigo de la funcion que me diste es bueno pero esta limitado...

    Antes de empezar a implementarlo en VBA consegui un codigo para ruby y he quedado sorprendido con su capacidad, ya que con ruby puedo obtener el factorial de un tan grande como lo es el 8000 sin uso de notacion cientifica y en menos de un minuto ya despues de 8500 el codigo no funciona, pero por lo menos ya supero lo que pidio mi compañero.

    En cuanto a lo que me comentas de que los numeros sean tratados como texto, esoty de acuerdo! Ese enfoque es que estoy aplicando! Voy a hacer uso de las mas de 1 millon de filas que me provee Excel 2007 para obtner el factorial...

    Creo que lo ideal seria una funcion que me devuelva el numero y hacer uso de matrices para dicho asunto, pero no soy muy bueno en ellas, primero lo hare de la forma rudimentaria en las celdas y posteriormente intentare hacerlo en una matriz.

    Saludos!
     
  4. mjrofra

    mjrofra Moderador Staff AyudaExcel

    Reg:
    28 May 2009
    Mensajes:
    2.686
    Me Gusta recibidos:
    95
    Género:
    Masculino
    Hola digitalboy,

    me ha parecido muy interesante tu problema y me he puesto a investigar un rato (bueno, me han dado las 3 am acá, menos mal mañana es día de descanso para mí :D).

    El problema, más que con algún algoritmo en específico, esta en el tipo de datos. Excel puede manejar valores numéricos de hasta 308 cifras y de ahí que no pueda calcular el factorial de número mayores a 170, pues éstos ya tienen más de 308 cifras.

    El algoritmo en sí es bastante sencillo. Por ejemplo, esto hará exactamente lo mismo que la función fact de Excel:

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
    pero llegando a desbordamiento tras pasar el factorial de 170.

    Ahora, debido a que el problema más que en algún algoritmo en particular está en el tipo de datos, revisando la ayuda de Excel sobre las variables dobles (double), se lee esto:

    Como se ve y esto me iluminó a mi para romper de alguna forma el problema del desbordamiento, cuando se trabaja con decimales el límite es de 324 cifras y no de 308. Así que una solución podría ser correr de entrada los decimales 300 cifras a la izquierda, es decir, en lugar de trabajar con 1, trabajar con 1E-300, en lugar de trabajar con 170, trabajar con 170E-300, y así sucesivamente, igual en algún punto se llegarán a las 308 cifras y ahí se dará el error de desbordamiento, pero habiendo ganado algo de espacio con los 324 al trabajar con decimales... esta sería una forma de hacerlo:

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
    Esta función dará como resultado los valores con el punto decimal corrido 300 puestos a la izquierda, pero ya nos permite avanzar hasta el factorial de 297, sólo habrá que tener en mente lo anterior... o convertir el resultado a tipo string y hacer algunas manipulaciones para 'disfrazar' el resultado, algo así:

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
    Los valores devueltos por esta función todos serán de texto y con el formato: "0.00000000000000E+00" y he usado este formato ya que excel trunca los resultados más allá de 15 dígitos, por lo que no tiene sentido buscar más precisión añadiendo más ceros.

    yendo un poco más allá, se puede 'discriminar' si el valor con el que se va a trabajar es menor a 170, para usar la 'función normal' que permite devolver un valor, o si el número ingresado es mayor y por lo tanto devolver texto, algo así:

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
    Esta última función tendrá un límite de 297, con los que son mayores a 170 convertidos a texto (pues no hay forma de que excel maneje números mayores a 308 dígitos).

    Bueno, algunas ideas que te podrían servir para ir avanzando... adjunto el archivo con las funciones que he descrito acá y ten por seguro que estaré pendiente de cualquier avance que logres :D.
     

    Adjuntos:

  5. mjrofra

    mjrofra Moderador Staff AyudaExcel

    Reg:
    28 May 2009
    Mensajes:
    2.686
    Me Gusta recibidos:
    95
    Género:
    Masculino
    y una avance más, con esta udf ya se llega al factorial de 719 antes de alcanzar el desbordamiento. De nuevo, con las limintaciones inherentes a Excel, por lo que los factoriales mayores a 170 son convertidos a texto y se muestran con una precisión de 15 dígitos:

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
    Como ves no es más que una ligera modificación de lo uqe ya venía haciendo, en este caso dividiendo en cada iteración el resultado entre 100.... probé en dividirlo por 1000 para ver si alcanzaba a avanzar un poco más pero ya se perdían los resultados, seguro por ser ya muy pequeños todos eran convertidos a 0.... igual creo que por ahí puede estar el camino... el tiempo de cálculo hasta ahora no ha sido mayor problema, al menos en mi equipo... lo he probado con esta macro:

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
     

    Adjuntos:

  6. neverdelimon1

    neverdelimon1 Moderador Staff AyudaExcel

    Reg:
    25 Ago 2008
    Mensajes:
    894
    Me Gusta recibidos:
    76
    Hola.

    Por ejemplo puedes usar algo como esto:

    -Nos ahorramos el trabajo hasta el maximo valor decimal que puede leer VBA (para obligar a notación decimal y no científica), de ahi en adelante trabajamos con strings (simulando una multiplicación manual) en cuanto a proceso, porque afortunadamente VBA sabe multiplicar solito jejejejeje, aqui te coloco el ejemplo, parece que funciona y es estable, el limite es los 2 000 millones de caracteres que puede introducirse en un string, en cuanto a velocidad ya conoces como es VBA 'aunque parece que si gana algo de velocidad' pero podras trasladarlo a C y ya nos contarás, la función principal se llama MYFactoria, intenta pasandole por ejemplo un numero culaquiera (entero, por ejemplo 850)

    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.

    Saludos cordiales

    PD.
    Recueda que MS Excel solo muestra en una celda 255 caracteres, para poder ver todos los numeros, copia el resultado de la formula y pegalo como valor en otra celda, luego situate sobre ella, presiona F2 y podras navegar sobre el total de numeros que hay dentro
     
    Última edición: 4 Abr 2010
  7. Ajedrez

    Ajedrez Usuario

    Reg:
    4 Jul 2009
    Mensajes:
    382
    Me Gusta recibidos:
    10
    Género:
    Masculino
    Asi es neverdelimon1 ¡funciona muy bien!. Te felicito, un excelente codigo/aporte a la comunidad Excel. Sin duda me dare mi tiempo para estudiar dicho codigo/función poco a poco.

    Saludos.
     
    Última edición: 4 Abr 2010
  8. mjrofra

    mjrofra Moderador Staff AyudaExcel

    Reg:
    28 May 2009
    Mensajes:
    2.686
    Me Gusta recibidos:
    95
    Género:
    Masculino
    ¡Never! sencillamente impresionante... patenta ese código y véndeselo a Microsoft :D, monstruoso, de verdad un monstruo en esto tú.

    Como siempre, un placer compartir contigo y ver tus aportes, siempre aprendiendo de ti.
     
  9. digitalboy

    digitalboy Usuario Activo

    Reg:
    28 Jul 2008
    Mensajes:
    500
    Me Gusta recibidos:
    90
    Género:
    Masculino
    Guau! no espera que despertara mucho interes mi tema....

    Y me sorprende ver las respuestas brindadas por cada uno de ustedes. Les agradezco el interes y tiempo dedicado a mi duda y problema!

    Denme tiempo de probar cada una de las soluciones brindadas. Por el reojo que le he echado todas son UDF (funciones definidas por el usuarioa).

    La solucion de mjrofra tambien me vino a la mente en un primer instante pero la deseche aun asi hare pruebas con ella. En cuanto a la solucion brindada por neverdelimon1 Guau! estoy sorprendido! Yo en estos momentos estaba desglosando el numero en cada celda para excel 2007 aprovechando las 16000 columnas brindadas para hacer la suma numero por numero (se que es lento pero es lo primero que se me vino a la mente). En cuanto a tu solucion neverdelimon1 como dices, la pasare a C y ahi utilizare asignacion dinamica para reservar hasta demasiada memoria en un puntero y ver hasta donde puedo llegar!

    Sean pacientes ya que no dispongo de mucho tiempo.

    Gracias a todos y en breve espero subir mis soluciones!
     
  10. neverdelimon1

    neverdelimon1 Moderador Staff AyudaExcel

    Reg:
    25 Ago 2008
    Mensajes:
    894
    Me Gusta recibidos:
    76
    Hola

    Master Mjrofra (mauricio), como siempre es todo un gusto compartir un post contigo, aprovecho para saludarte.
    ¡
    Muchas gracias por los apreciables comentarios, y pues que decir todos tus aportes son maravillosos master, en mi caso me he beneficiado mucho con cada uno de ellos ( adquiriendo conocimientos)

    fornelasa

    Muchas gracias por los comentarios, pero en parte el merito es tuyo, ya que tome tu idea original de manejar strings.


    Digitalboy

    Entonces quedamos a espera de ver los resultados (porque me imagino que en C si se ganara bastante velocidad)

    Sin lugar a duda el código aun se puede mejorar para ganar velocidad, ayer intente quitar matrices y manejar solo dos variables strings (pero haciendo pruebas no logre que fuese más rápido)... por lo que quedemos en espera de algun compañero del foro quizas haya alguna forma de acelerarlo.

    Revisando el código se me paso un signo de igual en la tercer linea, debe ser asi:
    CÓDIGO:
    Es necesario iniciar sesión o registrarse para ver este contenido.
    saludos cordiales
     
    Última edición: 4 Abr 2010
  11. digitalboy

    digitalboy Usuario Activo

    Reg:
    28 Jul 2008
    Mensajes:
    500
    Me Gusta recibidos:
    90
    Género:
    Masculino
    Ya termine mi propia implementacion del factorial y es bueno por una parte ya que lo hice por mi mismo, pero por otra... debo aceptar que es bastante lenta y limitada en comparacion a la brindada por neverdelimon.... Tan solo para obtner el factorial de 200, se tarda como 7 minutos y usando la funcion de neverdelimon al calcular el factorial del numero 1000 solo tardo 35 segundos!

    Bien... les dejo el archivo que yo realice y es la que pienso mostrarle a mi compañero y aun que es lenta y deja mucho que desear en desempeño, fue la que yo hice por mi cuenta y mi etiqueta y codigo de honor como programador me prohibe atribuirme algo que no he creado! Pero si me compañero se mofa de mi creacion... mostrare el trabajo de neverdelimon dandole el credito correspondiente!

    En cuanto a la implementacion en C, les pido sean pacientes... ya que probablemente tarde tarde algo de tiempo, en estos momento me encuentro abrumado con tareas (Tendo que desarrollar un punto de venta como proyecto) y trabajo, ademas de que tratare de hacerlo sin basarme en el ejemplo de neverdelimon ya que mi orgullo me impide tomar respuestas faciles...

    Otra cosa.... segun lo poco que pude apreciar neverdelimon tu utlizaste multiplicacion y yo como podras darte cuenta utlice solo sumas es por eso la lentitud de ejecucion intentare otro artulugio para acelerar la velocidad en C y por que no crear una dll y distribuirla y donarla al foro, pero sean pacientes.

    Les dejo mi implementacion! Saludos y gracias!
     

    Adjuntos:

    • facto.zip
      Tamaño de archivo:
      14 KB
      Visitas:
      19
  12. digitalboy

    digitalboy Usuario Activo

    Reg:
    28 Jul 2008
    Mensajes:
    500
    Me Gusta recibidos:
    90
    Género:
    Masculino
    Perdon! una ultima duda mas neverdelimon...

    2 mil millones eh? a cuanto equivale eso en Megabytes?
    Segun mis calculos...

    2,000,000,000 / 1024 = 1,953,125 Kilobytes
    1,953,125 / 1024 = 1,907 MegaBytes

    Si miscalculos son correctos... eso equivale a mas de un Giga en memoria o no? y si solo dispongo de 500 MB acaso pagina lo restante o que pex? Perdon por ser pregunton, pero prefierno no quedarme con la duda!
     
  13. neverdelimon1

    neverdelimon1 Moderador Staff AyudaExcel

    Reg:
    25 Ago 2008
    Mensajes:
    894
    Me Gusta recibidos:
    76
    Hola

    Los 2000 millones me referia a la cantidad máxima de caracteres que acepta un string, si se usa dentro de una celda de excel, estará limitado a la cantidad maxima de caracteres que puede almacenar MS Excel en un celda, la cual varia dependiendo de la version, por ejemplo la version 2007 tiene como límite 32 767

    Como bien sabes una de las cosas que siempre le han criticado a VBA y VB es que no permite la gestion/administración de la memoria (por parte del programador).

    Saludos cordiales
     

Compartir esta página