🌟

【Unity/C#】二項分布の成功数を近似的に求める

2023/09/04に公開

コード

MyMath.cs
using UnityEngine;

public static class MyMath
{
    public static int RandomBinomialApproxValue(int trials, float probability)
    {
        // 二項分布の平均と標準偏差を計算
        float mean = trials * probability;
        float stdDev = Mathf.Sqrt(trials * probability * (1 - probability));

        // 正規分布からのサンプリング
        float normalValue = RandomNormal(mean, stdDev);

        // 結果を整数に四捨五入
        return Mathf.RoundToInt(normalValue);
    }

    // Box-Muller法を使用して正規分布からのサンプリングを行う
    private static float RandomNormal(float mean, float stdDev)
    {
        float u1 = UnityEngine.Random.value; // 0から1までの適当な数字を1つ取る
        float u2 = UnityEngine.Random.value; // もう一度、0から1までの適当な数字を1つ取る

        // Box-Muller法で乱数を取得する
        float randStdNormal = Mathf.Sqrt(-2.0f * Mathf.Log(u1)) *
            Mathf.Sin(2.0f * Mathf.PI * u2);

        // 結果を計算する
        return mean + stdDev * randStdNormal;
    }
}

用例

ドロップ率1%のアイテムのドロップ判定を1万回行うとして、アイテムのドロップ数をランダムに求めたい。(ランダム判定を1万回やるより高速で求めたい)

ItemDrop.cs
public class ItemDrop : MonoBehaviour
{
    void Start()
    {
        int trials = 100000; // 試行回数
        float dropProbability = 0.01f; // ドロップ確率

        // 設定した試行回数とドロップ確率でアイテムが何回落ちるか計算する
        int result = MyMath.RandomBinomialApproxValue(trials, dropProbability);
	// 結果をコンソールに表示する
        Debug.Log($"Dropped items count: {result}");
    }
}

注意事項

  • 近似的な処理で問題ないかは十分に精査してください。
  • 乱数生成の箇所は簡易的に書いているので、厳密な処理においてはUnityEngine.Random.valueの箇所をもっと精査してください。

参考

ボックス=ミュラー法

Discussion