有没有一种好的方法可以获得正态分布的随机生成整数?
我想到的第一种方法是:
int rndi = (int)Math.floor(random.nextGaussian()*std);
有更好的方法吗?
严格来说,你不能拥有正态分布的整数。也许你想要的是正态分布输出按桶排序后的结果。在这种情况下,你可能想根据数组大小调整和缩放你的正态分布。如果你只是从标准正态分布(平均值=0,范围=1)中取样,那么99%的时间会得到-2到2之间的样本。
假设你想要从大小为N的数组中随机抽样。你希望中间的条目被选择的频率比末尾的样本更高,但你希望接近末尾的样本偶尔出现,比如1%的时间。那么你可以计算类似于 N/2 + N*z/4 的东西,其中z是标准正态分布,然后将这些数字转换为整数。如果你这样做,偶尔会得到一个超出你的数组索引范围的索引。当发生这种情况时,只需测试并获取一个新值即可。
public class DiscreteRandom {
private final double[] probDist;
public DiscreteRandom(double... probs) {
this.probDist = makeDistribution(probs);
}
private double[] makeDistribution(double[] probs) {
double[] distribution = new double[probs.length];
double sum = 0;
for (int i = 0; i < probs.length; i++) {
sum += probs[i];
distribution[i] = sum;
}
return distribution;
}
public int nextInt() {
double rand = Math.random();
int i = 0;
while (rand > probDist[i]) i++;
return i;
}
/**
* Simple test
*/
public static void main(String[] args) {
// We want 0 to come 3 times more often than 1.
// The implementation requires normalized probability
// distribution thus testProbs elements sum up to 1.0d.
double[] testProbs = {0.75d, 0.25d};
DiscreteRandom randGen = new DiscreteRandom(testProbs);
// Loop 1000 times, we expect:
// sum0 ~ 750
// sum1 ~ 250
int sum0 = 0, sum1 = 0, rand;
for (int i = 0; i < 1000; i++) {
rand = randGen.nextInt();
if (rand == 0) sum0++;
else sum1++;
}
System.out.println("sum0 = " + sum0 + "sum1 = " + sum1);
}
}
这取决于您想要如何使用这些随机数。
java.util.Random
存在一些缺陷。正如 JavaDoc 中所述,nextGaussian()
方法使用 Box Muller 变换。它依赖于使用线性同余生成器实现的 Random.nextDouble()
。而且实现并不是最好的,正如一个错误修复建议中所述:
Sun 的方法使用了 48 位种子,并且(就底部位而言)只访问了其中的 17 位 - 产生了极其严重的非随机性。
因此,如果您对高统计质量感兴趣,应该避免使用 Sun 的实现。查看此 "Not so random" applet 以获得可视化证明。
如果统计质量是您关注的问题,则最好的选择是使用一些外部 PRNG 库。
java.util.Random
对许多应用程序提供可接受的结果。http://en.wikipedia.org/wiki/Linear_congruential_generator - trashgod