Java: генерация случайных чисел с логарифмическим распределением - PullRequest
3 голосов
/ 19 сентября 2010

Я пытаюсь сгенерировать случайные числа с логарифмическим распределением.

Если n = 1 встречается в половине времени, n = 2 - в четверти, n = 3 - в восьмой частивремя и т. д.

    int maxN = 5;
    int t = 1 << (maxN); // 2^maxN
    int n = maxN -
            ((int) (Math.log((Math.random() * t))
            / Math.log(2))); // maxN - log2(1..maxN)
    System.out.println("n=" + n);

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

Почему это так?На мой взгляд, максимальное значение Math.random() равно 1,0;
, поэтому максимальное значение (Math.random() * t)) равно t;
, следовательно, максимальное значение log2 (t) равно maxN, поскольку t =2 ^ maxN;

Куда пошла моя логика?

Спасибо

Ответы [ 3 ]

6 голосов
/ 19 сентября 2010

логарифм чисел меньше 1,0 отрицателен. Когда генерируемое случайное число таково, что оно меньше 1,0, выражение ((int) (Math.log(Math.random() * t) / Math.log(2))) является отрицательным числом и, следовательно, maxN - (the negative number) больше, чем maxN.

Следующее выражение должно давать правильное распределение.

n = Math.floor(Math.log((Math.random() * t) + 1)/Math.log(2))

Обратите внимание, что:

0.0 <= Math.random() <= 1.0
0.0 <= Math.random() * t <= t
1.0 <= (Math.random() * t) + 1 <= t + 1.0
0.0 <= Math.log((Math.random() * t) + 1) <= Math.log(t + 1.0)
0.0 <= Math.log((Math.random() * t) + 1)/Math.log(2) <= Math.log(t + 1.0)/Math.log(2)

Since t = 2^maxN,
Math.log(t + 1.0)/Math.log(2) is slightly larger than maxN.

So do a Math.floor and you get the correct result:
0.0 <= Math.floor(Math.log((Math.random() * t) + 1)/Math.log(2)) <= maxN
2 голосов
/ 19 сентября 2010

Если Math.random()*t меньше 1, то вы получите отрицательный ответ, когда вы берете Math.log(Math.random()*t) по правилам логарифмов. Это означает, что вы получите отрицательный ответ при делении на Math.log(2), потому что это 0.69314718055994530941723212145818. Это отрицательное число, разделенное на положительное число. Ответ отрицательный. maxN - отрицательное число = maxN + что-то положительное, поэтому n больше, чем maxN. Чтобы исправить это приведение Math.random () * t к int и добавьте 1:

int n = maxN -
        ((int) (Math.log((int)((Math.random() * t)+1))
        / Math.log(2))); // maxN - log2(1..maxN)

Обратите внимание на приведение внутри журнала и добавление 1.

Цель добавления единицы состоит в том, чтобы избежать нуля. Невозможно взять журнал 0. Также без добавления 1 вы никогда не получите maxN внутри журнала, потому что Math.random () никогда не выдаст 1. Кстати, вместо получения 1 половины, 2, четвертого, 3 и восьмого он просто начинается с 0. Это дает 0, половина, 1 четвертое, 2 восьмое и т. д.

1 голос
/ 19 сентября 2010

Проблема в другом конце шкалы.

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

...