Perl
Biraz rekabete aykırı olmaya karar verdim ve bu tür bir sorunu Perl'de normalde nasıl kodlayacağınızı gösterdim.
Ayrıca sonunda 46 (toplam) karakter kodu-golf girişi vardır.
Bu ilk üç örneğin tümü bu başlık ile başlar.
#! /usr/bin/env perl
use Modern::Perl;
# which is the same as these three lines:
# use 5.10.0;
# use strict;
# use warnings;
while( <> ){
chomp;
last unless $_;
Collatz( $_ );
}
Basit özyinelemeli sürüm
use Sub::Call::Recur;
sub Collatz{
my( $n ) = @_;
$n += 0; # ensure that it is numeric
die 'invalid value' unless $n > 0;
die 'Integer values only' unless $n == int $n;
say $n;
given( $n ){
when( 1 ){}
when( $_ % 2 != 0 ){ # odd
recur( 3 * $n + 1 );
}
default{ # even
recur( $n / 2 );
}
}
}
Basit yinelemeli sürüm
sub Collatz{
my( $n ) = @_;
$n += 0; # ensure that it is numeric
die 'invalid value' unless $n > 0;
die 'Integer values only' unless $n == int $n;
say $n;
while( $n > 1 ){
if( $n % 2 ){ # odd
$n = 3 * $n + 1;
} else { #even
$n = $n / 2;
}
say $n;
}
}
Optimize edilmiş yinelemeli sürüm
sub Collatz{
my( $n ) = @_;
$n += 0; # ensure that it is numeric
die 'invalid value' unless $n > 0;
die 'Integer values only' unless $n == int $n;
#
state @next;
$next[1] //= 0; # sets $next[1] to 0 if it is undefined
#
# fill out @next until we get to a value we've already worked on
until( defined $next[$n] ){
say $n;
#
if( $n % 2 ){ # odd
$next[$n] = 3 * $n + 1;
} else { # even
$next[$n] = $n / 2;
}
#
$n = $next[$n];
}
say $n;
# finish running until we get to 1
say $n while $n = $next[$n];
}
Şimdi bu son örneği Perl'in v5.10.0'dan önceki bir sürümüyle nasıl yapacağınızı göstereceğim.
#! /usr/bin/env perl
use strict;
use warnings;
while( <> ){
chomp;
last unless $_;
Collatz( $_ );
}
{
my @next = (0,0); # essentially the same as a state variable
sub Collatz{
my( $n ) = @_;
$n += 0; # ensure that it is numeric
die 'invalid value' unless $n > 0;
# fill out @next until we get to a value we've already worked on
until( $n == 1 or defined $next[$n] ){
print $n, "\n";
if( $n % 2 ){ # odd
$next[$n] = 3 * $n + 1;
} else { # even
$next[$n] = $n / 2;
}
$n = $next[$n];
}
print $n, "\n";
# finish running until we get to 1
print $n, "\n" while $n = $next[$n];
}
}
Kıyaslama
İlk olarak IO her zaman yavaş olan kısım olacak. Dolayısıyla, onları olduğu gibi değerlendirdiyseniz, her birinden yaklaşık aynı hızı almalısınız.
Daha sonra bunları test etmek için, /dev/null
( $null
) için bir dosya tanıtıcısı açtım ve say $n
bunun yerine okumak için her şeyi düzenledim say {$null} $n
. Bu, IO'ya olan bağımlılığı azaltmak içindir.
#! /usr/bin/env perl
use Modern::Perl;
use autodie;
open our $null, '>', '/dev/null';
use Benchmark qw':all';
cmpthese( -10,
{
Recursive => sub{ Collatz_r( 31 ) },
Iterative => sub{ Collatz_i( 31 ) },
Optimized => sub{ Collatz_o( 31 ) },
});
sub Collatz_r{
...
say {$null} $n;
...
}
sub Collatz_i{
...
say {$null} $n;
...
}
sub Collatz_o{
...
say {$null} $n;
...
}
10 kez çalıştırdıktan sonra, işte temsili bir örnek çıktı:
Yinelemeli Yinelemeli Optimize Edilmiş Oranı
Yinelemeli 1715 / sn - -% 27 -% 46
Yinelemeli 2336 / sn% 36 - -% 27
Optimize edilmiş 3187 / s 86% 36% -
Son olarak, gerçek bir kod-golf girişi:
perl -nlE'say;say$_=$_%2?3*$_+1:$_/2while$_>1'
Toplam 46 karakter
Başlangıç değerini yazdırmanız gerekmiyorsa, 5 karakter daha kaldırabilirsiniz.
perl -nE'say$_=$_%2?3*$_+1:$_/2while$_>1'
Gerçek kod bölümü için 41 karakter toplam
31 karakter, ancak kod -n
anahtar olmadan çalışmayacaktır . Bu yüzden sayıma tüm örneği dahil ediyorum.