【问题标题】:How to generate normally distributed random from an integer range?如何从整数范围生成正态分布随机数?
【发布时间】:2010-11-21 03:53:05
【问题描述】:

给定一个整数范围的开始和结束,我如何计算这个范围之间的正态分布随机整数?

我意识到正态分布进入 -+ 无穷大。我猜尾巴可以被截断,所以当随机计算超出范围时,重新计算。这提高了该范围内整数的概率,但只要这种影响是可以容忍的(

public class Gaussian
{
    private static bool uselast = true;
    private static double next_gaussian = 0.0;
    private static Random random = new Random();

    public static double BoxMuller()
    {
        if (uselast) 
        { 
            uselast = false;
            return next_gaussian;
        }
        else
        {
            double v1, v2, s;
            do
            {
                v1 = 2.0 * random.NextDouble() - 1.0;
                v2 = 2.0 * random.NextDouble() - 1.0;
                s = v1 * v1 + v2 * v2;
            } while (s >= 1.0 || s == 0);

            s = System.Math.Sqrt((-2.0 * System.Math.Log(s)) / s);

            next_gaussian = v2 * s;
            uselast = true;
            return v1 * s;
        }
    }

    public static double BoxMuller(double mean, double standard_deviation)
    {
        return mean + BoxMuller() * standard_deviation;
    }

    public static int Next(int min, int max)
    {
        return (int)BoxMuller(min + (max - min) / 2.0, 1.0); 
    }
}

我可能需要将标准偏差相对于范围进行一些缩放,但不明白如何。

答案:

    // Will approximitely give a random gaussian integer between min and max so that min and max are at
    // 3.5 deviations from the mean (half-way of min and max).
    public static int Next(int min, int max)
    {
        double deviations = 3.5;
        int r;
        while ((r = (int)BoxMuller(min + (max - min) / 2.0, (max - min) / 2.0 / deviations)) > max || r < min)
        {
        }

        return r;
    }

【问题讨论】:

    标签: c# random range gaussian normal-distribution


    【解决方案1】:

    如果 Box-Muller 方法返回“标准”正态分布,它的均值为 0,标准差为 1。要转换标准正态分布,将随机数乘以 X 得到标准差 X,然后添加如果我没记错的话,Y 来获得平均 Y。

    请参阅Wikipedia article's section on normalizing standard normal variables (property 1) 以获得更正式的证明。


    根据您的评论,经验法则是 99.7% 的正态分布将在标准偏差的 +/- 3 倍范围内。例如,如果您需要从 0 到 100 的正态分布,那么您的平均值将是一半,您的 SD 将是 (100/2)/3 = 16.667。因此,无论您从 Box-Muller 算法中得到什么值,乘以 16.667 以“拉伸”分布,然后加上 50 使其“居中”。


    约翰,作为对您最新评论的回应,我真的不确定Next 函数的意义何在。它始终使用 1 的标准差和最小值和最大值之间的平均值。

    如果您想要 Y 的平均值,大约 99.7% 的数字在 -X 到 +X 范围内,那么您只需调用 BoxMuller(Y, X/3)

    【讨论】:

    • 是的,这就是上面的 BoxMuller(double mean, double standard_deviation) 实现的。然而,问题在于 Next(int min, int max) 返回的值非常接近范围的一半。这是因为我不明白如何正确“缩放”偏差。
    • 所以对于 3.5 个标准差,它将是“返回 (int)BoxMuller(min + (max - min) / 2.0, (max - min) / 2.0 / 3.5);”?
    • 我可以评论一下,+/- 3 倍的标准差给你的不是 97%,而是 99.7%。 +/-sigma:~68% +/-2sigma:~95% +/-3sigma:~99.7% en.wikipedia.org/wiki/68-95-99.7_rule
    • 感谢您指出这一点,德米特里——显然,我的统计数据有点生疏。我更新了答案。
    【解决方案2】:

    嗯,-2*sigma..+2*sigma 将为您提供 95% 的钟形曲线。 (查看已经提到的 wiki 文章中的“标准差和置信区间”部分)。

    所以修改这块:

    return (int)BoxMuller(min + (max - min) / 2.0, 1.0);
    

    并将 1.0(标准偏差)更改为 2.0(如果您想要超过 95% 的覆盖率,甚至可以更大)

    return (int)BoxMuller(min + (max - min) / 2.0, 2.0);
    

    【讨论】:

    • 感谢您,我现在明白了我想要表达的意思。我希望 -2*sigma .. +2*sigma 位于范围的开头和结尾(最小值,最大值)分别。
    • 啊,我明白了。所以你想从你的平均值左右跳出,并以 95% 的置信度“击中”最小值或最大值。在这种情况下 - 你保持你的平均值 (min + (max-min)/2),但你需要计算你的 sigma (标准偏差)。步出 2*sigma 为我们提供了 95% 的区间。所以这个区间的长度是4*sigma。但我们也可以将其计算为 (max-min)。这给了我们 sigma=(max-min)/4。你能试试吗?
    • “命中”在 min..max 范围内,有 95% 的置信度 - 准确地说是我的措辞。
    • 这也有效,可惜我只能做出一个正确的答案。 Stackoverflow 应该添加“辅助”或“共享”答案。
    猜你喜欢
    • 2021-09-01
    • 2016-09-21
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 2013-05-02
    • 2013-11-19
    • 2017-05-18
    • 1970-01-01
    相关资源
    最近更新 更多