有一种很好的方法来获得具有正态分布的随机生成的整数吗?
第一种让我想到的方法:
int rndi = (int)Math.floor(random.nextGaussian()*std);
有更好的方法吗?
答案 0 :(得分:4)
严格来说,你不能拥有正态分布的整数。也许你想要的是分配到桶中的正态分布的输出。在这种情况下,您可能希望根据数组的大小来移动和缩放正态分布。如果您只是从标准正态分布(均值= 0和比例= 1)中取样,您将在99%的时间内得到介于-2和2之间的样本。
假设您需要来自大小为N的数组的随机样本。您希望中间的条目比最后的样本更频繁地选择,但您希望偶数附近的样本偶尔出现,例如1%的时间。然后你可能想要计算N / 2 + N * z / 4之类的东西,其中z是你的标准法线,然后将这些数字转换为整数。如果你这样做,你偶尔会在阵列外得到一个索引。只需测试它,并在发生这种情况时获得新值。
答案 1 :(得分:2)
您应该更新问题,以明确您的用例。
根据您的评论,您根本不应该使用正态分发。而是尝试使用许多离散分布中的一个,因为最后需要整数。有很多这些,但我推荐一个 - 非常简单。它使用stochastic vector作为离散概率分布。
以下是示例实现:
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);
}
}
答案 2 :(得分:1)
这取决于你试图用这些随机数做什么。
java.util.Random
有一些缺陷。如JavaDoc中所述,nextGaussian()
方法使用Box Muller变换。它取决于使用线性同余生成器实现的Random.nextDouble()
。并且实现不是最好的,如错误修正提案中所述:
Sun的方法使用48位种子(就底部位而言)仅访问其中的17位 - 产生非常严重的非随机性。
因此,如果您对高统计质量感兴趣,您应该真正避免Sun的实施。看看这个"Not so random" applet,看看它有多糟糕。
如果统计质量是您关注的问题,您可以做的最好的事情就是使用一些外部PRNG库。
答案 3 :(得分:1)
您可以预先计算“随机”整数列表,然后手动调整该列表以获得所需的分布。
然后,如果您想要一个“随机”数字,只需从列表中提取下一个可用的数字......
这样可以确保分布,从而确保选择特定项目的概率。为了好玩,您可以随时“混淆”您的列表。