Создать случайный uint
Мне нужно генерировать случайные числа с диапазоном для byte
, ushort
, sbyte
, short
, int
и uint
. Я могу генерировать для всех этих типов, используя метод Random в С# (например, values.Add((int)(random.Next(int.MinValue + 3, int.MaxValue - 2)));
), за исключением uint, поскольку Random.Next
принимает только значения int.
Есть ли простой способ генерации случайных uint
?
Ответы
Ответ 1
Простейшим подходом, вероятно, будет использование двух вызовов: один для 30 бит и один для последних двух. Более ранняя версия этого ответа предполагала, что Random.Next()
имеет инклюзивную верхнюю границу int.MaxValue
, но она оказывается исключительной - поэтому мы можем получить только 30 равномерных битов.
uint thirtyBits = (uint) random.Next(1 << 30);
uint twoBits = (uint) random.Next(1 << 2);
uint fullRange = (thirtyBits << 2) | twoBits;
(Вы можете взять это в двух 16-битных значениях, конечно, в качестве альтернативы... или различных опций между ними.)
В качестве альтернативы вы можете использовать NextBytes
для заполнения 4-байтового массива, затем используйте BitConverter.ToUInt32
.
Ответ 2
Хосе летние кубики
Или существует простой способ генерации истинного случайного uint?
Я признаю, что это не OQ. Становится ясно, что существуют более быстрые способы генерации случайных uint, которые не являются истинными. Тем не менее я предполагаю, что никто не слишком заинтересован в их создании, за исключением случаев, когда по какой-то причине требуется не-плоское распределение. Начнем с некоторых исследований, чтобы упростить и ускорить работу на С#. Легко и быстро часто ведут себя как синонимы, когда я пишу код.
Сначала: некоторые важные свойства
См. MSDN.
Random
конструкторы:
-
Random()
: Инициализирует новый экземпляр класса Random
, используя временное начальное значение по умолчанию.
-
Random(int seed)
: Инициализирует новый экземпляр класса Random
, используя указанное начальное значение.
Чтобы повысить производительность, создайте один объект Random
для генерации множества случайных чисел с течением времени, вместо того, чтобы многократно создавать новые объекты Random
для генерации одного случайного числа, поэтому:
private static Random rand = new Random();
Random
методы:
-
rand.Next()
: возвращает положительное случайное число, большее или равное нулю, меньше int.MaxValue
.
-
rand.Next(int max)
: возвращает положительное случайное число, большее или равное нулю, меньше max, max должно быть больше или равно нулю.
-
rand.Next(int min, int max)
: возвращает положительное случайное число, большее или равное min, меньше max, max должно быть больше или равно min.
Домашнее задание показывает, что rand.Next()
примерно в два раза быстрее, чем rand.Next(int max)
.
Второе: решение.
Предположим, что положительный int имеет только два бита, забудьте знаковый бит, он равен нулю, rand.Next()
возвращает три разных значения с равной вероятностью:
00
01
10
Для истинного случайного числа младший бит равен нулю так часто, как он один, то же самое для самого старшего бит.
Чтобы он работал для наименьшего использования бит: rand.Next(2)
Предположим, что int имеет три бита, rand.Next()
возвращает семь разных значений:
000
001
010
011
100
101
110
Чтобы заставить его работать для младших двух бит, используйте: rand.Next(4)
Предположим, что int имеет n бит.
Чтобы заставить его работать для n бит, используйте: rand.Next(1 << n)
Чтобы он работал максимум на 30 бит, используйте: rand.Next(1 << 30)
Это максимум, 1 < 31 больше, чем int.MaxValue
.
Это приводит к способу генерации истинного случайного uint:
private static uint rnd32()
{
return (uint)(rand.Next(1 << 30)) << 2 | (uint)(rand.Next(1 << 2));
}
Быстрая проверка: какова вероятность генерации нуля?
1 < 2 = 4 = 2 2 1 < 30 = 2 30
Вероятность нуля равна: 1/2 2 * 1/2 30= 1/2 32
Общее число uint, включая ноль: 2 32
Это ясно, как дневной свет, без предупреждения о смоге, не так ли?
Наконец: вводящая в заблуждение идея.
Возможно ли это сделать быстрее, используя rand.Next()
int.Maxvalue is: (2^31)-1
The largest value rand.Next() returns is: (2^31)-2
uint.MaxValue is: (2^32)-1
Когда rand.Next()
используется дважды и результаты добавляются, наибольшее возможное значение:
2*((2^31)-2) = (2^32)-4
Разница с uint.MaxValue:
(2^32)-1 - ((2^32)-4) = 3
Чтобы достичь uint.MaxValue
, необходимо добавить другое значение rand.Next(4)
, таким образом, получим:
rand.Next() + rand.Next() + rand.Next(4)
Какова вероятность генерации нуля?
Примерно: 1/2 31 * 1/2 31 * 1/4 = 1/2 64 это должно быть 1/2 32
Подождите секунду, как насчет:
2 * rand.Next() + rand.Next(4)
Опять же, какова вероятность генерации нуля?
Примерно: 1/2 31 * 1/4 = 1/2 33 слишком мал, чтобы быть действительно случайным.
Еще один простой пример:
rand.Next(2) + rand.Next(2)
, все возможные результаты:
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 2
Равные вероятности? Никоим образом Хосе.
Заключение: добавление истинных случайных чисел дает случайное число, но не истинное случайное число. Бросьте две честные кости...
Ответ 3
Установите диапазон, "uint u0 <= возвращаемое значение <= uint u1", используя System.Random
Легче начать с диапазона от "нуля" (включительно) до "u" (включительно).
Вы можете взглянуть на мою другую
ответ.
Если вас интересует более быстрый/эффективный способ:
Равномерные псевдослучайные числа в диапазоне. (Это довольно много кода/текста).
Ниже "rnd32 (uint u)" возвращает: 0 <= значение <= u.
Самый сложный случай: "u = int.MaxValue". Тогда вероятность того, что первая итерация "do-loops"
(одна итерация как внешнего, так и внутреннего "do-loop" ), возвращает действительное значение 50%.
После двух итераций вероятность равна 75% и т.д.
Шанс мал, что внешний "do-loop" повторяется более одного раза.
В случае "u = int.MaxValue": 0%.
Очевидно, что: "rnd32 (uint u0, uint u1)" возвращает значение между u0 (включая) и u1 (вкл.).
private static Random rand = new Random();
private static uint rnd32(uint u) // 0 <= x <= u
{
uint x;
if (u < int.MaxValue) return (uint)rand.Next((int)u + 1);
do
{
do x = (uint)rand.Next(1 << 30) << 2;
while (x > u);
x |= (uint)rand.Next(1 << 2);
}
while (x > u);
return x;
}
private static uint rnd32(uint u0, uint u1) // set the range
{
return u0 < u1 ? u0 + rnd32(u1 - u0) : u1 + rnd32(u0 - u1);
}
Ответ 4
public uint NextUInt()
{
uint x=int.MinValue;
uint y;
uint z;
uint w;
uint t= (x^(x<<11));
x=y;
y=z;
z=w;
return (w= (w^(w>>19))^(t^(t>>8)));
}
Попробуйте эту функцию.