如何从整数范围生成正态分布随机数?

发布于 2024-08-01 22:36:26 字数 1700 浏览 13 评论 0原文

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

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

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;
    }

Given the start and the end of an integer range, how do I calculate a normally distributed random integer between this range?

I realize that the normal distribution goes into -+ infinity. I guess the tails can be cutoff, so when a random gets computed outside the range, recompute. This elevates the probability of integers in the range, but as long as the this effect is tolerable (<5%), it's fine.

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); 
    }
}

I probably need to scale the standard deviation some how relative to the range, but don't understand how.

Answer:

    // 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;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

紧拥背影 2024-08-08 22:36:26

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

有关更正式的证明,请参阅维基百科文章中有关规范化标准正态变量(属性 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) 即可。

If the Box-Muller method returns a "standard" normal distribution, it will have mean 0 and standard deviation 1. To transform a standard normal distribution, you multiply your random number by X to get standard deviation X, and you add Y to obtain mean Y, if memory serves me correctly.

See the Wikipedia article's section on normalizing standard normal variables (property 1) for a more formal proof.


In response to your comment, the rule of thumb is that 99.7% of a normal distribution will be within +/- 3 times the standard deviation. If you need a normal distribution from 0 to 100 for instance, than your mean will be halfway, and your SD will be (100/2)/3 = 16.667. So whatever values you get out of your Box-Muller algorithm, multiply by 16.667 to "stretch" the distribution out, then add 50 to "center" it.


John, in response to your newest comment, I'm really not sure what is the point of the Next function. It always uses a standard deviation of 1 and a mean of halfway between your min and max.

If you want a mean of Y, with ~99.7% of the numbers in the range -X to +X, then you just call BoxMuller(Y, X/3).

始于初秋 2024-08-08 22:36:26

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

因此修改这一部分:

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);

Well, the -2*sigma..+2*sigma will give you 95% of the bell curve.
(check the "Standard deviation and confidence intervals" section in the already mentioned wiki article).

So modify this piece:

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

and change 1.0 (standard deviation) to 2.0 (or even more if you want more than 95% coverage)

return (int)BoxMuller(min + (max - min) / 2.0, 2.0);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文