• Publicidad

Comparativa de lenguajes

Todo lo relacionado con lenguajes de programación distintos de Perl: PHP, Java, C++, Ruby, Python, etc.

Comparativa de lenguajes

Notapor roldan » 2008-01-15 08:17 @387

He realizado una pequeña y chapucera comparativa entre varios lenguajes: C, Perl, Ruby y Python (lo tenéis más bonito en mi blog: http://roldarin.blogspot.com/2008/01/co ... jes-i.html ).
Lo que quería preguntaros es el asunto de Perl...

Comparativa entre lenguajes I

Vamos a ir realizando una comparativa entre varios lenguajes de programación.
Estos serán C, Perl, Python y Ruby.

Elegimos C porque es un lenguaje de nivel medio que nos dará un buen tope de eficiencia. Utilizaremos programas sencillos para que la habilidad como programador influya lo menos posible.

Tampoco nos importa la eficiencia. Se trata de una comparativa en tiempos de ejecución, no de realmente comparar lenguajes.

El primer programa consistirá en mostrar los primeros 33 números de Fibonacci. El último número calculado es 3524578.

Primero utilizaremos una implementación recursiva. Mostraremos además el número de llamadas a la función, que debería ser independiente del lenguaje.

También es de esperar que las funciones recursivas tarden más, ya que estamos haciendo simples sumas y al hacerlo recursivo añadimos complejidad.

RECURSIVO

Códigos

Sintáxis: [ Descargar ] [ Ocultar ]
Using c Syntax Highlighting
#include
long int llamadas=0;
int fibonacci(int n) {
llamadas++;
if (n==0 | n==1)
return 1;
else
return fibonacci(n-1) + fibonacci(n-2);
}

main() {
int i;

for (i=0; i<33;i++)>
printf("%d \n", llamadas);
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using ruby Syntax Highlighting
#!/usr/bin/ruby
$llamadas=0
def fibonacci(n)
$llamadas+=1
return 1 if n==1 or n==0
fibonacci(n-1)+fibonacci(n-2)
end

33.times { |num| puts fibonacci(num).to_s }
puts $llamadas.to_s
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
$llamadas=0;
sub fibonacci {
$llamadas++;
my $n = shift;
return $n if ( $n == 0 or $n == 1 );
return fibonacci( $n-1 ) + fibonacci( $n-2 );
}
for ($num=0; $num < n="=" n="=" llamadas="0" n="=" n="=" fibo="fibonacci">
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using python Syntax Highlighting
#!/usr/bin/python
llamadas=0
def fib(n):
global llamadas
llamadas+=1
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)

for i in range(34):
print fib(i)
print llamadas
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Tiempos
Código: Seleccionar todo
C: 18454895 llamadas

real 0m0.636s
user 0m0.628s
sys 0m0.004s

Ruby: 18454895 llamadas

real 1m12.161s
user 1m4.044s
sys 0m8.093s

Perl: 29860668 llamadas !!!

real 1m5.042s
user 1m5.000s
sys 0m0.012s


Python: 18454895 llamadas

real 0m29.577s
user 0m29.562s
sys 0m0.004s



ITERATIVO

Códigos

Sintáxis: [ Descargar ] [ Ocultar ]
Using c Syntax Highlighting
#include
int fib (int n)
{
if (n==0 | n==1) return 1;
int a = 1, b = 1;
int i;
for (i = 3; i <= n; ++i) { int a_prev = a; a = b; b += a_prev; } return b; } main() { int i; for (i=0; i<34;i++) printf("%d \n", fib(i)); }
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using ruby Syntax Highlighting
#!/usr/bin/ruby
def fibonacci(n)
curr = 1 succ = 1
n.times do |i|
curr, succ = succ, curr + succ
end
return curr
end
33.times { |num| puts fibonacci(num).to_s }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using python Syntax Highlighting
#!/usr/bin/python
def fib(n): a, b = 1, 1 for i in range(n): a, b = b, a + b return a for i in range(33): print fib(i)
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -w
sub fibonacci
{
my ($n, $a, $b) = (shift, 1, 1);
($a, $b) = ($b, $a + $b) while $n-- > 0;
$a;
}
for ($num=0; $num < 33; $num++) {
print fibonacci($num) ."\n";
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Tiempos
Código: Seleccionar todo
C:

real 0m0.002s
user 0m0.000s
sys 0m0.000s

Ruby:

real 0m0.012s
user 0m0.008s
sys 0m0.000s

Python:

real 0m0.028s
user 0m0.012s
sys 0m0.008s

Perl:

real 0m0.010s
user 0m0.004s
sys 0m0.004s


Vemos la potencia de C y que la recursividad se paga caro.

Extraña el numero de llamadas que hacer Perl, y que en modo iterativo Python sea más lento. Aun así parece el más rápido de los lenguajes interpretados.

Lo que más me extraña es lo de Perl. Lo comprobé varias veces y siempre salian una cantidad de llamadas
superior al resto.

¿A alguien se le ocurre el por qué?
roldan
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2008-01-15 08:00 @375

Publicidad

Notapor explorer » 2008-01-15 10:33 @481

No cabe duda de que la función debería dar el mismo número de llamadas que el resto de lenguajes:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -l
$llamadas = 0;

sub fibonacci {
    my $n = shift;
    $llamadas++;
    return $n if $n < 2;
    return fibonacci( $n-1 ) + fibonacci( $n-2 );
}

for ( 0 .. 32 ) {
    print fibonacci( $_ );
}
print "$llamadas\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Esto es lo que sale:
Código: Seleccionar todo
18454895

real    0m29.155s
user    0m28.938s
sys     0m0.048s
Bueno, los tiempos son distintos a los tuyos porque mi máquina es distinta a la tuya.

Pero... este asunto de los tiempos es interesante...

Puede ser interesante cuando se comparan cosas que pertenecen al mismo universo de aplicación, pero estás comparando un programa en C, compilado, con programas escritos en lenguajes de script.

Hay muchos estudios que intentan comparar estas soluciones, para justificar en contra o a favor el uso de estas soluciones, pero casi todos están sesgados: solo tienen en cuenta un factor, como por ejemplo, en tu caso, la velocidad de ejecución.

Hoy en día, el hardware es barato, comparado con lo más caro: el programador. Por lo tanto, en un desarrollo real, lo importante es que el programador genere la solución lo más rápidamente posible. Si lo hace en un determinado lenguaje, se supone que ese lenguaje lo ha elegido alguien que presupone que es el mejor para esa tarea (a veces no: lo elige el jefe por razones desconocidas incluso para él).

El año pasado salieron comentarios que mostraban que un programador de Perl era 2.4 veces más productivo que un programador de Java, y generaba una solución 2,75 veces más corta.

El comparar velocidad de ejecución puede ser interesante si el problema a resolver requiere un esfuerzo computacional muy fuerte, según los requerimientos, frente a otros más livianos, como los de gestión.

Y una vez elegido el lenguaje, también la experiencia del programador será determinante. Cuanto más especializado esté, más posibilidades habrá de que encuentre una solución más óptima, que aproveche el hardware, dentro del poco tiempo que él ha prometido que tardaría en dar la solución.

Por ejemplo, el anterior ejemplo de Fibonacci es ideal para demostrar el uso de un módulo incluido en las distribuciones Perl llamado Memoize. Modificamos, muy ligeramente, el programa anterior, añadiendo estas líneas al principio:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
use Memoize;
memoize('fibonacci');
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Con este cambio, le decimos a Perl que "recuerde" todas las llamadas a la función fibonacci, ya que una solución recursiva hace muchas llamadas iguales con los mismos parámetros. No tiene sentido volver a calcular lo mismo una y otra vez si nos podemos acordar de lo que hicimos antes.

Si lo ejecutamos sale:
Código: Seleccionar todo
65

real    0m0.023s
user    0m0.016s
sys     0m0.004s
Sí... solo son necesarias 65 llamadas para resolver el problema del cálculo de Fibonacci de los primeros 33 números. Y en poco más de dos centésimas de segundo.

Mil veces más rápido, con solo añadir dos líneas.

¿Cómo medimos esa mejora con un test como los que muestras?

Otra cosa, en la solución iterativa, la implementación correcta es esta:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -l
sub fibonacci {
    my ($n, $a, $b) = (shift, 0, 1);
    ($a, $b) = ($b, $a + $b) while $n-- > 0;
    $a;
}

for ( 0 .. 32 ) {
    print fibonacci($_);
}
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
para que salga el mismo resultado que en la recursiva.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor roldan » 2008-01-15 14:28 @644

Joder, ya veo dónde metí la pata. Resulta que hay códigos que empiezan 0,1,2,3,5.....3524578
mientra que otros son 1,1,2,3,5.....3524578.

Supuse equivocadamente que esto no sería importante a efectos generales pero sí lo es debido a que también implica cambiar la cota para parar de calcular.

He corregido los scripts para que den todos 1,1,2,3,5.....3524578. Ahora si que dan el mismo número de llamadas como cabría esperar. :D

A modo de curiosidad, ahora estoy en otro ordenador, lanzo el script de Python, y funciona, si lo vuelvo a lanzar peta, y sigue petando:
Código: Seleccionar todo
....
 return fib(n-1) + fib(n-2)
 RuntimeError: maximum recursion depth exceeded


Mañana los vuelvo a probar y pongo tiempos.

La idea de mis comparaciones era ver cómo se comportan Perl, Python y Ruby respecto a realizar tareas SENCILLAS.

Más que nada por curiosidad. Puse C para ver cuánta eficiencia se perdía al hacerlo en un lenguaje de más alto nivel. Estuve por poner ensamblador pero lo tengo muyyy olvidado.

Además, Ruby, Python y Perl me parecen que están escritos en C, así se puede ver la complejidad que hay detrás al menos en lo que a estos cálculos se refiere.

Como ya dije, a pesar del título, no es una comparativa de lenguajes sino más bien de tiempos de ejecución. Tengo pensado hacer alguno más, para comparar cómo manejan estructuras de datos, IO, cálculos "complejos". Curiosidad... cada lenguaje es diferente, y sobre todo depende del proyecto a realizar y del programador.

Respecto a la productividad yo creo que el mejor es Ruby, cuya filosofía es justamente esa, desarrollar código lo más rápido y fácilmente posible. Aunque a costa de eficiencia.

La idea de Perl de que cada cosa se puede hacer de varias maneras se lleva al límite en Ruby, cada cosa se puede escribir de varias maneras, aunque hagan lo mismo, y esa comodidad se paga.

También me imaginaba que Python los superaría en tiempos, es un lenguaje muy ordenado y eso para un interpretado es muy importante. La filosofía de Python tira más hacia solo hay una manera clara de hacerlo.

También conocía el memoize, y por supuesto que se pueden hacer mejoras, como por ejemplo reemplazar if n==1 or n==0 por if n<2 te ahorras una comparación y un or. Pero justamente no me interesaba la eficiencia del código, y mucho menos tirar de bibliotecas sino que los códigos dieran trabajo y que fueran lo más análogos posibles en todos los lenguajes.
roldan
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2008-01-15 08:00 @375

Notapor explorer » 2008-01-15 17:39 @777

Pues nada, es mejor hacer eso que no hacer nada, desde luego.

Te animo a que sigas investigando.

No puedo decirte si Ruby es más productivo, ya que no lo conozco. He intentado aprender Python pero solo he visto problemas comparado con Perl. Por eso sigo con él. Te animo a que los aprendas todos y así luego decir cuál es el mejor. Yo ya decidí, pero en parte, por mi edad :-)

Por favor, edita el mensaje con los ejemplos y arréglalos...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor creating021 » 2008-01-15 19:10 @840

Yo, curioso por C y C++, comparé los tiempos de ejecución de un Hola Mundo y como era de esperarse, C es más rápido que C++ ya que C usa menos librerías, esto lo digo ya que pasa lo mismo con los scripts y sería interesante comparar estos lenguajes usando librerías/módulos ya que el tiempo de ejecución aumenta.

Por otro lado, cada lenguaje tendrá su truco... como memoize o SelfLoader, pero lo que cuenta es lo que haces... nada te da hacer un programa ( mal hecho ) en ASM, aunque un ejecutable de estos tome menos tiempo en ejecutar, el código mal hecho usará ese tiempo o más.
Expect the worst, is it the least you can do?
Avatar de Usuario
creating021
Perlero frecuente
Perlero frecuente
 
Mensajes: 595
Registrado: 2006-02-23 16:17 @720
Ubicación: Frente al monitor

Notapor roldan » 2008-01-16 04:53 @245

Ya lo he corregido, espero. Los códigos ahora van por separado.
El editor de blogger es un poco penoso. Si editas un post a veces te lo corta por las buenas, confunde partes del código con html... hay que hacer apaños.

He hecho otra comparativa
http://roldarin.blogspot.com/2008/01/co ... es-ii.html

Como podéis ver el tiempo de calculo de Perl es muy bueno.

El siguiente será comparar IO.

Yo de Python apenas sé. De C y Perl tengo poca practica. Me llevo bastante mejor con Ruby.
Se aprende enseguida ya que está enfocado a ponerle las cosas fáciles al programador.
roldan
Perlero nuevo
Perlero nuevo
 
Mensajes: 3
Registrado: 2008-01-15 08:00 @375


Volver a Programación en general

¿Quién está conectado?

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

cron