誰かがPerlでこのコードを段階的に説明できますか:
$.=.5;
$\=2/$.++-$\for$...1e6;
print
空白を追加します。
$. = .5;
$\ = (2 / $.++) - $\ for $. .. 1e6;
saner var名に置き換えます:
$x = .5;
$pi = (2 / $x++) - $pi for $x .. 1e6;
2つの目的で同じ変数を使用しないでください。
$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
これは、ウィキペディアにグレゴリー-ライプニッツシリーズとしてリストされています。
print;
isはprint($_);
、$_
(未使用、つまりundef、空の文字列に文字列化)の後に$\
(通常は空の文字列ですが、元のコードではアキュムレータとして使用されます)を出力します。
まず、コードをより読みやすいものに分解し、空白を追加することから始めましょう。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
したがって、これにより解読が少し簡単になり、円周率を計算するための標準的な収束ルーチンになります。いくつかの異なるものがありますが、基本的に、それをステップ実行すると、有名な 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
それ自体では$_
、デフォルトの変数である が出力されますが、これは空になります。pi の値は$\
、実質的に行末となる値に含まれるため、空白の値の後に計算された pi の値が出力されます (従来の行末はありません)。
うわー、それは美しさです。誰かがそれを可能な限り複雑に見せようとしていました. より読みやすいバージョンは次のとおりです。
my $pi = 0;
for (my $i=0.5; $i < 1e6+1; $i++)
{
$pi=2/$i - $pi;
}
print $pi."\n";
元のバージョンでは、いくつかのPerl 特殊変数を使用して混乱させています。ここ$.
では完全に不必要であり、純粋に難読化のためです。は$\
、出力レコード セパレータです。つまり、この変数はprint
ステートメントの後に追加されます。したがって、print
最後のシングルは、 に格納された計算結果を単純に出力し$\
ます。最後に、コードは、私のバージョンのより明示的な for ループの代わりに、post-fixfor
ループと..
演算子を使用します。これで少しは問題が解決することを願っています。
これは次のように書き換えることができます。
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 の回答を参照)。