2013-06-18 3 views
0

После прочтения некоторых сообщений, я выяснил, что использование Math.random() в Java для генерации целого числа является каким-то предвзятым.Unbiased random integer generator

я наткнулся алгоритма в этом посте:

Unbiased random number generator using a biased one

Он генерирует непредвзятый результат между 0 и 1, и я хотел бы использовать его для моей программы.

Однако я пытаюсь создать непредвиденный генератор между 0 и определенным значением (например, 7) в Java, но я не уверен, что если этот алгоритм работает для ряда чисел.

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

+3

Вместо этого вы посмотрели на 'java.util.Random'? –

+1

@JonSkeet документация 'Math.random()' говорит: «Когда этот метод сначала вызывается, он создает один новый генератор псевдослучайных чисел, точно так же, как если бы выражение new java.util.Random« –

+0

@JonSkeet. уверен, что это беспристрастно? –

ответ

-1

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

+1

Собственно, это будет ** не ** работать так легко, потому что округление до целых чисел испортит это. Однако, как уже отмечал @JonSkeet, 'java.util.Random' имеет пару вещей на выбор. –

+1

@ Anony-Mousse ** ** будет работать даже с округлением, потому что, если вы получаете одинаковое случайное число дважды в один раунд в одну и ту же точку каждый раз. Число может быть не совсем таким, как вы получите, когда вы правильно умножаете на 7, но его все еще случайным, и поскольку он исходит от несмещенного генератора, он непредвзятен. –

+0

Умножение всегда приведет к некоторому смещению, потому что некоторые числа будут невозможны в качестве вывода. (В этом случае возможны только «кратные» значения из 7.) – jpaugh

1

Попробуйте это:

int randomizer(int min, int max) 
{ 
    int n = max - min + 1; 
    int remainder = RAND_MAX % n; 
    int x; 
    do 
    { 
     x = rand(); 
    } while (x >= RAND_MAX - remainder); 
    return min + x % n; 
} 

Это измененная версия другого алгоритма, с которым вы связались.

2

Вы можете использовать только Random.nextInt(int). Для ваших нужд используйте new Random().nextInt(8). Как говорится в документации:

Возвращает псевдослучайный, равномерно распределенные Int значения от 0 (включительно) и заданного значения (эксклюзив)

Но на самом деле, я думаю, вы могли бы использовать Math.random() все вместе. Its documentation says:

Когда этот метод сначала вызывается, он создает один новый генератор псевдослучайных чисел, точно так, как если бы выражением new java.util.Random

Исходный код Math.random() является:

public static double random() { 
    if (randomNumberGenerator == null) initRNG(); 
    return randomNumberGenerator.nextDouble(); 
} 

И documentation для nextDouble также говорит:

Возвращает следующие псевдохаотическом равномерно распределены двойного значения между 0,0 и 1,0

+0

Ну, ключевой вопрос: он ** предвзятый ** или нет? –

+0

@ Anony-Mousse: Разве «равномерно распределенная» не означает объективность? Какая разница? –

+0

Существуют различные виды предвзятости. RNG, оптимизированный для скорости, может даже быть предвзятым в том смысле, что он генерирует * чрезмерно * равномерные случайные числа. –

2

Я считаю, что вы неправильно эти сообщения. Тот, который вы связали, по сути говорит, что вы не должны использовать random.nextInt() % max, что действительно предвзято; поэтому этот подход очень наивен. Однако, если вы посмотрите на документацию или исходный код Javas nextInt(max), то он is более умный. Возможно достаточно непредвзято для вас. Просто узнайте больше о Java API, у него много функциональности ...

В этом примере подробно генерирует один бит непредвзято, не несмещенной двойной случайной между 0 и 1!

Я не уверен, что случайный генератор Java в значительной степени предвзято в том, как вас беспокоят. Но это, безусловно, не качественное случайное, потому что для большинства пользователей оно должно быть fast. Если вы хотите, чтобы высокая энтропия была случайной, попробуйте использовать высококачественные случайные источники вашей операционной системы.

В любом случае, если вы хотите случайное число от 0 до 7 , используя метод, связанный с вашего поста (!, Который, вероятно, является общей избыточна), сделайте следующее:

int bit1 = generateOneBitOfRandom(); 
int bit2 = generateOneBitOfRandom(); 
int bit3 = generateOneBitOfRandom(); 
int zerotoseven = (bit1 << 2) + (bit2 << 1) + bit3; 

// Probably at least as good is the proper Java API: 
Random random = new Random(); 
int zerotoseven2 = random.nextInt(8); 

Опять же, скорее всего, java.util.Random nextInt(8) будет достаточно для вас. Если вы не выполняете криптографию. Тогда вам действительно стоит просто прочитать байт от /dev/random, который может иметь доступ к пулу энтропийного оборудования, если ваш процессор или материнская плата имеют такие функции (просто надеюсь, что один из них не смещен/смещен). Скорее всего, что делает Javas SecureRandom. Опять же пример того, что Java API, вероятно, гораздо умнее, чем вы думаете.

4

Вы должны указать ссылку, в которой утверждается, что Java Math.random() является предвзятым и точно каким образом. Это была бы огромная проблема, так как это очень важная часть стандартной библиотеки Java.

Java предоставляет SecureRandom, что более подходит для генерации случайных чисел криптографической силы. Чтобы использовать это для генерации числа от 0 до N, вы можете использовать тот же алгоритм, который представлен в Random.nextInt(int) documentation, но с SecureRandom.

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