RNGCryptoServiceProvider с минимальным и максимальным включением

Мне нужен метод, который возвращает случайные числа от мин до макс, оба числа включительно. Я нашел некоторый код в статье .NET Matters: Tales из CryptoRandom от Стивена Тауба и Шона Фаркаса, где метод будет выглядеть примерно так:

// Note - maxValue is excluded!
public static int GetRandomIntBetween(int minValue, int maxValue)
{
    if (minValue > maxValue) throw new ArgumentOutOfRangeException("minValue");
    if (minValue == maxValue) return minValue;

    var rng = new RNGCryptoServiceProvider();
    var uint32Buffer = new byte[4];
    long diff = maxValue - minValue;

    while (true)
    {
        rng.GetBytes(uint32Buffer);
        uint rand = BitConverter.ToUInt32(uint32Buffer, 0);
        const long max = (1 + (long)int.MaxValue);
        long remainder = max % diff;
        if (rand < max - remainder)
        {
            return (int)(minValue + (rand % diff));
        }
    }
}

Моя попытка сделать maxValue включительно:

public static int GetRandomIntBetween(int minValue, int maxValue)
{
    if (minValue > maxValue) throw new ArgumentOutOfRangeException("minValue");
    if (minValue == maxValue) return minValue;

    // Make maxValue inclusive.
    maxValue++;

    var rng = new RNGCryptoServiceProvider();
    var uint32Buffer = new byte[4];
    long diff = maxValue - minValue;

    while (true)
    {
        rng.GetBytes(uint32Buffer);
        uint rand = BitConverter.ToUInt32(uint32Buffer, 0);
        const long max = (1 + (long)int.MaxValue);
        long remainder = max % diff;
        if (rand < max - remainder)
        {
            return (int)(minValue + (rand % diff));
        }
    }
}

Выглядит странно, но кажется, что я могу оставить первые две проверки, как они есть, и это все еще работает, хотя семантика немного отличается. Также данные результатов выглядят хорошо. Я что-то пропустил или мои изменения в порядке?

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

2 ответа

Решение

Ваши изменения верны, случайное целое число между [a,b] случайное целое число между [a,b+1[,

Пока maxValue не является int.MaxValue, ++ будет переполнен, поэтому безопаснее не изменять maxValue и переносить изменение в вычисление diff:

long diff = (long)maxValue - minValue + 1;

Однако вторая проверка в исходной функции, очевидно, неверна, если minValue == maxValueвозврат minValue не является значением исключительно между minValue и maxValue.

Посмотрите на мое решение (нажмите там)

Вы можете добавить дополнительный метод к классу:

public int NextInclusive(int minValue, int maxValue) {
        return Next(minValue, maxValue + 1);
}
Другие вопросы по тегам