通常分布的随机整数?

时间:2010-07-19 10:14:12

标签: java integer random

有一种很好的方法来获得具有正态分布的随机生成的整数吗?

第一种让我想到的方法:

int rndi = (int)Math.floor(random.nextGaussian()*std);

有更好的方法吗?

4 个答案:

答案 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)

您可以预先计算“随机”整数列表,然后手动调整该列表以获得所需的分布。

然后,如果您想要一个“随机”数字,只需从列表中提取下一个可用的数字......

这样可以确保分布,从而确保选择特定项目的概率。为了好玩,您可以随时“混淆”您的列表。