2016-08-25 128 views
4

我已经知道如何在一个范围内产生随机数。我可以通过使用在标准偏差的特定范围内生成随机数?

rand.nextInt((max - min) + 1) + min; 

问题是我还想为这些数字设置一个标准偏差。这些数字还需要积极的,他们不是0和1之间

编辑我删除了ThreadLocalRandom类,因为我不能在类中设置一个种子和这些随机数字应该在不同的系统中可再生的。

+2

请问这有帮助吗? ... http://stackoverflow.com/questions/31754209/can-random-nextgaussian-sample-values-from-a-distribution-with-different-mean –

+0

提示:我花了更少的时间找到“重复”问题比阅读你的问题。我想:写下你的问题需要更长的时间。所以,请;下次做一些事先研究。 – GhostCat

+0

@GhostCat“重复”的答案不能解决我的问题,因为我需要一个范围内的数字。 – statboy

回答

3

选择有界分布的标准偏差(或方差)只能根据所选分布和您的间隔的边界(min, max)的约束条件进行。某些分布可能允许您将变化任意小(例如Beta distribution),其他分布(如Uniform distribution)在设置边界(min, max)后不允许任何灵活性。无论如何,你会从不能够使方差任意大 - 边界确实阻止了这一点(它们将始终输入分布方差的表达式)。

我将举例说明一个非常简单的例子,它可以在不需要任何第三方库的情况下实现。假设您想在区间(min, max)上进行对称分布,对称性意味着分布的均值E(X)位于区间的中间:E(X) = (min + max)/2

使用随机的nextDoublex = a + (b - a) * rnd.nextDouble()会给你,有一个固定的方差Var(X) = (b - a)^2/12(不是我们想要的)的间隔a <= x < b均匀分布的随机变量。

OTH,在相同的时间间隔(a, b)模拟对称triangular distribution会给我们一个随机变量蒙山相同的均值,但只有一半的方差:Var(X) = (b - a)^2/24(也是固定的,所以也并不是我们想要的)。

具有参数(a < b < c < d)的对称trapezoidal distribution位于区间(a, d)上的均匀和三角形分布中间的某处。对称条件意味着d - c = b - a,在下文中我将把距离b - a指定为x或称为“位移​​”(我已经编制了该名称,这不是技术术语)。

如果您让x从上方接近0.0,则梯形将看起来非常类似于均匀分布,其方差将趋于最大可能值(d - a)^2/12。如果让x从下方接近最大可能值(d - a)/2,则梯形将看起来与对称三角形分布非常相似,其方差将接近最小可能值(d - a)^2/24)(但请注意,我们应该远离这些极端值为了不打破方差公式或我们的梯形算法)。

所以,这个想法是构建与x是得到你想要的标准偏差值的梯形分布,因为你的目标的标准偏差必须在开区间(大致)由(0.2041(d - a), 0.2886(d - a))里面给出的条件。为了方便,我们假设a = min = 2.0d = max = 10.0,它给了我们这个可能的stddevs范围:(1.6328, 2.3088)。我们进一步假设我们想要构建一个stddev为2.0的分布(当然,它必须在可接受的范围内)。

解决这需要3个步骤:

1),我们需要有给定min, max方差和用于位移的容许值的公式x

2),我们需要以某种方式“反转”这种表达给我们的x的价值,为目标方差

3)一旦我们知道的x的价值,我们必须构建具有与参数的等腰梯形分布的随机变量(min, max, x)

步骤1

/** 
* Variance of a symmetric trapezoidal distribution with parameters 
* {@code a < b < c < d} and the length of {@code d - c = b - a} 
* (by symmetry) identified by {@code x}. 
* 
* @param a support lower bound 
* @param d support upper bound 
* @param x length of {@code d - c = b - a}, constrained to lie in the open 
*   interval {@code (0, (d-a)/2)} 
* @return variance of the symmetric trapezoidal distribution defined by 
*   the triple {@code (a, d, x)} 
*/ 
static double varSymTrapezoid(double a, double d, double x) { 
    if (a <= 0.0 || d <= 0.0 || a >= d) { 
     throw new IllegalArgumentException(); 
    } 
    if (x <= 0.0 || x >= (d - a)/2) { 
     throw new IllegalArgumentException(); 
    } 
    double b = a + x; 
    double c = d - x; 
    double b3 = pow(b, 3); 
    double c3 = pow(c, 3); 
    double ex2p1 = pow(b, 4)/4 - a * b3/3 + pow(a, 4)/12; 
    double ex2p2 = (c3/3 - b3/3) * (d - c); 
    double ex2p3 = pow(c, 4)/4 - d * c3/3 + pow(d, 4)/12; 
    double ex2 = (ex2p1 + ex2p2 + ex2p3)/((d - b) * (d - c)); 
    return ex2 - pow((a + d)/2, 2); 
} 

请注意,此公式仅适用于对称的梯形分布。举个例子,如果你调用这个方法的位移为2.5(varSymTrapezoid(2.0, 10.0, 2.5))它会给你回差约为3.0416,这太低了(我们需要4.0),这意味着2.5的位移太多(更高的位移给出较低的差异)。

方差表达式是x中的一个4阶多项式,我不想分析求解。然而,对于允许范围内的目标x这个表达式是单调递减的,所以我们可以构造一个函数,它为我们的目标方差穿过零,并通过简单的bisection来解决这个问题。这是

步骤2

/** 
* Find the displacement {@code x} for the given {@code stddev} by simple 
* bisection. 
* @param min support lower bound 
* @param max support upper bound 
* @param stddev the standard deviation we want 
* @return the length {@code x} of {@code d - c = b - a} that yields a 
* standard deviation roughly equal to {@code stddev} 
*/ 
static double bisect(double min, double max, double stddev) { 
    final double eps = 1e-4; 
    final double var = pow(stddev, 2); 
    int iters = 0; 
    double a = eps; 
    double b = (max - min)/2 - eps; 
    double x = eps; 
    double dx = b - a; 

    while (abs(dx) > eps && iters < 150 && eval(min, max, x, var) != 0.0) { 
     x = ((a + b)/2); 
     if ((eval(min, max, a, var) * eval(min, max, x, var)) < 0.0) { 
      b = x; 
      dx = b - a; 
     } else { 
      a = x; 
      dx = b - a; 
     } 
     iters++; 
    } 
    if (abs(eval(min, max, x, var)) > eps) { 
     throw new RuntimeException("failed to find solution"); 
    } 
    return x; 
} 

/** 
* Function whose root we want to find. 
*/ 
static double eval(double min, double max, double x, double var) { 
    return varSymTrapezoid(min, max, x) - var; 
} 

调用bisect方法与用于标准偏差(bisect(2.0, 10.0, 2.0))给了我们所需要的位移所需的值2.0:~ 1.1716。现在我们已经知道x值是已知的,我们要做的最后一件事是建立一个适当分布的随机变量,它是

步骤3

这是概率论是一个众所周知的事实如果a1 + b2 < a2 + b1(情况1)或a2 + b1 < a1 + b2(情况2),两个独立的均匀分布的随机变量X1 ~ U[a1, b1]X2 ~ U[a2, b2]的总和是区间[a1 + a2,b1 + b2]上的对称梯形分布的随机变量。我们必须避免案例a2 + b1 = a1 + b2(案例3),因为总和具有我们不想要的对称三角分布。

我们将选择案例1(a1 + b2 < a2 + b1)。在这种情况下,b2 - a2的长度将等于“排量”x

因此,所有我们要做的是选择区间的边界A1,A2,B1和B2,使得a1 + a2 = minb1 + b2 = maxb2 - a2 = x和上述不等式fullfilled:

/** 
* Return a pseudorandom double for the symmetric trapezoidal distribution 
* defined by the triple {@code (min, max, x)} 
* @param min support lower bound 
* @param max support upper bound 
* @param x length of {@code max - c = b - min}, constrained to lie in the 
*   open interval {@code (0, (max-min)/2)} 
*/ 
public static double symTrapezoidRandom(double min, double max, double x) { 
    final double a1 = 0.5 * min; 
    final double a2 = a1; 

    final double b1 = max - a2 - x; 
    final double b2 = a2 + x; 

    if ((a1 + b2) >= (a2 + b1)) { 
     throw new IllegalArgumentException(); 
    } 

    double u = a1 + (b1 - a1) * rnd.nextDouble(); 
    double v = a2 + (b2 - a2) * rnd.nextDouble(); 
    return u + v; 
} 

调用symTrapezoidRandom(2.0, 10.0, 1.1716)反复给你具有所需分布的随机变量。

你可以用Beta等其他更复杂的发行版做类似的事情。这会给你其他(通常更灵活)的容许差异的界限,但你需要第三方库,如commons.math

abspowsqrt在代码指静态进口java.lang.Math中的方法和rnd是java.util.Random中的一个实例。

+0

你能告诉我你从哪里得到对称梯形的方差公式吗?我无法在任何地方找到它。 – apophis

+0

@apophis我用笔和纸手动计算它。有趣的是,给出的公式[这里](http://doc.openturns。org/openturns-latest/sphinx/user_manual/_generated/openturns.Trapezoidal.html)虽然看起来合理,却是错误的。也许他们只是交换了变量。 [这](https://de.wikipedia.org/wiki/Trapezverteilung)一个更糟糕的是甚至没有'E(X)'是正确的。我找不到一个使用'(a,b,c,d)'表示的正确方程,所以我必须自己推导它。 –

相关问题