Last modified: September 25, 2024

This article is written in: 馃嚨馃嚤

Liczby losowe i generatory liczb losowych

W j臋zyku C++ liczby losowe generuje si臋 za pomoc膮 standardowej biblioteki <random>. Proces losowania zaczyna si臋 od utworzenia generatora liczb pseudolosowych, np. std::mt19937, kt贸ry bazuje na algorytmie Mersenne Twister. Aby uzyska膰 bardziej losowe wyniki, generator inicjalizuje si臋 za pomoc膮 unikalnej warto艣ci, zwanej "ziarnem" (ang. seed), co mo偶na zrobi膰 np. poprzez std::random_device. Nast臋pnie u偶ywa si臋 odpowiednich dystrybucji, takich jak std::uniform_int_distribution (dla liczb ca艂kowitych z r贸wnomiernym rozk艂adem) lub std::uniform_real_distribution (dla liczb zmiennoprzecinkowych), aby wygenerowa膰 liczby z okre艣lonego zakresu. Dzi臋ki tej bibliotece losowanie w C++ jest bardziej elastyczne i daje kontrol臋 nad r贸偶nymi aspektami generowania liczb losowych, w tym nad zakresem i typem warto艣ci.

Liczby losowe

Liczby losowe to warto艣ci numeryczne generowane w taki spos贸b, 偶e nie da si臋 przewidzie膰 ich kolejno艣ci czy warto艣ci bez znajomo艣ci wewn臋trznych mechanizm贸w generowania. W kontek艣cie informatyki i matematyki, liczby te s膮 niezb臋dne w wielu zastosowaniach, takich jak symulacje komputerowe, kryptografia, statystyka czy gry losowe.

Pseudolosowo艣膰 a prawdziwa losowo艣膰

Warto zauwa偶y膰, 偶e komputery, b臋d膮c maszynami deterministycznymi, nie s膮 w stanie generowa膰 prawdziwie losowych liczb bez zewn臋trznego 藕r贸d艂a entropii. Dlatego te偶 korzystaj膮 z algorytm贸w generuj膮cych liczby pseudolosowe (PRNG - Pseudorandom Number Generator). Algorytmy te produkuj膮 sekwencje liczb, kt贸re wygl膮daj膮 na losowe i spe艂niaj膮 pewne statystyczne w艂asno艣ci losowo艣ci, ale s膮 deterministyczne i powtarzalne, je艣li znany jest ich stan pocz膮tkowy (tzw. ziarno - seed).

Zastosowania liczb losowych

Liczby losowe s膮 kluczowe w:

Generowanie liczb losowych w C++

W j臋zyku C++ od wersji C++11 wprowadzono nowoczesne narz臋dzia do generowania liczb pseudolosowych w postaci biblioteki <random>. Biblioteka ta oferuje r贸偶norodne generator贸w i dystrybucji, pozwalaj膮c na precyzyjn膮 kontrol臋 nad procesem generowania.

Generatory i dystrybucje

Proces generowania liczb losowych w C++ opiera si臋 na dw贸ch elementach:

  1. Generator liczb losowych to algorytm dostarczaj膮cy sekwencj臋 losowych bit贸w. Przyk艂ady to std::mt19937 (Mersenne Twister) czy std::random_device.
  2. Dystrybucja to funkcja przekszta艂caj膮ca losowe bity z generatora na liczby w okre艣lonym rozk艂adzie (np. r贸wnomiernym, normalnym, Poissona).

Inicjalizacja generatora

Wa偶ne jest, aby generator zosta艂 zainicjalizowany odpowiednim ziarnem, co zapewnia r贸偶norodno艣膰 generowanych sekwencji. std::random_device mo偶e by膰 u偶yty do pobrania entropii z systemu operacyjnego, co jest szczeg贸lnie istotne w aplikacjach kryptograficznych.

Przyk艂ad funkcji losowa_z_przedzialu():

#include <random>

int losowa_z_przedzialu(int start, int end) {
    // Inicjalizacja generatora liczb losowych
    std::random_device rd;   // 殴r贸d艂o prawdziwej entropii (je艣li dost臋pne)
    std::mt19937 gen(rd());  // Mersenne Twister PRNG, zainicjalizowany za pomoc膮 rd()
    std::uniform_int_distribution<> dist(start, end); // Dystrybucja r贸wnomierna na przedziale [start, end]
    return dist(gen); // Generowanie liczby losowej
}

W powy偶szym kodzie:

Przyk艂ady zastosowania

Rzut monet膮

Symulacja rzutu monet膮 jest klasycznym przyk艂adem wykorzystania liczb losowych. Moneta ma dwa mo偶liwe wyniki: orze艂 lub reszka, co odpowiada zdarzeniu losowemu z prawdopodobie艅stwem 0.5 dla ka偶dego wyniku.

#include <iostream>
#include <random>

bool orzel_lub_reszka() {
    // U偶ycie dystrybucji Bernoulliego
    std::random_device rd;
    std::mt19937 gen(rd());
    std::bernoulli_distribution dist(0.5); // Prawdopodobie艅stwo sukcesu 0.5
    return dist(gen);
}

int main() {
    if (orzel_lub_reszka()) {
        std::cout << "Orze艂" << std::endl;
    } else {
        std::cout << "Reszka" << std::endl;
    }
    return 0;
}

Rzut kostk膮

Symulacja rzutu sze艣cio艣cienn膮 kostk膮 wymaga generowania liczb ca艂kowitych z przedzia艂u [1,6], gdzie ka偶da liczba ma jednakowe prawdopodobie艅stwo wyst膮pienia.

#include <iostream>
#include <random>

int rzut_kostka() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(1, 6); // Dystrybucja r贸wnomierna ca艂kowitoliczbowa
    return dist(gen);
}

int main() {
    std::cout << "Wynik rzutu kostk膮: " << rzut_kostka() << std::endl;
    return 0;
}

Generator hase艂

Generowanie silnych, losowych hase艂 jest kluczowe dla bezpiecze艅stwa danych. W tym przyk艂adzie tworzymy has艂o o okre艣lonej d艂ugo艣ci, sk艂adaj膮ce si臋 z losowo wybranych znak贸w z predefiniowanego zestawu.

#include <iostream>
#include <string>
#include <random>

std::string generuj_haslo(int dlugosc) {
    const std::string zestaw_znakow = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+";
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(0, zestaw_znakow.size() - 1);

    std::string haslo;
    for(int i = 0; i < dlugosc; i++) {
        haslo += zestaw_znakow[dist(gen)];
    }
    return haslo;
}

int main() {
    int dlugosc_hasla = 12;
    std::cout << "Wygenerowane has艂o: " << generuj_haslo(dlugosc_hasla) << std::endl;
    return 0;
}

Zastosowanie r贸偶nych dystrybucji

Biblioteka <random> oferuje r贸偶ne dystrybucje, kt贸re pozwalaj膮 generowa膰 liczby losowe zgodnie z okre艣lonymi rozk艂adami statystycznymi.

Dystrybucja r贸wnomierna

Dystrybucja r贸wnomierna zapewnia jednakowe prawdopodobie艅stwo wyst膮pienia ka偶dej warto艣ci w okre艣lonym przedziale.

#include <iostream>
#include <random>

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dist(1, 100);

    std::cout << "Przyk艂adowe liczby z dystrybucji r贸wnomiernej:" << std::endl;
    for (int i = 0; i < 10; ++i) {
        std::cout << dist(gen) << " ";
    }
    std::cout << std::endl;

    return 0;
}

Dystrybucja normalna (Gaussa)

Dystrybucja normalna, zwana r贸wnie偶 rozk艂adem Gaussa, jest powszechnie stosowana w statystyce i modelowaniu naturalnych zjawisk.

#include <iostream>
#include <random>

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::normal_distribution<> dist(50, 10); // 艢rednia 50, odchylenie standardowe 10

    std::cout << "Przyk艂adowe liczby z dystrybucji normalnej:" << std::endl;
    for (int i = 0; i < 10; ++i) {
        double liczba = dist(gen);
        std::cout << liczba << " ";
    }
    std::cout << std::endl;

    return 0;
}

Dystrybucja Bernoulliego

Dystrybucja Bernoulliego opisuje zdarzenia dwuwarto艣ciowe (sukces/pora偶ka) z okre艣lonym prawdopodobie艅stwem sukcesu p.

#include <iostream>
#include <random>

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());
    double p = 0.3; // Prawdopodobie艅stwo sukcesu
    std::bernoulli_distribution dist(p);

    std::cout << "Przyk艂adowe wyniki z dystrybucji Bernoulliego (p = " << p << "):" << std::endl;
    for (int i = 0; i < 10; ++i) {
        bool wynik = dist(gen);
        std::cout << wynik << " "; // 1 - sukces, 0 - pora偶ka
    }
    std::cout << std::endl;

    return 0;
}

Zalety i wady r贸偶nych metod

Korzystanie z std::random

Zalety:

Wady:

Por贸wnanie z rand()

rand() to starsza funkcja z biblioteki C, kt贸ra jest nadal dost臋pna w C++.

#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
    std::srand(std::time(nullptr)); // Inicjalizacja ziarna
    for (int i = 0; i < 10; ++i) {
        std::cout << std::rand() % 100 << " ";
    }
    std::cout << std::endl;

    return 0;
}

Zalety rand():

Wady rand():

Spis Tre艣ci

  1. Liczby losowe
    1. Pseudolosowo艣膰 a prawdziwa losowo艣膰
    2. Zastosowania liczb losowych
  2. Generowanie liczb losowych w C++
    1. Generatory i dystrybucje
    2. Inicjalizacja generatora
  3. Przyk艂ady zastosowania
    1. Rzut monet膮
    2. Rzut kostk膮
    3. Generator hase艂
  4. Zastosowanie r贸偶nych dystrybucji
    1. Dystrybucja r贸wnomierna
    2. Dystrybucja normalna (Gaussa)
    3. Dystrybucja Bernoulliego
  5. Zalety i wady r贸偶nych metod
    1. Korzystanie z std::random
    2. Por贸wnanie z rand()