2

有人可以在 Perl 中逐步解释这段代码:

$.=.5;
$\=2/$.++-$\for$...1e6;
print
4

4 回答 4

11

添加空格:

$. = .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) 后跟$\(通常是空字符串,但在原始代码中用作累加器)。

于 2013-02-02T23:25:11.157 回答
2

让我们首先将代码分解成一些更易读的东西,并带有一些空格。空白在 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 值(不是传统的行尾)。

于 2013-02-02T23:36:24.177 回答
1

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.

于 2013-02-03T00:10:02.320 回答
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 的回答)

于 2013-02-02T23:31:14.940 回答