Как мне генерировать случайное целое число в С#?
Класс Random
используется для создания случайных чисел. (Псевдослучайный, конечно.)
Пример:
Random rnd = new Random();
int month = rnd.Next(1, 13); // creates a number between 1 and 12
int dice = rnd.Next(1, 7); // creates a number between 1 and 6
int card = rnd.Next(52); // creates a number between 0 and 51
Если вы собираетесь создать более одного случайного числа, вам следует сохранить экземпляр Random
и использовать его повторно. Если вы создаете новые экземпляры слишком близко по времени, они будут производить ту же серию случайных чисел, что и генератор случайных чисел, посеянный из системных часов.
Каждый раз, когда вы делаете новый Random(), он инициализируется. Это означает, что в тесном цикле вы получаете одно и то же значение много раз. Вы должны сохранить один экземпляр Random и продолжать использовать Next на том же экземпляре.
//Function to get random number
private static readonly Random getrandom = new Random();
public static int GetRandomNumber(int min, int max)
{
lock(getrandom) // synchronize
{
return getrandom.Next(min, max);
}
}
Вопрос выглядит очень простым, но ответ немного сложен. Если вы видите, почти все предложили использовать класс Random, а некоторые предложили использовать криптографический класс RNG. Но тогда когда выбирать что.
Для этого нам нужно сначала понять термин СЛУЧАЙНОСТЬ и его философию.
Я бы посоветовал вам посмотреть это видео, которое углубляется в философию случайности, используя С# https://www.youtube.com/watch?v=tCYxc-2-3fY
Прежде всего, давайте поймем философию СЛУЧАЙНОСТИ. Когда мы говорим человеку выбирать между КРАСНЫМ, ЗЕЛЕНЫМ и ЖЕЛТЫМ, что происходит внутри. Что заставляет человека выбирать КРАСНЫЙ, ЖЕЛТЫЙ или ЗЕЛЕНЫЙ?
Некоторая начальная мысль приходит в ум человека, который решает его выбор, это может быть любимый цвет, счастливый цвет и так далее. Другими словами, некоторый начальный триггер, который мы называем в СЛУЧАЙНОМ как SEED. Этот SEED является начальной точкой, триггером, побуждающим его выбрать СЛУЧАЙНОЕ значение.
Теперь, если SEED легко угадать, то такие виды случайных чисел называются PSEUDO, а когда семени трудно угадать, эти случайные числа называются SECURED случайными числами.
Например, человек выбирает цвет в зависимости от сочетания погоды и звука, тогда будет трудно угадать начальное зерно.
Теперь позвольте мне сделать важное выражение:
* "Случайный" класс генерирует только случайное число PSEUDO, и для генерации БЕЗОПАСНОГО случайного числа нам нужно использовать класс "RNGCryptoServiceProvider".
Случайный класс берет начальные значения из вашего процессора, что очень предсказуемо. Другими словами, случайный класс С# генерирует псевдослучайные числа, ниже приведен код этого же.
Random rnd= new Random();
int rndnumber = rnd.Next()
В то время как класс RNGCryptoServiceProvider использует энтропию ОС для генерации начальных чисел. Энтропия ОС - это случайное значение, которое генерируется с использованием звука, времени нажатия клавиш мыши и клавиатуры, температуры и т.д. Ниже приведен код для того же самого.
using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider())
{
byte[] rno = new byte[5];
rg.GetBytes(rno);
int randomvalue = BitConverter.ToInt32(rno, 0);
}
Чтобы понять энтропию ОС, посмотрите это видео с 14:30 https://www.youtube.com/watch?v=tCYxc-2-3fY, где объясняется логика энтропии ОС. Таким образом, говоря простыми словами, RNG Crypto генерирует БЕЗОПАСНЫЕ случайные числа.
Остерегайтесь того, что new Random()
добавляется в текущую метку времени.
Если вы хотите сгенерировать только один номер, вы можете использовать:
new Random().Next( int.MinValue, int.MaxValue )
Для получения дополнительной информации посмотрите на класс Random, хотя, пожалуйста, обратите внимание:
Однако, поскольку часы имеют конечное разрешение, использование конструктора без параметров для создания различных случайных объектов в тесной последовательности создает генераторы случайных чисел, которые создают идентичные последовательности случайных чисел.
Поэтому не используйте этот код для генерации серии случайных чисел.
Random r = new Random();
int n = r.Next();
Я хотел добавить криптографически безопасную версию:
Класс RNGCryptoServiceProvider (MSDN или dotnetperls)
Он реализует IDisposable.
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] randomNumber = new byte[4];//4 for int32
rng.GetBytes(randomNumber);
int value = BitConverter.ToInt32(randomNumber, 0);
}
Вы можете использовать метод Jon Skeet StaticRandom внутри библиотеки классов MiscUtil, который он построил для псевдослучайного числа.
using System;
using MiscUtil;
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine(StaticRandom.Next());
}
}
}
лучше заполнить объект Random текущими миллисекундами, чтобы обеспечить истинное случайное число, и вы почти не найдете дубликаты, использующие его много раз
Random rand = new Random(DateTime.Now.Millisecond);
Обновить
Я знаю, что new Random()
использует текущие тики в качестве начального числа, но задание с текущими миллисекундами все еще достаточно хорошо, так как это хороший случайный запуск
Последний оставшийся момент заключается в том, что вам не нужно инициализировать new Random()
каждый раз, когда вам нужно случайное число, инициировать один объект Random, затем использовать его столько раз, сколько вам нужно внутри цикла или что-то еще
new Random()
использует текущие тики в качестве начального числа. Когда вы создаете несколько экземпляров в течение одной миллисекунды (в отличие от тика), вы получите одно и то же возвращаемое значение.
Я пробовал все эти решения, исключая ответ COBOL... lol
Ни одно из этих решений не было достаточно хорошим. Мне нужны рандомы в быстром для цикла int, и я получал тонны повторяющихся значений даже в очень широких пределах. После долгого урегулирования случайных результатов я решил окончательно решить эту проблему раз и навсегда.
Все о семени.
Я создаю случайное целое, анализируя нецифровые данные от Guid, затем я использую это, чтобы создать экземпляр класса Random.
public int GenerateRandom(int min, int max)
{
var seed = Convert.ToInt32(Regex.Match(Guid.NewGuid().ToString(), @"\d+").Value);
return new Random(seed).Next(min, max);
}
Обновление: седирование не требуется, если вы создаете экземпляр класса Random один раз. Поэтому было бы лучше создать статический класс и вызвать метод с этим.
public static class IntUtil
{
private static Random random;
private static void Init()
{
if (random == null) random = new Random();
}
public static int Random(int min, int max)
{
Init();
return random.Next(min, max);
}
}
Затем вы можете использовать статический класс, как это сделать.
for(var i = 0; i < 1000; i++)
{
int randomNumber = IntUtil.Random(1,100);
Console.WriteLine(randomNumber);
}
Я признаю, что мне нравится этот подход лучше.
Я использую ниже код для случайного числа:
var random = new Random((int)DateTime.Now.Ticks);
var randomValue = random.Next(startValue, endValue + 1);
Цифры, генерируемые встроенным классом Random
(System.Random), генерируют псевдослучайные числа.
Если вам нужны истинные случайные числа, самое близкое, что мы можем получить, это "безопасный псевдослучайный генератор", который может быть сгенерирован с использованием криптографических классов в С#, таких как RNGCryptoServiceProvider
.
Тем не менее, если вам все еще нужны истинные случайные числа, вам нужно будет использовать внешний источник, такой как устройства, учитывающие радиоактивный распад, в качестве семени для генератора случайных чисел. Поскольку, по определению, любое число, порожденное чисто алгоритмическими средствами, не может быть по-настоящему случайным.
Random random = new Random ();
int randomNumber = random.Next (lowerBound,upperBound);
Это класс, который я использую. Работает как RandomNumber.GenerateRandom(1, 666)
internal static class RandomNumber
{
private static Random r = new Random();
private static object l = new object();
private static Random globalRandom = new Random();
[ThreadStatic]
private static Random localRandom;
public static int GenerateNewRandom(int min, int max)
{
return new Random().Next(min, max);
}
public static int GenerateLockedRandom(int min, int max)
{
int result;
lock (RandomNumber.l)
{
result = RandomNumber.r.Next(min, max);
}
return result;
}
public static int GenerateRandom(int min, int max)
{
Random random = RandomNumber.localRandom;
if (random == null)
{
int seed;
lock (RandomNumber.globalRandom)
{
seed = RandomNumber.globalRandom.Next();
}
random = (RandomNumber.localRandom = new Random(seed));
}
return random.Next(min, max);
}
}
Пока все в порядке:
Random random = new Random();
int randomNumber = random.Next()
Вы хотите контролировать ограничение (min и max mumbers) большую часть времени. Поэтому вам нужно указать, где начинается и заканчивается случайное число.
Метод Next()
принимает два параметра: min и max.
Итак, если я хочу, чтобы мое случайное число было между 5 и 15, я просто делал
int randomNumber = random.Next(5, 16)
Измененный ответ здесь.
Если у вас есть доступ к совместимому с Intel Secure Key процессору, вы можете генерировать реальные случайные числа и строки, используя эти библиотеки: https://github.com/JebteK/RdRand и https://www.rdrand.com/
Просто загрузите последнюю версию из здесь, включите Jebtek.RdRand и добавьте для нее инструкцию using. Затем все, что вам нужно сделать, это следующее:
bool isAvailable = RdRandom.GeneratorAvailable(); //Check to see if this is a compatible CPU
string key = RdRandom.GenerateKey(10); //Generate 10 random characters
string apiKey = RdRandom.GenerateAPIKey(); //Generate 64 random characters, useful for API keys
byte[] b = RdRandom.GenerateBytes(10); //Generate an array of 10 random bytes
uint i = RdRandom.GenerateUnsignedInt() //Generate a random unsigned int
Если у вас нет совместимого процессора для выполнения кода, просто используйте службы RESTful на странице rdrand.com. С библиотекой обертки RdRandom, включенной в ваш проект, вам просто нужно это сделать (вы получаете 1000 бесплатных звонков при регистрации):
string ret = Randomizer.GenerateKey(<length>, "<key>");
uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
Random rand = new Random();
int name = rand.Next()
Поместите любые значения, которые вы хотите во второй круглый скоб убедитесь, что вы установили имя, написав подсказку и двойную вкладку, чтобы сгенерировать код
Для сильных случайных семян я всегда использую CryptoRNG, а не Time.
using System;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
var random = new Random(GetSeed());
Console.WriteLine(random.Next());
}
public static int GetSeed()
{
using (var rng = new RNGCryptoServiceProvider())
{
var intBytes = new byte[4];
rng.GetBytes(intBytes);
return BitConverter.ToInt32(intBytes, 0);
}
}
}
Я хотел продемонстрировать, что происходит, когда новый случайный генератор используется каждый раз. Предположим, у вас есть два метода или два класса, для каждого из которых требуется случайное число. И наивно вы их кодируете, как:
public class A
{
public A()
{
var rnd=new Random();
ID=rnd.Next();
}
public int ID { get; private set; }
}
public class B
{
public B()
{
var rnd=new Random();
ID=rnd.Next();
}
public int ID { get; private set; }
}
Как вы думаете, вы получите два разных идентификатора? NOPE
class Program
{
static void Main(string[] args)
{
A a=new A();
B b=new B();
int ida=a.ID, idb=b.ID;
// ida = 1452879101
// idb = 1452879101
}
}
Решение состоит в том, чтобы всегда использовать один статический случайный генератор. Вот так:
public static class Utils
{
public static readonly Random random=new Random();
}
public class A
{
public A()
{
ID=Utils.random.Next();
}
public int ID { get; private set; }
}
public class B
{
public B()
{
ID=Utils.random.Next();
}
public int ID { get; private set; }
}
Числа, вычисленные компьютером через детерминированный процесс, по определению не могут быть случайными.
Если вам нужны настоящие случайные числа, случайность возникает из-за атмосферного шума или радиоактивного распада.
Вы можете попробовать, например, RANDOM.ORG(это снижает производительность)
К сожалению, OP действительно требует случайного значения int
, но для простой цели обмена знаниями, если вы хотите случайное значение BigInteger
вы можете использовать следующее утверждение:
BigInteger randomVal = BigInteger.Abs(BigInteger.Parse(Guid.NewGuid().ToString().Replace("-",""), NumberStyles.AllowHexSpecifier));
Используйте один экземпляр Random несколько раз
// Somewhat better code...
Random rng = new Random();
for (int i = 0; i < 100; i++)
{
Console.WriteLine(GenerateDigit(rng));
}
...
static int GenerateDigit(Random rng)
{
// Assume there'd be more logic here really
return rng.Next(10);
}
В этой статье рассматривается, почему случайность вызывает так много проблем, и как их решать. http://csharpindepth.com/Articles/Chapter12/Random.aspx
Random
не является потокобезопасным классом. Если вы создаете один экземпляр, вы должны ограничить доступ к нему за механизм блокировки.
У меня всегда есть методы, которые генерируют случайные числа, которые помогают для различных целей. Я надеюсь, что это может помочь вам тоже:
public class RandomGenerator
{
public int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
public string RandomString(int size, bool lowerCase)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
if (lowerCase)
return builder.ToString().ToLower();
return builder.ToString();
}
}
Я предполагаю, что вы хотите равномерно распределенный генератор случайных чисел, как показано ниже. Случайные числа в большинстве языков программирования, включая С# и C++, не перетасовываются должным образом перед их использованием. Это означает, что вы будете получать одно и то же число снова и снова, что на самом деле не случайно. Чтобы не рисовать одно и то же число снова и снова, вам нужно семя. Как правило, тики во времени хорошо для этой задачи. Помните, что вы будете получать одно и то же число снова и снова, если будете использовать одно и то же семя каждый раз. Поэтому старайтесь всегда использовать разные семена. Время является хорошим источником для семян, потому что они всегда растеряны.
int GetRandomNumber(int min, int max)
{
Random rand = new Random((int)DateTime.Now.Ticks);
return rand.Next(min, max);
}
если вы ищете генератор случайных чисел для нормального распределения, вы можете использовать преобразование Бокса-Мюллера. Проверьте ответ по yoyoyoyosef в вопросе о случайной гауссовой переменной. Поскольку вам нужно целое число, вы должны привести в конце двойное значение к целому.
Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)
Быстро и легко для встраивания, используйте ниже код:
new Random().Next(min, max);
// for example unique name
strName += "_" + new Random().Next(100, 999);
Вы можете попробовать со случайным начальным значением, используя ниже:
var rnd = new Random(11111111); //note: seed value is 11111111
string randomDigits = rnd.Next().ToString().Substring(0, 8);
var requestNumber = $"SD-{randomDigits}";
Почему бы не использовать int randomNumber = Random.Range(start_range, end_range)
?
Попробуйте эти простые шаги для создания случайных чисел:
Создать функцию:
private int randomnumber(int min, int max)
{
Random rnum = new Random();
return rnum.Next(min, max);
}
Используйте вышеуказанную функцию в месте, где вы хотите использовать случайные числа. Предположим, вы хотите использовать его в текстовом поле.
textBox1.Text = randomnumber(0, 999).ToString();
0 - это минимум, а 999 - это максимум. Вы можете изменить значения на то, что вы хотите.
Я надеюсь, что этот код может быть полезен
public static string GeneratePassword()
{
string strPwdchar = "abcdefghijklmnopqrstuvwxyz0123456789#+@&$ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string strPwd = "";
Random rnd = new Random();
for (int i = 0; i <= 7; i++)
{
int iRandom = rnd.Next(5, strPwdchar.Length - 1);
strPwd += strPwdchar.Substring(iRandom, 1);
}
return strPwd;
}
Играйте с ним... надеюсь, вы сможете получить то, что хотите.
int n = new Random().Next();
вы также можете дать минимальное и максимальное значение функции Next()
. Как
int n = new Random().Next(5,10);