tag:blogger.com,1999:blog-1320528867223721914.post7888296082060676018..comments2024-03-18T10:00:22.981+01:00Comments on #!/perl/bioinfo: Código en C dentro de un programa Perlbrunocontrerashttp://www.blogger.com/profile/06780659979139333360noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-1320528867223721914.post-12722129751961431752010-08-26T13:19:00.176+02:002010-08-26T13:19:00.176+02:00Aqui esta el codigo completo con algunas variacion...Aqui esta el codigo completo con algunas variaciones más:<br /><br />http://pastebin.com/kRbW24kr<br /><br />En mi ordenador (un no muy reciente Pentium 4 a 3GHz), las diferencias entre perl2, perl3 y perl4 son mínimas y a veces gana uno y otras veces otro aunque en promedio parece que perl4 es el más rápido y perl2 el más lento.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1320528867223721914.post-74669583857030052832010-08-26T05:33:56.012+02:002010-08-26T05:33:56.012+02:00¿Dónde está potencia_C2()? Parece que el código es...¿Dónde está potencia_C2()? Parece que el código está cortado.<br /><br />Solo un detalle: si <br /><br />sub potencia_perl2 {<br /> my ($base, $exp) = @_;<br /> my $r = 1;<br /> while ($exp) {<br /> $r *= $base if $exp & 1;<br /> $exp >>= 1;<br /> $base *= $base;<br /> }<br /> $r;<br />}<br /><br />la escribimos de esta manera:<br /><br />sub potencia_perl2 {<br /> my ($r, $base, $exp) = (1, @_);<br /> while ($exp) {<br /> $r *= $base if $exp & 1;<br /> $base *= $base if $exp >>=1;<br /> }<br /> $r;<br />}<br /><br />mejoramos los tiempos un 2% (en mi equipo). <br /><br />De todas maneras, sigue estando muy lejos de los tiempos de '**' (en mi ordenador, '**' es un 1405% más rápido que potencia_perl2).<br /><br />Ahora bien, si lo pasamos a C:<br />float potencia_C2( double base, int exp ) { <br /> double result = 1; <br /> while(exp) { <br /> if (exp & 1) { result *= base; }<br /> if (exp >>= 1) { base *= base; }<br /> } <br /> return result; <br />} <br /><br />Entonces ya empezamos a obtener valores interesantes:<br />Perl (sub) 3523/s<br />Perl (sub2) 132332/s<br />Perl (sub3) 136533/s<br />C 378508/s<br />C2 1654153/s<br />Perl (**) 1942492/s (solo un 17% más rápido que C2)<br /><br />Mi equipo es un AMD Turion(tm) 64 X2 Mobile (x86_64) a 1.6GhzAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-1320528867223721914.post-79828011042113946432010-08-25T11:00:20.580+02:002010-08-25T11:00:20.580+02:00Suele ocurrir que la mejor forma de hacer que algo...Suele ocurrir que la mejor forma de hacer que algo vaya más rapido no sea pasandolo a C sino empleando un mejor algoritmo:<br /><br />#!/usr/bin/perl<br /><br />use strict;<br />use warnings;<br /><br />use Inline 'C';<br />use strict;<br />my $BASE = 0.987654321;<br />my $EXP = 1000;<br />print "# $BASE^$EXP = \n";<br />print "# ".potencia_perl($BASE,$EXP)." (perl)\n";<br />print "# ".potencia_perl2($BASE,$EXP)." (perl2)\n";<br />print "# ".potencia_C($BASE,$EXP)." (C)\n";<br />print "# ".potencia_C2($BASE,$EXP)." (C2)\n";<br /><br />sub potencia_perl {<br /> my ($base,$exp) = @_;<br /> my $result = $base;<br /> for(my $p=1; $p<$exp; $p++) {<br /> $result *= $base;<br /> }<br /> return $result;<br />}<br /><br />sub potencia_perl2 {<br /> my ($base, $exp) = @_;<br /> my $r = 1;<br /> while ($exp) {<br /> $r *= $base if $exp & 1;<br /> $exp >>= 1;<br /> $base *= $base;<br /> }<br /> $r;<br />}<br /><br />use Benchmark 'cmpthese';<br /><br />my @base = map rand(1.5), 1..1000;<br />my @exp = map rand(5000), @base;<br /><br />cmpthese(-1, { perl => sub { potencia_perl ($base[$_], $exp[$_]) for 0..$#base },<br /> perl2 => sub { potencia_perl2($base[$_], $exp[$_]) for 0..$#base },<br /> C => sub { potencia_C ($base[$_], $exp[$_]) for 0..$#base },<br /> C2 => sub { potencia_C2 ($base[$_], $exp[$_]) for 0..$#base } } );<br /><br />__END__<br /> ### alternativa en C <br />__C__<br />#include <br />double potencia_C( double base, int exp ) {<br /> double result = base;<br /> int p;<br /> for(p=1; p>= 1;<br /> base *= base;<br /> }<br /> return r;<br />}<br /><br />-------<br /><br />que resulta en...<br /><br /> Rate perl C perl2 C2<br />perl 1.96/s -- -85% -99% -100%<br />C 13.3/s 580% -- -91% -99%<br />perl2 142/s 7117% 961% -- -86%<br />C2 982/s 49961% 7262% 594% --Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1320528867223721914.post-80632927408917296052010-08-24T20:42:25.019+02:002010-08-24T20:42:25.019+02:00Gracias por tu comentario,
quisiera añadir que tam...Gracias por tu comentario,<br />quisiera añadir que también la forma de representar internamente los números afecta a la precisión numérica, como se demuestra en el ejemplo de <br />http://www.eead.csic.es/compbio/material/bioinfoPerl/node79.html <br /><br />Bruno<br /><br />Enlaces interesantes sobre esto:<br />http://docstore.mik.ua/orelly/perl/prog3/ch02_06.htm<br />http://perldoc.perl.org/perlnumber.html<br />http://stackoverflow.com/questions/2056681/does-scientific-notation-affect-perls-precisionbrunocontrerashttps://www.blogger.com/profile/06780659979139333360noreply@blogger.comtag:blogger.com,1999:blog-1320528867223721914.post-66902944450588470312010-08-24T19:54:13.730+02:002010-08-24T19:54:13.730+02:00Solo dos matices sobre el artículo. El primero es ...Solo dos matices sobre el artículo. El primero es sobre la precisión: no depende del lenguaje sino de las librerías matemáticas que ellos usan.<br /><br />Y segundo matiz, hay que indicar que la solución de integrar código C dentro de Perl, es, normalmente, para llamar a librerías externas o acelerar una parte del proceso que Perl lo hace de forma muy lenta, como es este caso.<br /><br />En concreto, y usando el módulo Benchmark, sale<br /><br /> Rate Perl (sub) C<br />Perl (sub) 3576/s -- -99%<br />C 384615/s 10656% --<br /><br />Sí: C es más de un 10.000% más rápido que Perl.<br /><br />Ahora bien... esto no siempre es cierto. Se pierde una cierta cantidad de tiempo entre el paso de parámetros, la llamada a la función y la recogida de los resultados. Y puede ser apreciable. Por ejemplo, si ejecutamos un benckmark con la función de exponenciación de Perl (**) nos quedaremos asombrados:<br /><br /> Rate Perl (sub) C Perl (**)<br />Perl (sub) 3584/s -- -99% -100%<br />C 389610/s 10772% -- -81%<br />Perl (**) 2093023/s 58305% 437% --<br /><br />Así que usando la propia función de exponenciación de Perl, el resultado es que es un 58.305% más rápida que la función potencia_Perl() y un 437% más rápida que la función potencia_C().<br /><br />Naturalmente, esto es solo un ejemplo. En la vida real sí que encontraremos muchos casos en los que sí merece la pena hacer un trabajo extra para rehacer una parte de nuestro programa en C. Usaremos los perfiladores (como Devel::NYTProf) para averiguar qué partes de nuestro programa son los más lentos.Anonymousnoreply@blogger.com