Создать случайный 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)));
}

Попробуйте эту функцию.