「モンティ・ホール問題」を実際に実験して確かめよう

Posted on

 モンティ・ホール問題というのをご存知でしょうか?

 大学受験生をやっていた時に、確か東工大の問題か何かで題材となっていて、それで知ったお話です。今日は国公立大学の入試日ですし、ついでなので公開しちゃいます!…懐かしいですね、去年はエア東大合格(?)して胴上げされてました。あれから1年かー。

モンティ・ホール問題

 モンティ・ホール問題は、こんな問題です。

 とある視聴者参加ゲームショー番組のハイライト。

 あなたは3つのドアの中から、一つを選び、開けることができます。3つのうち、一つのドアの先にだけ景品がありますが、残りの2つの先には…残念、ヤギが居ます。

 さて、まずあなたはこの3つの中から一つを選びました。次に、どのドアが正解かを知っている番組の司会者が、残った2つのドアのうち、「正解でない方」を一つ開けました。

 残るドアは一つ。あなたは、今のドアから、この残ったドアに変える自由があります。

 この場合、変える方がトク(当たりやすい)でしょうか?それとも、最初の選択を貫いたほうが得でしょうか?

 「結局2つのうちから一つ選ぶんだから、どっちも一緒でしょ?」と当時の私は思ってしまったのですが…実は変えたほうがトクです!

なっとくいかない!!

 よろしい、ならば実験だ!JavaScriptだっ!

 JavaScript版のメルセンヌ・ツイスタのライブラリがあったので、これを使ってみました。乱数は完璧です。

「モンティホール問題」実験プログラム

 20120225.png

 ご納得頂けたと思います(ドヤ

な、なんで?

 冷静に考えれば、わかります。

 最初にハズレを選んでいた場合、最後に残るドアは正解のドアですから、「変えた」場合に景品がもらえます。

 逆に、最初アタリを選んでいたら、「変えない」場合だけ景品がもらえます。

 よって、「変える」場合にもらえる確率は最初ハズレる確率で2/3。「変えた」場合にもらえるのは最初アタる確率で1/3。

 実験通りですね!

えーやっぱり納得いかない

 「100個のドアのうち、最初に1つのドアを選びます。残った99個のドアのうち、一つを残して他98個のハズレのドアを司会者が開けてくれます。あなたは変えますか?」と、数を増やしてみるという説明で私は理解しました。いかがでしょう?

 こういった話に興味がある場合は、「ベイズ推定」について調べてみてくださいね。


派生クラスへの「変身タイミング」のC++とJavaの違い

Posted on

恥ずかしながら、知らなかったので投稿です。めちゃ細かい話です。ソースはこちらZIPはこちら。

まとめると

派生クラスの初期化の際には、原則的に基底クラス部分を初期化した後に、派生クラスに「変身」して、派生クラス部分が初期化されるのですが、

  • C++は、基底クラスのコンストラクタが終わるまで派生クラスに「変身」しない。
  • Javaは、基底クラスのコンストラクタの実行開始時からいきなり派生クラスに「変身」済み(ただしフィールドを除く)

オブジェクト指向といえばクラス、クラスといえばオブジェクト

オブジェクトといえば初期化、初期化といえばコンストラクタ!

というわけで、こんなオブジェクト継承関係を考えてみましょう。(Sample1.java)

public class Parent{
	public Parent(){
		System.out.println("親コンストラクタだよー。");
	}
	public void method(){
		System.out.println("親のメソッドだよー。");
	}
}
public class Child extends Parent {
	public Child(){
		super();
		System.out.println("子コンストラクタだよー。");
	}
	public void method(){
		System.out.println("子供のメソッドだよー。");
	}
}

ええと、特に意味のある例が思い浮かばなかったので、安直にParentとChildです。すいません。

この状態で

public class Launch{
	public static void main(String args){
		Child child = new Child();
		child.method();
	}
}

とすると、

% java Sample1 
親コンストラクタだよー。
子コンストラクタだよー。
子供のメソッドだよー。

と表示されます。これは予想通りですよね。親クラスのコンストラクタで、親クラスのフィールドが初期化されたあとに、その派生クラスの子クラスのコンストラクタが呼ばれて、子クラスが初期化されます。入門書通りです。

コンストラクタ中に子クラスのメソッドを呼ぶ…?

さて。親クラスを元にした派生クラスを色々と作って、それらの種類で処理を分ける…というのが、一般的なケースです。

とするなら。もしかすると、基底クラスの初期化の最中に子クラスの初期化をして、その結果を使いたいと思うかもしれません。

そう思ったら、こんなコードを書くかも。(Sample2.java)

abstract class Parent{ //抽象クラスになりました。
	public Parent(){
		System.out.println("親コンストラクタだよー。");
		/* 全派生クラス共通の初期化処理がこの間に入ってる(という気持ち) */
		final int result = doInit(); //派生クラスごとで違う初期化処理
		/* ここも全派生クラス共通の初期化処理が入ってる(という気持ち) */
		System.out.println("親コンストラクタ終わりだよー。結果は"+result+"だったよー。");
	}
	public void method(){
		System.out.println("親のメソッドだよー。");
	}
	protected abstract int doInit();
}
class Child extends Parent {
	public Child(){
		super();
		System.out.println("子コンストラクタだよー。");
	}
	public void method(){
		System.out.println("子供のメソッドだよー。");
	}
	protected int doInit(){
		System.out.println("子供が初期化してるよー。");
		return 184; //特に意味はない
	}
}

実行すると、

% java Sample2
親コンストラクタだよー。
子供が初期化してるよー。
親コンストラクタ終わりだよー。結果は184だったよー。
子コンストラクタだよー。
子供のメソッドだよー。

というわけで、Javaでは、親クラスのコンストラクタを実行中でもすでに「this」は子クラスに「変身」しており、親クラスのコンストラクタから、子クラスのメソッドを呼ぶことができます。

インスタンス変数は二回初期化される

ただし。インスタンス変数は違います。先程のソース、親子両方にfieldというフィールドを入れて、親クラスを0、子クラスを1と宣言時に初期化すると…。(Sample3.java)

% java Sample3 
親コンストラクタだよー。fieldは0だったよー。
子供が初期化してるよー。
親コンストラクタ終わりだよー。結果は184だったよー。
子コンストラクタだよー。fieldは1だったよー。
子供のコンストラクタだよー。

親クラスの値0で初期化されたあと、子クラスのコンストラクタ実行前に再度初期化されます。

親クラスのコンストラクタを呼ぶ前は「何者でもない」

また、親クラスのコンストラクタ実行前は「何者にもなっていない透明な存在」です。え?どういう事かって?

こういうことはできません。

abstract class Parent{ //抽象クラスになりました。
	public Parent(int param){
		/* なにか処理 */
	}
}
class Child extends Parent {
	public Child(){
		super(getParam()); // <= 残念、コンパイルできない!
	}
	protected int getParam(){ /* 基底クラスの初期化に使う値を、事前に計算したいなあ、と */
		return 184; //特に意味はない
	}
}

「スーパータイプのコンストラクタの呼び出し前は this を参照できません。」と言われてエラーでした。

結局、それぞれの実行タイミングはどうなってるの?

クラスのフィールドの初期化は、コンストラクタ内だけでなく、フィールドの宣言時にも行うことができます。大方予想はついていると思いますが、一応調べておきましょう。(Sample4.java)

abstract class Parent{
	protected static final int log(String msg){
		System.out.println(msg);
		return 0;
	}
	protected int field = log("親クラス・フィールド宣言時");
	public Parent(){
		log("親クラス・コンストラクタ");
	}
}
class Child extends Parent {
	protected int field = log("子クラス・フィールド宣言時");
	public Child(){
		super();
		log("子クラス・コンストラクタ");
	}
}

とすると、

% java Sample4
親クラス・フィールド宣言時
親クラス・コンストラクタ
子クラス・フィールド宣言時
子クラス・コンストラクタ

というわけで、原則的に「フィールド宣言→コンストラクタ」が親から子にわたって続く感じです。コンストラクタ内からフィールドにはアクセスできますから、まあ想像通りですね。

ただし、Javaの場合、親クラスのフィールド宣言開始時ですでに子クラスに「変身」していて、メソッドがオーバーライドされていた場合、子供クラスのコンストラクタが呼ばれる前でも、そちらが呼ばれてしまいます。複数人で開発していた場合、この仕様が思いがけないバグになるかもしれません。

明確に子クラスの責任としたいメソッドじゃない場合は、コンストラクタから呼ばれるメソッドはfinal宣言したほうがいいかもですね。

ソビエトロシアC++では親クラスが子クラスに変身する!

最後のJavaと似たようなコードを書きました。(Sample.cpp)

#include <iostream>
#include <string>

using namespace std;

int log(const string& msg){
	cout << msg << endl;
	return 0;
}

class Parent{
	protected:
		int attr;// = log("親クラスフィールド初期化"); //これはできないんでした。
	public:
		Parent():
		attr(log("親クラスフィールド初期化"))
		{
			log("親クラスコンストラクタ開始");
			doInit();
			log("親クラスコンストラクタ終了");
		}
		virtual ~Parent(){
		}
		virtual void doInit(){
			log("親クラスの初期化処理");
		};
		virtual void method(){
			log("*親メソッド*");
		}
};

class Child : public Parent{
	protected:
		int attr;
	public:
		Child():
		Parent(),
		attr(log("子クラスフィールド初期化"))
		{
			log("子クラスコンストラクタ");
		};
		virtual ~Child(){
		};
		virtual void doInit(){
			log("子クラスの初期化処理");
		};
		virtual void method(){
			log("*子メソッド*");
		}
};

int main(){
	Child child;
	child.method();
	return 0;
}

そもそもフィールド宣言時に初期化できなくて、コンストラクタの初期化子に書くんでしたね。さてコンパイルです。

% ./test 
親クラスフィールド初期化
親クラスコンストラクタ開始
親クラスの初期化処理 ← 子供のdoInit()じゃなくて、親のdoInit()が呼ばれてる!
親クラスコンストラクタ終了
子クラスフィールド初期化
子クラスコンストラクタ
*子メソッド*

コードの位置からすぐわかるように、Javaと同じように「フィールド初期化→コンストラクタ」の流れなのは同じです。

が、C++は親クラスの初期化が終わるまでは「厳密に親クラス」で、子クラスではないので、子クラスのメソッドを呼ぶことはできません。

子クラスに勝手にメソッドがオーバーライドされて…という事はなくなるため、この仕様はこの仕様で合理的な気がします。

まとめ

えっと、まあ、その、普通に使ってても結構気づかないことって多いんだなあ…って感じです…。


GENETOSのBGMを差し替えられるパッチ作ってみた

Posted on

 以前、フリーのSTGゲーム“GENETOS”の音楽を復号化する“Oreshiki Decrypter”を公開する時に書いた、GENETOSのBGMを差し替えるための改造パッチを公開する…と言いながら忘れていましたが、最近ソースコードのフォルダを眺めていたら発見されたので配布します。

ダウンロード

 け、結構前…。

使い方

 ダウンロードして出てくる「_patch_genetos.EXE」を実行するとパッチが適用されます。

 次に、BGMのファイルを次のように書き換えてください。

  • 最終面の「origin.mp3.ore」と「answer.mp3.ore」、エンディングの「rebirth.mp3.ore」はそのまま置き換えられます。“Oreshiki Decrypter”で差し替えたいmp3を暗号化し、そのまま置き換えてください。
  • それ以外は拡張子が変わった上で、拡張子以外のファイル名が4文字減ります。こんな感じ:
    • 「little_invader.mid.ore」を差し替えたい場合は「little_inv.mp3.ore」という名前のファイルを用意してください。
    • Oreshiki Decrypterを利用して差し替えたいmp3を暗号化した後、上記のようなファイル名に変更してBGMフォルダにコピーしてください。
  • 自機が進化した後のBGMに関して、最初の数秒間が再生されません†1。予め自分で数秒間分のブランクを挿入しておく必要があります、

パッチについて簡単な解説。

 内部では音楽を再生する関数はmidiを再生するものとMP3を再生する関数に別れています。どちらもファイル名と追加のいくつかの引数を取るもので、これを利用して、midiを再生する関数を書き換えてmp3を再生する関数にバイパスしています。

 ただしひとつ問題があって、midiを再生する関数は、ステージ開始時に一気にmidiをロードしてしかるタイミングで再生するBGMを変更する、という事ができるのですが、mp3の関数ではそれはできませんでした。この問題を解決すべくいろいろ試行錯誤した結果、自機が進化する瞬間の処理をフックしてMP3再生関数を呼んでBGMを切り替えています。

パッチ適用時の注意。

 メニューから普通にゲームを開始する時以外の動作に関してはうまく動かないと思われます。フリープレイでちゃんと動く事とかは考えてません。

  • †1: 原因はよくわかりません

インターネットのカタチ:いんたーねっとがこわれた!

Posted on

「Geekなぺーじ」の中の人による、「インターネットそのもの」を、”インターネットが壊れる”を切り口に、その壊れ方と直し方を通して解説した、ちょっと変わった本です。図書館をぶらぶらしてたら目についたので、読んでみました。

インターネットのカタチ―もろさが織り成す粘り強い世界―
あきみち 空閑 洋平
オーム社
売り上げランキング: 47632

いわゆる「インターネットの仕組み」の本とは、一味違います。もちろん、ルーティングとかDNSとか海底ケーブル網とか、そういうテクノロジーの話は沢山出てきます。

が、インターネットは、ケーブルと機械の集まりというだけではありません。人間が作って維持しているネットワークです。

機械の故障によって「壊れる(繋がらなくなる)」だけでなく、機械は問題なくても設定ミスでネットワークが「壊れる」ことも有るでしょうし、政治的な理由†1で「壊されてしまう」ことも、あるいは悪意を持った人がDDoSを仕掛けて「破壊する」こともあります。でも、そうやって壊れてしまったら、物理的に、あるいは論理的・政治的に、さらには仕様の見直しによる破壊工作の防止まで含めて、「インターネットを治す」ような仕組みも、あるのです。

この本は、そういったインターネットを取り巻き、壊れたら治して維持する、ありとあらゆる営みの視点から、インターネットを概観できる、肩肘張らずに読めるゆる~い読み物です。

いくつか本の中で私がこれは!と思ったものをご紹介。

ルーターのその先のプロバイダのその先ってどうなってるの?

私は自宅内のネットワークに関してはある程度知ってるつもりです†2。が、その先に関しては、教養番組でよくあるような「雲」以上のイメージが正直無かったですorz

私の加入しているプロバイダは、So-netです†3。So-netのようなプロバイダは、私の家のような家庭内LANをたくさん束ねて、インターネット外部への接続サービスを行っています。そのつながり方は、どのようなもので、どのようにデータのやり取りを行っているのでしょう?

Wikipediaとか読んでてもいまいちイメージがつかめなかったのですが、今回この本で可視化ツールが有ると知ったので、試してみました。

自宅周辺のネットワークがどうなってるか調べてみる!

「自宅周辺」とか言ってますが、今大学なので大学周辺を調べます(ぁ

まずは、インターネットの住所の基本、IPアドレスを調べます。いつもの通り、診断くんで調べます。133.11.70.109だそうです。

次に、RADbのサイトにアドレスを入れて検索すると、AS番号とIPアドレスの割当範囲が分かります。(AS番号だけでしたら、Team CYMRUからも調べられます。)

このAS番号というのは、プロバイダや大学、あるいはGoogleのような大規模なネットワークを持っている団体がDNSのドメイン名のように、RIRというしかるべき団体から一意で貰ってる番号で、よく聞く「IPアドレスの割当て」は、このAS番号を持っている団体に対して行われています。恥ずかしながら、ネットワークの上位でもDHCPみたいにダイナミックに割り振ったりしてるのかなあ、とか思ってました。最終的に「IPアドレスは誰のものか?」は、ちゃんとテーブルで決まってる!のです。

さて、先ほどのRADbに入力することで、AS番号はAS2501だと分かりました(か、かなり若いのでは…)。また、133.11.70.109という番号は、133.11.0.0/16の割当のうちの一つ、だそうです。

さてさて。これから、ネットワークの可視化がやっと行えます。BGPlayというネットワーク可視化ツールを使って、調べてみましょう。

20120131.png

おおお、なかなかそれっぽいですね。ASの間ではBGPと呼ばれるプロトコルで通信していて、「AS2501の隣にはAS2907がいるよ!」といったメッセージを流し合っていて、その情報を使ってルーティングをしているのだそうです。恥ずかしながら知りませんでしたorz

先ほどのRADbにAS2501と入れる事で、その生のデータが取得できます。

import:     from AS2500
	           action pref=100;
	           accept ANY
import:     from AS2907
	           action pref=100;
	           accept ANY
import:     from AS7531
	           action pref=100;
	           accept AS7531
export:     to AS2500
	           announce AS2501 AS7531
export:     to AS2907
	           announce AS2501 AS7531
export:     to AS7531
	           announce ANY

さてこのルーティング情報、実はちょくちょく変わります。この可視化ツールでは下の▶ボタンを押すと、このつながりが変わっていく様を見る事ができる…はずなのですが、今私がやったところでは、あまり変わりません。どうやら、”大学だから”のようです。

お使いのプロバイダですと、結構アニメーションがくるくると動いて、同じASにつなぐにしても、色々なルートを通ってるって、分かりはずです。

基本的には、BGPにおいてAS同士は対等(なはず;自信ない)。でも、平等なこの現実社会にもリア充と非リア充がいるように、他のたくさんのネットワーク同士をつなげている「Tier1」と呼ばれる大きなASと、そのおこぼれに預かっている下々の「Tier2」のようなASが居て、大体のプロバイダはTier2以下です。下々のプロバイダは、リア充たる上位のネットワーク様に、まるで私がプロバイダと契約しているように、お金を払って繋がせていただいています(敬語)。

というわけで、ほかのネットワークにパケットを流すときには、プロバイダは流す先のASにお金を払っています(同規模程度のAS同士ではPeerといって、無料でパケットを流し合ってる所もあるようです)。またもちろん、人間のやってる組織同士ですから、その他もろもろの政治問題があって流しやすかったりそうでも無かったりするようです…。

ということで、同じASに送り届けるにしても、どのASを経由させるかは重大な問題だ、という事になります。

だからAS同士のつながりは、ちょくちょく切り替わっているって事なのかな…?…この辺は自信ないですごめんなさいorz

誰か教えて〜!!

RFCとかって、どうやって決まるの?

上が長くなったので、軽く。IETFっていうRFCを出してる所のメーリングリストとか、リアルで集まる会合で決めてるんだそうです。基本的には参加資格なしで、誰でも参加できます!

とはいえ、人間が集まっている以上、誰が言ったかで賛否が分かれたり、リアル会合に何度も出れる(ほどのお金や時間がある)人が有利になったり、はするそうで、よほどの事でもない限りいきなりちょろっとMLに顔を出しても相手にはされなさそうです。

電車内でサクッと読める

軽めのBlog記事を沢山繋げたような構成で、かなり読みやかったです。私は本を読むのはかなり遅い方で、一冊のライトノベルに三ヶ月掛けるのもままあることなのですが、2日ほどで読み終わってしまいました。ライトノベルよりも軽く読めるので、暇つぶしにいかが。

  • †1: 日本だと児童ポルノとか青少年健全育成条例とか
  • †2: 自宅サーバも含めて、自宅のネットワークはすべて私が管理しているので…一応…
  • †3: Gyaoだったんですが、買収されてしまいました…