我正在扩展生成 n 个随机数的想法,并取它们的平均值以获得钟形曲线效应。“紧密度”参数控制曲线的陡峭程度。
编辑:Central Limit Theorem支持对一组随机点求和以获得“正态”分布。使用偏置函数来影响特定方向的结果是一种常见的技术,但我不是那里的专家。
为了解决问题末尾的注释,我通过操纵“内部”随机数来扭曲曲线。在此示例中,我将其提高到您提供的指数。由于 Random 返回的值小于 1,因此将其提高到任何幂都不会超过 1。但是平均值偏向零,因为小于一的数字的正方形、立方体等甚至小于基数。exp = 1 没有偏斜,而 exp = 4 有相当大的偏斜。
private Random r = new Random();
public double RandomDist(double min, double max, int tightness, double exp)
{
double total = 0.0;
for (int i = 1; i <= tightness; i++)
{
total += Math.Pow(r.NextDouble(), exp);
}
return ((total / tightness) * (max - min)) + min;
}
我对 exp 的不同值进行了试验,生成了 0 到 99 之间的 100,000 个整数。这是分布的结果。
![偏斜随机分布](https://i.stack.imgur.com/X5iEz.png)
我不确定峰值与 exp 值的关系,但 exp 越高,范围内的峰值越低。
您还可以通过将循环内部的线更改为:
total += (1 - Math.Pow(r.NextDouble(), exp));
...这会在曲线的高端产生偏差。
编辑:那么,我们如何知道如何制作“exp”才能达到我们想要的峰值?这是一个棘手的问题,可能可以通过分析来解决,但我是一名开发人员,而不是一名数学家。因此,应用我的交易,我进行了大量试验,收集各种 exp 值的峰值数据,并通过Wolfram Alpha的三次拟合计算器运行数据,以获得 exp 作为峰值函数的方程。
这是一组实现此逻辑的新函数。GetExp(...) 函数实现由 WolframAlpha 找到的方程.
RandomBiasedPow(...) 是感兴趣的函数。它返回指定范围内的随机数,但趋于峰值。这种趋势的强度由紧密度参数控制。
private Random r = new Random();
public double RandomNormal(double min, double max, int tightness)
{
double total = 0.0;
for (int i = 1; i <= tightness; i++)
{
total += r.NextDouble();
}
return ((total / tightness) * (max - min)) + min;
}
public double RandomNormalDist(double min, double max, int tightness, double exp)
{
double total = 0.0;
for (int i = 1; i <= tightness; i++)
{
total += Math.Pow(r.NextDouble(), exp);
}
return ((total / tightness) * (max - min)) + min;
}
public double RandomBiasedPow(double min, double max, int tightness, double peak)
{
// Calculate skewed normal distribution, skewed by Math.Pow(...), specifiying where in the range the peak is
// NOTE: This peak will yield unreliable results in the top 20% and bottom 20% of the range.
// To peak at extreme ends of the range, consider using a different bias function
double total = 0.0;
double scaledPeak = peak / (max - min) + min;
if (scaledPeak < 0.2 || scaledPeak > 0.8)
{
throw new Exception("Peak cannot be in bottom 20% or top 20% of range.");
}
double exp = GetExp(scaledPeak);
for (int i = 1; i <= tightness; i++)
{
// Bias the random number to one side or another, but keep in the range of 0 - 1
// The exp parameter controls how far to bias the peak from normal distribution
total += BiasPow(r.NextDouble(), exp);
}
return ((total / tightness) * (max - min)) + min;
}
public double GetExp(double peak)
{
// Get the exponent necessary for BiasPow(...) to result in the desired peak
// Based on empirical trials, and curve fit to a cubic equation, using WolframAlpha
return -12.7588 * Math.Pow(peak, 3) + 27.3205 * Math.Pow(peak, 2) - 21.2365 * peak + 6.31735;
}
public double BiasPow(double input, double exp)
{
return Math.Pow(input, exp);
}
这是使用 RandomBiasedPow(0, 100, 5, peak) 的直方图,图例中显示了各种峰值。我四舍五入得到 0 到 99 之间的整数,将紧密度设置为 5,并尝试了 20 到 80 之间的峰值。(在极端峰值时事情会变得不稳定,所以我把它省略了,并在代码中添加了警告。)你可以在它们应该在的地方看到山峰。
![各种峰值,紧密度=5](https://i.stack.imgur.com/DS8Mx.png)
接下来,我尝试将 Tightness 提高到 10...
![在此处输入图像描述](https://i.stack.imgur.com/1paGg.png)
分布更紧密,峰值仍在应有的位置。它也相当快!