Los bucles no son equivalentes, y usted está principalmente golpeando el paquete bigint y no tiene nada que ver con for
vs for
per se.
El ciclo while usa la notación '$s *= $i
' pero el ciclo for usa '$s = $s * $i
'. Es lo suficientemente simple para demostrar que estos no son idénticos. Además, un ciclo cuenta hacia arriba; el otro cuenta hacia abajo. Esto afecta cuán grandes son los números que se multiplicarán. Es un efecto de segundo orden, pero no completamente despreciable.
[Actualización: revisada para mostrar solo una versión del código, con intervalos de segundos. Hay espacio para pensar que la impresión debe excluirse de los cálculos de tiempo; eso hace las cosas más desordenadas, así que no me molesté. He solucionado el error en la versión anterior: el bucle 4 era el mismo que el bucle 3; ahora no lo es. También introduje el formato de salida (aunque el manejo por debajo del segundo podría mejorarse, un ejercicio para el lector), y hay mejor "informe de progreso".]
Los resultados de sincronización en un Mac Mini (Snow Leopard 10.6.2) fueron:
Count up $s *= $i: 00:00:12.663337
Count up $s = $s * $i: 00:00:20.686111
Count down $s *= $i: 00:00:14.201797
Count down $s = $s * $i: 00:00:23.269874
El guión:
use Time::HiRes qw(gettimeofday);
use strict;
use warnings;
use bigint;
use constant factorial_of => 13000;
sub delta_t
{
my($tag, $t1, $t2) = @_;
my($d) = int($t2 - $t1);
my($f) = ($t2 - $t1) - $d;
my($s) = sprintf("%.6f", $f);
$s =~ s/^0//;
printf "%-25s %02d:%02d:%02d%s\n",
$tag, int($d/3600), int(($d % 3600)/60), int($d % 60), $s;
}
my $t1 = gettimeofday;
{
my $n = factorial_of;
my $s = 1;
for (my $i = 2; $i <= $n; $i++)
{
$s *= $i;
}
print "$s\n: Loop 1\n";
}
my $t2 = gettimeofday;
delta_t('Count up $s *= $i:', $t1, $t2);
{
my $n = factorial_of;
my $s = 1;
for (my $i = 2; $i <= $n; $i++)
{
$s = $s * $i;
}
print "$s\n: Loop 2\n";
}
my $t3 = gettimeofday;
delta_t('Count up $s *= $i:', $t1, $t2);
delta_t('Count up $s = $s * $i:', $t2, $t3);
{
my $n = factorial_of;
my $s = 1;
for (my $i = $n; $i > 1; $i--)
{
$s *= $i;
}
print "$s\n: Loop 3\n";
}
my $t4 = gettimeofday;
delta_t('Count up $s *= $i:', $t1, $t2);
delta_t('Count up $s = $s * $i:', $t2, $t3);
delta_t('Count down $s *= $i:', $t3, $t4);
{
my $n = factorial_of;
my $s = 1;
for (my $i = $n; $i > 1; $i--)
{
$s = $s * $i;
}
print "$s\n: Loop 4\n";
}
my $t5 = gettimeofday;
delta_t('Count up $s *= $i:', $t1, $t2);
delta_t('Count up $s = $s * $i:', $t2, $t3);
delta_t('Count down $s *= $i:', $t3, $t4);
delta_t('Count down $s = $s * $i:', $t4, $t5);
Y aquí es una versión mucho más compacta de el código anterior, extendido para probar bucles "while" así como bucles "for". También se ocupa de la mayoría de los problemas de sincronización. Lo único que no es ideal (para mí) es que utiliza un par de variables globales, y arrugué ligeramente el código en el código refs para que todo encaje en una línea sin activar una barra de desplazamiento (en mi pantalla, de todos modos) Claramente, con un poco más de trabajo, la prueba podría ser envuelta en una matriz, de modo que la prueba se haga de forma iterativa: un ciclo a través de la matriz que ejecuta la función de temporizador en la información en la matriz. Etc ...es un SMOP - Materia simple de programación. (Imprime el hash MD5 del factorial, en lugar del factorial en sí, porque es más fácil comparar los resultados, etc.) Señaló un par de errores ya que estaba refactorizando el código anterior. Sí, MD5 no es seguro. pero yo no lo estoy usando para la seguridad; sólo para detectar cambios involuntarios) checksum
use Time::HiRes qw(gettimeofday);
use Digest::MD5 qw(md5_hex);
use strict;
use warnings;
use bigint;
use constant factorial_of => 13000;
my ($s, $i);
my $l1 = sub {my($n) = @_; for ($i = 2; $i <= $n; $i++) { $s *= $i; }};
my $l2 = sub {my($n) = @_; for ($i = 2; $i <= $n; $i++) { $s = $s * $i; }};
my $l3 = sub {my($n) = @_; for ($i = $n; $i > 1; $i--) { $s *= $i; }};
my $l4 = sub {my($n) = @_; for ($i = $n; $i > 1; $i--) { $s = $s * $i; }};
my $l5 = sub {my($n) = @_; $i = 2; while ($i <= $n) { $s *= $i; $i++; }};
my $l6 = sub {my($n) = @_; $i = 2; while ($i <= $n) { $s = $s * $i; $i++; }};
my $l7 = sub {my($n) = @_; $i = $n; while ($i > 1) { $s *= $i; $i--; }};
my $l8 = sub {my($n) = @_; $i = $n; while ($i > 1) { $s = $s * $i; $i--; }};
sub timer
{
my($n, $code, $tag) = @_;
my $t1 = gettimeofday;
$s = 1;
&$code(factorial_of);
my $t2 = gettimeofday;
my $md5 = md5_hex($s);
printf "Loop %d: %-33s %09.6f (%s)\n", $n, $tag, $t2 - $t1, $md5;
}
my $count = 1;
timer($count++, $l1, 'for - Count up $s *= $i:');
timer($count++, $l2, 'for - Count up $s = $s * $i:');
timer($count++, $l3, 'for - Count down $s *= $i:');
timer($count++, $l4, 'for - Count down $s = $s * $i:');
timer($count++, $l5, 'while - Count up $s *= $i:');
timer($count++, $l6, 'while - Count up $s = $s * $i:');
timer($count++, $l7, 'while - Count down $s *= $i:');
timer($count++, $l8, 'while - Count down $s = $s * $i:');
Ejemplo de salida (MD5 comprimido para evitar los saltos de línea - el valor total es 584b3ab832577fd1390970043efc0ec8
):
Loop 1: for - Count up $s *= $i: 12.853630 (584b3ab8...3efc0ec8)
Loop 2: for - Count up $s = $s * $i: 20.854735 (584b3ab8...3efc0ec8)
Loop 3: for - Count down $s *= $i: 14.798155 (584b3ab8...3efc0ec8)
Loop 4: for - Count down $s = $s * $i: 23.699913 (584b3ab8...3efc0ec8)
Loop 5: while - Count up $s *= $i: 12.972428 (584b3ab8...3efc0ec8)
Loop 6: while - Count up $s = $s * $i: 21.192956 (584b3ab8...3efc0ec8)
Loop 7: while - Count down $s *= $i: 14.555620 (584b3ab8...3efc0ec8)
Loop 8: while - Count down $s = $s * $i: 23.790795 (584b3ab8...3efc0ec8)
I. consistentemente observa una pequeña penalización (< 1%) para el bucle 'while' sobre el correspondiente bucle 'for', pero no tengo una buena explicación para eso.
Probablemente esté tratando de optimizar lo incorrecto. Me pregunto por qué crees que esta parte del lenguaje en particular es tan importante. – Ether
Ejecútelos cada uno varias veces, y probablemente promedien aproximadamente el mismo – CaffGeek
@Chad, en realidad ya he probado el código un par de veces. Tomaron diferentes períodos de tiempo para terminar el mismo trabajo. Creo que la explicación de @Jonathan Leffler con el código de la ilustración tiene mucho sentido. – Mike