Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Factorial hasta 1000 (https://www.clubdelphi.com/foros/showthread.php?t=48264)

Cheswar 20-09-2007 01:13:15

Factorial hasta 1000
 
Alguien me podria ayudar, necesito saber como puedo hacer factorial hasta n numeros, su limite es 1000, y no se si hay algun tipo de variable que tenga capacidad para un numero tan grande como el factorial de 1000.
Les agradezco.:D

Robert01 20-09-2007 01:59:42

Hola

Podrías usar una variable de tipo extended:

Extended
: 3.4 x 10^-4932 a 1.1 x 10^4932.

Creo que el factorial de 1000 es menor que 1.1 x 10^4932.

Saludos

Robert01 20-09-2007 02:08:41

Hola

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  Num: extended;
  Numt:extended;
begin
  Num:=1;
  for i:=1 to 1000 do begin
    Num:=Num*i;
  end;
  Edit1.Text:=FloatToStr(num);

end;

El factorial de 1000 es = 4,02387260077094 E2567

Saludos

Cheswar 20-09-2007 02:12:11

Te agradezco la ayuda, no estaba seguro del tipo de variable que necesitaba, pero gracias ya lo probe y funciona bien.:D:D:D

seoane 20-09-2007 02:20:22

Bueno, el factorial de 1000 tiene 2.568 cifras :eek: Lamento decir que no existe (al menos no conozco) ninguna variable numérica de delphi que soporte ese numero de cifras. Así que toca hacerlo "a mano", para esto vamos a echar mano de los números "SuperLargos" que ya describir en algún otro hilo. No es la forma mas eficiente de hacerlo, pero funciona :D :
Código Delphi [-]
program Calcular;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
  Max = 2600;

type
  TSuperLargo = array[0..Max] of Byte;

function AddSuper(a,b: TSuperLargo; Acarreo: Integer): TSuperLargo; overload;
var
  i,j: integer;
begin
  for i := 0 to Max do
  begin
    j:= (Integer(a[i]) + Integer(b[i])) + Acarreo;
    Result[i]:= j mod 10;
    Acarreo:= j div 10;
  end;
end;

function AddSuper(a,b: TSuperLargo): TSuperLargo; overload;
begin
  Result:= AddSuper(a,b,0);
end;

function IncSuper(a: TSuperLargo; Acarreo: Integer): TSuperLargo; overload;
var
  i,j: integer;
begin
  for i := 0 to Max do
  begin
    j:= Integer(a[i]) + Acarreo;
    Result[i]:= j mod 10;
    Acarreo:= j div 10;
  end;
end;

function MulSuper(a: TSuperLargo; b: Byte): TSuperLargo; overload;
var
  i,j: integer;
  Acarreo: Integer;
begin
  Acarreo:= 0;
  for i := 0 to Max do
  begin
    j:= (Integer(a[i]) * Integer(b)) + Acarreo;
    Result[i]:= j mod 256;
    Acarreo:= j div 256;
  end;
end;

function ShiftLSuper(a: TSuperLargo): TSuperLargo;
var
  i: integer;
begin
  Result[0]:= 0;
  for i:= 0 to Max - 1 do
    Result[i+1]:= a[i];
end;

function ShiftRSuper(a: TSuperLargo): TSuperLargo;
var
  i: integer;
begin
  Result[Max]:= 0;
  for i:= 1 to Max do
    Result[i-1]:= a[i];
end;

function MulSuper(a,b: TSuperLargo): TSuperLargo; overload;
var
  i: integer;
begin
  FillChar(Result,Sizeof(Result),0);
  for i:= Max downto 0 do
  begin
    Result:= ShiftLSuper(Result);
    Result:= AddSuper(Result,MulSuper(a,b[i]));
  end;     
end;

function SuperToStr(a: TSuperLargo): string;
var
  i: integer;
  flag: Boolean;
begin
  Result:= '';
  flag:= FALSE;
  for i := Max downto 0 do
  begin
    if flag then
      Result:= Result + IntToStr(a[i])
    else if a[i] > 0 then
    begin
      flag:= TRUE;
      Result:= Result + IntToStr(a[i]);
    end;
  end;
end;

function Factorial(i: int64): String;
var
  a,b: TSuperLargo;
  j: Integer;
begin
  FillChar(a,Sizeof(a),#0);
  FillChar(b,Sizeof(b),#0);
  a[0]:= 1;
  b[0]:= 1;
  for j:= 2 to i do
  begin
    b:= incSuper(b,1);
    a:= MulSuper(a,b);
  end;
  Result:= SuperToStr(a);
end;

var
  Marca: TDateTime;
begin
  Writeln('Calculando el factorial de 1000 ...');
  Writeln;
  Marca:= Now;
  Writeln(Factorial(1000));
  Writeln;
  Writeln;
  Writeln('Se empleo en el calculo un tiempo de: ' + TimeToStr(Now-Marca));
end.
Aunque es mejor que te lo tomes con tranquilidad, en mi equipo tardo 8 minutos y 21 segundos en calcular el factorial de 1000.

Por si alguien tiene curiosidad, esta es la salida del programa:
Código:

Calculando el factorial de 1000 ...

402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000


Se empleo en el calculo un tiempo de: 0:08:21


Robert01 20-09-2007 02:57:35

Hay una forma aproximada de calcular el factorial de un número muy grande, es a través de la fórmula de Sterling:

N! := Sqr(2 * PI * N) * (N / E) ^ N

Saludos

dec 20-09-2007 02:59:22

Hola,

Yo no he dejado de hacer otras cosillas y bueno...

Código:

Calculando el factorial de 1000 ...

402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Se empleo en el calculo un tiempo de: 0:14:22

AMD Athlon a 1000 Mhz y 768 MB de RAM en un Windows XP SP2

seoane 20-09-2007 02:59:52

Cita:

Empezado por Robert01 (Mensaje 232420)
Hay una forma aproximada de calcular el factorial de un número muy grande, es a través de la fórmula de Sterling

¿No te gusto la mia? El de 1000 lo clava :D

seoane 20-09-2007 03:02:03

Buena idea dec, ¿alguno tiene uno de esos procesadores de doble núcleo y un montón de Mhz? :D Lo digo por comparar ...

Robert01 20-09-2007 03:32:41

Me gustó, es un muy buen código.

Mañana lo voy a probar en freepascal bajo ubuntu a ver cuanto tarda, de ese modo vamos a compara linux vs windows.

Saludos

Delphius 20-09-2007 06:52:55

Pues yo obtuve este resultado: 0:11:15

En un AMD Duron de 1,16 Ghz, RAM: 480 Mb, Window$ XP Profesional versión 2002 (5.1) SP2

Esto me hace recordar a algunas comparaciones de algoritmia que hacía de cuando era joven:p:D, snif... ¡que recuerdos aquellos! Y ahora que hago memoria... es posible que nunca vuelva a recuperar el libro (original. No copia) de Estructuras de datos y algoritmos... no debí haberlo prestado. Justo cuando lo necesito para repasar algunas cosas que no recuerdo y no tomé apunte:( (menos mal que existe San Google:D) ¿Puede considerarse como una religión, o acaso me debo conformar con la religión de los simpson:D?

Saludos,
PD: No se porque pero que me dieron cuerda... soy una máquina de decir... pe.......:p

seoane 20-09-2007 11:20:29

Voy a dar ejemplo y poner mis resultados.

En un AthlonXP 2600 / 512MB de RAM / Ubuntu 7.04 / Wine 0.9.33
-- > 07:08

En un AthlonXP 1800 / 512 de RAM / WindowsXP SP2
--> 08:14

Era de esperar que en el ordenador mas rápido el calculo se terminara antes, lo que no era tan previsible es que ejecutando el programa sobre linux con la ayuda de wine se obtuviera un resultado tan bueno. Que cada uno saque sus conclusiones ....

Robert01 20-09-2007 12:23:04

Tengo un pequeño problema: cuando ejecuto el programa no me da el tiempo empleado sino un número con formato de hora, por ejemplo 12:05:34 am

No se que es lo que anda mal porque yo no toqué para nada el código

seoane 20-09-2007 12:33:05

El timepo se calcula como la diferencia entre do TDateTime:
Código Delphi [-]
TimeToStr(Now-Marca)
El resultado de esta operación también es un TDateTime. El problema puede ser al convertir esa variable a texto, seguramente por la configuración de la hora en tu equipo este interpretando lo que debería ser "05:34" como "12:05:34".

¿Que equipo tienes? ¿05:34 te parece que es el tiempo que mas o menos le llevo?

seoane 20-09-2007 13:05:42

Acabo de comprobar que como ya advertía no es la forma mas eficiente de hacerlo, por ejemplo en python, un script tan sencillo como este:
Código:

a=1
for i in range(1000):
        a=a*(i+1)

print a

Devuelve el factorial de forma inmediata, sin necesidad de esperar :(

ArdiIIa 20-09-2007 13:47:10

Cita:

Empezado por seoane (Mensaje 232423)
Buena idea dec, ¿alguno tiene uno de esos procesadores de doble núcleo y un montón de Mhz? :D Lo digo por comparar ...

Se empleo en el calculo un tiempo de 0:02:10


Ver Imagen: factorial1pz28z6.jpg

Código:

Intel(R) Core(TM) 2 CPU
6600 @ 2.40 GHz
4 GB RAM


Robert01 20-09-2007 13:51:41

Cita:

Empezado por seoane (Mensaje 232480)
Acabo de comprobar que como ya advertía no es la forma mas eficiente de hacerlo, por ejemplo en python, un script tan sencillo como este:
Código:

a=1
for i in range(1000):
    a=a*(i+1)

print a

Devuelve el factorial de forma inmediata, sin necesidad de esperar :(

Es similar al código que yo puse al principio y además es mucho más rápido.

En mi compu tu código se ejecuta en 5:25 bajo windows, es una máquina con micro intel em64t 3.08 Ghz con 512 mb de Ram.

xEsk 20-09-2007 13:53:36

Cita:

Empezado por seoane (Mensaje 232423)
Buena idea dec, ¿alguno tiene uno de esos procesadores de doble núcleo y un montón de Mhz? :D Lo digo por comparar ...

Hola, he probado el programa a ver mis resultados, la primera vez he sido un tontolaba lo he probado dandole doble click al programa, pero como era de esperar se ha cerrado nada mas terminar y no pude ver nada xDDD

La segunda vez, este ha sido el resultado:

Código:

Calculando el factorial de 1000 ...

402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Se empleo en el calculo un tiempo de: 0:05:19

Lo he probado en un AMD Athlon 64 X2 Dual Core Processor 3800+, no es de los mas potentes ni mucho menos, pero... xDDDDD
Mientras el programa estaba funcionando yo iba haciendo cosas, pero no creo que afecte mucho, pq solo uno de los procesadores estaba trabajando al 100% (50% del total).

Saludos.

seoane 20-09-2007 14:06:28

:eek: La leche, de donde sacáis tremendos equipos. El mio parece un ábaco al lado de los vuestros :(

Cita:

Empezado por Robert01
Es similar al código que yo puse al principio y además es mucho más rápido.

La diferencia es que python te devuelve las 2.568 cifras exactas, nada de aproximaciones. En cambio si utilizas un extended en delphi, es verdad que el calculo es rápido pero solo obtienes una aproximación, ya que solo te devuelve las 15 primeras cifras.

Se me hace raro que delphi no pueda manejar números tan grandes. En otra ocasión el amigo Roman nos hablo del tipo TBCD, pero ni siquiera el soporta 1000 cifras. ¿Alguien conoce algún algoritmo eficiente de multiplicación para números grandes? Solo por curiosidad ...

seoane 20-09-2007 15:42:34

1 Archivos Adjunto(s)
Bueno, alguien que crea un programa para no tener que resolver los sudokus a mano :D, no podía contentarse con el algoritmo anterior.

Así que considerando que que 1000, incluso 10000, nos cabe dentro de una variable de tipo integer, podemos optimizar "un poco" el algoritmo de multiplicación.
Código Delphi [-]
program Fast;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

const
  Lon = 2600;
type
  TSuperLargo = array[0..Lon] of Byte;

function MulSuper(A: TSuperLargo; B: Integer): TSuperLargo;
var
  i,j: integer;
  Ac, Desp, Dig: Integer;
begin
  Desp:= 0;
  FillChar(Result,Sizeof(Result),#0);
  while B > 0 do
  begin
    Dig:= B mod 10;
    B:= B div 10;
    Ac:= 0;
    for i:= 0 to Lon - Desp do
    begin
      j:= Integer(Result[i+Desp]) + (Integer(A[i]) * dig) + Ac;
      Result[i+Desp]:= j mod 10;
      Ac:= j div 10;
    end;
    inc(Desp);
  end;
end;

function SuperToStr(a: TSuperLargo): string;
var
  i: integer;
  flag: Boolean;
begin
  Result:= '';
  flag:= FALSE;
  for i := Lon downto 0 do
  begin
    if flag then
      Result:= Result + IntToStr(a[i])
    else if a[i] > 0 then
    begin
      flag:= TRUE;
      Result:= Result + IntToStr(a[i]);
    end;
  end;
end;

function Factorial(i: integer): String;
var
  j: Integer;
  A: TSuperLargo;
begin
  FillChar(A,Sizeof(A),#0);
  A[0]:= 1;
  for j:= 2 to i do
  begin
    A:= MulSuper(A,j);
  end;
  Result:= SuperToStr(a);
end;

var
  Cont1, Cont2: int64;
  Frec: int64;
begin
  Writeln('Calculando el factorial de 1000 ...');
  Writeln;
  QueryPerformanceFrequency(Frec);
  QueryPerformanceCounter(Cont1);
  Writeln(Factorial(1000));
  QueryPerformanceCounter(Cont2);
  Writeln;
  Writeln;
  Writeln(Format('Se emplearon %d milisegundos',[((Cont2-Cont1) * 1000) div Frec]));
end.

La nueva marca es de tan solo 589 milisegundos :eek:

Que a gusto me he quedado :p :D

Edito:
El factorial de 10,000 (35,659 cifras) tarda 67,202 milisegundos, poco mas de un minuto.

Si alguien tiene curiosidad de saber cual es que se baje el adjunto :D


La franja horaria es GMT +2. Ahora son las 01:08:09.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi