1

私の教授は顧客が銀行に到着する様子をシミュレートしています。クライアントは、平均 3.5、標準偏差 1.3 の正規分布に従って到着すると言われています。

問題は、なぜこのコードを使用しているのか理解に苦しむことです。彼が提供したコードは、乱数を生成するためにストリーム、平均、および標準を受け取っていると思います

コード

public class Random {

    private static double second=0;

    static double normal(int stream, double mean, double std){
        double v1=0, v2=0, y1, y2, x1, x2, w=2;

        if (second!=0 ){
            return second;
        }

        while(w>1){
            v1=2*RandomGenerator.rand(stream)-1;
            v2=2*RandomGenerator.rand(stream)-1;
            w=Math.pow(v1,2)+Math.pow(v2,2);
        }

        y1=v1*Math.pow((-2*Math.log(w))/w, 0.5);
        y2=v2*Math.pow((-2*Math.log(w))/w, 0.5);
        x1=mean+y1*std;
        x2=mean+y2*std;
        second=x2;
        return x1;
    }

} 

私の数学の授業は何年も前のことなので、この正規分布を理解するのは少し難しく、正規分布の計算方法をインターネットで検索した後、与えられたコードに似た式を見つけることができませんでした.

それで、これらは私の質問です。

  1. 何をしsecondますか?何かのお守りですか?
  2. このコードは正規分布をどのように使用していますか? わからないようです...
4

1 に答える 1

2

質問には逆順でお答えします。この方法の中心部分は、[0, 1] の一様分布から引き出された 2 つの確率変数を、指定された平均と標準偏差を持つ正規分布から引き出された 2 つの確率変数に変換するための標準的な手法です。(これはBox-Muller 変換と呼ばれます。)whileループでは、生成とテストの手法を使用して、単位円上の 2 次元一様分布からランダムな点 (v1、v2) を生成します。(v1, v2) から (y1, y2) へのマッピングは、一様分布を平均がゼロで標準偏差が 1 の 2 次元正規分布に変換します。次に、これをシフトおよびスケーリングして、目的の平均と標準偏差を持つ (x1, x2) を取得します。

正規分布変数のペアを生成する方法が手元にあるので、コードの残りの部分は次のように機能します。 ifの場合second == 0、これは新しい値を生成する必要があるという信号であるため、 を通過してif値のペアを生成します。次に、値の 1 つを保存し、もう 1 つをsecond返します。次にメソッドが呼び出されたときに、有効な値があることに気付き、それsecond以上の値を生成する代わりに、すぐにそれを返します。

コードには重大なバグがありますsecond。値が返される前にゼロにリセットする必要があります。それ以外の場合は、常に 2 番目のランダム値を返し続けます (2 番目の呼び出しの後はそれほどランダムに見えません)。その欠陥が修正されたとしても、2 つ目の問題があります。他のすべての戻り値は、値 0 を持つ確率がゼロになります。理論的には、これはそれほど悪くはありません。なぜなら、正規分布のランダム サンプルの値が正確にゼロになる確率は...ゼロだからです! しかし、それはまだ欠陥です。

コードを次のように書き直します。

public class Random {

    private static double second;
    private static boolean secondValid = false;

    static double normal(int stream, double mean, double std) {
        double v1, v2, y1, y2, x1, x2, w;

        if (secondValid) {
            secondValid = false;
            return second;
        }

        do {
            v1 = 2 * RandomGenerator.rand(stream) - 1;
            v2 = 2 * RandomGenerator.rand(stream) - 1;
            w = v1 * v1 + v2 * v2;
        } while (w > 1);

        y1 = v1 * Math.sqrt(-2 * Math.log(w) / w);
        y2 = v2 * Math.sqrt(-2 * Math.log(w) / w);
        x1 = mean + y1 * std;
        x2 = mean + y2 * std;
        second = x2;
        secondValid = true;
        return x1;
    }

}
于 2012-05-02T15:27:59.167 に答える