在高斯范围内生成随机数?

我想使用随机数生成器,在高斯范围内创建随机数,我可以自己定义中位数。 我已经在这里问了一个类似的问题,现在我正在使用这段代码:

class RandomGaussian { private static Random random = new Random(); private static bool haveNextNextGaussian; private static double nextNextGaussian; public static double gaussianInRange(double from, double mean, double to) { if (!(from < mean && mean < to)) throw new ArgumentOutOfRangeException(); int p = Convert.ToInt32(random.NextDouble() * 100); double retval; if (p < (mean * Math.Abs(from - to))) { double interval1 = (NextGaussian() * (mean - from)); retval = from + (float)(interval1); } else { double interval2 = (NextGaussian() * (to - mean)); retval = mean + (float)(interval2); } while (retval  to) { if (retval  to) retval = to - (retval - to); } return retval; } private static double NextGaussian() { if (haveNextNextGaussian) { haveNextNextGaussian = false; return nextNextGaussian; } else { double v1, v2, s; do { v1 = 2 * random.NextDouble() - 1; v2 = 2 * random.NextDouble() - 1; s = v1 * v1 + v2 * v2; } while (s >= 1 || s == 0); double multiplier = Math.Sqrt(-2 * Math.Log(s) / s); nextNextGaussian = v2 * multiplier; haveNextNextGaussian = true; return v1 * multiplier; } } } 

然后为了validation结果,我用gaussianInRange(0,0.5,1)绘制了n = 100000000 在此处输入图像描述

可以看出中位数实际上是0.5,但实际上并没有可见的曲线。 那么我做错了什么?

编辑

我想要的是这样的东西,我可以通过传递一个值来设置最高概率。

在此处输入图像描述

绘制正常偏差的最简单方法是条件是它们处于特定范围内是拒绝采样:

 do { retval = NextGaussian() * stdev + mean; } while (retval < from || to < retval); 

当您在无条件法线生成器中绘制圆形坐标( v1v2 )时,会使用相同的类型。

简单地折叠范围之外的值不会产生相同的分布。


此外,如果您具有错误函数及其逆的良好实现,则可以使用反向CDF直接计算值。 正态分布的CDF是

 F(retval) = (1 + erf((retval-mean) / (stdev*sqrt(2)))) / 2 

被删失分发的CDF是

 C(retval) = (F(retval) - F(from)) / (F(to) - F(from)), from ≤ x < to 

要使用CDF绘制随机数,可以从[0,1]上的均匀分布中绘制v并求解C(retval) = v 。 这给了

 double v = random.NextDouble(); double t1 = erf((from - mean) / (stdev*sqrt(2))); t2 = erf((to - mean) / (stdev*sqrt(2))); double retval = mean + stdev * sqrt(2) * erf_inv(t1*(1-v) + t2*v); 

您可以预先计算特定参数的t1t2 。 这种方法的优点是没有拒绝采样,因此每次绘制只需要一个NextDouble() 。 如果[from,to]间隔很小,这将更快。


但是,听起来你可能想要二项分布 。

我的Graph生成器中有类似的方法(必须稍微修改一下):

使用具有特定范围的生成器函数返回随机浮点数:

 private double NextFunctional(Func func, double from, double to, double height, out double x) { double halfWidth = (to - from) / 2; double distance = halfWidth + from; x = this.rand.NextDouble() * 2 - 1;// -1 .. 1 double y = func(x); x = halfWidth * x + distance; y *= height; return y; } 

高斯函数:

 private double Gauss(double x) { // Graph should look better with double-x scale. x *= 2; double σ = 1 / Math.Sqrt(2 * Math.PI); double variance = Math.Pow(σ, 2); double exp = -0.5 * Math.Pow(x, 2) / variance; double y = 1 / Math.Sqrt(2 * Math.PI * variance) * Math.Pow(Math.E, exp); return y; } 

使用随机数生成图形的方法:

 private void PlotGraph(Graphics g, Pen p, double from, double to, double height) { for (int i = 0; i < 1000; i++) { double x; double y = this.NextFunctional(this.Gauss, from, to, height, out x); this.DrawPoint(g, p, x, y); } } 

我宁愿使用余弦函数 - 它更快,非常接近高斯函数满足您的需求:

 double x; double y = this.NextFunctional(a => Math.Cos(a * Math.PI), from, to, height, out x); 

NextFunctional()方法中的out double x参数就在那里,因此您可以在图形上轻松测试它(我在我的方法中使用迭代器)。