我已经知道如何在一个范围内生成随机数。我可以使用
来做到这一点rand.nextInt((max - min) + 1) + min;
问题是我还想为这些数字设置一个标准偏差。数字也需要是正数,它们不在0和1之间
编辑我删除了ThreadLocalRandom类,因为我无法在该类中设置种子,这些随机数应该可以在不同的系统中重现。
答案 0 :(得分:4)
选择有界分布的标准偏差(或方差)只能在依赖于所选分布和区间的边界(min, max)
的约束条件下进行。一些分布可能允许你使方差任意小(例如Beta distribution),其他分布(如Uniform distribution)在边界(min, max)
之后不允许任何灵活性组。在任何情况下,你都永远不会能够使方差任意大 - 边界确实可以防止这种情况(他们总是会输入分布式方差的表达式) )。
我将举例说明一个非常简单的示例,无需任何第三方库即可实现。让我们假设你想要在区间(min, max)
上进行对称分布,对称性意味着分布的平均E(X)位于区间的中间:E(X) = (min + max)/2
。
在nextDouble
中使用随机x = a + (b - a) * rnd.nextDouble()
将在a <= x < b
区间内为您提供均匀分布的随机变量,该变量具有固定的方差Var(X) = (b - a)^2 / 12
(不是我们想要。)
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
或&#34;置换&#34; (我已经说出了这个名字,它不是一个技术术语)。
如果让x
从上方接近0.0,则梯形将看起来非常类似于均匀分布,其方差将倾向于最大可能值(d - a)^2 / 12
。如果让x
从下面接近最大可能值(d - a)/2
,则梯形将看起来非常类似于对称三角形分布,其方差将接近(d - a)^2 / 24)
的最小可能值(但请注意我们应该远离这些极端值,以免破坏方差公式或梯形算法。
因此,我们的想法是构造一个梯形分布,其值为x
,产生您想要的标准偏差,条件是您的目标标准偏差必须位于由{给出的开放范围(粗略)内。 {1}}。为方便起见,我们假设(0.2041(d - a), 0.2886(d - a))
和a = min = 2.0
为我们提供了一系列可能的stddevs:d = max = 10.0
。让我们进一步假设我们想构建一个stddev为(1.6328, 2.3088)
的分布(当然,它必须在允许的范围内)。
解决这个问题需要3个步骤:
1)我们需要有一个给定2.0
方差的公式和一个位移min, max
的可接受值
2)我们需要某种方式&#34;反转&#34;这个表达式为我们提供了目标方差的x
值
3)一旦我们知道x
的值,我们必须构造一个具有参数x
的对称梯形分布的随机变量
第1步:
(min, max, x)
请注意,此公式仅对对称梯形分布有效。例如,如果您使用2.5(/**
* 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);
}
)的位移调用此方法,它会返回大约varSymTrapezoid(2.0, 10.0, 2.5)
的差异,这个差异太小(我们需要4.0),这意味着2.5的位移太大(位移越高,方差越小)。
方差表达式是3.0416
中的4阶多项式,我不想分析求解。但是,对于允许范围内的目标x
,此表达式是单调递减的,因此我们可以为目标方差构造一个过零的函数,并通过简单的bisection求解。这是
第2步:
x
使用标准差(/**
* 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;
}
)所需的值2.0调用bisect
方法,可以得到所需的位移:bisect(2.0, 10.0, 2.0)
。既然知道了~ 1.1716
的值,我们最后要做的就是构造一个适当分布的随机变量
第3步:
概率论的一个众所周知的事实是,两个独立的均匀分布随机变量x
和X1 ~ U[a1, b1]
之和是区间[a1 + a2,b1]上的对称梯形分布随机变量+ b2]提供了X2 ~ U[a2, b2]
(案例1)或a1 + b2 < a2 + b1
(案例2)。我们必须避免案例a2 + b1 < a1 + b2
(案例3),因为那时总和具有我们不想要的对称三角形分布。
我们将选择案例1(a2 + b1 = a1 + b2
)。在这种情况下,a1 + b2 < a2 + b1
的长度将等于&#34;置换&#34; b2 - a2
。
所以,我们所要做的就是选择区间边界a1,a2,b1和b2,以便x
,a1 + a2 = min
,b1 + b2 = max
和上面的不等式完全填满:< / p>
b2 - a2 = x
重复调用/**
* 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;
}
会为您提供具有所需分布的随机变量。
你可以与Beta之类的其他更复杂的发行版做同样的事情。这将为您提供允许差异的其他(通常更灵活)界限,但您需要第三方库,如commons.math。
代码中的 symTrapezoidRandom(2.0, 10.0, 1.1716)
,abs
,pow
引用静态导入的java.lang.Math方法,sqrt
是java.util.Random的实例。