这是一个讨论从HN thread移到这里,关于使用实现Sieve of Sundaram查找素数的算法对Perl6与Perl5进行基准比较。
这是原始帖子中的原始代码:
perl5 0m0.156s
perl6 0m6.615s
与Perl5实现相比,问题在于Perl6版本需要很长时间才能找到素数。部分原因是使用浮动作为输入,但仍然太慢了。
目标不一定是优化算法,而是确定Perl6与其他语言相比如此之慢的原因。
答案 0 :(得分:13)
事实证明即使素数是整数,在你的Perl 6版本中,每个计算都是通过使用浮点来完成的。这是由对子程序的调用引起的。如果你愿意的话:
sieve_sundaram(1000)
而不是:
sieve_sundaram(1e3)
然后它突然变得快4倍。在Perl 5中,你永远不会知道你在处理价值方面做了什么。在Perl 6中,如果你告诉它使用一个浮点,那么它将在之后感染所有计算。 1e3
是浮点值。 1000
是Perl 6中的整数。
此外,您似乎有一个次优算法:第二个foreach
不需要从1..$n
开始,但可以从$i..$n
转而来。这将Perl 5版本代码的运行时间缩短为89毫秒。
由于您的程序在Perl 5版本中没有使用BigInt,因此它基本上使用本机整数。在Perl 6中,除非将它们标记为本机,否则所有整数计算都是BigInts。如果我为此调整你的Perl 6版本,那么这个版本的运行时间从4671毫秒下降到414毫秒:
sub sieve_sundaram(int $n) {
my %a;
my int @s = 2;
my int $m = $n div 2 - 1;
for 1..$n -> int $i {
for $i..$n -> int $j {
my int $p = $i + $j + 2 * $i * $j;
if $p < $m {
%a{$p} = True;
}
}
}
for 1..$m -> int $k {
if ! %a{$k} {
my int $q = 2 * $k + 1;
@s.push($q);
}
}
return @s;
}
sieve_sundaram(1000);
所以,比以前快了大约11倍。而且速度只有Perl 5版本的5倍。
在Perl 6中获得素数的最惯用的版本是:
(1..1000).grep( *.is-prime )
对我来说,在原始Perl 5算法的噪声中执行。对于多CPU机器上的较大值,我将其写为:
(1..2500).hyper.grep( *.is-prime )
大约2500它变得更快hyper
它,因此工作自动分布在多个CPU上。
答案 1 :(得分:6)
我认为我可以为Liz所说的更多补充。除了:
&#34;但为了对多种语言进行基准测试,我需要运行相同的语言 到处都是#34;
...其中&#34;相同&#34;在英语中被定义为类似的语法,是一个非常差异的标准,用于完全不同的编程语言之间的等价。 Perl 6与Perl 5具有非常相似甚至相同的语法,同时在下面执行非常不同的语义。整个语言已被调整为正确性,默认容易达到语法,而不是最佳行为。另一个很好的例子是Perl 6字符串,它们非常慢,它们总是完全规范化的unicode而不是一串普通的字节。对它们的所有操作都考虑了字形的unicode概念,而不是字节和字节偏移。哪个好极了!但是,对于C / Perl 5字符串来说,更等效的类型可能是Buf
,遗憾的是它并没有像字符串一样多的运算符/方法,但只是一个字节块。