有人可以在Perl中逐步解释这段代码:
$.=.5;
$\=2/$.++-$\for$...1e6;
print
答案 0 :(得分:11)
添加空格:
$. = .5;
$\ = (2 / $.++) - $\ for $. .. 1e6;
用saner 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
维基百科中的listed为Gregory-Leibniz系列。
print;
是print($_);
,它打印$_
(未使用,因此undef,其字符串化为空字符串)后跟$\
(通常为空字符串,但是在原始代码中用作累加器。)
答案 1 :(得分:2)
让我们首先将代码分解为具有一些空白区域的可读性。在Perl中,空白区域相对不重要。
$. = .5;
$\ = 2 / $.++ - $\ for $. .. 1e6;
print
此代码利用Perl特有的内置全局变量使事情变得简短(man perlvar
,以获取有关此代码使用的特定变量的更多详细信息)。让我们用可读的名称替换它们,使它更具可读性。
$denominator = .5;
$pi = 2 / $denominator++ - $pi for $denominator .. 1e6
print $pi
只是为了帮助,让我们将内联循环移动到一个更详细的循环中。
$denominator = .5;
foreach my $i ($denominator .. 1e6) {
$pi = 2 / $denominator - $pi;
$denominator += 1;
}
print $pi
因此,这使得解密变得容易一些,并且它是用于计算pi的标准收敛例程。有一些different ones,但基本上,如果你单步执行它,你会看到它收敛到着名的3.14159 ......分母可以用作序列发生器的第一个元素,因为它会floor到整数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
本身将打印$_
,默认变量为空。 pi的值将在$\
值中,该值实际上是行结束,因此它打印出一个空白值,后跟pi的计算值(没有传统的行结束)。
答案 2 :(得分:1)
my $pi = 0;
for (my $i=0.5; $i < 1e6+1; $i++)
{
$pi=2/$i - $pi;
}
print $pi."\n";
的数学表示
原始版本使用一些Perl special variables来混淆您。 $.
在这里完全没有必要,纯粹是为了混淆。 $\
是输出记录分隔符。这意味着此变量将在print
语句后附加。因此,最后的单个print
只打印存储在$\
中的计算结果。最后,代码使用了一个后修复for
循环和..
运算符,而不是我的版本中更明确的for循环。我希望能稍微澄清一下。
答案 3 :(得分:0)
这可以改写为:
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的回答)