我在perl中解决this琐碎的spoj问题。所以我提出了这个解决方案:
while ("0 0 0\n" ne ($string = <STDIN>)) {
my @a = split ' ', $string;
$a1 = $a[0];
$a2 = $a[1];
$a3 = $a[2];
if($a2 - $a1 == $a3 - $a2) {
$c = $a2 - $a1;
$a4 = $a3 + $c;
print("AP ", $a4);
}
else {
$c = $a2 / $a1;
$a4 = $a3 * $c;
print("GP ", $a4);
}
print "\n";
}
令我惊讶的是,它超出了时间限制。当我在C中尝试相同的事情时,它以最小的运行时间成功运行。这是C版本:
#include <stdio.h>
int main()
{
int a1, a2, a3, a4, c;
while (1) {
scanf("%d %d %d", &a1, &a2, &a3);
if (a1 == 0 && a2 == 0 && a3 == 0) break;
if (a2 - a1 == a3 - a2) {
c = a2 - a1;
a4 = a3 + c;
printf("AP %d\n", a4);
}
else {
c = a2 / a1;
a4 = a3 * c;
printf("GP %d\n", a4);
}
}
return 0;
}
那么,请你告诉我:
在遇到这个问题时,perl真的比C慢了多少(至少200倍)吗?我怀疑它与输入和高级结构(如使用的数组)有关,或者我的代码中有一个错误导致程序停止。
答案 0 :(得分:6)
您的基准测试存在各种问题:
但最重要的是:
你做的计算绝对便宜,最昂贵的部分是读取和扫描输入。与最高级别的PerlIO系统相比,最小C的速度更快,这并不奇怪。
你没有意识到的另一件事是Perl是解释语言,而C通常是编译的。在Perl的情况下,实际上有一个C程序查看某些数据结构(操作码),并根据某些标志进行加法,乘法,分支或比较。 Perl变量是标量,实际上是SV*
- 指向SV结构的指针。这些结构比int
大得多。每次执行Perl程序时,perl
解释器都会将整个源代码解析并编译为操作码。
C编译为比操作码更有效的机器代码。这是在执行之前完成的,因此编译时间不会考虑到此基准测试中。由于这个原因,启动速度会更快。可以优化C以使用寄存器而不是堆上的位置,这使得像int
这样的简单数据结构更快。 C标准库中的IO系统比Perl具有的复杂系统(解码层,缓冲)要简单得多。总而言之,C的间接水平低于Perl。
因为perl是一个C程序,所以这些级别的间接使Perl慢100倍。数学繁重基准的差距越大(SV比整数更昂贵),但对index
和正则表达式等字符串运算更接近。
对于记录,这是Perl代码的惯用版本。不,它不会跑得更快。
while (<>) {
last if $_ eq "0 0 0\n";
my ($a1, $a2, $a3) = split;
if($a2 - $a1 == $a3 - $a2) {
my $a4 = $a3 + $a2 - $a1;
print "AP $a4\n";
}
else {
my $a4 = $a3 * $a2 / $a1;
print "GP $a4\n";
}
}