[ 0081: 棒投げで何がわかる? ]
[ 千手春弥さんの出題 ]
青天中学の三方 (= 算法 = アルゴリズム) 先生が校庭に生徒たちを集め、
3 本 の長い平行線を引きました。
それぞれの間隔は 1 メートル。
先生はそれから長さ 2 メートル の棒を持ってきました。
「みんな、順番に目をつぶって中央の線を目がけて棒を投げてごらん」
「棒の中点が外側の 2 本 の線内にはいらなかった場合は無視」
「それ以外の場合の総試行数と棒が中央の線にかかった場合だ」
「それらを数えて何になるんですか?」
「充分な回数やると面白いことがわかる」
さて、先生は何を教えようとしているのでしょう?
[ 広世正憲君の回答 ]
3 本の線はX方向に走っているとし、中央の線は Y = 0、外側の2本の線は
それぞれ Y = -1、 Y = 1 とします。X は度外視できます。
棒が地面に落ちたときの中点の Y 座標を y とし、
中点を中心にした棒の角度を θ とします。
(極座標みたいな感じ)
そうすると、棒が中央の線とクロスする必要十分条件は:
y が y = -sin(θ) と y = sin(θ) の2曲線の間(境界線も含む)に落ちること。
この領域は当然θ軸にもy軸にも対称になります。
面積で代用してみましょう。
N |
ノーカウントを除外した総トライアル数 |
n |
棒と中央線のクロスが生じる回数 |
N は、 θ が -π から π、y が -1 から 1 の範囲の長方形ですので、
仮想的な面積は 2*π * 2 = 4*π
一方 n は定積分から 2 * 4 = 8 です。
したがって: n/N = 2/π
(円周率 π が出てきます。)
多数回試行して n/N の統計 (約 0.6366) をとって逆数にし
2 を掛ければ円周率が求まります。
これが三方万理先生の狙いでしょう。
多絵さん、乱数を使ったシミュレーションのプログラムを作って実行してみてください。
N がいくらぐらいで 3.142 に近づくか。
[ 西尾三奈さんのコメント ]
正憲くん、すごい。私が中学生の頃はこんなこと思いつかなかったわ。
友達を集めて大学のグラウンドでやってみようかな。 (笑)
千手さんの問題の作りかたも面白いですね。奇手あり妙手あり。手がいっぱい。
湯会老人の影響かしら。
[ 大宙乗児君のコメント ]
なるほど。
(y = 0 のときを除いて) θ が 0 とか ±π だと、どうあがいてもアウトになるんだなあ。
y = 0 で θ が 0 または ±π の場合は、
棒がたまたま中央の線にピッタリ重なるように落ちたことを意味しますね。
それにしても統計から三角関数の式に持ち込んで円周率を計算するというのは美しすぎる。
[ 湯会老人のコメント ]
正憲君の書いてくれた回答に補足します。縦方向は y ですが、
横方向は x 軸ではなく θ 軸 です。
たとえば y の位置が y=a という値だったとき、y=a という直線 (θ軸に平行) が
有効範囲(2つの sin曲線 ではさまれた領域)を切るイメージを考えてください。
a が 0 を離れるにしたがってクロスと判定される θ の範囲は狭まってきます。
棒が y 方向に立ってくるわけです。
a が -1 より小さくなる、あるいは 1 より大きくなる場合はノーカウントになります。
a が -1 <= a <=1 の場合は θ しだいです。
[ 浅見多絵さんのコメント ]
私は簡単な Perl スクリプトで sin 関数を使ってやってみました。
角度 (θ: theta) の単位としてラディアン (radian) を使う必要上、
円周率を求めるスクリプトの中に円周率自身が出てくるのは、まあいいか。
収束が遅いですね。生徒たち、疲れてしまいます。
N | n | 円周率近似値 |
10 | 6 | 3.3333 |
50 | 31 | 3.2258 |
100 | 62 | 3.2258 |
500 | 328 | 3.0488 |
1000 | 640 | 3.1250 |
5000 | 3181 | 3.1437 |
10000 | 6383 | 3.1333 |
50000 | 31915 | 3.1333 |
100000 | 63537 | 3.1478 |
ソースコードは以下のとおりです。
#!/usr/local/bin/perl
use Math::Trig; # 三角関数を使う。
$N = 100000;
$n = 0;
for ($i=1; $i<=$N; $i++) {
$y = rand(1) * 2.0 - 1.0;
$phi = rand(1) * 2.0 * pi;
$n++ if (($y - abs(sin($phi))) *
($y + abs(sin($phi))) <= 0);
}
printf ("N: %6d n: %6d pi: %6.4f\n",
$N, $n, $N*2.0/$n);
# ■ $N: 総試行数。ノーカウントははじめから除外。
# ■ $n: 何らかの形で棒が中央線にかかった場合のカウント。
| |
|