【C#】正态分布(高斯分布)算法

/// <summary>
/// 正态分布(高斯分布)
/// </summary>
public class Gaussian
{
    public const int MIU = 0;
    public const int SIGMA = 1;

    private readonly Random rnd;

    public Gaussian()
    {
        rnd = new Random((int)DateTime.Now.Ticks & 0xFFFFFF);
    }

    /// <summary>
    /// 获取一个指定范围内的标准正态分布随机数
    /// </summary>
    /// <param name="min">最小值(返回的值可包含最小值)</param>
    /// <param name="max">最大值(返回的值可包含最大值)</param>
    /// <returns></returns>
    public double Random(double min, double max) => Random2(min, max)[0];

    /// <summary>
    /// 获取一个或两个指定范围内的标准正态分布随机数
    /// </summary>
    /// <param name="min">最小值(返回的值可包含最小值)</param>
    /// <param name="max">最大值(返回的值可包含最大值)</param>
    /// <returns></returns>
    public double[] Random2(double min, double max)
    {
        if (max <= min) return new[] { min };

        var list = new List<double>();
        while (list.Count == 0)
        {
            foreach (var normal in GetValue(rnd, SIGMA, MIU))
            {
                var value = ConvertValue(normal, min, max);
                if (value >= min && value <= max)
                {
                    list.Add(value);
                }
            }
        }

        return list.ToArray();
    }

    /// <summary>
    /// 转换为指定范围内的值。返回结果可能会超出范围为,因为大约99.7%概率在范围内(3σ原则)。
    /// </summary>
    /// <param name="normal">正态分布数</param>
    /// <param name="min">最小值</param>
    /// <param name="max">最大值</param>
    /// <returns></returns>
    private static double ConvertValue(double normal, double min, double max)
    {
        var median = (max - min) / 2.0;

        return (normal * median / 3) + min + median;
    }

    /// <summary>
    /// 获取两个正态分布随机数
    /// </summary>
    /// <param name="random">生成随机数的对象</param>
    /// <param name="deviation">标准差σ</param>
    /// <param name="expected">期望值μ</param>
    /// <returns></returns>
    public static double[] GetValue(Random random, double deviation, double expected)
    {
        double x, y, s;
        do
        {
            x = 2 * random.NextDouble() - 1;
            y = 2 * random.NextDouble() - 1;
            s = x * x + y * y;
        }
        while (s > 1 || s == 0);
        double multi = Math.Sqrt(-2 * Math.Log(s) / s);

        //return new double[] { Math.Round(x * multi, 2) * deviation + expected, Math.Round(y * multi, 2) * deviation + expected };
        return new double[] { x * multi * deviation + expected, y * multi * deviation + expected };
    }
}
posted @ 2024-07-04 08:49  qiutian-hao  阅读(145)  评论(0编辑  收藏  举报