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);
}