Náhodná čísla a seed

PHP, JavaScript, Go

Seed přímo ovlivňuje jak budou vypadat pseudo-náhodná čísla. Jsou také případy, kdy se hodí, aby počítač generoval stejnou posloupnost "náhodných" čísel. A jak to využít ve svůj prospěch?

Náhodná čísla a seed

V programovacích jazycích jako je C/C++, ale i Go, je potřeba před vygenerováním náhodného čísla nastavit seed. Ten totiž přímo určuje, jak bude vypadat posloupnost čísel, které bude vracet generátor (PRNG). U jazyků jako je Python, PHP Nebo JavaScript se seed nastavovat nemusí. Je totiž nastaven automaticky, nejčastěji pomocí aktuálního času počítače nebo jiného vstupu.

Proč si chtít nastavit vlastní seed?

Z odstavce výše tedy vyplývá, že pokud se seed nenastaví, nebo se nastaví pomocí konstanty, bude generována posloupnost vždy stejná. To se může hodit při debugování nebo unit testech. Ale jsou i jiné situace, kdy se to může hodit. Osobně jsem možnost nastavit vlastní seed využil 2x.

  1. Na hlavní stránce mého webu se zobrazují 3 náhodné recenze z 5. Nemění se ale při každém načtení, ale po celý den je výběr a pořadí stejné. Jako seed totiž používám aktuální číslo dne.
  2. V nástroji Regex patterns to sentences pro generování souborů pro Google DialogFlow se v některých případech vybírají náhodná slova. Pokud je ale výsledný soubor verzován, není příjemné, když se kompletně změní při přegenerování. Proto je možné si seed nastavit.

Na hlavní stránce používám sice vlastní seed, ale zamíchat pole není tak triviální, jak se může zdát. Více je to rozebráno v článku Shuffle - náhodné seřazení pole.

Malá ukázka s Pythonem, jak konstantní seed bude stále generovat stejnou posloupnost. Kód lze spustit online a bez instalace třeba bez na programiz.com.

import random
import math

random.seed(10)
# Vždy vypíše [57, 42, 57, 20, 81, 82, 65, 16, 52]
print([math.floor(random.random()*100) for x in range(1,10)])

Jak si seed nastavit?

package main

import (
	crand "crypto/rand"
	"fmt"
	"math/big"
	mrand "math/rand"
	"time"
)

func main() {
	mrand.Seed(time.Now().UTC().UnixNano())
	fmt.Println(mrand.Int31n(50))

	// crypto/rand.Int vrací kromě čísla ještě error
	fmt.Println(crand.Int(crand.Reader, big.NewInt(50)))
}

Zkušenosti s jazyky a náhodnými čísly můžete sdílet v komentářích

K tomuto článku již není možné přidávat další komentáře