2

誰かがPerlでこのコードを段階的に説明できますか:

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

4 に答える 4

11

空白を追加します。

$. = .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、空の文字列に文字列化)の後に$\(通常は空の文字列ですが、元のコードではアキュムレータとして使用されます)を出力します。

于 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

したがって、これにより解読が少し簡単になり、円周率を計算するための標準的な収束ルーチンになります。いくつかの異なるものがありますが、基本的に、それをステップ実行すると、有名な 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 の値が出力されます (従来の行末はありません)。

于 2013-02-02T23:36:24.177 に答える
1

うわー、それは美しさです。誰かがそれを可能な限り複雑に見せようとしていました. より読みやすいバージョンは次のとおりです。

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ループと..演算子を使用します。これで少しは問題が解決することを願っています。

于 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 に答える