Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek

©2024 mgr Jerzy Wałaszek
I LO w Tarnowie

Wbudowane generatory liczb pseudolosowych

SPIS TREŚCI
Podrozdziały
Współczesne języki programowania posiadają wbudowane generatory liczb pseudolosowych udostępniające programiście swoje funkcje poprzez prosty interfejs. W tym rozdziale pokażemy, jak się z tych funkcji korzysta we własnych programach.

Pascal (Lazarus, Free Pascal)

Inicjalizacja

Ziarno generatora pseudolosowego (ang. random seed) można zainicjować w języku Pascal na dwa sposoby. W pierwszym odwołujemy się bezpośrednio do zmiennej przechowującej ziarno:

randseed := nowa wartość dla ziarna pseudolosowego;

Po takiej inicjalizacji generator pseudolosowy będzie produkował zawsze ten sam ciąg liczb pseudolosowych, co można wykorzystać do prostej, amatorskiej kryptografii (zwykłe generatory LCG nie są zalecane dla profesjonalnych systemów kryptograficznych).

Drugi sposób wykorzystuje procedurę:

randomize;

Procedura randomize inicjuje randseed wartością odczytaną z zegara systemowego. Ponieważ zegar systemowy w komputerach IBM-PC działa niezależnie od  reszty sprzętu, możemy go potraktować jako źródło wartości losowych – nie wiadomo przecież, w którym momencie zostanie wywołana procedura randomize. Procedurę tę wywołujemy zwykle tylko jeden raz na samym początku programu.

Zupełnie bez sensu jest poniższa konstrukcja programowa:

…
for i := 1 to 10 do
begin
  randomize;
  writeln(random (100));
end;
…

Jeśli komputer działa szybko, to zegar systemowy, z którego procedura randomize pobiera czas, nie zdąży się zmienić w pętli. Zatem w każdym obiegu pętli ziarno generatora pseudolosowego będzie inicjowane tą samą wartością. W  efekcie generator wyprodukuje tę samą liczbę pseudolosową – aczkolwiek zwykle różną w kolejnych uruchomieniach programu, gdyż czas zegara będzie wtedy inny. Poniżej mamy wynik działania programu.

Wynik:
19
19
19
19
19
19
19
19
19
19

Poprawnie program powinien wyglądać tak:

…
randomize;          // inicjujemy generator pseudolosowy
…
for i := 1 to 10 do // generujemy liczby pseudolosowe
begin
  writeln(random (100));
end;
…

Generacja całkowitych liczb pseudolosowych

Do generacji całkowitych liczb pseudolosowych wykorzystujemy funkcję random(n), która zwraca wartość pseudolosową w zakresie od 0 do n - 1. Parametr n może być liczbą 32 bitową longint lub 64 bitową int64. Wtedy wynik funkcji również jest tego samego typu. Jeśli chcemy wygenerować liczbę pseudolosową z przedziału domkniętego , to stosujemy następujące wyrażenie:

a + random(a - b + 1)

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Przykładowy program generuje 10 liczb pseudolosowych z przedziału <10, 20>:
Pascal
// Wewnętrzny generator pseudolosowy
// Data:   17.04.2008
// (C)2020 mgr Jerzy Wałaszek
//----------------------------------

program prg;

var i : integer;

begin
  randomize;
  for i := 1 to 10 do writeln(10 + random(11));
end.
Wynik:
19
20
16
19
19
16
11
15
12
18

Generacja rzeczywistych liczb pseudolosowych

Liczby rzeczywiste generuje funkcja random bez parametrów. Zwraca wtedy wartość zmiennoprzecinkową typu extended (20 cyfr znaczących) z przedziału <0, 1) – od 0 domknięty do 1 otwarty.

Jeśli chcemy wygenerować pseudolosową liczbę rzeczywistą z przedziału <a, b) (a domknięty, b  otwarty), stosujemy wzór:

a + random * (b - a)

Jeśli chcemy wygenerować pseudolosową liczbę rzeczywistą z przedziału (a, b> (a otwarty, b domknięty), stosujemy wzór:

a + (1 - random) * (b - a)

Jeśli chcemy wygenerować pseudolosową liczbę rzeczywistą z przedziału <a, b> (obustronnie domknięty), stosujemy wzór:

a + random(2147483647) / 2147483646 * (b - a)

Jeśli chcemy wygenerować pseudolosową liczbę rzeczywistą z przedziału (a, b) (obustronnie otwarty), stosujemy wzór:

a + (1 + random(2147483646)) / 2147483647 * (b - a)

Na początek:  podrozdziału   strony 

C++ (Code::Blocks)

Język C++ posiada wiele różnych generatorów pseudolosowych, z których najprostszym jest generator pochodzący z języka C, który tutaj opiszemy.

Inicjalizacja

Dostęp do funkcji generatora pseudolosowego uzyskujemy po dołączeniu do programu pliku nagłówkowego cstdlib. Literka c na początku nazwy pliku oznacza, iż plik zawiera definicje pochodzące z języka C. Język C, poprzednik języka C++, przez wiele lat królował wśród programistów, np. system operacyjny Windows był napisany pierwotnie w języku C. W języku tym stworzono olbrzymią bazę programów, wychowało się na nim wielu programistów (łącznie z moją skromną osobą). Następca języka C, język C++, jest do pewnego stopnia kompatybilny ze swoim poprzednikiem. Dlatego w C++ możemy korzystać z funkcji języka C. Zatem, jeśli w swoim programie chcesz korzystać z generatora pseudolosowego z języka C, umieść na jego początku dyrektywę:

#include <cstdlib>

Generator pseudolosowy jest inicjowany za pomocą funkcji:

srand(x0);

Argument x0  zostanie użyty jako ziarno generacji liczb pseudolosowych. Oby otrzymywać w programach bardziej losowe ciągi liczb pseudolosowych, generator inicjujemy wybraną wartością losową, np. wynikiem funkcji time(), który zmienia się co  sekundę. Funkcja time() pochodzi z języka C i wymaga dołączenia pliku nagłówkowego ctime. Funkcja zwraca czas w sekundach liczony od pewnej daty startowej. Parametrem funkcji jest adres struktury, która jest wypełniana różnymi informacjami o czasie (data, godzina, numer dnia tygodnia, itp.). Jeśli nie masz takiej struktury i jej nie potrzebujesz, to jako parametr przekazujesz pusty wskaźnik NULL. Wtedy funkcja time() ograniczy się tylko do zwrócenia liczby sekund. Na  początku programu umieszczamy:

#include <cstdlib> // funkcje z C
#include <ctime>   // funkcje czasu z C
…
srand(time(NULL));
…

Ponieważ czas jest zliczany niezależnie od procesów obliczeniowych komputera, to nie wiadomo, w którym momencie program zostanie uruchomiony i wywołana będzie funkcja time(). Dlatego jej wynik możemy potraktować jako losowy. Wpisanie go do ziarna generatora pseudolosowego spowoduje generowanie sekwencji liczb pseudolosowych od innego miejsca w ciągu przy każdym uruchomieniu programu.

Inicjalizację generatora pseudolosowego wykonujemy tylko jeden raz, zawsze na  początku programu, przed generacją liczb pseudolosowych. Nie ma sensu umieszczanie wywołania funkcji srand(time(NULL)) wewnątrz pętli tworzącej kolejne liczby pseudolosowe – efekt będzie wręcz odwrotny do zamierzonego. Zobacz na podobny przykład w Pascalu!

Generacja całkowitych liczb pseudolosowych

Dostęp do kolejnych liczb pseudolosowych uzyskujemy za pomocą funkcji rand(), która zwraca wygenerowaną przez generator liczbę pseudolosową z  zakresu od 0 do RAND_MAX (stała RAND_MAX zdefiniowana jest w pliku nagłówkowym cstdlib i ma wartość 32767 = 215 - 1). Funkcja rand() nie zwraca całej liczby pseudolosowej, tylko jej górne 15  bitów. Takie rozwiązanie przyjęto dlatego, iż okazuje się, że generatory LCG generują młodsze bity z mniejszymi okresami powtarzania niż okresy bitów starszych. Zwracanie starszych bitów po części niweluje tę wadę.

Jeśli wystarcza nam 15 bitowy zakres liczb pseudolosowych, to do generacji liczby pseudolosowej w przedziale stosujemy prosty wzór:

a + rand() % (b - a + 1)

Lepszym rozwiązaniem będzie sprowadzenie wyniku rand() do wartości zmiennoprzecinkowej w przedziale <0,1>, a następnie wykorzystanie tej wartości do generacji liczby pseudolosowej w przedziale całkowitym.

a + (int)(((double)rand() / (double)RAND_MAX) * (b - a))

Jeśli potrzebujemy większego zakresu liczb pseudolosowych niż 15 bitów, to  możemy wykorzystać funkcję rand() kilkakrotnie:

16 bitów:
(rand() | (rand() << 15)) & 0xFFFF
20 bitów:
(rand() | (rand() << 15)) & 0xFFFFF
24 bity:
(rand() | (rand() << 15)) & 0xFFFFFF
32 bity:
(rand() | (rand() << 15) | (rand() << 30)) & 0xFFFFFF

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Program demonstruje sposób uzyskania 64-bitowych liczb pseudolosowych przy pomocy wbudowanego generatora pseudolosowego. Lepszym jednakże rozwiązaniem jest zaprojektowanie własnego generatora pseudolosowego o okresie 64-bitowym, ponieważ jakość tak otrzymanych liczb pseudolosowych nie jest najlepsza.
C++
// Generacja 64-bitwych liczb pseudolosowych
// Data:  18.04.2008
// (C)2020 mgr Jerzy Wałaszek
//--------------------------

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

using namespace std;

typedef unsigned long long ulong;

int main()
{
  ulong X;
  int i;

  srand(time(NULL));

  for(i = 1; i <= 20; i++)
  {
    X = (ulong)rand()|((ulong)rand()<<15)|
       ((ulong)rand()<<30)|((ulong)rand()<<45)|
       ((ulong)rand()<<60);
    cout << setw(20) << X << endl;
  }
  cout << endl;
  return 0;
}
Wynik:
15909354788557317506
 5646388612325884585
 7784116433065307603
 6793609578895196532
 5097235556346604900
12640517263571584278
12678029710029330624
 3892314973318364887
10783580981138539261
11361218186090798356
 8678502750446328685
 2341839668675288386
 4165020744942595238
 9942264302309224210
18329511796073573700
11968297997906007137
12073339878835311061
11130308925736402900
10947078756288983245
 8939441636943881298

Generacja rzeczywistych liczb pseudolosowych

Do generacji rzeczywistych liczb pseudolosowych wynik funkcji rand() sprowadzamy do przedziału {0…1}, a następnie otrzymaną wartość wykorzystujemy do uzyskania rzeczywistej liczby pseudolosowej. Poniżej podajemy prosty sposób realizacji tego zadania.

<0,1)
: (double)rand() / (double)(RAND_MAX + 1)
<0,1> 
: (double)rand() / (double)(RAND_MAX)
(0,1> 
: 1 - (double)rand() / (double)(RAND_MAX + 1)
(0,1) 
: (double)(1 + rand()) / (double)(RAND_MAX + 2)

Rzeczywistą liczbę pseudolosową z przedziału {0…1} wykorzystujemy do  generacji liczby pseudolosowej w przedziale {a…b} następująco:

a + liczba_pseudolosowa{0…1} * (b - a)

Na przykład chcemy wygenerować liczbę pseudolosową w przedziale od a = 2.5 do b = 4.0 włącznie. Przedział ma być domknięty, zatem potrzebujemy liczby pseudolosowej z przedziału domkniętego <0, 1>. Wzór jest następujący:

2.5 + (double)rand() / (double)(RAND_MAX) * 1.5

Biblioteka generatorów liczb pseudolosowych

W języku C++ od wersji 11 istnieje cała biblioteka obiektów związanych z generacją liczb pseudolosowych. Dostęp do jej funkcji uzyskuje się po dołączeniu do programu pliku nagłówkowego random.

Standardowy generator liczb pseudolosowych języka C++ posiada wiele ograniczeń, z których najbardziej bolesnym jest mały zakres generowanych liczb (0 … RAND_MAX, RAND_MAX = 32767). Oczywiście ograniczenie to można ominąć losując kilka liczb pseudolosowych i łącząc je w jedną liczbę. Jest to jednak niewygodne. W  takich wypadkach pomocna może być biblioteka obiektowa random. Udostępnia ona różne generatory liczb pseudolosowych oraz różne rozkłady liczbowe. Tutaj krótko opiszemy podstawowe zasady pracy z obiektami pseudolosowymi.

Generator pseudolosowy jest klasą C++. Istnieją typy ogólne tych klas oraz typy zaadaptowane do określonych rodzajów generatorów pseudolosowych:

default_random_engine : wybrany generator pseudolosowy, który daje dobre wyniki w typowych, prostych zastosowaniach.
minstd_rand : prosty, liniowy generator multiplikatywny LCG:

x = x * 48271 % 2147483647
Zakres liczb 1 … 2147483646.

minstd_rand0 : prosty, liniowy generator multiplikatywny LCG:

x = x * 16807 % 2147483647
Zakres liczb 1 … 2147483646.

mt19937 : generator pseudolosowy typu Mersenne Twister. Daje w wyniku liczby 32-bitowe.
mt19937_64 : generator pseudolosowy typu Mersenne Twister. Daje w wyniku liczby 64-bitowe.
ranlux24_base   generator pseudolosowy typu Ranlux o  podstawie 24-bitowej. Daje w wyniku liczby 32-bitowe.
ranlux48_base   generator pseudolosowy typu Ranlux o  podstawie 48-bitowej. Daje w wyniku liczby 64-bitowe.
ranlux24   generator pseudolosowy typu Ranlux o  podstawie 24-bitowej z przyspieszonym postępem. Daje w  wyniku liczby 32-bitowe.
ranlux48   generator pseudolosowy typu Ranlux o  podstawie 48-bitowej z przyspieszonym postępem. Daje w  wyniku liczby 64-bitowe.
knuth_b   generator pseudolosowy typu Knuth-B. Daje w wyniku liczby 32 bitowe.

Każda klasa generatora posiada funkcje składowe:

(konstruktor) : tworzy obiekt danej klasy i inicjuje jego elementy składowe, tak aby był gotowy do użytku. Jako parametr dla konstruktora przekazuje się ziarno typu całkowitego bez znaku.
min() : zwraca minimalną wartość generowanych liczb pseudolosowych.
max() : zwraca maksymalną wartość generowanych liczb pseudolosowych.
seed (v)   inicjuje na nową wartość wewnętrzne ziarno pseudolosowe wg wartości v.
operator()   generuje kolejną liczbę pseudolosową i  zwraca ją jako wynik operatora nawiasy().
discard()   generuje kolejną liczbę pseudolosową, lecz nie zwraca jej.

Zobaczmy, jak to działa w praktyce. Najpierw musisz włączyć obsługę standardu 11 języka C++ w swoim kompilatorze. Jeśli korzystasz ze środowiska Code::Blocks, to z menu wybierz opcję SettingsCompiler i w okienku dialogowym zaznacz wskazaną opcję kompilatora:

 

Poniższy program tworzy różne generatory liczb pseudolosowych i wyświetla informacje o zakresach generowanych przez nie liczb.

C++
// Liczby pseudolosowe
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <ctime>
#include <random>

using namespace std;

int main()
{
    setlocale (LC_ALL, "");

    cout << "Zakresy bibliotecznych generatorów pseudolosowych" << endl
         << "-------------------------------------------------" << endl << endl;

    // Tworzymy klasy generatorów pseudolosowych

    default_random_engine dgen (time(NULL));
    minstd_rand mgen (time(NULL));
    minstd_rand0 m0gen (time(NULL));
    mt19937 mtgen (time(NULL));
    mt19937_64 mt64gen (time(NULL));
    ranlux24_base rl24gen (time(NULL));
    ranlux48_base rl48gen (time(NULL));
    knuth_b kbgen (time(NULL));

    // Wyświetlamy zakresy liczb pseudolosowych dla każdego generatora

    cout << "standardowy          : " << dgen.min() << " … " << dgen.max() << endl;
    cout << "multiplikatywny LCG  : " << mgen.min() << " … " << mgen.max() << endl;
    cout << "multiplikatywny LCG 0: " << m0gen.min() << " … " << m0gen.max() << endl;
    cout << "Mersenne Twister     : " << mtgen.min() << " … " << mtgen.max() << endl;
    cout << "Mersenne Twister 64  : " << mt64gen.min() << " … " << mt64gen.max() << endl;
    cout << "Ranlux 24-bitowy     : " << rl24gen.min() << " … " << rl24gen.max() << endl;
    cout << "Ranlux 48-bitowy     : " << rl48gen.min() << " … " << rl48gen.max() << endl;
    cout << endl;

    return 0;
}
Wynik:
Zakresy bibliotecznych generatorów pseudolosowych
-------------------------------------------------

standardowy          : 1 … 2147483646
multiplikatywny LCG  : 1 … 2147483646
multiplikatywny LCG 0: 1 … 2147483646
Mersenne Twister     : 0 … 4294967295
Mersenne Twister 64  : 0 … 18446744073709551615
Ranlux 24-bitowy     : 0 … 16777215
Ranlux 48-bitowy     : 0 … 281474976710655

Następny program generuje 15 liczb pseudolosowych za pomocą wybranego generatora pseudolosowego. Generator możesz zmienić na inny.

C++
// Liczby pseudolosowe
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <ctime>
#include <random>
#include <iomanip>

using namespace std;

int main()
{
    cout << "Generacja liczb pseudolosowych generatorem Mersenne Twister" << endl
         << "-----------------------------------------------------------" << endl << endl;

    // Tworzymy generator pseudolosowy Mersenne Twister
    mt19937_64 mt64gen(time(NULL));

    // Wyświetlamy 15 liczb pseudolosowych
    for(int i = 0; i < 15; i++)
        cout << setw (22) << mt64gen() << endl;
    cout << endl;
    return 0;
}
Wynik:
Generacja liczb pseudolosowych generatorem Mersenne Twister
-----------------------------------------------------------

  10537470712149690863
  16289189653767349705
  17446861035845780457
   8462092411226512412
  11670304320697365710
     89603159830766338
  11893928287530825151
   4391792179446479643
   5359857403735253840
    939567318540422672
   1708525228151313803
   7177467170986783977
  12812186784476095291
   9706571523780530581
  17589396534050711681

Jeśli chcesz otrzymywać liczby z zakresu A…B, to możesz zastosować podany wcześniej wzór:

A + generator() % (B - A + 1)

Istnieje jednak lepszy sposób, który wykorzystuje rozkład generowanych liczb. Rozkład określa prawdopodobieństwo pojawienia się określonej wartości w zakresie generowanych liczb. Jeśli prawdopodobieństwo każdej wartości w zakresie jest takie samo, to mamy do czynienia z rozkładem jednorodnym (ang. uniform distribution). Rozkład nazywamy dyskretnym, jeśli w podanym zakresie liczby mogą przyjmować tylko wybrane wartości (np. całkowite).

Biblioteka random udostępnia mnóstwo różnych rozkładów, których dokładne omówienie wykracza poza ramy tego artykułu.

Rozkład w bibliotece random jest klasą. Zasady użycia są następujące:

  1. Tworzymy klasę rozkładu przekazując do jej konstruktora odpowiednie parametry. Dla rozkładu jednorodnego są to granice zakresu liczb pseudolosowych.
  2. Tworzymy klasę generatora liczb pseudolosowych.
  3. Generujemy liczby pseudolosowe poprzez operator() klasy rozkładu przekazując w parametrze klasę generatora pseudolosowego.

Poniższy program generuje 200 liczb pseudolosowych o rozkładzie jednorodnym.

C++
// Liczby pseudolosowe
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <ctime>
#include <random>
#include <iomanip>

using namespace std;

int main()
{
    setlocale (LC_ALL, "");

    cout << "200 liczb pseudolosowych od 1 do 999 o rozkładzie jednorodnym" << endl
         << "-------------------------------------------------------------" << endl << endl;

    // Tworzymy klasę szablonową int rozkładu jednorodnego
    uniform_int_distribution<int> dist(1, 999);

    // Tworzymy standardowy generator pseudolosowy
    default_random_engine gen(time(NULL));

    // Wyświetlamy 200 liczb pseudolosowych
    int c = 0;
    for(int i = 0; i < 200; i++)
    {
        cout << setw (4) << dist (gen);
        C++;
        if(c == 10)
        {
            c = 0; cout << endl;
        }
    }
    cout << endl;
    return 0;
}
Wynik:
200 liczb pseudolosowych od 1 do 999 o rozkładzie jednorodnym
-------------------------------------------------------------

 573 919  35 724 241 623 106  20  82 683
 348 233 137  86 408  63 412 421 587 607
 258  98 355 342 460 672 321 263 826 787
 566 971  51 926 816 717 123 672 934 280
 408 420 474 933 267  81 139 854 987 419
 480 307 248 827 297 164  85 819 579 958
 700 226 399 256 436 158 283 405 259 162
 122  32 698 944 703  57 552 928 498  45
 951 516 167 871 772 782 119 133 770 156
 788 844 272 726 856 927 678 644 892 503
 124 696 332 919 855 357 369 751 227 387
 956 786 707 827 193 582 829 395  10  11
 861 638 255 437  80 473 237  53 380 314
 874 728 443 586 624 196 813 612 530 778
 965 817 821 334 548 610 647 386 437 806
 781 806 756  60 961 360 142 748 270 435
 143 857 623 427 801 409 388 656 922 956
 252  54  40 442 825 103 297 195  91 642
 191 549 537 140 565 425 247 305 938 687
 132 996 955 424  24 668 189 463 479 275

Biblioteka random pozwala również na generowanie rzeczywistych liczb pseudolosowych za pomocą obiektów rozkładu. Przy obiekcie rozkładu uniform_real_distribution parametry a, b określają przedział <a, b) – domknięty lewostronnie, otwarty prawostronnie. Poniższy program generuje rzeczywiste liczby pseudolosowe z przedziału <a, b).

C++
// Liczby zmiennoprzecinkowe
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <random>
#include <ctime>
#include <iomanip>

using namespace std;

int main()
{
    double a, b, x;

    cout << setprecision(5) << fixed;
    cout << "Zmiennoprzecinkowe liczby pseudolosowe w przedziale <a, b)" << endl
         << "----------------------------------------------------------" << endl << endl
         << "Podaj granice:" << endl;

    // Odczytujemy granice przedziału liczb pseudolosowych
    cout << "a = ? "; cin >> a;
    cout << "b = ? "; cin >> b;
    cout << endl;

    // Tworzymy obiekt generatora pseudolosowego i inicjujemy go
    mt19937 gen(time(NULL));

    // Tworzymy klasę rozkładu:
    // Rozkład jednorodny liczb rzeczywistych w przedziale <a, b)
    uniform_real_distribution <double> dist(a, b);

    // Generujemy 10 liczb pseudolosowych
    for(int i = 0; i < 10; i++)
    {
        x = dist(gen);
        cout << setw(12) << x << endl;
    };
    cout << endl;
    return 0;
}
Wynik:
Zmiennoprzecinkowe liczby pseudolosowe w przedziale <a, b)
----------------------------------------------------------

Podaj granice:
a = ? -10
b = ? 10

    -1.49019
    -0.70826
     5.20275
     3.89604
     8.31401
     0.76755
    -7.90011
    -2.96140
     5.07277
    -3.50012

Na początek:  podrozdziału   strony 

Basic (Free Basic)

Inicjalizacja

Ziarno generatora pseudolosowego inicjujemy za pomocą instrukcji:

Randomize X0

Aby otrzymywać przy każdym uruchomieniu programu inne sekwencje liczb pseudolosowych, jako ziarno stosuje się wartość licznika czasu:

Randomize Timer

Inicjalizację generatora pseudolosowego wykonuje się jeden raz na samym początku programu. Zobacz na odpowiednie przykłady dla języka Pascal – w Basicu jest bardzo podobnie.

Generacja całkowitych liczb pseudolosowych

W języku Basic istnieje funkcja Rnd, która zwraca tylko rzeczywistą wartość pseudolosową z przedziału <0, 1) (lewostronnie domkniętego, prawostronnie otwartego). Aby otrzymać liczbę pseudolosową z przedziału całkowitego , stosujemy następujące wyrażenie:

a + Int(Rnd * (b - a + 1)) lub a + Cint(Rnd * (b - a))

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Program wyświetla 15 liczb pseudolosowych z przedziału całkowitego <20, 30>.
Basic
' Wbudowany generator liczb pseudolosowych
' Data:   18.04.2008
' (C)2020 mgr Jerzy Wałaszek
'-----------------------------------------

Dim i As Integer

Randomize Timer

For i = 1 To 15
    Print Int (Rnd * 11) + 20
Next
End
Wynik:
 26
 23
 30
 28
 26
 27
 20
 27
 25
 30
 25
 27
 26
 22
 25

Generacja rzeczywistych liczb pseudolosowych

W języku Basic funkcja Rnd zwraca rzeczywistą liczbę pseudolosową z przedziału <0, 1).

Aby uzyskać rzeczywistą liczbę pseudolosową w przedziale <a, b) stosujemy wyrażenie:

a + Rnd * (b - a)

Aby uzyskać rzeczywistą liczbę pseudolosową w przedziale (a, b> stosujemy wyrażenie:

a + (1 - Rnd) * (b - a)

Aby uzyskać rzeczywistą liczbę pseudolosową w przedziale domkniętym stosujemy konstrukcję:

If Rnd > 0.5) Then
    x = a + Rnd * (b - a)
Else
    x = a + (1 - Rnd) * (b - a)
End If

Aby uzyskać rzeczywistą liczbę pseudolosową w przedziale otwartym (a, b) stosujemy konstrukcję:

Do
    x = a + Rnd * (b - a)
Loop Until x <> a

Na początek:  podrozdziału   strony 

Python (dodatek)

Język Python udostępnia moduł random do generacji liczb pseudolosowych. Liczby te powstają w wewnętrznym generatorze Mersenne Twister. Aby skorzystać z funkcji modułu random, musisz go dołączyć do swojego programu:

…
import random
…

Wewnętrzny generator pseudolosowy jest automatycznie inicjowany przy starcie programu. Zatem przy każdym uruchomieniu otrzymamy inny ciąg liczb pseudolosowych. Uruchom kilka razy poniższy program i porównaj wyniki.

Python (dodatek)
# Liczby pseudolosowe
# Data   : 17.02.2024
# (C)2024 mgr Jerzy Wałaszek
# ---------------------------

import random

for i in range(10):
    print("x%1d = %6.4f" % (i, random.random()))
Wynik:
x0 = 0.2078
x1 = 0.9407
x2 = 0.6044
x3 = 0.0972
x4 = 0.5944
x5 = 0.5142
x6 = 0.6073
x7 = 0.3462
x8 = 0.6713
x9 = 0.4202

Funkcja random.random( ) jest bezparametrowa i zwraca liczbę pseudolosową rzeczywistą z przedziału <0, 1).

Następny program ustawia ziarno generatora przed rozpoczęciem generacji liczb pseudolosowych:

Python (dodatek)
# Liczby pseudolosowe
# Data   : 17.02.2024
# (C)2024 mgr Jerzy Wałaszek
# ---------------------------

import random

random.seed(10)
for i in range(10):
    print("x%1d = %6.4f" % (i, random.random()))
Wynik:
x0 = 0.5714
x1 = 0.4289
x2 = 0.5781
x3 = 0.2061
x4 = 0.8133
x5 = 0.8236
x6 = 0.6535
x7 = 0.1602
x8 = 0.5207
x9 = 0.3278

Funkcja random.seed( ) pozwala ustawiać w różny sposób ziarno generatora. Jeśli ziarno nie jest zdefiniowane, to generator zostanie zainicjowany bieżącym czasem systemu.

Parametr n funkcji random.seed(n) jest liczbą całkowitą (wartości innych typów muszą być zamienione na liczbę całkowitą). Jeśli parametr n zostanie pominięty, to jako ziarno generatora pseudolosowego zostanie użyty czas systemowy. Uruchom powyższy program kilkakrotnie i wyciągnij wnioski.

Funkcja random.random( ) zwraca liczbę pseudolosową z przedziału <0,1). Jeśli potrzebujemy liczb z innego przedziału, to używamy funkcji: random.uniform(a,b), która zwraca liczbę pseudolosową z przedziału obustronnie domkniętego <a,b> o równomiernym rozkładzie. Uruchom poniższy program:

Python (dodatek)
# Liczby pseudolosowe
# Data   : 17.02.2024
# (C)2024 mgr Jerzy Wałaszek
# ---------------------------

import random

a = float(input("a = "))
b = float(input("b = "))
for i in range(10):
    print("x%1d = %9.4f" % (i, random.uniform(a, b)))
Wynik:
a = -999
b = 999
x0 = -769.4328
x1 = -731.6576
x2 =  977.0122
x3 =  328.0549
x4 = -842.0332
x5 = -169.9523
x6 = -895.1615
x7 = -748.6257
x8 =  670.3304
x9 = -723.4715

Do generacji liczb całkowitych używamy funkcję:

random.randrange(start, stop, przyrost)
start : dolna granica
stop : górna granica
przyrost : określa, co ile zmieniają się wartości w przedziale <start, stop). Standardowo co 1.

Poniższy program generuje liczby pseudolosowe z przedziału <1,7) (np. wynik rzutów kostką).

Python (dodatek)
# Liczby pseudolosowe
# Data   : 17.02.2024
# (C)2024 mgr Jerzy Wałaszek
# ---------------------------

import random

for i in range(10):
    print(random.randrange(1,7), end=" ")
print()
Wynik:
2 3 3 4 6 6 6 1 4 3

Moduł random zawiera więcej funkcji. Ich opis znajdziesz w instrukcji języka Python.

Podsumujmy:

random
: moduł z funkcjami generacji liczb pseudolosowych.
random.seed(n)
: ziarno pseudolosowe generatora Mersenne Twister. Jeśli parametr n zostanie pominięty, to ziarno będzie ustawione wartością czasu systemowego.
random.random()
: rzeczywista liczba pseudolosowa z przedziału <0, 1).
random.uniform(a,b)
: rzeczywista liczba pseudolosowa z przedziału <a, b>.
random.randrange(a,b,k)
: całkowita liczba pseudolosowa z przedziału <a,b). Parametr k określa krok, o który rosną kolejne liczby w przedziale. Jeśli krok k będzie pominięty, to krok wyniesie 1. Np. random.randrange(1,10,2) będzie losować liczby ze zbioru: {1 3 5 7 9}.

Na początek:  podrozdziału   strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2024 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.