Одним из распространенных дефектов генераторов случайных чисел является небольшое смещение в сторону меньших результатов (в основном небольшое смещение в сторону 0 в старших битах). Это часто происходит, когда перенос внутреннего состояния RNG в выходной диапазон выполняется с помощью простого мода, который смещен в сторону высоких значений, если только RAND_MAX не является делителем размера внутреннего состояния. Вот типичная реализация предвзятого отображения:
static unsigned int state;
int rand() {
state = nextState(); /* this actually moves the state from one random value to the next, eg., using a LCG */
return state % RAND_MAX; /* biased */
}
Смещение возникает из-за того, что более низкие выходные значения имеют еще одно отображение под модом из состояния. Например, если состояние может иметь значения 0–9 (10 значений), а RAND_MAX равно 3 (значения 0–2), то результатом операции % 3
в зависимости от состояния
Output State
0 0 3 6 9
1 1 4 7
2 2 5 8
Результат 0 перепредставлен, потому что он имеет шанс быть выбранным 4/10 по сравнению с 3/10 для других значений.
В качестве примера с более вероятными значениями, если внутреннее состояние RNG является 16-целым числом, а RAND_MAX
равно 35767 (как вы упомянули, это на вашей платформе), тогда все значения [0,6000] будут выведены для 3 разных значения состояния, но оставшиеся ~30 000 значений будут выведены только для 2 различных значений состояния — значительное смещение. Этот тип смещения может привести к тому, что значение вашего счетчика будет выше, чем ожидалось (поскольку меньшие, чем универсальные, результаты rand() благоприятствуют условию p_scaled >= 1
.
Было бы полезно, если бы вы могли опубликовать точную реализацию rand() на вашей платформе. Если окажется, что это смещение в старших битах, вы можете устранить это, передав значения, полученные от rand(), через хорошую хэш-функцию, но лучший подход, вероятно, состоит в том, чтобы просто использовать высококачественный источник случайных данных. числа, например, Вихрь Мерсенна. У лучшего генератора также будет больший выходной диапазон (эффективный, более высокий RAND_MAX), что означает, что ваш алгоритм будет подвергаться меньшему количеству повторных попыток/меньшей рекурсии.
Даже если реализация среды выполнения Visual Studio страдает от этого дефекта, стоит отметить, что это, вероятно, было, по крайней мере частично, преднамеренным выбором дизайна — использование RAND_MAX, такого как 35767, которое является относительно простым по отношению к размеру состояния (обычно степени 2), гарантирует лучшая случайность младших битов, поскольку операция % эффективно смешивает биты старшего и младшего разрядов, а наличие смещенных/неслучайных битов младшего разряда на практике часто является более серьезной проблемой, чем небольшое смещение битов старшего разряда из-за вездесущности вызывающего rand()
уменьшает диапазон с помощью %, который эффективно использует только младшие биты для модулей, которые являются степенями 2 (также очень распространены).
person
BeeOnRope
schedule
27.01.2014
if
не заботятся обо всех числах в диапазоне]0,1[
; вы, вероятно, захотите переосмыслить весь код и то, что он делает. Просто используйтеBernoulli PRNG
- person user2485710   schedule 26.01.2014return rand() < probability*(RAND_MAX+1.0)
, то я бы получалtrue
из этой функции каждые1.0/32768
попыток (в среднем) даже дляprobability = 1.0e-100
, что было бы непригодно для моих целей. - person fiktor   schedule 26.01.2014if
не заботятся обо всех возможных числах, возвращаемыхrand()
. Вот почему у меня в конце есть операторreturn
, который вызывается с небольшой вероятностью около1.0/RAND_MAX
. - person fiktor   schedule 26.01.2014double
в качестве возвращаемого типа, когда в 2 случаях из 3 вы возвращаетеbool
. - person user2485710   schedule 27.01.2014