[英]Generate a random number in a Gaussian Range?
我想使用一個隨機數生成器,在高斯范圍內創建隨機數,我可以自己定義中位數。 我已經在這里問了一個類似的問題,現在我正在使用這段代碼:
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 < from || retval > to)
{
if (retval < from)
retval = (from - retval) + from;
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;
}
}
}
然后為了驗證結果,我用gaussianInRange(0,0.5,1)繪制了n = 100000000
可以看出,中位數實際上是0.5,但實際上並沒有可見的曲線。 那么我做錯了什么?
我想要的是這樣的東西,我可以通過傳遞一個值來設置最高概率。
繪制正常偏差的最簡單方法是條件是它們處於特定范圍內是拒絕采樣:
do {
retval = NextGaussian() * stdev + mean;
} while (retval < from || to < retval);
當您在無條件法線生成器中繪制圓形中的坐標( v1 , v2 )時,會使用相同的類型。
簡單地折疊范圍之外的值不會產生相同的分布。
此外,如果您具有錯誤函數及其逆的良好實現,則可以使用反向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);
您可以預先計算特定參數的t1
和t2
。 這種方法的優點是沒有拒絕采樣,因此每次繪制只需要一個NextDouble()
。 如果[from,to]間隔很小,這將更快。
但是,聽起來您可能想要二項分布 。
我的Graph生成器中有類似的方法(必須稍微修改一下):
使用具有特定范圍的生成器函數返回隨機浮點數:
private double NextFunctional(Func<double, double> 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
參數就在那里,因此您可以在圖形上輕松測試它(我在我的方法中使用迭代器)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.