fel
le

Véletlenszám előállítás működése

Nagyon fontos megérteni hogyan működik a véletlenszám előállítás a Random segítségével! Sok futásközbeni fura működésre fény derül ha tudjuk pontosan hogyan is állít elő a Next(...) véletlen számokat.

Első lépésben értsük meg, hogy nincs olyan, hogy véletlen szám A gép nem képes véletlen számokat előállítani, csak számokat képes előállítani, melyek felületes fogalmazásban véletlen számoknak tűnnek.

A 'véletlen' számok előállítása egy számítási folyamat eredménye. Egy kiinduló értékből (hívjuk 'x'-nek) egy komoly képlet szerint egyszerűen kiszámol egy új értéket ('y'). Ezen 'y' érték az 'x'-től egyértelműen függ, vagyis ugyanazon 'x' értékből mindíg ugyanazon 'y' értéket kapjuk a számítás végén.

A Next egy kiinduló 'x' értékből kiszámol egy 'y' értéket, bevarázsolja a megadott intervallumba (mindjárt lesz szó róla hogyan), majd ezen új 'y' értéket tekinti kiinduló értéknek. Vagyis a következő Next az 'y'-ból számítja ki a következő 'véletlen' értéket (hívjuk ezt 'z'-nek). A következő Next ezek szerint a 'z'-t tekinti alapszámnak, és számol belőle újabb véletlen értéket.

1. ábra: Random generálás sorozata

Ezt ki is tudjuk próbálni. Amikor a random változót hozzuk létre, van lehetőség a kezdőérték beállítására is. A kezdőértéket a változó értékének beállítása során a Random konstruktorában lehet megadni. Például a new Random(100) módon a kezdőérték a 100 lesz. Ennek segítségével indul a véletlenszámok előállítása.

Random rnd = new Random(100);
 

Figyeljük meg az alábbi kódot. Ebben két különböző random változónk lesz, r1 és r2. Mindkettő esetén megadjuk a kezdőértéket, esetünkben a 20-t. A két writeline 3-3 véletlenszámot állít elő és ír ki a képernyőre. Mindkét sorozat ugyanazon számokat tartalmazza. Ez is bizonyítja, hogy szó sincs itt véletlen számokról.

2. ábra: Két egyforma random sorozat

A Random kezdőértéke

A titok nyitja abban rejlik, hogy általában nem adjuk meg a Random kezdőértékét, vagyis new Random() módon kezdünk. Ez esetben a Random maga keres kezdőértéket - méghozzá a számítógép belső órájának segítségével. Két különböző programindítás esetén (egymás utáni programindítások) a belső óra nyilván más-más időpontot mutat - így más-más különböző véletlenszám sorozatot kapunk.

Ugyanazon programban két Random változó - amely gyors egymásután került létrehozásra - azonban hajlamos még az idő alapján is ugyanazt a kezdőértéket felvennni. A számítógép ugyanis nagyon gyors, miközben a belső óra nem kettyen egyet sem - képes több utasítást is végrehajtani.

Az alábbi program mutatja, hogy bár az első r1 random változó létrehozása után legyártunk három véletlen számot a sorozatból, ki is írjuk a képernyőre, a következő r2 random változó létrehozásakor még mindíg ugyanaz a belső idő értéke, így ugyanazt a random sorozatot kapjuk.

3. ábra: Ez is két egyforma random sorozat

A probléma kiküszöbülése végett a programokban kerüljük a két vagy több Random változót használatát. Igyekszünk ugyanazon egyetlen Random változót használni mindenhol.

A Random típusú változók egyszerű esetben a gép belső órájának aktuális értékbét használják kiinduló értékként. A programban (időben) közel egymáshoz létrehozott random változók ugyanazon kezdőértékről indulnak, így ugyanazt a számsorozatot hozzák létre. Ezt kerüljük el, lehetőleg ne hozzunk létre ugyanazon programban két Random változót. Helyette egyetlen változót használunk mindenütt a véletlen számok létrehozására.

Intervallum kezelése

A Next tehát számítással hozza létre a következő véletlen számot. Amennyiben ezt például rnd.Next(10,30) módon kezdeményeztük, úgy tudnunk kell, hogy semmi sem garantálja azt, hogy a képlet alkalmazása után kapott érték a [10,30) intervallumba fog esni.

Ekkor a Next eljárhatna úgy is, hogy folytatja a számok előállítását mindaddig, míg az végül beleesik az adott intervallumba. Így megjósolhatatlan lenne, hogy mennyi ideig fog tartani. Ezért nem is ez történik.

A Next által előállított értéket a Next bevarázsolja a kért intervallumba maradékos osztás révén. Amennyiben Next(10,30) kértünk, úgy a generált X értéket elosztja 20-al (30-10) maradékosan (X%20), így kap egy 0..19 közötti számot. Ehhez hozzáad 10-et, így kap egy 10..29 közötti értéket. Ez pontosan a tőle elvárt érték.

Ez magyarázza, hogy a Next(10,30) miért nem állítja elő a 30-t magát, csak maximum a 29-et.

Az rnd.Next(A,B) először generál számolás révén egy X értéket, majd X%(B-A)+A képlettel azt az [A,B) intervallumba alakítja.
Hernyák Zoltán
2013-01-13 14:20:34