Vấn đề sinh số ngẫu nhiên trong C++
samedi 28 octobre 2006 18:36:50
Bài viết này giới thiệu cách thức sinh một số ngẫu nhiên trong chương trình C++
I. Các thư viện liên quan đến vấn đề sinh số ngẫu nhiên
1. Thư viện stdlib.h
Thư viện này bao gồm các chức năng liên quan đến việc cấp phát, giải phóng bộ nhớ; Chuyển đổi các kiểu dữ liệu; Điều khiển tiến trình; Sắp xếp và tìm kiếm dữ liệu; Một số phép tính toán học.
Trong bài viết này, ta chỉ làm việc với 2 hàm rand() và srand() cùng với hằng số RAND_MAX trong thư viện stdlib.h
2. Thư viện time.h
Thư viện này cung cấp các hàm làm việc với thời gian.
Trong bài viết này, ta chỉ làm việc với 2 hàm time() và kiểu dữ liệu time_t trong thư viện time.h
II. Các hàm, hằng số và kiểu dữ liệu liên quan đến vấn đề sinh số ngẫu nhiên
1. Hằng số RAND_MAX (nằm trong thư viện stdlib.h)
Hằng số RAND_MAX là một hằng số nguyên, nó đại diện cho giá trị lớn nhất mà có thể được trả về từ hàm rand(). Giá trị của RAND_MAX = 7FFFH = 32767D
Để biết giá trị của RAND_MAX ta có thể sử dụng đoạn chương trình sau:
#include <stdlib.h>
#include <iostream.h>
void main()
{
cout << "Gia tri cua RAND_MAX la: " << RAND_MAX << endl;
}
2. Hàm rand() (nằm trong thư viện stdlib.h)
Cú pháp:
int rand();
Hàm rand() được sử dụng để sinh ra một số nguyên ngẫu nhiên nằm trong khoảng từ 0 đến RAND_MAX.
Ta sử dụng đoạn chương trình sau để sinh ra một số nguyên ngẫu nhiên nằm trong khoảng từ 0 đến RAND_MAX.
#include <stdlib.h>
#include <iostream.h>
int main()
{
int so_nguyen_ngau_nhien = rand();
cout << so_nguyen_ngau_nhien << endl;
}
Nhận xét: Ta nhận thấy là mỗi khi chạy lại chương trình ta đều nhận được một số nguyên giống nhau nằm trong khoảng từ 0 đến RAND_MAX. Để giải quyết vấn đề này ra sẽ phải sử dụng hàm srand() khi bắt đầu chạy chương trình (ta sẽ tìm hiểu hàm srand() ở phần dưới)
3. Kiểu dữ liệu time_t (nằm trong thư viện time.h)
Kiểu dữ liệu time_t được khai báo trong time.h như sau:
typedef long time_t;
Ta thấy rằng time_t là một số nguyên kiểu long và nó mô tả số giây đã trôi qua được tính từ điểm mốc là 0 giờ 0 phút 0 giây ngày mùng 1 tháng 1 năm 1970.
Ta sử dụng đoạn mã sau để biết khoảng thời gian từ 00:00:00 ngày 01/01/1970 đến thời điểm hiện tại là bao nhiêu giây:
#include <time.h>
#include <iostream.h>
void main()
{
time_t seconds;
time(&seconds);
cout << seconds << endl;
}
4. Hàm time() (nằm trong thư viện time.h)
Cú pháp:
time_t time (time_t *timer);
Hàm time() được sử dụng để lấy số giây tính từ 0 giờ 0 phút 0 giây ngày 1 tháng 1 năm 1970 cho đến thời điểm hiện tại.
Chú ý:
- Nếu con trỏ timer bằng NULL thì số giây sẽ được trả về cho hàm.
- Nếu con trỏ timer khác NULL thì số giây sẽ được trả về cho cả tham số là con trỏ timer và cả cho hàm.
Ta thấy đoạn mã dưới hai biến seconds, my_seconds và return_seconds đều có giá trị như nhau và giá trị đó thể hiện khoảng thời gian từ 00:00:00 ngày 01/01/1970 đến thời điểm hiện tại là bao nhiêu giây:
#include <time.h>
#include <iostream.h>
void main()
{
time_t seconds;
time_t my_seconds;
time_t return_seconds;
seconds = time(&my_seconds);
return_seconds = time(NULL);
cout << seconds << endl;
cout << my_seconds << endl;
cout << return_seconds << endl;
}
5. Hàm srand() (nằm trong thư viện stdlib.h)
Cú pháp:
void srand (unsigned int seed);
Hàm này được sử dụng để đặt điểm bắt đầu cho việc sinh số ngẫu nhiên của hàm rand(). Tham số seed chính là điểm bắt đầu để sinh số ngẫu nhiên.
Ta thấy rằng nếu dùng hàm rand() mà không sử dụng hàm srand() để đặt điểm bắt đầu thì mỗi lần chạy chương trình hàm rand() sẽ sinh ra các con số tương tự nhau. Để giải quyết vấn đề này ta sẽ đặt hàm srand() phía trên hàm rand() và thay đổi giá trị của tham số seed trong hàm srand() mỗi khi bắt đầu chạy chương trình. Việc thay đổi này, ta sẽ sử dụng giá trị trả về của hàm time() để làm giá trị cho seed bởi tại mỗi thời điểm thì giá trị trả về của hàm time() là khác nhau. Cách viết cụ thể như sau: srand ( (unsigned) time(NULL) );
Chú ý:
- Nếu seed = 1 thì kết quả số ngẫu nhiên do rand() sinh ra tương tự như không có hàm srand() ở phía trên.
- Nếu seed là một hằng số nguyên không đổi thì mỗi khi chạy chương trình, mặc dù có hàm srand() ở phía trên hàm rand() thì số ngẫu nhiên được sinh ra vẫn là một con số giống nhau (Điều này được giải thích bởi điểm bắt đầu vào chương trình do hàm srand() xác định là như nhau)
Đoạn chương trình sau sẽ sinh ra một số ngẫu nhiên trong khoảng từ 0 đến RAND_MAX và mỗi lần chạy lại thì chương trình sẽ không sinh ra các số giống nhau nữa.
#include <stdlib.h>
#include <time.h>
#include <iostream.h>
void main()
{
srand((unsigned)time(NULL)); //unsigned để xác định là số không dấu
int random_integer = rand();
cout << random_integer << endl;
}
III. Sinh số ngẫu nhiên trong một khoảng xác định trước
1. Sinh số nằm trong khoảng từ 0 cho đến n (với n <= RAND_MAX)
#include <stdlib.h>
#include <time.h>
#include <iostream.h>
void main()
{
int random_integer;
int n;
cout << "Nhap so n voi n nho hon RAND_MAX: "; cin >> n;
srand((unsigned)time(NULL));
for(int index=0; index<20; index++)
{
random_integer = (rand() % n)+1;
cout << random_integer << endl;
}
}
2. Sinh số nằm trong khoảng [a, b] (với 0 <= a <= b <= RAND_MAX)
#include <stdlib.h>
#include <time.h>
#include <iostream.h>
void main()
{
srand((unsigned)time(0));
int random_integer;
int a, b;
cout << "Nhap vao khoang [a, b]: "; cin >> a >> b;
int range=(b-a)+1;
for(int index=0; index<20; index++)
{
random_integer = a + int(range*rand()/(RAND_MAX + 1.0));
cout << random_integer << endl;
}
}