有人可以在 Perl 中逐步解释这段代码:
$.=.5;
$\=2/$.++-$\for$...1e6;
print
添加空格:
$. = .5;
$\ = (2 / $.++) - $\ for $. .. 1e6;
用更健全的 var 名称替换:
$x = .5;
$pi = (2 / $x++) - $pi for $x .. 1e6;
不要将相同的 var 用于两个目的:
$x = .5;
$pi = (2 / $x++) - $pi for 0 .. 1e6;
转换为公式:
pi = 2/1000000.5 - ( ... - (2/2.5 - (2/1.5 - (2/0.5))))
= 2/1000000.5 - ... + 2/2.5 - 2/1.5 + 2/0.5
= 4/2000001 - ... + 4/5 - 4/3 + 4/1
= 4/1 - 4/3 + 4/5 - ... + 4/2000001
在 Wikipedia 中被列为Gregory-Leibniz 系列。
print;
is print($_);
,打印$_
(unused, so undef, stringifying to empty string) 后跟$\
(通常是空字符串,但在原始代码中用作累加器)。
让我们首先将代码分解成一些更易读的东西,并带有一些空格。空白在 Perl 中相对不重要。
$. = .5;
$\ = 2 / $.++ - $\ for $. .. 1e6;
print
此代码使用 Perl 的特殊内置全局变量来使事情看起来很短(man perlvar
有关此代码使用的特定变量的更多详细信息)。让我们通过将它们替换为人类可读的名称来使其更具可读性。
$denominator = .5;
$pi = 2 / $denominator++ - $pi for $denominator .. 1e6
print $pi
为了提供帮助,让我们将内联 for 循环移动到更详细的循环中。
$denominator = .5;
foreach my $i ($denominator .. 1e6) {
$pi = 2 / $denominator - $pi;
$denominator += 1;
}
print $pi
因此,这使得它更容易破译,并且它是计算 pi 的标准收敛例程。有许多不同的,但基本上,如果你单步执行,你会看到它收敛到著名的 3.14159... 分母可以用作序列生成器的第一个元素,因为它会下降到整数 0。
Pass 1: 2 / 0.5 - 0 = 4
Pass 2: 2 / 1.5 - 4 = -2.666...
Pass 3: 2 / 2.5 - (-2.666...) = 3.4666...
Pass 4: 2 / 3.5 - 3.4666... = -2.895...
Pass 5: 2 / 4.5 - (-2.895...) = 3.339...
你明白了。代码运行 1,000,001 次,以达到最终的近似值。只要它运行奇数个近似值,它就应该收敛到 pi(偶数个近似值收敛到负 pi)。
print 语句起作用的原因$\
是输出记录分隔符。 print
它本身将 print $_
,默认变量,将为空。pi 的值将在$\
value 中,这实际上是行尾,因此它会打印出一个空白值,然后是计算出的 pi 值(不是传统的行尾)。
Wow, that's a beauty. Someone was trying to make that look as convoluted as possible. Here's a more readable version:
my $pi = 0;
for (my $i=0.5; $i < 1e6+1; $i++)
{
$pi=2/$i - $pi;
}
print $pi."\n";
This is the mathematical representation of the Gregory-Leibnitz Formula
The original version uses a few Perl special variables to confuse you. The $.
is entirely unnecessary here and purely for obfuscation. The $\
is the output record separator. That means this variable will be appended after a print
statement. Therefore, the single print
at the end simply prints the result of the calculation that was stored in $\
. Finally, the code uses a post-fix for
loop and the ..
operator instead of the more explicit for loop in my version. I hope that clears things up a bit.
这可以重写为:
use strict;
use warnings;
my $divisor = 0.5;
my $pi = 0;
for my $i (0..1e6)
{
$pi = 2 / $divisor++ - $pi
}
print "$pi\n";
所以它使用一些数学级数展开来计算 pi(参见@ikegami 的回答)