RNGCryptoServiceProvider - быстрее сгенерировать номер в диапазоне и сохранить распределение?

Сначала я разговариваю по телефону, поэтому, пожалуйста, извините за плохое форматирование!

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

Я использую поставщика криптографии ГСЧ для генерации чисел в диапазоне действительно наивным способом:

byte[] bytes = new byte[4];
int result = 0;
while(result < min || result > max)
{
   RNG.GetBytes(bytes);
   result = BitConverter.ToInt32(bytes);
}  

Это замечательно, когда диапазон достаточно широк, так что есть приличный шанс получить результат, но ранее сегодня я столкнулся со сценарием, когда диапазон достаточно мал (в пределах 10 000 чисел), что может занять время.

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

Моя идея:

  • получить наивысшие битовые позиции мин и макс, например для 4 это будет 3, а для 17 будет 5
  • выберите количество байтов из prng, которое может содержать как минимум старшие биты, например 1 в этом случае для 8 бит
  • , посмотрите, есть ли какие-либо из верхних биты в разрешенном диапазоне (3-5) устанавливаются
  • , если да, превратите это в число до старшего бита
  • включительно, если это число находится между min и max, вернуть.
  • если любой из предыдущие тесты терпят неудачу, начните снова.

Как я уже сказал, это может быть чрезвычайно наивно, но я уверен, что он вернет совпадение в узком диапазоне быстрее, чем текущая реализация. Я сейчас не перед компьютером, поэтому не могу проверить, буду делать это завтра утром по британскому времени.

Но, конечно, скорость - не единственное, что меня беспокоит, иначе я бы просто использовал Random (нужна пара отметок для правильного форматирования, если кто-то будет достаточно любезен - их нет на клавиатуре Android!).

Самая большая проблема, которую я испытываю в связи с вышеуказанным подходом, заключается в том, что я всегда бросаю до 7 бит, которые были сгенерированы prng, что кажется плохим. Я думал о способах их учета (например, простое добавление), но они кажутся ужасно ненаучными!

Я знаю о трюке с модом, когда вам нужно создать только одну последовательность, но я также знаю о его слабых сторонах.

] Это тупик? В конечном счете, если лучшим решением будет придерживаться текущей реализации, я просто чувствую, что должен быть лучший способ!

27
задан Andras Zoltan 6 November 2017 в 21:01
поделиться