Odpowiedzi:
Random
Klasa służy do tworzenia liczb losowych. (To oczywiście pseudolosowe).
Przykład:
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
Jeśli zamierzasz utworzyć więcej niż jedną liczbę losową, powinieneś zachować Random
instancję i użyć jej ponownie. Jeśli utworzysz nowe wystąpienia zbyt blisko siebie, wygenerują one tę samą serię liczb losowych, jak generator losowy jest wysyłany z zegara systemowego.
rnd
jako static
i / lub ustawić go tylko raz podczas inicjalizacji kodu.
Random
...
Random
, dzięki którym twoja losowość jest bardziej niezawodna: ericlippert.com/2019/02/04/fixing-random-part-2 i codeblog.jonskeet.uk/2009/11/04/revisiting losowość .
Pytanie wygląda na bardzo proste, ale odpowiedź jest nieco skomplikowana. Jeśli widzisz, prawie wszyscy sugerowali użycie klasy Random, a niektórzy sugerowali użycie klasy kryptograficznej RNG. Ale kiedy wybrać, co.
W tym celu musimy najpierw zrozumieć termin RANDOMNESS i leżącą u jego podstaw filozofię.
Zachęcam do obejrzenia tego filmu, który wnika głęboko w filozofię RANDOMNESS przy użyciu C # https://www.youtube.com/watch?v=tCYxc-2-3fY
Po pierwsze, zrozummy filozofię RANDOMNESS. Gdy mówimy osobie, aby wybierała między CZERWONYM, ZIELONYM i ŻÓŁTYM, co dzieje się wewnętrznie. Co sprawia, że dana osoba wybiera CZERWONY, ŻÓŁTY lub ZIELONY?
Pewna wstępna myśl przychodzi do głowy osoby, która decyduje o jego wyborze, może to być ulubiony kolor, szczęśliwy kolor i tak dalej. Innymi słowy, jakiś początkowy wyzwalacz, który określamy w LOSOWO jako SEED. To SEED jest punktem początkowym, wyzwalaczem, który skłania go do wybrania wartości LOSOWANEJ.
Teraz, jeśli SEED jest łatwy do odgadnięcia, wówczas tego rodzaju liczby losowe są określane jako PSEUDO, a gdy nasiona są trudne do odgadnięcia, te liczby losowe są określane jako BEZPIECZNE liczby losowe.
Na przykład osoba wybiera kolor w zależności od pogody i kombinacji dźwięków, wtedy trudno odgadnąć początkowe ziarno.
A teraz pozwólcie, że złożę ważne oświadczenie:
* Klasa „Random” generuje tylko losową liczbę PSEUDO i aby wygenerować BEZPIECZNĄ liczbę losową, musimy użyć klasy „RNGCryptoServiceProvider”.
Klasa losowa pobiera wartości początkowe z zegara procesora, co jest bardzo przewidywalne. Innymi słowy, klasa RANDOM języka C # generuje pseudolosowe liczby, poniżej znajduje się kod tego samego.
** Uwaga: ** .NET Core 2.0.0+
używa innego ziarna w konstruktorze bez parametrów: używa zegara procesora Guid.NewGuid().GetHashCode()
.
var random = new Random();
int randomnumber = random.Next()
Podczas gdy RNGCryptoServiceProvider
klasa używa entropii systemu operacyjnego do generowania nasion. Entropia systemu operacyjnego jest wartością losową, która jest generowana przy użyciu dźwięku, kliknięcia myszą i ustawień klawiatury, temperatury termicznej itp. Poniżej podano kod dla tego samego.
using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider())
{
byte[] rno = new byte[5];
rg.GetBytes(rno);
int randomvalue = BitConverter.ToInt32(rno, 0);
}
Aby zrozumieć entropię systemu operacyjnego, zobacz ten film od 14:30 https://www.youtube.com/watch?v=tCYxc-2-3fY, gdzie wyjaśniono logikę entropii systemu operacyjnego. Tak więc, mówiąc prosto, RNG Crypto generuje BEZPIECZNE losowe liczby.
RandomNumberGenerator.Create()
zamiast wywoływania konstruktora, RNGCryptoServiceProvider
ponieważ nie jest on dostępny na wszystkich platformach.
Za każdym razem, gdy robisz nowy Random (), jest on inicjowany. Oznacza to, że w ciasnej pętli dostajesz tę samą wartość wiele razy. Powinieneś zachować pojedyncze Losowe wystąpienie i dalej używać Dalej w tym samym wystąpieniu.
//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
obiekt. W obu przypadkach mam ten sam losowy numer. Przy podejściu Pankaja tak się nie stało. Być może jest to przypadkowe , ale teraz wątpię. Pytam o liczbę losową w tej samej sekundzie z różnych wątków.
Uważaj, który new Random()
jest rozsiewany według bieżącego znacznika czasu.
Jeśli chcesz wygenerować tylko jeden numer , możesz użyć:
new Random().Next( int.MinValue, int.MaxValue )
Aby uzyskać więcej informacji, spójrz na klasę Random , ale pamiętaj:
Ponieważ jednak zegar ma skończoną rozdzielczość, użycie konstruktora bez parametrów do tworzenia różnych obiektów losowych w krótkim odstępie czasu tworzy generatory liczb losowych, które wytwarzają identyczne sekwencje liczb losowych
Dlatego nie używaj tego kodu do generowania serii liczb losowych.
new Random()
w pętli jest ważnym punktem.
Chciałem dodać bezpieczną kryptograficznie wersję:
Klasa RNGCryptoServiceProvider ( MSDN lub dotnetperls )
Implementuje IDisposable.
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] randomNumber = new byte[4];//4 for int32
rng.GetBytes(randomNumber);
int value = BitConverter.ToInt32(randomNumber, 0);
}
Możesz użyć metody StaticRandom Jona Skeeta w bibliotece klas MiscUtil, którą zbudował dla pseudolosowej liczby.
using MiscUtil;
...
for (int i = 0; i < 100;
Console.WriteLine(StaticRandom.Next());
Wypróbowałem wszystkie te rozwiązania z wyjątkiem odpowiedzi COBOL ... lol
Żadne z tych rozwiązań nie było wystarczająco dobre. Potrzebowałem liczb losowych w szybkiej pętli int i dostawałem mnóstwo zduplikowanych wartości nawet w bardzo szerokich zakresach. Po zbyt długim zadowoleniu z losowych wyników postanowiłem ostatecznie rozwiązać ten problem raz na zawsze.
Chodzi o ziarno.
Tworzę losową liczbę całkowitą, parsując nie-cyfry z Guida, a następnie używam jej do utworzenia mojej losowej klasy.
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);
}
Aktualizacja : Seeding nie jest konieczny, jeśli raz utworzysz klasę Random. Dlatego najlepiej byłoby stworzyć klasę statyczną i wywołać z niej metodę.
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);
}
}
Następnie możesz użyć klasy statycznej w taki sposób ...
for(var i = 0; i < 1000; i++)
{
int randomNumber = IntUtil.Random(1,100);
Console.WriteLine(randomNumber);
}
Przyznaję, że podoba mi się to podejście.
Liczby generowane przez wbudowaną Random
klasę (System.Random) generują pseudolosowe liczby.
Jeśli chcesz prawdziwych liczb losowych, najbliższym rozwiązaniem jest „bezpieczny Pseudo losowy generator”, który można wygenerować za pomocą klas kryptograficznych w języku C #, takich jak RNGCryptoServiceProvider
.
Mimo to, jeśli nadal potrzebujesz prawdziwych liczb losowych, będziesz musiał użyć zewnętrznego źródła, takiego jak urządzenia odpowiedzialne za rozpad radioaktywny, jako zalążek generatora liczb losowych. Ponieważ z definicji dowolna liczba wygenerowana za pomocą metod czysto algorytmicznych nie może być prawdziwie losowa.
utwórz obiekt losowy
Random rand = new Random();
i użyj go
int randomNumber = rand.Next(min, max);
nie musisz inicjować za new Random()
każdym razem, gdy potrzebujesz losowej liczby, zainicjuj jedną Losowo, a następnie użyj jej tyle razy, ile potrzebujesz w pętli lub cokolwiek innego
new Random()
używa bieżących kleszczy jako nasion. Kiedy utworzysz wiele instancji w ciągu tej samej milisekundy (w przeciwieństwie do tyknięcia), otrzymasz taką samą wartość.
Zmodyfikowana odpowiedź stąd .
Jeśli masz dostęp do procesora zgodnego z Intel Secure Key, możesz generować prawdziwe losowe liczby i ciągi znaków za pomocą tych bibliotek: https://github.com/JebteK/RdRand i https://www.rdrand.com/
Wystarczy pobrać najnowszą wersję stąd , dołącz Jebtek.RdRand i dodaj dla niej instrukcję using. Następnie wszystko, co musisz zrobić, to:
// Check to see if this is a compatible CPU
bool isAvailable = RdRandom.GeneratorAvailable();
// Generate 10 random characters
string key = RdRandom.GenerateKey(10);
// Generate 64 random characters, useful for API keys
string apiKey = RdRandom.GenerateAPIKey();
// Generate an array of 10 random bytes
byte[] b = RdRandom.GenerateBytes(10);
// Generate a random unsigned int
uint i = RdRandom.GenerateUnsignedInt();
Jeśli nie masz zgodnego procesora do wykonania kodu, skorzystaj z usług RESTful na stronie rdrand.com. Z biblioteką otoki RdRandom zawartą w projekcie, wystarczy to zrobić (otrzymasz 1000 darmowych połączeń podczas rejestracji):
string ret = Randomizer.GenerateKey(<length>, "<key>");
uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
Chociaż jest to w porządku:
Random random = new Random();
int randomNumber = random.Next()
Chcesz kontrolować limit (min. I maks. Mumbers) przez większość czasu. Musisz więc określić, gdzie zaczyna się i kończy losowa liczba.
Next()
Sposób dwa parametry, wartości minimalne i maksymalne.
Więc jeśli chcę, aby mój losowy numer wynosił między 5 a 15, po prostu bym to zrobił
int randomNumber = random.Next(5, 16)
Z tej klasy korzystam. Działa jakRandomNumber.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);
}
}
Chciałem pokazać, co się dzieje, gdy za każdym razem używany jest nowy generator losowy. Załóżmy, że masz dwie metody lub dwie klasy, z których każda wymaga losowej liczby. I naiwnie kodujesz je w następujący sposób:
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; }
}
Myślisz, że dostaniesz dwa różne identyfikatory? NIE
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
}
}
Rozwiązaniem jest zawsze stosowanie pojedynczego statycznego generatora losowego. Lubię to:
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; }
}
RNGCryptoServiceProvider
i tak lepiej zadzwonić.
W przypadku silnych losowych nasion zawsze używam CryptoRNG, a nie 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);
}
}
}
Random random = new Random ();
int randomNumber = random.Next (lowerBound,upperBound);
Tak jak notatka do wykorzystania w przyszłości.
Jeśli używasz platformy .NET Core, wiele przypadkowych wystąpień nie jest tak niebezpiecznych, jak wcześniej. Wiem, że to pytanie pochodzi z 2010 roku, ale ponieważ jest ono stare, ale ma pewną atrakcję, myślę, że dobrze jest udokumentować zmianę.
Możesz odnieść się do pytania, które zadałem:
Czy Microsoft zmienił domyślny domyślny seed?
Zasadniczo zmienili domyślny materiał siewny z Environment.TickCount
na Guid.NewGuid().GetHashCode()
, więc jeśli utworzysz 2 instancje Losowo, nie będą wyświetlać tych samych liczb.
Różnice między plikami z .NET Framework / .NET Core (2.0.0+) można zobaczyć tutaj: https://github.com/dotnet/coreclr/pull/2192/commits/9f6a0b675e5ac0065a268554de49162c539ff66d
Nie jest tak bezpieczny jak RNGCryptoServiceProvider, ale przynajmniej nie da ci dziwnych rezultatów.
Interop.GetRandomBytes((byte*)&result, sizeof(int));
.
Liczby obliczone przez komputer w procesie deterministycznym nie mogą z definicji być losowe.
Jeśli chcesz prawdziwych liczb losowych, losowość pochodzi z hałasu atmosferycznego lub rozpadu radioaktywnego.
Możesz spróbować na przykład RANDOM.ORG (zmniejsza wydajność)
Random rand = new Random();
int name = rand.Next()
Umieść dowolne wartości w drugim nawiasie, upewnij się, że ustawiłeś nazwę, pisząc prop i podwójną tabulator, aby wygenerować kod
Jeśli chcesz, aby CSRNG generował losowe liczby od min. Do maks., Jest to dla Ciebie. Zainicjuje Random
klasy za pomocą bezpiecznych losowych nasion.
class SecureRandom : Random
{
public static byte[] GetBytes(ulong length)
{
RNGCryptoServiceProvider RNG = new RNGCryptoServiceProvider();
byte[] bytes = new byte[length];
RNG.GetBytes(bytes);
RNG.Dispose();
return bytes;
}
public SecureRandom() : base(BitConverter.ToInt32(GetBytes(4), 0))
{
}
public int GetRandomInt(int min, int max)
{
int treashold = max - min;
if(treashold != Math.Abs(treashold))
{
throw new ArithmeticException("The minimum value can't exceed the maximum value!");
}
if (treashold == 0)
{
throw new ArithmeticException("The minimum value can't be the same as the maximum value!");
}
return min + (Next() % treashold);
}
public static int GetRandomIntStatic(int min, int max)
{
int treashold = max - min;
if (treashold != Math.Abs(treashold))
{
throw new ArithmeticException("The minimum value can't exceed the maximum value!");
}
if(treashold == 0)
{
throw new ArithmeticException("The minimum value can't be the same as the maximum value!");
}
return min + (BitConverter.ToInt32(GetBytes(4), 0) % treashold);
}
}
Niestety, OP rzeczywiście wymaga int
wartości losowej , ale dla prostego celu dzielenia się wiedzą, jeśli chcesz mieć BigInteger
wartość losową , możesz użyć następującej instrukcji:
BigInteger randomVal = BigInteger.Abs(BigInteger.Parse(Guid.NewGuid().ToString().Replace("-",""), NumberStyles.AllowHexSpecifier));
Zakładam, że chcesz równomiernie rozłożonego generatora liczb losowych, jak poniżej. Losowa liczba w większości języków programowania, w tym C # i C ++, nie jest poprawnie tasowana przed użyciem. Oznacza to, że będziesz otrzymywać tę samą liczbę w kółko, co nie jest tak naprawdę losowe. Aby uniknąć ciągłego rysowania tej samej liczby, potrzebujesz ziarna. Zazwyczaj kleszcze w czasie są odpowiednie do tego zadania. Pamiętaj, że będziesz otrzymywał ten sam numer w kółko, jeśli używasz tego samego ziarna za każdym razem. Staraj się więc zawsze używać różnych nasion. Czas jest dobrym źródłem dla nasion, ponieważ zawsze się odradzają.
int GetRandomNumber(int min, int max)
{
Random rand = new Random((int)DateTime.Now.Ticks);
return rand.Next(min, max);
}
jeśli szukasz generatora liczb losowych do rozkładu normalnego, możesz użyć transformacji Boxa-Mullera. Sprawdź odpowiedź yoyoyoyosef w Losowym pytaniu zmiennym gaussowskim. Ponieważ chcesz liczbę całkowitą, musisz rzucić podwójną wartość na liczbę całkowitą na końcu.
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)
Najprostszym sposobem jest prawdopodobnie tylko Random.range(1, 3)
To wygenerowałoby liczbę od 1 do 2.
Możesz spróbować z losową wartością nasion, używając poniżej:
var rnd = new Random(11111111); //note: seed value is 11111111
string randomDigits = rnd.Next();
var requestNumber = $"SD-{randomDigits}";
Dlaczego nie użyć int randomNumber = Random.Range(start_range, end_range)
?
Używaj wielokrotnie jednej instancji Losowo
// 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);
}
W tym artykule wyjaśniono, dlaczego losowość powoduje tak wiele problemów i jak je rozwiązać. http://csharpindepth.com/Articles/Chapter12/Random.aspx
Random
nie jest klasą bezpieczną dla wątków. Jeśli utworzysz pojedyncze wystąpienie, powinieneś ograniczyć do niego dostęp za mechanizmem blokującym.
Wypróbuj te proste kroki, aby utworzyć losowe liczby:
Utwórz funkcję:
private int randomnumber(int min, int max)
{
Random rnum = new Random();
return rnum.Next(min, max);
}
Użyj powyższej funkcji w miejscu, w którym chcesz użyć liczb losowych. Załóżmy, że chcesz go użyć w polu tekstowym.
textBox1.Text = randomnumber(0, 999).ToString();
0 to min, a 999 to max. Możesz zmienić wartości na cokolwiek chcesz.
Zawsze mam metody generujące liczby losowe, które pomagają w różnych celach. Mam nadzieję, że to też może ci pomóc:
public class RandomGenerator
{
public int RandomNumber(int min, int max)
{
var random = new Random();
return random.Next(min, max);
}
public string RandomString(int size, bool lowerCase)
{
var builder = new StringBuilder();
var 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();
}
}
Szybkie i łatwe do wstawienia, użyj poniżej kodu:
new Random().Next(min, max);
// for example unique name
strName += "_" + new Random().Next(100, 999);