• Publicidad

Ayuda con programa números primos

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Notapor Perl user » 2005-06-08 12:27 @560

Después de unas largas vacaciones, me pareció interesante que comenzaran con cuestiones matemáticas (de implementación), así que tomaré el post de macgregor que fué al que le encontré algunas pequeñas fallas de implementación, para en general explicar la cuestión recursiva y su funcionamiento.

Efectivamente, la posibilidad más instructiva para el problema de la sucesión de fibonacci es utilizando la ayuda de las matemáticas y su implementación computacional, es decir, generar la función recurrente del problema como se menciona abajo:

macgregor escribiste:el numero de fibonacci se calcula como
f(1)=1 caso base
f(2)=1 caso base
f(n)=f(n-1)+f(n-2) caso recursivo


Aqui hay 2 cosas importantes... la función recurrente está correcta, pero... le hace falta su condición de comienzo y los casos bases dados, estan "correctos" si así se quiere ver... pero... falta uno muy importante: f(0). Entonces nuestra recurrencia quedaría planteada de la siguiente manera:
Código: Seleccionar todo
f(0) = 0;
f(1) = 1;
f(n) = f(n-1) + f(n-2) cuando n >= 2


Consta de 2 casos base (los cuales computacionalmente detendrán las llamadas recursivas) y luego viene el caso recursivo o matemáticamente llamado también caso hipotético (es simple inducción matemática), donde se asume que la sucesión se calcula a partir de los 2 valores anteriores dados a la función.

Esto nos permite ver que computacionalmente, generaremos una función, cuyos valores de parada serán, al recibir un número con valor 0 ó 1, y que mientras no se cumpla dicha condición, se llame asímisma con los valores anteriores.

Veamos la implementación dada:

macgregor escribiste:
Código: Seleccionar todo
sub fibo
{
  my $n=@_[0];
 
  if ($n==0){return 1;}
  else
  {
     if ($n==1){return 1;}
     else
     {
        return( fibo($n-1)+fibo($n-2) );
     {
  }
}


Bueno, si se prueba dicho código utilizando use warnings se podrá observar que el intérprete nos advertirá sobre una pequeña falla de asociación de valores: intentaste utilizar un slice en vez de un simple valor escalar sobre los parámetros enviados.
Funciona.... claro... por qué? porque dicho slice a fin de cuentas regresa un valor... pero ¿sabes que retorna? retorna una lista, una lista con un solo valor (que escalarmente es un 1, así que cuidado).
La otra cuestión es... no hay necesidad de separar los 2 casos base, y generar 4 condiciones, con 1 sola condición es suficiente, por lo tanto el código quedaría de la siguiente manera:

Código: Seleccionar todo
sub fib {
    my $n = shift; # o $_[0]
    return $n if ( $n == 0 or $n == 1 ); #casos base
    return fib( $n-1 ) + fib( $n-2 ); #caso recursivo
}


El orden de dicho algoritmo es O(n^n), por lo tanto como se mencionó en el post de macgregor, crece exponencialmente de acuerdo al parámetro mandado. Dependiendo de la pila máxima soportada, es el nivel de recursividad que el algoritmo podrá soportar.

Recomendaciones:
No es comercial pero... es 100 no.... 10000% recomendado el nuevo libro Higher Order Perl del autor Mark Jason Dominus, editorial Morgan Kauffman (or something like that), el cual tiene como finalidad aplicar conocimientos del paradigma funcional en el lenguaje de programación Perl. Así que esto de la recursividad es un tópico en el libro, y una técnica muy buena para "salvar" recursos llamada Memoization.

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Publicidad

Notapor kidd » 2005-06-08 14:40 @653

Perl user escribiste:Recomendaciones:
No es comercial pero... es 100 no.... 10000% recomendado el nuevo libro Higher Order Perl del autor Mark Jason Dominus, editorial Morgan Kauffman ( or something like that ), el cual tiene como finalidad aplicar conocimientos del paradigma funcional en el lenguaje de programación Perl. Así que esto de la recursividad es un tópico en el libro, y una técnica muy buena para "salvar" recursos llamada Memoization.


El libro es:

Higher-Order Perl de Mark Jason Dominus
Click para comprar (ahora si es un comercial de "Perl en Español", jeje :wink: )


SALUDOS
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

Mi respuesta al programa sucesión de fibonacci

Notapor QUEDIFICILPERL » 2005-06-08 23:40 @027

:twisted:

Que tal amigos. Me disponía a dormir y me dije voy a ver que hay de nuevo en el foro y me encuentro con la propuesta de Kidd sobre la sucesión de fibonacci, se me hizo interesante y decidí posponer unos minutos el sueño, así que antes de leer sus propuestas para el programilla de la sucesión decidi hacerlo sólo y con lo poco que sé, el código que se me ocurrio es:

Código: Seleccionar todo
@fibonacci=(1,1);
print "$fibonacci[0]\n";
print "$fibonacci[1]\n";
for ($z=2;$z<=10;$z++)
{
  $fibonacci[$z]=$fibonacci[$z-1]+$fibonacci[$Z-2];
  print "$fibonacci[$z]\n";
}


No alcancé a analizar las otras respuestas (ya saben ahi que levantarse temprano) pero al parecer mi respuesta es similar a la de MCGregor y por lo que veo Perl User la critica extensamente, y lo que hace Kidd se ve muy interesante así que manaña en la noche la checare con detalle; ¿saben que me da gusto? que empiezo a deletrear Perl....... :P
QUEDIFICILPERL
Perlero nuevo
Perlero nuevo
 
Mensajes: 15
Registrado: 2004-11-17 14:07 @630
Ubicación: México

Notapor macgregor » 2005-06-09 06:37 @317

my $Código:
Código: Seleccionar todo
sub fibo
{
  my $n=@_[0];
 
  if ($n==0){return 1;}
  else
  {
     if ($n==1){return 1;}
     else
     {
        return( fibo($n-1)+fibo($n-2) );
     {
  }
}


Comentario de PerlUser:

Bueno, si se prueba dicho código utilizando use warnings se podrá observar que el intérprete nos advertirá sobre una pequeña falla de asociación de valores: intentaste utilizar un slice en vez de un simple valor escalar sobre los parámetros enviados.
Funciona.... claro... por qué? porque dicho slice a fin de cuentas regresa un valor... pero sabes que retorna? retorna una lista, una lista con un solo valor ( que escalarmente es un 1, asi que cuidado ).
La otra cuestión es... no hay necesidad de separar los 2 casos base, y generar 4 condiciones, con 1 sola condición es suficiente, por lo tanto el código quedaría de la siguiente manera:

(PerlUser) Código:

Código: Seleccionar todo
sub fib {
    my $n = shift; # o $_[0]
    return $n if ( $n == 0 or $n == 1 ); #casos base
    return fib( $n-1 ) + fib( $n-2 ); #caso recursivo
}



En cuanto a la mejora del codigo simplificando los casos base me parece muy buena. :P
Pero creo que que es incorrecto decir que f(0)=0 ya que el primer numero de la sucesion es un 1. quiero decir que si preguntas al programa el valor del primer numero de fibonacci debe responder un 1 y no un 0.

creo que cuando escribi :
el numero de fibonacci se calcula como

f(1)=1 caso base
f(2)=1 caso base
f(n)=f(n-1)+f(n-2) caso recursivo


deberia haber puesto:

Código: Seleccionar todo
el numero de fibonacci se calcula como

f(0)=1 caso base
f(1)=1 caso base
f(n)=f(n-1)+f(n-2) caso recursivo





Pero la verdadera intencion al escribir este mensaje es decir que no entiendo la parte en la que PerlUser habla del slice (que es un slice? :( ) y me gustaria que explicaras con mas detalle que significa que retorne un valor que escalarmente es un 1 ??? :shock:

Creo que no hay nada peor que quedarse con dudas sobre algo, ya que saber a medias se parece mas a no saber nada que a conocer algo.

PD: QUEDIFICILPERL, MACGREGOR se escribe con A.
Sin ella es anglosajon :x en lugar de hispano. :D
Verdad que a nadie se le ocurriria escribir Mcario?
MACARIO es un nombre hispano, ni escoces (MAC) ni aleman(ARIO), pues lo mismo le pasa a mi alias !!! :D :D

PD2: PerlUser me alegra volver a verte por aqui, espero ansioso tu respuesta. Gracias de antemano.
MACGREGOR [TM]
Avatar de Usuario
macgregor
Perlero nuevo
Perlero nuevo
 
Mensajes: 80
Registrado: 2004-12-09 07:32 @355
Ubicación: españa

Notapor Perl user » 2005-06-09 11:15 @511

macgregor escribiste:En cuanto a la mejora del codigo simplificando los casos base me parece muy buena. :P
Pero creo que que es incorrecto decir que f(0)=0 ya que el primer numero de la sucesion es un 1. quiero decir que si preguntas al programa el valor del primer numero de fibonacci debe responder un 1 y no un 0.

creo que cuando escribi :
el numero de fibonacci se calcula como

f(1)=1 caso base
f(2)=1 caso base
f(n)=f(n-1)+f(n-2) caso recursivo


deberia haber puesto:

Código: Seleccionar todo
el numero de fibonacci se calcula como

f(0)=1 caso base
f(1)=1 caso base
f(n)=f(n-1)+f(n-2) caso recursivo



Nope, f(0) no puede ser 1, el algoritmo explícitamente dice que cuando el parámetro de la función sea un 0, el valor retornado es 0, puesto que no hay sucesión de fibonacci para dicho número. Y nuevamente te faltó la condición de recursividad de que para todo n >= 2 se ejecutará.


macgregor escribiste:Pero la verdadera intencion al escribir este mensaje es decir que no entiendo la parte en la que PerlUser habla del slice (que es un slice? :( ) y me gustaria que explicaras con mas detalle que significa que retorne un valor que escalarmente es un 1 ??? :shock:

Creo que no hay nada peor que quedarse con dudas sobre algo, ya que saber a medias se parece mas a no saber nada que a conocer algo.


Ok, normalmente el acceso a una lista puede darse desde 2 ámbitos:
1) Un valor único ( escalar )
2) Una lista

El último caso, no solamente es explícitamente la lista en sí, sino que puedes obtener una sublista, ejemplo:
Código: Seleccionar todo
my @list = qw( "foo", "bar", "baz" ); # la lista
my $value = $list[2] # "baz"
my $value = $list[-1] # "baz"
my @sublist = @list[1,2]; # ( "bar", "baz" );
my @sublist = @list[1,-1]; #( "foo", "baz" );


Los 2 últimos casos son slices ( particiones ), es decir un subconjunto de tu lista, el cual puede ser un número explícito de elementos o un rango.
por lo tanto en el ejemplo @a[1]; lo que te regresa no es el elemento 1 de la lista, te regresa una lista con dicho elemento... es decir:
Código: Seleccionar todo
my @a = ( "foo", "bar", "baz" );
my $val = $a[1]; # "bar"
my @val = @a[1]; # ( "bar" );
my $val = @a[1]; # 1, lo cual es incorrecto


La última expresion por ser una lista evaluada en contexto escalar, regresa la cantidad de elementos en la lista. Pero como el interprete de Perl es muy inteligente y ese es un error común en los programadores iniciales, te lo evaluará como $a[1] ( o sea como debería ser correctamente ) PERO te dará la advertencia de que eso está mal escrito de tu parte y que debes corregirlo.

macgregor escribiste:PD2: PerlUser me alegra volver a verte por aqui, espero ansioso tu respuesta. Gracias de antemano.


Gracias, estuve ocupado mucho tiempo escribiendo un compilador y un lenguaje para un proyecto, el cual ya está terminado.

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor macgregor » 2005-06-10 09:13 @426

Hola a todos.

Muchas veces me resulta dificil a veces entender lo que me dicen por las palabras que utilizan.
Por ejemplo cuando PerlUser habla de listas no lo entendia, yo entiendo que @_ es un vector, array, arreglo pero no una lista.

Entiendo que estos pequeños problemas para entendernos es por la forma diferente que tenemos para expresarnos.

(por cierto PerlUser tienes mas razon que un santo, debia haber puesto $_[0] para recoger el valor que recibe la funcion pero utilize el signo @, no fue por ignorancia, simplemente fue un error. De todas formas gracias por tu ultima aclaracion, ahora entiendo lo que decias.)

Para mi una lista es una estructura de nodos, cada nodo contiene un dato o varios, mas un puntero al siguiente elemento.
Si la lista es doblemente enlazada tenemos la estructura con un nodo y dos punteros, uno a siguiente y otro al anterior. (de forma que se puede avanzar y retroceder)
En ambos casos siempre tenemos un puntero al primer elemento y segun la funcionalidad que se desee un puntero al ultimo.

Dependiendo de como la definamos y las operaciones que permitamos hacer, en realidad estaremos creando una lista, una cola, una pila o incluso un buffer circular. (si el puntero a siguiente del ultimo nodo apunta al primer nodo)

Esta estructura en realidad es parecida a un vector o arreglo, es mas lenta a la hora de acceder ya que hay que recorrer nodo a nodo desde el principio hasta el que queremos.
Sin envargo es mucho mas rapida si se necesita una estructura ordenada y se van a realizar muchas inserciones, ya que permite realizar inserciones ordenadas de nuevos nodos sin tener que desplazar elementos (como sucede en un vector).

Despues de esplicar esto (que espero que sirva a alguien con ganas de experimentar programando) me gustaria saber como llamarian ustedes a esta estructura :?

Un saludo.
MACGREGOR [TM]
Avatar de Usuario
macgregor
Perlero nuevo
Perlero nuevo
 
Mensajes: 80
Registrado: 2004-12-09 07:32 @355
Ubicación: españa

Notapor Perl user » 2005-06-10 11:45 @531

macgregor escribiste:Hola a todos.

Muchas veces me resulta dificil a veces entender lo que me dicen por las palabras que utilizan.
Por ejemplo cuando PerlUser habla de listas no lo entendia, yo entiendo que @_ es un vector, array, arreglo pero no una lista.

Es correcto que lo llames de esa manera también( es decir vector, array, arreglo )

macgregor escribiste:Para mi una lista es una estructura de nodos, cada nodo contiene un dato o varios, mas un puntero al siguiente elemento.
Si la lista es doblemente enlazada tenemos la estructura con un nodo y dos punteros, uno a siguiente y otro al anterior. (de forma que se puede avanzar y retroceder)
En ambos casos siempre tenemos un puntero al primer elemento y segun la funcionalidad que se desee un puntero al ultimo.

No, creo que alli es donde tenemos exactamente el problema, y creo que si es confusión tuya. La estructura que tu mencionas es una LISTA LIGADA ( linked list ), aquí y en China, así se llama, en cualquier paper que te encuentres sobre estructuras de datos ( en especial TDA's ), encontrarás que una lista ligada es una estructura de datos abstracta que contiene nodos, cada nodo esta ligado uno a otro por una o dos ( doubly ) ligas hacia adelante y/o hacía atrás ( circular ) dependiendo de las necesidades. Si son apuntadores o no es lo de menos, aquí la implementación dependen del lenguaje, pero lo que define un tipo de dato son sus operaciones.

Una lista en sí, es un conjunto de elementos, en este caso en Perl, una lista es un conjunto de elementos que pueden o NO ser mutables, al igual que en python, hay listas inmutables. Un array, arreglo en Perl es una lista de elementos ( ojo... lista, no lista ligada ), la cual contiene elementos únicos de valores ( escalares ). Pero.... aquí viene el pero... no forzosamente una lista está siempre en un @, ejemplo:
Código: Seleccionar todo
my @a = ( 1, 2, 3, 4 ); # lista de números, puede ser mutable
( 1, 2, 3, 4 ); # lista inmutable de números
foreach( @a ) .... # iteracion sobre @a
foreach( ( 1, 2, 3, 4 ) ) .... # iteración sobre una lista inmutable


Ves la diferencia? Y esto nos lleva a la conclusión de que a un arreglo SIEMPRE le asignas una lista, de esta manera la lista puede ser mutable. Y la mayoría de las operaciones para arreglos son aplicables a listas mutables ( arreglos mismos ) y listas inmutables.

macgregor escribiste:Dependiendo de como la definamos y las operaciones que permitamos hacer, en realidad estaremos creando una lista, una cola, una pila o incluso un buffer circular. (si el puntero a siguiente del ultimo nodo apunta al primer nodo)

Lo que estas definiendo son tipos de datos abstractos, un arreglo jamás es considerado un tipo de dato abstracto, es un tipo de dato compuesto. Siempre contendrá elementos del mismo tipo.

macgregor escribiste:Esta estructura en realidad es parecida a un vector o arreglo, es mas lenta a la hora de acceder ya que hay que recorrer nodo a nodo desde el principio hasta el que queremos.
Sin envargo es mucho mas rapida si se necesita una estructura ordenada y se van a realizar muchas inserciones, ya que permite realizar inserciones ordenadas de nuevos nodos sin tener que desplazar elementos (como sucede en un vector).

No se que a que estructura te refieras aquí, pero nuevamente un vector/arreglo es completamente diferente a una lista ligada.

Saludos,

PD. te recomiendo checar un buen libro de Estructuras de Datos, y un libro de compiladores para que cheques el verdadero significacion de un tipo de dato, y sus abstracciones. Ahora bien si quieres ver la implementación de una lista ligada en Perl, escribe lo siguiente:
Código: Seleccionar todo
perldoc -q linked list
perldoc -q circular list
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor kidd » 2005-06-10 15:33 @689

Hola:

Si te interesa realmente saber como funcionan internamente los arrays en perl, te recomiendo que leas el siguiente artículo que se llama "PerlGust Illustrated", en él encontrarás como funcionan las variables en perl, dentro de ello los arreglos:
http://gisle.aas.no/perl/illguts/

Estructura de un AV Array Value
Imagen


SALUDOS
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

Notapor Perl user » 2005-06-10 16:33 @731

No creo que realmente le sirva ver Perl internals... lo que es importante recalcar es simplemente qué es un arreglo/lista y cómo se utilizan, y para ello perl internals no ayuda mucho a entenderlo.

Pero bueno, ya hablando de internals, yo recomiendo "Extending and Embedding Perl" de Simon Cozens editorial Manning. Y como lo actual es trabajar con parrot, adelante con parrot internals. ( TODO: Echarle un ojo a Haskell )

Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor kidd » 2005-06-10 17:10 @757

Muy bien, es hora de otro corte comercial en el foro de "Perl en Español":


Extending and Embedding Perl de Tim Jenness, Simon Cozens
$$ Comprar Ahora


NOTA: Recuerden que si compran libros por este medio, ayudan al sitio de Perl en Español :wink:


P.D: Marco me impresiona la cantidad de libros que has leído. Yo también soy un fan de leer libros para mi aprendizaje, ya llevo varios, aunque todavía me faltan muchos :)
Uriel Lizama Perl programmer fundador de Perl en Español
Perl Programming Language
Avatar de Usuario
kidd
Creador de Perl en Español
Creador de Perl en Español
 
Mensajes: 1166
Registrado: 2003-10-15 16:52 @744
Ubicación: México

AnteriorSiguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 19 invitados