Нормально распределенные случайные целые числа? - PullRequest
3 голосов
/ 19 июля 2010

Есть ли хороший способ получить случайно сгенерированные целые числа с нормальным распределением?

Первый метод, который мне приходит в голову:

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

Есть ли лучший способ?

Ответы [ 4 ]

4 голосов
/ 19 июля 2010

Строго говоря, вы не можете иметь нормально распределенные целые числа. Может быть, вам нужен вывод нормального распределения, отсортированного по сегментам. В этом случае вы, вероятно, захотите сместить и масштабировать свое нормальное распределение в соответствии с размером вашего массива. Если вы просто возьмете образцы из стандартного нормального распределения (среднее = 0 и масштаб = 1), вы получите выборки между -2 и 2 примерно в 99% случаев.

Предположим, вы хотите, чтобы случайные выборки из массива размера N. Вы хотите, чтобы записи в середине выбирались чаще, чем выборки в конце, но вы хотите, чтобы выборки вблизи концов иногда появлялись, скажем, 1% времени. Затем вы можете захотеть вычислить что-то вроде N / 2 + N * z / 4, где z - ваш стандартный нормаль, а затем привести эти числа к целому числу. Если вы сделаете это, вы будете иногда получать индекс вне вашего массива. Просто проверьте это и получите новое значение, когда это произойдет.

2 голосов
/ 19 июля 2010

Вы должны обновить вопрос, чтобы уточнить, какой именно у вас вариант использования.

Согласно вашему комментарию, вам вообще не следует использовать нормальное распространение.Вместо этого попробуйте один из многих дискретных дистрибутивов, так как вы хотите целые числа в конце.Их много, но я бы порекомендовал один - очень простой.Он использует стохастический вектор в качестве дискретного распределения вероятностей.

Вот пример реализации:

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);
    }
}
1 голос
/ 19 июля 2010

Вы можете предварительно вычислить список «случайных» целых чисел, а затем вручную настроить этот список, чтобы получить желаемое распределение.

Тогда, когда вы хотите "случайное" число, просто вытащите следующее доступное число из списка ...

Таким образом, вы гарантируете распределение и, следовательно, вероятность выбора определенного элемента. Для развлечения вы можете просто «перепутать» свой список, когда вам нужно.

1 голос
/ 19 июля 2010

Это зависит от того, что вы пытаетесь сделать с этими случайными числами.

У java.util.Random есть некоторые недостатки. Как указано в JavaDoc, метод nextGaussian() использует преобразование Бокса-Мюллера. Это зависит от Random.nextDouble(), который реализован с использованием линейного конгруэнтного генератора. И реализация не лучшая, как указано в предложении об исправлении ошибки:

В методе Sun используется 48-разрядное начальное число и (что касается нижнего бита) доступ только к 17-битному из них, что создает чрезвычайно серьезную неслучайность .

Так что, если вы заинтересованы в высоком статистическом качестве , вам действительно следует избегать внедрения Sun. Взгляните на этот "Не очень случайный" апплет для наглядного доказательства того, насколько он плох.

Если вам важно статистическое качество, лучшее, что вы можете сделать, - это использовать какую-нибудь внешнюю библиотеку PRNG.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...