質問<3356>2006/9/2
from=なべちゃん
「少なくとも1つ以上ペアができる確率は?」


正14面体のサイコロがあったと仮定する。
サイコロの各面には整数が記してあり、それは以下の通りである。
「1」~「7」が1個ずつ、「8」と「9」は2個ずつ、「10」は3個
このサイコロを6個用意し、同時に振り出した場合、少なくとも1組以上、
同じ数字のペアができる確率を以下の場合で求めよ。
(1)6個のサイコロを同じ色で準備した場合(サイコロを区別しない場合)
(2)6個のサイコロを色違いで準備した場合(サイコロを区別する場合)

正14面体のサイコロなど存在しませんが、例えで表現しています。
どうぞよろしくお願いします。

★完全解答希望★

お便り2006/11/8
from=亀田馬志


う~~ん・・・・・この問題メンドくさそうですねえ。
まあ、未解決問題化するよかだったら、どんな形であれ、解いた方がいいかもしれません。
と言うわけで、アクロバットな解き方を示唆します。
どうやるか、と言うと、実際そのサイコロを作って実験してしまうのです。
1万回もふれば答えが分かるかな(笑)?

「冗談言うな!!!」

とか思うかもしれませんが、マジです(笑)。本気と書いて「マジ」と読みます(笑)。
とは言っても、これはある意味、応用数学の範疇では良く行われています。
そう言う意味ではそれほど「アクロバットな」方法論でもありません。
その名も「モンテカルロ法」と言います。

「モンテカルロ法」とは第2次世界大戦で、数学者フォン・ノイマン博士を中心とした科学者の
グループがマンハッタン計画で行った、コンピュータを用いた乱数シミュレーションに端を発
する方法論です。まあ、数学者中心で作ったんで、そう言う意味では別に「高校"数学"の窓」
ともそんなに乖離していない筈です。多分(笑)。
ここではフリーの数値演算ソフトウェアOctaveWorkshopを利用して
初歩的なプログラミングを学びながら問題を解いていこうと思います。OctaveWorkshopはそんなに
難しいソフトではありませんし、手軽にプログラムを書けるので、最初に覚えるプログラム言語
としてはそんなに悪くない選択でしょう。内蔵されている数学関数も豊富ですし、実際、世界中
の大学で愛用されている実績があります。そんなワケで、今後の事(例えば大学進学とか、研究職
に就く)を考えても、ワリと応用が利く選択なんじゃないか、と思います。

なお、(2)の問題は意味が分からないので割愛します(と言うのも、色分けしたら数字が少なくとも
一つは一致する、と言うのが意味の無い設定だと思ったからです。他に条件ありませんか?)。

ではOctaveWorkshopをクリックしたらダウンロードが開始されると思うので、指示に従って、
暫く待ってください。(無料のソフトなんで気にしないように)
ダウンロードが終了したらデスクトップ上にOctaveWorkshopのアイコンが出来てるハズです。
それをダブルクリックしてOctaveWorkshopを起動して下さい。(ちょっと起動まで時間が掛かるかも
しれませんが、気長に待つように)

さて、OctaveWorkshopが起動すると、
3分割にされた作業スペースが出てきます。実際使用するスペースの1/3くらいは右のスペースだけです。
ここで「計算(プログラム)」を実行します。左半分のスペースに付いては忘れて下さい(笑)。

もう一つ基本的に覚えておく事は、プログラムを書く為の「エディタ」に付いて、です。これは左上に
「File」ってプルダウンメニューがありますから、ここから「New」を選択すると、新規の「エディタ」が
立ち上がります。まあ、エディタは「メモ帳」みたいなものなんで、味もそっけも無いものですが、ここに
今から色々なプログラムを書いていくのです。取り合えずエディタを立ち上げておいてください。

まずはこのエディタを使って、

>サイコロの各面には整数が記してあり、それは以下の通りである。
>「1」~「7」が1個ずつ、「8」と「9」は2個ずつ、「10」は3個

と言うヘンテコリンな正14面体のサイコロを記述してみましょう。
これがOctaveWorkshopで最初に書くプログラムなので、取り合えずは次のプログラムを丸写しでも
いいからエディタに書き込んで下さい。解説は後に就けます。なお「%」以降は「コメント」と言って、
これは直接にはプログラムの実行内容に関係ありません。単に人間が読んだ時に「何をやってるのか?」
分かりやすくする為に書かれたものです。

 function y = dice()   %diceと言うプログラムを設定
  x = unifrnd(0, 14);  %一様乱数を0~14の範囲で発生
   if (x <= 1)           %サイコロの面の条件分け
     men = 1;
   elseif (x > 1 && x <= 2)
     men = 2;
   elseif (x > 2 && x <= 3)
     men = 3;
   elseif (x > 3 && x <= 4)
     men = 4;
   elseif (x > 4 && x <= 5)
     men = 5;
   elseif (x > 5 && x <= 6)
     men = 6;
   elseif (x > 6 && x <= 7)
     men = 7;
   elseif (x > 7 && x <= 9)
     men = 8;
   elseif (x > 9 && x <= 11)
     men = 9;
   else
     men = 10;
   endif                   %条件分け終了
  y = men;                %返り値

これが最初に書くべきプログラム「dice」です。
では内訳を説明しながらOctaveWorkshopでのプログラムの基本を学んで頂きましょう。

①プログラムの最初は必ず

 function y = 関数名(引数)

で書き始める。

OctaveWorkshopで書かれたプログラムは関数(function)と言います。
従って、最初に「これはfunction(関数)です」と宣言しなければなりません。
次に返り値(最終的に計算結果として返す値)を記述します。これはここではyと指定していますが、
別にzだろうと何だろうと構いません。ただし、プログラムの最終行の返り値の指定文字と同じでなければ
ならない事だけは把握しておいてください。
次に関数名(引数)を指定します。関数名は何でも構いません。ここではdice(サイコロの意)と言う名前に
しました。なお、引数とは、プログラム実行時にプログラム外部から入力したい数を指定する部分ですが、
取り合えずこのプログラム「dice」には関係ないので、()のままにしておきます。

②x = unifrnd(0, 14);

xに一様乱数で発生させた値を代入せよ、と言った意味。
なお、このように計算実行に関係ある部分の最後はセミコロン(;)を置いておけばいいです(別に必須って
ワケではないですが、セミコロンを置かないと、プログラム実行時に凄い事になります・笑)。

③一様乱数関数unifrnd(a, b)

unifrnd(a, b)と言うのがOctaveWorkshopでの一様乱数の関数です。
unifrndと言う字面自体は、英語の「一様乱数」(Uniform Random Number)に由来しています。
なお、a、b、がa以上b以下の一様乱数を発生せよ、と言った指定(引数)となります。

④条件設定1

OctaveWorkshopでは、条件設定の基本構文は

 if (条件)~endif

で挟みます。これが基本構文です。
条件が1つのばあいは

 if (条件)
   計算内容
 endif

条件が2つの場合は、

 if (条件①)
   計算内容①
 else
   計算内容②
 endif

条件が3つ以上の場合は
 if (条件①)
   計算内容①
 elseif (条件②)
   計算内容②
 else
   計算内容③
 endif

となります。
今回は14面体のサイコロを作るので、3番目の構文ですね。
elseifの使い方に注目して下さい。

⑤条件設定2

if~endifでの条件設定は()の中身に書き込みます。
書き方は基本的には数学で行う「~以上、~以下」の表記と同じ書き方です。
ただし、不等号で=を含む書き方は「<=」とか「>=」等と書きます。
それと「かつ」ですが、OctaveWorkshopでは「&&」と表記します。
他にも特殊なOctaveWorkshop用の「数学記号」の置き換えがありますが、ここでは割愛します。

⑥men

menは「面」の事です。これも文字式なんで、自由に設定が可能で、かつ、ここが④の「計算内容」にあたり
ます。結果、例えば

   if (x <= 1)
     men = 1;

と言うのは、日本語に直せば

 もし、x(一様乱数の値)が1以下だったら、「面」を1とせよ。

と言う事を言っているのです。
これはまさしく「サイコロを振って、目がいくつなのか」を記述しているのです。

⑦返り値

プログラムの最後は返り値で締めくくります。
diceと言うプログラムでは、最終的にどの目が出るのかはさておき、

「サイコロを振った結果」

を示さねばなりません。つまり、これが「返り値」として設定されなければなりません。
プログラムの最初で

 function y

と宣言しているので、最後の代入に使う文字はyでないとならない、と言うのが約束です。
そして、サイコロの目が何かは分かりませんが、変数menがその代入すべき数となります。
よって締めくくりは

 y = men;

となるのです。

さて、以上のプログラムをエディタで書けばプログラムdiceは完成です。まずはこれをsaveしちゃいましょう。
エディタの左上部に「File」と言うプルダウンメニューがあります。ここで

Save as

を選択します。そうするとSave Fileと言うポップアップが表れるハズです。そして「保存する場所」を訊いて
きます。ここが大事です。
OctaveWorkshopでは、こうやってプログラムを記述したファイルを特に「Mファイル」と呼ぶのですが、
このMファイルはどこにsaveしても簡単にOctaveWorkshopから自由に呼び出せるような設計には
なっていません。しかるべき場所にSaveしなければならないのです。
Save Fileと言うポップアップが表れた時、初期に示されているフォルダは「octave-workshop」と書かれた
ソフトウェア本体がインストールされているフォルダなんですが、ここからスタートして、

octave.workshop→msys→octave-2.9.4→share→octave→2.9.4→m

とどんどんフォルダをクリックしていって、「m」フォルダの中にSaveして下さい。6階層先のフォルダ内
(専門的にはディレクトリと呼ぶ)なんですが、mファイルを作ったら必ずココにSaveするように心がけてく
ださい。なお、現在作ったdiceと言うプログラムですが、ファイルの名前は拡張子が見えていれば、自動で
「dice.m」と言う名前になっていると思うので、そのまま名前は弄らずにSaveすれば完了です。Saveし
終わったらプログラムを記述したエディタは閉じて結構です。取りあえずどんなプログラムなのか見て
みましょう。
OctaveWorkshop本体の右側のウィンドでプログラムを呼び出して実行する事が出来ます。
そこにはプロンプト

>

が表示されていると思うので、次のように入力してみて、

>dice()

そしてリターンキーを押してください。数が返ってきますよね?これが問題文にある「14面体のサイコロ」
です。(ひょっとしたらm.fileをSaveしたばかりだと認識してくれないケースがあります。その場合は
あわてないで、一回OctaveWorkshopを閉じてソフトを再起動して下さい。
そうすれば実行されます。)
何度か

dice()

を実行して、実際サイコロを転がしてみてください。面白いと思いますよ。

さて、diceと言う14面体のサイコロを実現したプログラムを書きましたが、これだけじゃあまだまだですし、
とても「モンテカルロ法」とは呼べません。そこで、今作成した「dice」を利用して次は具体的な
「モンテカルロ法」の為のプログラムを書いてみましょう。新しく「dicemontecarlo」と言うプログラムを
作ります。
OctaveWorkshopや、他のプログラミング言語でも大体そうだとは思うんですけど、プログラムを作る際、
「全部の過程を記述する」必要は全然無くって、別に作った関数(プログラム)をあるプログラムで呼び出して
実行させる事が出来るのです。つまり、「dicemontecarlo」と言うプログラムは先ほど作った「dice」を
呼び出して実行するプログラムなんですね。
問題文の

>サイコロを6個用意し、同時に振り出した場合、少なくとも1組以上、
>同じ数字のペアができる確率

は実際にそのサイコロを1万回も振れば「大数の法則」に従って、殆ど正確にその値を知る事が出来ます。
が、実際に人間が1万回もサイコロを振るのはメンド臭いワケです。実際、例えばコイン投げなんかでは、
昔のベルヌーイと言う偉い数学者は何万回も投げて実験したようですが、我々のような凡人は・・・・・・
やりたくないですよね(笑)。
そこで代わりにコンピュータにやらせるのです。そうすればコンピュータはプログラム(指令)に従って、
ドラマの中の草薙剛クンよろしく馬鹿正直に
1万回サイコロを投げて結果を知らせてくれるのです。
てな与太はさておき、実際プログラムを書いてみましょうか。エディタを開いて次のように記述して下さい。

 function y = dicemontecarlo(n) %dicemontecarloと言うプログラムを設定
  count = 0;             %カウンターを0にする
   for i = 1:n             %ループ開始
     a = dice();           %サイコロを6個用意
     b = dice();
     c = dice();
     d = dice();
     f = dice();
     g = dice();
      if (a ~= b && b ~= c && c ~= d && d ~= f && f ~= g && g ~= a)%条件設定
      count = count + 1;    %条件に見合えばカウンターに1を足す
      else               %それ以外の場合
        count = count;       %カウンターはそのまま
      endif               %条件分け終了
   endfor                %ループ終了
  y = 1-count/n;            %返り値の設定

ではここまで書いて、前述のようにSaveして下さい。
プログラム「dicemontecarlo」の内訳は以下に説明します。

①function y = dicemontecarlo(n)
この部分は前述の通り、「コレはdicemontecarloと言う名前の関数ですよ」と言う宣言です。
ここでプログラム「dice」との最大の違いは引数(ひきすう)をnと指定している事です。
引数とは何か、と言うと、これは数学で言う関数の「変数」にあたります。どう言う関数を数学的に作るか、
は基本的に関数設定者の自由ですし、どう言う「変数」が代入に際してのものなのか、と言うのも関数設定者
に委ねられる、と言うのと似ています。
ここでは実際「モンテカルロ法」を何回行うのか、を「変数=引数」として指定しているのです。プログラムを
走らせる人間(数学で言う関数の振る舞いを見る人間)が実際どう言う値を指定=代入するのか、その自由を
与えているワケですね。
数学的に言うと、

  y=f(n)

と言う関数を今から作りますが、「nに関しては貴方のお好きな値を代入して下さい」と言ってるワケです。
nさえ与えれば関数yは値を返してくれるのです。

②count = 0;
「カウンターを0とします」と言う意味です。
この「カウンター」は初期値を0として、例えば1万回サイコロを振ってある現象がx回観察された後は
「count=x」となります。累積して、現時点が「何回目のサイコロ振りでの成功回数なのか?」教えてくれる
部分なんですが、まだ1回もサイコロを振っていない状態では「サイコロを振って実験が成功した回数=0」
としている、と言うのは感覚的には納得出来るでしょう。

③for~endfor
「ループ構文」と言われる部分で、このモンテカルロ法の心臓部にあたります。
「ループ」とはこのfor~endforに挟まれた部分を「機械的に繰り返せ」と言った命令で、問題に即して言うと、
6個のサイコロを実際n回振って成功数を勘定する「人間がやりたくない作業」を記述するのです。
冒頭の

for i =1:n

と言うのは、「ループを1からスタートしてn回まで繰り返せ」と言った指定で、ここの「n」が先程①で記述
した「引数」nと対応しています。
つまり、実際dicemontecarloを実行した場合、dicemontecarlo(100)と指定した場合、「1からスタートして
100回繰り返せ」と言う指令になりますし、dicemontecarlo(1000)と指定した場合「1からスタートして
1000回繰り返せ」と言う指令になるわけです。

④a=dice()~g=dice()
実際にバラバラにa~gの6つのサイコロをここで設定しています。(なお、eを抜いてるのは、
通常OctaveWorkshopでは、eはネピア数として使われている定数だから、です)
ここで関数diceを呼び出してるんですね。
正確に言うと、a~gと言う6つの文字は「サイコロを振った結果」をそれぞれ代入しているだけです。
まあ、a~gと言う6つのサイコロをここで用意してる、と思ってもあながち見当外れでもないでしょう。

⑤if (a ~= b && b ~= c && c ~= d && d ~= f && f ~= g && g ~= a)
これは先程diceで行った条件設定の部分if~endifと構造上は同じです。
大事なのはその「中身」ですね。
問題文では、

>サイコロを6個用意し、同時に振り出した場合、少なくとも1組以上、
>同じ数字のペアができる確率

と指定されていますが、この「少なくとも1組以上」ってのがクセモノなんです。これを定式化するのは少々骨が折れます。
こう言う場合は常套手段なんですが、対偶を持ってくるんですね。すなわち、

「少なくとも1組以上」⇔「全ての目が食い違う」

を考慮して、対偶の方を「成功」として数えるのです。
従って、条件設定の

a ~= b && b ~= c && c ~= d && d ~= f && f ~= g && g ~= a

と言うのは日本語に直せば、

aがbに等しくなく、かつbがcに等しくなく、かつcがdに等しくなく、かつdがfに等しくなく、
かつfがgに等しくなく、かつgがaに等しくなく

となっていて、数学的には

a≠b≠c≠d≠f≠g

と言う事を指しています。これをOctaveWorkshopに分かるように記述すると

a ~= b && b ~= c && c ~= d && d ~= f && f ~= g && g ~= a

となるワケです。
ここで「~=」と言うのがOctaveWorkshopで言う「≠」の意味で、&&が「かつ」、数学記号で言うと∩の意味
になります。

⑥count = count + 1;
⑤の条件に一致した場合、すなわち、「全部のサイコロの数が1組も一致しない場合」、カウンターのそれ
までの値に1を足して「カウンターを更新」します。つまり、ループプログラム上「成功」のケースの値を
累積して行くワケです。

⑦else
if節で設定された条件以外の場合、です。

⑧count = count;
⑦のケースの場合は「カウンターを弄るな」と言う指令です。つまり、⑦の条件の場合、カウンターの数は
更新されないし累積されません。

⑨y = 1-count/n;
返り値の指定ですね。ループ内では「全てのサイコロの数が一致しない」のを「成功」と判別しています。
つまり確率は

全てのサイコロの数が一致しない確率=成功数/試行回数

なんですが、このままでは問題の題意を満たしません。
そこで、

少なくとも1組以上同じ数字のペアができる確率=100%-全てのサイコロの数が一致しない確率

と調整してやって、最終的な返り値としているわけです。

どうでしょうか?理解できたでしょうか?

では、プログラム「dicemontecarlo」を起動してみましょう。プロンプト

>

の後に、そうですね、1万回振るとして、

>dicemontecarlo(10000)

とでもして実験してみて下さい。どうなりますか?(結構時間がかかります。覚悟して下さい・笑。)
僕のパソコン上で実験してみると、

> dicemontecarlo(10000)
ans = 0.53380

が出ましたね。もちろん、乱数ベースなんで、実験によって値は変わります。が、大体50%辺りに収束する
ようです。すなわち、

少なくとも1組以上同じ数字のペアができる確率≒1/2

辺りではないか、と推測が出来るのです。
何度かdicemontecarloを走らせて、実験してみて下さい。

モンテカルロ法は如何でしたでしょうか?これは現時点多方面で使われている手法なんで、応用も効きますし
面白いと思います。
なお、こう言ったコンピュータを使用した統計の分野を特に「計算統計」等と呼んだりするようです。


お便り2006/11/11
from=JJon.com


To: 亀田馬志 さん

亀田さんの力作の回答をいつも楽しんで読んでおります一読者です。
今回もネタがたっぷり詰まった文章で読み応えがあり,
通勤時間を楽しく過ごすことができました(私,W-ZERO3[es]ユーザです)。
私は OctaveWorkshop というソフトを見たことも使ったこともないのですが,
動作しているパソコン画面の様子が目に浮かんでくるかのようです。

------------------------------------------------------------------------
前述のとおり,私は Octave というソフトをぜんぜん知らないのですが,
どうやら,他のプログラム言語と同じような構文を用いているように見えます。
とすると,たぶん,
        if (a ~= b && b ~= c)
は「aとbは比較した,bとcも比較した(しかしcとaは比較していない)」
という判断分岐になってしまうのではないだろうか,と感じました。
このままでは,a=1,b=2,c=1 の場合も
「賽の目はすべて違っている」と誤判断してしまうように思われるのです。

Octave が数値演算の専門ソフトであっても,
この if 構文を用いる限りでは,6つの賽の目(a,b,c,d,f,g)を
ぜんぶ総当たりでチェックしなければならない,ということはないでしょうか?

私は Perl言語の方がなじみ深いので,
6つの賽の目を総当たりするプログラムを試しに Perlで書いてみました。
考え方や変数名は,亀田さんのソースコードをそのまま流用しています。
説明も,亀田さんの文章が全面的に流用できます。(パクったとも言う,笑)

----------------------------------------------------------------------------
$count = 0;
foreach (1..10000) {            #10000回の繰り返し
    $a = &dice();

    $b = &dice();
    if ($b == $a) { next; }     #同じ目が出てしまったら次の回(next)へ

    $c = &dice();
    if ($c == $a || $c == $b) { next; }

    $d = &dice();
    if ($d == $a || $d == $b || $d == $c) { next; }

    $f = &dice();
    if ($f == $a || $f == $b || $f == $c || $f == $d) { next; }

    $g = &dice();
    if ($g == $a || $g == $b || $g == $c || $g == $d || $g == $f) { next; }

    $count = $count + 1;        #一度もnextにならなかったときだけ,カウント
}
print 1 - $count/10000;

sub dice() {
    $x = rand(14);                      #0以上14未満の実数乱数を発生
    if ($x < 1)     { $men = 1; }      #(「<」は半角です。管理人談)
    elsif ($x < 2)  { $men = 2; }
    elsif ($x < 3)  { $men = 3; }
    elsif ($x < 4)  { $men = 4; }
    elsif ($x < 5)  { $men = 5; }
    elsif ($x < 6)  { $men = 6; }
    elsif ($x < 7)  { $men = 7; }
    elsif ($x < 9)  { $men = 8; }
    elsif ($x < 11) { $men = 9; }
    else            { $men = 10; }
    return $men;
}
----------------------------------------------------------------------------

このプログラムを実行すると,表示される結果は約0.89となりました。
10回のうち9回の割で,同じ数字の目がでることになります。

(※プログラミング初心者の方へ。記号「||」は「または」を意味します)


お便り2006/11/12
from=亀田馬志


To JJon.comさん

>今回もネタがたっぷり詰まった文章で読み応えがあり,
通勤時間を楽しく過ごすことができました

いやはや、恐縮です(笑)。
「ネタがたっぷり詰まった」と言うより、ネタしか書けないんですが(苦笑)。
数学自体は全然苦手なモノで(笑)。

>私は OctaveWorkshop というソフトを見たことも使ったこともない

一応、背景を説明しますと、OctaveWorkshopと言うソフトウェアは、専門の研究者に使われている(らしい)
「MATLAB」と言うソフトウェアのフリーのクローンにあたります。
「MATLAB」は行列等の線形演算処理に特化したソフトウェアらしく、応用方面は例えば音声処理の実験に
使われたり、DSP(デジタル・シグナル・プロセッサ)組み立てたりする際のシミュレーションに使われてたり
するらしいです。
ただし、「MATLAB」は商用ソフトで高いので、貧乏人の選択肢として、一つはこの「OCTAVE」もしくは
「SciLab」と言うクローンソフトが海外では愛用者が多いようです。
いずれにせよ、直観的に行列のプログラミングが出来るし、ワリと構文が簡単なんで、これを紹介した次第
です。(汎用プログラミング言語ですと、リストから行列を生成するのは多少骨が折れるでしょ?)

以下の部分については仰るとおりでした。人為的なバグになっていますね。
図らずしもブール代数を良く知ってる人間(JJon.com氏)と良く分かっていない人間(亀田)の差が出たようです。
失礼致しました。
バグフィックス版のOctave Workshopでのdicemontecarloのソースコードは以下の通りです。

 function y = dicemontecarlo(n)
 count = 0;
 for i = 1:n
   a = dice();
   b = dice();
   c = dice();
   d = dice();
   f = dice();
   g = dice();
   if (a ~= b && a ~= c && a ~= d && a ~= f && a ~= g && %条件分けの修正版
       b ~= c && b ~= d && b ~= f && b ~= g &&        %JJon.com氏のご指摘通り
       c ~= d && c ~= f && c ~= g &&                                  %この条件設定は
       d ~= f && d ~= g &&                      %総当り式にしないと
       f ~= g)                               %バグになる
     count = count + 1;
   else
     count = count;
   endif
 endfor
 y = 1-count/n;

ちなみに亀田のパソコンでシミュレーションをやりなおすと、

> dicemontecarlo(10000)
ans = 0.89560

と確かに90%近い確率で「少なくとも1つ以上ペアができる」ようです。
いやいや、勉強になりました。条件わけ設定は今後もっと慎重になる事にします。
今更ながらプログラムって難しいですねえ。

>>なべちゃんさん

と言うワケでOctaveWorkshopでのソースコード修正版を試してみてください。
なお、JJon.com氏の使用した言語Perlは、ホームページでお馴染みのCGIスクリプト言語として有名な言語
です(例えばHPの掲示板のプログラムなんかも圧倒的にPerlで書かれるケースが多いです)。
強力なショートカットが多く、構文が醜くなるので有名な言語ですが(失礼・笑。ですが、掲示板等のCGIを
ダウンロード/アップロードした経験がある人なら分かりますが、漫画のふきだしのようなソースコードは見
た目ビックリします・笑。)BASICなんかより汎用性が高くて使い捨てのプログラムなんかも手早く書けるので、
世界中に愛用するハッカー(※)が多いです。従って現時点でもっとも使われている強力な言語のうちの一つな
んで、この機会にPerlに触れてみるのも悪くないでしょう。
(※ここで言うハッカーとは"プログラムの達人"の意です。一方、サーバに侵入したりウィルスをバラまく人間
はハッカーではなく、クラッカーと呼ぶ、のが正確な定義です。)
JJon.com氏は初心者にも分かりやすいように、「なるべく簡潔でキレイに」ソースコードを書いてくれている
ようです。(Perlは亀田もそのうち学びたい言語なんですが、亀田は今のところListとPythonの2つに全力投球
しています)
Perl自体もフリーウェアなので、インストールに関しては特に神経を使う必要性はありません。この機会に
インストールしてみましょう。詳しくは

http://pocketstudio.jp/win/activeperl/

に紹介されているインストール法に従って、「ActivePerl」をご自分のパソコンにインストールして下さい。
なお、Perlを利用する為には「環境変数」の設定を試みないといけません。同じページにWindowsでの
「システム環境変数」の設定方法に付いての説明もあるので、指示に従って、デスクトップも
システム環境変数として指定してしまいましょう。と言うのも、「書きなぐりのプログラム」は大体
デスクトップに置くのが一番分かりやすいでしょうし、遊んだ後は「即ゴミ箱行き」のケースも多いで
しょうから、デスクトップをシステム環境変数にしておくのが都合が良い。
例えば、亀田のパソコン上では

C:\Documents and Settings\kameda\デスクトップ

が指示すべきファイルパスとなっています(多分なべちゃんさんのパソコンでもデスクトップフォルダのパス
は似たようなモノだと思います)。

さて、ではPerlの使い方です。僕もPerlプログラムをパソコンで走らせるのは初めてなんでちょっと苦労
したんですが、大方間違ってないとは思います。
まず、メモ帳(NotePad)を開いて、JJon.com氏が上に記述しているソースコードをコピペします。これが
「プログラム」となります。
次にその「ソース」をOctave Workshopと同じようにSaveするんですが、まずは

「名前をつけて保存」

を選びます。ここで、名前は「dicemontecarlo」と名づけますが、大事なのは拡張子(エクステンション)です。
OctaveWorkshopの場合はエクステンションは「.m」でしたが、Perlの場合は「.pl」がエクステンションです。
すなわち、ファイル名を

dicemontecarlo.pl

としてデスクトップ上にSaveします。(ひょっとしてWindowsの初期設定が拡張子を隠すようになっているかも
しれないので、この機会に拡張子を見えるようにさせて下さい。詳しくは

http://www.itmedia.co.jp/help/tips/windows/w0018.html

辺りを参照して下さい。)

これでPerlによるモンテカルロ法のプログラムは完成です。あとは実行するだけ、です。
まずは「スタート」メニューから「すべてのプログラム」→「アクセサリ」→「コマンドプロンプト」
と進み起動します。そうすると真っ黒いDOS画面が現れるはずです。
そこで多分、プロンプトとしては、

C:\Documents and Settings\kameda>_

と表示されているでしょう。
そこで、今記述したJJon.com氏作成のソースコードのファイル

dicemontecarlo.pl

と打ち込んでプログラムを走らせます。
そうすると、計算結果を

C:\Documents and Settings\kameda>_dicemontecarlo.pl
0.8928
C:\Documents and Settings\kameda>_

てなカンジで返してくれると思います。JJon.com氏が仰るとおり、89.28%と言う「90%に近い」値を返して
くれました。(もちろんこれも乱数ベースなので、実験によって値は変わります)
今回Perlを初めて使ってみたんですが、非常に高速に計算してくれますね。OctaveWorkshopの比ではないです。
なかなか面白そうな言語です、やっぱり。
一般的な言語としては、例えばVBA程認知度は無いですが、ハッカーにとっては必須の言語Perl。色々応用も
利きそうですし、この機会に是非ともPerlも試してみてください。


お便り2007/12/19
from=pseudobasis


(1),(2)の答えはともに、29969/33614 (=0.891563…) です。
この14面体のサイコロを6個同時に振ったとき、同じ数字のペアが全くできない
確率を p とします。すると求める確率は 1-p です。
今からこの p を求めます。
p の分母は 14^6. 
このとき、p の分子は t についての多項式 
((1+t)^7)*((1+2t)^2)*(1+3t) 
を展開したときの t^6 の係数に 6! をかけた数です。
したがって、
p=(6!)*(Σ[a=0,1]Σ[b=0,2](3^a)*(2^b)*C(2,b)*C(7,6-a-b))/(14^6)
=(6!*1134)/(14^6)
=3645/33614.
求める確率は 1-p=1-3645/33614=29969/33614 (答).