生成具有抛物线分布的随机值

时间:2018-01-14 22:52:07

标签: normal-distribution

我想在x和y之间生成随机延迟。我希望输出比x或y更常见于x和y的中间。

例如,如果我的x为10且y为20,我希望最常见的输出为15。

我一直试图在纸上解决这个问题但不幸的是,我不是数学天才。

我尝试了一些使用Random.nextGuassian()的公式,但我根本无法理解它给出的奇数输出。

2 个答案:

答案 0 :(得分:0)

Java Random.nextGaussian()返回以均值为零为中心的值。如果希望值以15为中心,则将{15}添加到Random.nextGaussian()返回的值。更一般地说,如果您希望值位于xy之间的中间位置,请执行以下操作:

    delay = Random.nextGaussian + ( (x + y) * 0.5 );

在正态分布中,99.7%的数据样本位于平均值之上和之下的3个标准差内。 Random.nextGaussian()生成标准差为1.0的值,因此如果平均值为15,那么它返回的值的99.7%将介于12和18之间。但是,它偶尔会返回小于x的值或大于y,因此您需要检查这些情况。简单地强制值小于xx且大于yy的值可能足以满足您的使用案例:

    if (delay < x) { 
        delay = x;
    } else if (delay > y) {
        delay = y;
    }

参考文献:

答案 1 :(得分:0)

在实现具有抛物线分布的随机数生成器之前,您需要定义您的意思。这是一次尝试:

Parabolic distribution

分布在区间0到1上定义为二次多项式。在此间隔内,曲线下方的区域必须为1.通过改变参数 K M ,您可以调整分布。 K 确定抛物线中心在区间中的位置, M 决定“拉”抛物线的距离。在您的问题中, K 是½,因为您希望顶点位于间隔的中间。您没有指定 M

抛物线由函数

指定
  

f x )= ax 2 + bx + C

提供 K M 并且0到1区间曲线下方的区域应为1,您需要计算 a b c

如果 K =½且 M =½,那么确切的解决方案是

  

f x )= 6 x 2 - 6 x + 2。

如果此解决方案不充分(因为您需要 K 和/或 M 的其他值),则必须创建一组方程式。基于如何放置抛物线,已知 a 必须为正, b 为负且 c &gt; 中号

抛物线的顶点应触及( K M )。这意味着 f K )= M f K ) - M = 0。

为了使顶点触及这一点,修正的二次方程的判别式必须为0:

  

d' = b 2 - 4 a c - < EM>中号)

如果您知道 a c ,则可以计算 b (已知 b 已经 b 否定创造所需的抛物线):

  

b =-√(4 a c - M ))[等式A]

顶点的等式是:

  

f K ) - M = aK 2 + bK + c - M = 0 [等式B]

抛物线下面的区域是根据 f x )的间隔0到1的定积分计算的

  

0 1 f x dx = a / 3 + b / 2 + c = 1 [等式C]

您可以将等式A中的 b 替换为等式B和C,给出两个具有两个未知数 a c 的等式。不幸的是,这些方程是非线性的,我的数学生锈了所以我选择了“简单路径”并使用Excel中的Solver插件来查找 K 中号。如果你采用这种方法,你应该在求解器中添加一个 d'不能为负的约束以及对 a c 的约束如上所述。

现在您知道 a b c 所需的抛物线方程式,创建具有抛物线分布的随机数的方法是如下:

  • 使用均匀分布在抛物线方程的域上生成随机数(在视觉上,您可以将其视为生成 y 值或 f x )值)
  • 使用 f 的反转( x )计算相应的 x 值 - 注意有两种可能的解决方案
  • 如果其中一个解决方案超出0到1区间,则选择另一个解决方案
  • 如果两个解决方案都在0到1的区间内随机选择其中一个

这个挑选的解决方案是一个抛物线分布的随机数。

f x )的倒数是

  

x =( - b ±√( b 2 - 4 a c - y )))/ 2 a

结合所有这些我创建了一个C#类。您必须为参数 K M a b 替换所需的值ç的。或者您可以扩展此代码以从 K M a b c em>使用数值算法。

class ParabolicRandom
{
    const double k = 0.5D;
    const double m = 0.5D;

    const double a = 6;
    const double b = -6;
    const double c = 2;

    readonly double yMin = m;
    readonly double yMax = Math.Max(F(0D), F(1D));

    Random random;

    public ParabolicRandom() => random = new Random();

    public ParabolicRandom(int seed) => random = new Random(seed);

    public double Next()
    {
        var randomY = (yMax - yMin) * random.NextDouble() + yMin;
        var randomX1 = ReverseF1(randomY);
        var randomX2 = ReverseF2(randomY);

        if (randomX1 < 0D || randomX1 > 1D)
            return randomX2;
        if (randomX2 < 0D || randomX2 > 1D)
            return randomX1;
        return random.Next()%2 == 0 ? randomX1 : randomX2;
    }

    static double F(double x) => a * x * x + b * x + c;
    double ReverseF1(double y) => (-b + Math.Sqrt(b * b - 4 * a * (c - y))) / (2 * a);
    double ReverseF2(double y) => (-b - Math.Sqrt(b * b - 4 * a * (c - y))) / (2 * a);
}

要生成10到20之间的随机数,15的一半,而10和20,你可以像这样使用它:

var lowerInclusive = 10;
var upperInclusive = 20;
var value = (int) Math.Floor(
    (upperInclusive - lowerInclusive + 1)*parabolicRandom.Next() + lowerInclusive);