VBA posiada w swojej bogatej kolekcji funkcję Rnd, która jest odpowiednikiem funkcji arkuszowej LOS. Standardowo jej celem jest wylosowanie liczby zmiennoprzecinkowej z przedziału <0,1). Przy pewnej modyfikacji możemy jednak wylosować liczbę całkowitą z dowolnego zakresu wartości numerycznych.
Liczby pseudolosowe
Funkcja Rnd wbrew pozorom, jest dość nieintuicyjna. Wynika to z faktu, że domyślnie nie generuje wartości losowych tylko pseudolosowe… Brzmi dziwnie? Już tłumaczę.
Jeżeli otworzymy sobie dowolny plik Excela i w okienku Immediate odpalimy polecenie ? Rnd, to otrzymamy liczbę 0,7055475. Uruchamiając to samo polecenie drugi raz, otrzymamy 0,533424. Trzecie uruchomienie da nam wynik 0,5795186.
Podobne wyniki otrzymam otwierając dowolny plik w starszej wersji Excela.
Screeny wyglądają tak samo, ale pochodzą z różnych aplikacji. Pierwsza to Excel 365, druga – 2010.
Identyczne wyniki uzyska każdy, kto otworzy dowolny skoroszyt na swoim komputerze.
Płynie z tego prosty wniosek. Funkcja Rnd domyślnie nie generuje liczb losowych. Odczytuje ona liczby w trybie sekwencyjnym z wcześniej przygotowanej tablicy. Możemy to przyrównać do matematycznych tablic losowych, które wydrukowane znajdziemy w książkach.
Instrukcja Randomize
Co jednak w sytuacji gdy chcemy otrzymać liczby naprawdę losowe? Czy sprawa jest przegrana? Otóż nie! Z pomocą przychodzi polecenie Randomize, które wystarczy umieścić raz na początku makra, przed funkcją Rnd. Jej dodanie spowoduje, że kompilator za każdym razem wylosuje nam rzeczywiście przypadkową liczbę.
Losowanie od 0 do 10
Aby wylosować liczbę całkowitą od 0 do 10 należy użyć takiego wzoru:
Int(Rnd * (10 + 1))
Po pierwsze, należy zapamiętać, że funkcja Rnd nigdy nie wylosuje cyfry 1. Domyślnie losuje ona liczbę zmiennoprzecinkową z zakresu od 0 do 1, przy czym zakres ten jest lewostronnie domknięty. Możemy więc wylosować 0, ale nie 1. Zaokrąglając wylosowaną liczbę do całkowitej, zawsze otrzymamy 0.
Z tego też względu, chcąc wylosować liczbę z zakresu od 0 do 10, nie możemy przemnożyć Rnd * 10 i zaokrąglić wynik do liczby całkowitej. Po prostu taka instrukcja nigdy nie zwróci nam liczby 10, maksymalnie 9. Aby się z tym uporać, musimy dodać jedynkę i przemnożyć funkcję Rnd przez 11.
Poniższe makro wstawia do zakresu A1:E20 liczby losowe z zakresu od 0 do 10.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Public Sub LosujLiczby() Dim rngDane As Range Dim r As Integer, c As Integer Application.ScreenUpdating = False Set rngDane = wksLos.Range("Dane").Cells Randomize For r = 1 To rngDane.Rows.Count For c = 1 To rngDane.Columns.Count rngDane(r, c) = Int(Rnd * (10 + 1)) Next c Next r End Sub |
Losowanie od 1 do 10
Aby wylosować liczbę całkowitą z przedziału od 1 do 10 należy również dodać jedynkę, ale w innym miejscu.
Int(Rnd * 10) + 1
Polecenie Int(Rnd * 10) zwróci nam w wyniku cyfrę z przedziału 0-9. Jeżeli chcemy wylosować liczbę z zakresu 1-10, wystarczy do powyższej instrukcji dodać cyfrę 1.
Poniższe makro wstawia do zakresu A1:E20 liczby losowe z przedziału od 1 do 10.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Public Sub LosujLiczby() Dim rngDane As Range Dim r As Integer, c As Integer Application.ScreenUpdating = False Set rngDane = wksLos.Range("Dane").Cells Randomize For r = 1 To rngDane.Rows.Count For c = 1 To rngDane.Columns.Count rngDane(r, c) = Int(Rnd * 10) + 1 Next c Next r End Sub |
Losowanie od 5 do 10
Aby wylosować liczbę z konkretnego przedziału np. od 5 do 10, musimy rozbudować naszą instrukcję do następującej postaci.
Int(Rnd * (10 – 5 + 1)) + 5
Analizę zacznijmy od instrukcji w nawiasie. Od górnego zakresu (10) odejmujemy dolny zakres (5) i dodajemy 1. W wyniku otrzymujemy cyfrę 6.
Otrzymaną cyfrę (6) mnożymy przez funkcję Rnd. Całość zaokrąglamy do liczby całkowitej. Pamiętamy, że funkcja Rnd może zwrócić 0, ale nigdy nie zwróci 1, więc w w wyniku otrzymamy liczbę z przedziału 0-5.
Aby uzyskać liczbę całkowitą z zakresu 5-10, wystarczy dodać do wyniku cyfrę 5.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Public Sub LosujLiczby() Dim rngDane As Range Dim r As Integer, c As Integer Application.ScreenUpdating = False Set rngDane = wksLos.Range("Dane").Cells Randomize For r = 1 To rngDane.Rows.Count For c = 1 To rngDane.Columns.Count rngDane(r, c) = Int(Rnd * (10 - 5 + 1)) + 5 Next c Next r End Sub |
Losowanie od -10 do 10
Funkcja Rnd nie pozwala wylosować liczby ujemnej, dlatego należy wylosować wartość dodatnią i odjąć od niej większą liczbę.
Int(Rnd * (20 + 1)) – 10
W omawianym przykładzie najpierw losujemy liczbę całkowitą z zakresu od 0 do 20, a następnie odejmujemy 10. W ten sposób losujemy liczbę z zakresu od -10 do 10.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Public Sub LosujLiczby() Dim rngDane As Range Dim r As Integer, c As Integer Application.ScreenUpdating = False Set rngDane = wksLos.Range("Dane").Cells Randomize For r = 1 To rngDane.Rows.Count For c = 1 To rngDane.Columns.Count rngDane(r, c) = Int(Rnd * (20 + 1)) - 10 Next c Next r End Sub |