Генерация случайных Uint
Мне нужно генерировать случайные числа с диапазоном для byte
, ushort
, sbyte
, short
, int
, а также uint
, Я могу генерировать для всех этих типов, используя метод Random в C# (например, values.Add((int)(random.Next(int.MinValue + 3, int.MaxValue - 2)));
) кроме мяты, т.к. Random.Next
принимает только до значений int.
Есть ли простой способ генерировать случайные uint
?
6 ответов
Самый простой подход, вероятно, будет использовать два вызова: один для 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
,
Дневные кубики Хосе
Или есть простой способ генерировать истинную случайную uint?
Я признаю, это не OQ. Становится ясно, что существуют более быстрые способы генерирования случайных, которые не являются истинными. Тем не менее, я предполагаю, что никто не заинтересован в их генерации, за исключением случаев, когда требуется неплоское распределение по некоторым причинам. Давайте начнем с небольшого исследования, чтобы сделать это легко и быстро в C#. Легко и быстро часто ведут себя как синонимы, когда я пишу код.
Первое: некоторые важные свойства
Смотрите 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)
: Возвращает положительное случайное число, большее или равное нулю, меньше максимального, максимальное должно быть больше или равно нулю.rand.Next(int min, int max)
: Возвращает положительное случайное число, большее или равное min, меньше max, max должно быть больше или равно min.
Домашняя работа показывает, что rand.Next()
примерно в два раза быстрее rand.Next(int max)
,
Второе: решение.
Предположим, что у положительного целого есть только два бита, забудьте бит знака, это ноль, 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/22 * 1/230 = 1/232 Общее количество uints, включая ноль: 232
Это так же ясно, как дневной свет, нет смога, не так ли?
Наконец: вводящая в заблуждение идея.
Можно ли сделать это быстрее, используя 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/231 * 1/231 * 1/4 = 1/264, должно быть 1/232
Подождите секунду, как насчет:
2 * rand.Next() + rand.Next(4)
Опять же, каков шанс сгенерировать ноль?
Примерно: 1/231 * 1/4 = 1/233, слишком мало, чтобы быть действительно случайным.
Еще один простой пример:
rand.Next(2) + rand.Next(2)
Все возможные результаты:
0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 2
Равные вероятности? Ни за что, Хосе.
Вывод: добавление истинных случайных чисел дает случайное число, но не истинное случайное число. Бросай две честные кости...
Самый простой способ сгенерировать случайный
uint
:
uint ui = (uint) new Random().Next(-int.MaxValue, int.MaxValue);
Установите диапазон, " uint u0 <= возвращаемое значение <= uint u1 ", используя System.Random
Проще начать с диапазона от "нуля" (включительно) до "и" (включительно).
Вы могли бы взглянуть на мой другой ответ. Если вы заинтересованы в более быстром / более эффективном способе:
Унифицированные псевдослучайные числа в диапазоне. (Довольно много кода / текста).
Ниже "rnd32(uint u)" возвращает: 0 <= значение <= u .
Наиболее сложный случай: "u = int.MaxValue". Тогда шанс, что первая итерация из "do-loop"
(одна итерация как внешнего, так и внутреннего цикла "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);
}
На самом деле это так же просто, как этот небольшой пример с минимальным и максимальным диапазоном uint?:
public static class Utility
{
public static uint RandomUInt(uint min, uint max, Random? rand = null)
{
if (min > max) (min, max) = (max, min);
int intMin = (int)(int.MinValue + min);
int intMax = (int)(int.MinValue + max);
int rInt = rand?.Next(intMin, intMax) ?? new Random().Next(intMin, intMax);
return (uint)(int.MaxValue + rInt + 1);
}
}
Utility.RandomUInt(3000000000, 3000000010);
Выход:
| 3000000005
| 3000000001
| 3000000009
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)));
}
Пожалуйста, попробуйте эту функцию.