Cách sinh số ngẫu nhiên trong C++ – Random number library functions

random

Việc phát sinh số ngẫu nhiên là cần thiết khi chúng ta cần test chương trình. Việc tạo số ngẫu nhiên trong C++ cũng khá đơn giản. Thư viện chuẩn của C++ cung cấp môt hàm gọi là rand (#include <cstdlib>). Bài viết này sẽ giúp chúng ta hiểu hơn về chức năng tạo số ngẫu nhiên trong C++.

1. Tạo một số ngẫu nhiên:

Hàm rand() trả về một số nguyên nằm trong dãy [0, RAND_MAX], với RAND_MAX là một hằng số được định nghĩa trước. Hãy xem ví dụ bên dưới:

// First example 
#include <iostream>
#include <cstdlib>
using namespace std; int main() { int r0 = rand(); int r1 = rand(); int r2 = rand(); int r3 = rand(); int r4 = rand(); cout<< "r0 = "<< r0 << endl; cout<< "r1 = "<< r1 << endl; cout<< "r2 = "<< r2 << endl; cout<< "r3 = "<< r3 << endl; cout<< "r4 = "<< r4 << endl; system("pause"); return 0; }

- Output là:

image

-  Nhưng sau khi chạy nhiều lần chương trình trên, bạn vẫn nhận được một output như lúc đầu. Vấn đề này sẽ được giải quyết trong mục 2.

2. Tạo một số ngẫu nhiên thay đổi theo thời gian

-  Để tạo một số ngẫu nhiêu sau thay đổi khác nhau trong những lần chạy, bạn sử dụng hàm time (có trong #include<ctime>). Theo như thư viện MSDN (Microsoft Developers Network) nói rằng: time trả về số của giây được trôi qua được tính từ nữa đêm (00:00:00), ngày 1, tháng 1, năm 1970 theo UTC . (“The time function returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC), according to the system  clock”).

-  Các số ngẫu nhiên giả được tạo ra bắt đầu từ thời điểm bạn thiết lập sử dụng hàm srand. Dòng code dưới đây thiết lập điểm bắt đầu của thời gian hiện hành.

srand(time(0));

- Giá trị được trả về từ time là qua srand. Lưu ý rằng số ngẫu nhiên được tạo ra trước lời gọi rand.

Ví dụ với chương trình đầu tiên: chúng ta thêm srand(time(0)) trước lời gọi rand().

// Second example 
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std; int main() { srand(time(0)); int r0 = rand(); int r1 = rand(); int r2 = rand(); int r3 = rand(); int r4 = rand(); cout<< "r0 = "<< r0 << endl; cout<< "r1 = "<< r1 << endl; cout<< "r2 = "<< r2 << endl; cout<< "r3 = "<< r3 << endl; cout<< "r4 = "<< r4 << endl; system("pause"); return 0; }

-  Output lần đầu:

image

- Output lần 2:

image- Output lần 3:

image

3. Tạo số ngẫu nhiên nằm trong dãy xác định (Specifying the range)

-  Thông thường, một số ngẫu nhiên nằm trong dãy [0, RAND_MAX] không được mô tả. Đúng hơn là chúng ta không thích một dãy được xác định. Một số ngẫu nhiên trong dãy [0, n – 1] có thể được xác định bằng cách sử dụng toán tử % (modulus). Ví dụ như sinh ra một số ngẫu nhiên trong dãy [0, 21], thì bạn có thể viết như sau:

int num = rand();
int val = num % 22;

- Hoặc có thể viết một cách mạch lạc hơn là:

int num = rand() % 22;

- Khi chúng ta cần một dãy không bắt đầu từ 0. Ví dụ như sinh một số ngẫu nhiên nằm trong dãy [22, 100] thì phải làm sao? Chúng ta có thể thực hiện một cách khá đơn giản theo công thức

Để tạo một số ngẫu nhiên trong dãy [a, b] ta sử dụng công thức:

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

Như muốn sinh một số ngẫu nhiên từ dãy [22, 100] ta viết như sau:

int num = 22 + rand() % (100 – 22 + 1);

hay đúng hơn là:

int num = 22 + rand() % (79);

- Do phần tạo số ngẫu nhiên trong dãy [a, b]  một số bạn comment vẫn chưa làm được hoặc kết quả cho ra chưa như ý muốn. Cho nên sau đây tôi xin bổ sung một đoạn chương trình minh họa cho việc sinh số ngẫu nhiêu trong đoạn [22, 100].

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

using namespace std;
int main()
{
    srand(time(0));
    int number[200];
    for(int i = 1; i <= 200; i++)
    {
        number[i] = 1 + rand()%(100-22+1);    
        /* hoac co the viet:
           number[i] = 1 + rand()%(79);               
        */
    }
    for(int i = 1; i <= 200; i++)
    {
        cout<<number[i]<<"  ";
        if(i%20 == 0)
                cout<<"\n\n";
    }
    cout<<"\n";
    system("pause");
    return 0;
}

kết quả khi chạy chương trình lần 1:

SNAGHTML2f4318

kết quả lần chạy thứ 2:

SNAGHTML31db70

Sở dĩ chương trình của nhiều bạn không thể cho ra kết quả có số 100 (như bạn luphucnguyen@yahoo.com đã comment dưới bài viết này) là do chương trình của chưa sử dụng hàm srand(time(0)); để sinh ra số ngẫu nhiên trong mỗi lần chạy chương trình, hoặc có thể tập ngẫu nhiên bạn muốn sinh ra chưa đủ lớn nên xác suất có mặt các số mà bạn mong muốn nhỏ hơn (trong ví dụ trên mình sinh ra tập 200 số ngẫu nhiên trong đoạn [22, 100] nên xác suất có mặt của số 100 sẽ cao hơn Island with a palm tree).

** Lưu ý: Các ví dụ đề đã được chạy thử trên môi trường DevC++.

(Tham khảo Frank Luna,C++ Programming for Games – Module I)

About these ads

About thanhcuong1990

Handsome and talent!! ^^
This entry was posted in C++. Bookmark the permalink.

32 Responses to Cách sinh số ngẫu nhiên trong C++ – Random number library functions

  1. dac danh says:

    thank!!!!.

  2. Phan Tiến Quang says:

    thanks a lots!

  3. TRUNG says:

    THANKS

  4. Sơn says:

    Cám ơn vì bài viết của bạn!

  5. Zombie says:

    Thanks!

  6. foolish man says:

    Cảm ơn bạn! Bài viết rất hữu ích!

  7. tjanh says:

    tks very much

  8. xwhitelight says:

    Rất hay. Thanks u very much! ^^

  9. thinh says:

    thanhks you!

  10. thuy says:

    bài viết rất hay.thanks

  11. subasa says:

    Như muốn sinh một số ngẫu nhiên từ dãy [22, 100] ta viết như sau:

    int num = 22 + rand() % (100 – 22 + 1);
    – Mình thấy đoạn code này ko chính xác, nếu như thế num chỉ phát sinh ngẫu nhiên từ 22 -> 99 nhưng đề bài là từ 22 -> 100.

    • Max says:

      Đoạn này mình cũng không hiểu lắm..admin giải thích thêm được không?..mình test thử từ 1 tới 3…nếu dùng int num = 1 +rand()%(3-(1+1)); thì nó luôn ra kết quả là 1..mặc dù đã cho random ngẫu nhiên !!!
      Vậy có phải chăng không cần trừ đi số ban đầu mà chỉ cần nhập vào số đích như thế này int num = 1 + rand()%(3);
      Nếu làm như trên thì test nó sẽ random từ 1>>3..Chứ không còn ra mỗi kết quả là 1 như lúc trừ đi số ban đầu nữa !!

      • Có lẽ câu lệnh của bạn dùng chưa đúng như mình đã viết trong bài viết trên:
        Câu lệnh của bạn: int num = 1 +rand()%(3-(1+1)) nên thay bằng:
        int num = 1 +rand()%(3-1+1);
        ps: mình đã bổ sung ví dụ minh họa cho trường hợp của bạn ở cuối bài viết trên. Cảm ơn bạn đã qua tâm đối với blog của mình.

      • hdk says:

        theo minh hiểu thì:
        rand() % n thì sẽ có giá trị từ 0 -> n-1;
        khi bạn dung lệnh: rand() % (b-a +1) se cho gia trị chạy từ 0 đến b-a;
        vd: từ (22-100) thì rand() % (100-22+1) =rand() % 79 sẽ cho giá trị từ đến 78..
        cho nên muốn co giá trị từ 22-100 ban cần công thêm 22
        rand() % (b-a +1) +a
        vd: rand() %79 + 22 se cho giá trị [0,78] + 22; co nghĩa là giá trị sẽ từ khoảng 22-100;

    • Trường hợp của bạn có thể là do tập hợp số ngẫu nhiên mà bạn muốn sinh ra hơi nhỏ nên xác suất tạo ra số 100 hơi thấp. Bạn thử sinh ra mảng ngẫu nhiên khoảng 200 số nằm trong đoạn [22, 100] thì sẽ thấy bài viết của mình là đúng.
      Mình cũng đã bổ sung đoạn chương trình minh họa cho trường hợp của bạn ở cuối bài viết trên.

      • tam says:

        mình thử rùi 200 mà k xuất hiện số nào lớn hơn 79, mà mình thử 400,500 mà số xuất hiện chỉ có 200

  12. Thắng says:

    Bạn viết rất hay!

  13. teresaroserain says:

    nếu như mảng đó không đầy đủ các con số từ 22 đến 100 thì sao? ( Ý là mình không sử dụng đến một vài số như bỏ 24, 27, 28, 30, 50, 89, 90, 99) vậy nếu random lỡ trúng vào những con số đó thì sao? Giải quyết thế nào nhỉ? Thanks

    • Đơn giản thôi. Bạn sử dụng if hoặc switch-case để kiểm tra lại số ngẫu nhiên sinh ra được. Nếu nằm trong các số bạn không muốn lấy thì random lại số khác.

  14. MissReply says:

    mình có xem qua bài của bạn. trong ví dụ bạn cho sinh số ngẫu nhiên trong [22.100] thì đc kq ra đầy đủ các phần tử, nhưng nếu mình muốn sinh số ngẫu nhiên mà chỉ ra các phần tử ko có lặp thì mình nên làm thế nào. Mình đã thử 1 số cách nhưng chương trình chạy khá là chậm @@

  15. MrLeo says:

    theo bạn thanhcuong90 thì cách của bạn ấy là tuyệt đối nhưng mình muốn đóng góp 1 ý kiến là khi bạn dùng vòng lặp ( ví dụ dùng for) thì bạn cho phần tử a[i]=i+a+rand()%(b-a+1); như vậy sẽ giảm xác suất trùng lặp các phần tử ! Nhưng cái này càng đúng khi n càng lớn .

  16. VT Nghĩa says:

    Công nhận anh Cương am tường về C ghê, mình bằng 1/2 thế này thì tốt

  17. hai says:

    cho hoi lam sao de tao ra so thap phan trong c vay

  18. manh viking says:

    thanks a lots :D

  19. ta, says:

    number[i] = 1 + rand()%(100-22+1); tại sao lại là 1+… mình tưởng là 22+ chứ

  20. tam says:

    với lại khi minh thay tập thành 400,hay 300 số ngẫu nhiên xuất hiên trong khoảng từ [22,100] thì vẫn chỉ xuất hiện 200 số, mà các số xuất hiện đều nhỏ hơn 79 @@..

  21. Bay says:

    Cảm ơn bài viết của bạn, rất hữu ích!

  22. lò văn hoạt says:

    nếu như muốn sinh một chuỗi nhị phân. 32bit … thì có thể làm theo cách này không bạn. mình mới học lập trình nên muốn học hỏi từ mọi người

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s