Генерация случайных 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)));
}

Пожалуйста, попробуйте эту функцию.

Другие вопросы по тегам