Để sinh số nguyên trong lập trình C/C++. Chúng ta có thể sử dụng hàm rand(). Hàm này trả về một số nguyên có kiểu dữ liệu là int
Ví dụ:
0
1
2
3
4
5
6
7
8
9
10
11

 
#include
#include
 
int main(){
    int r;
    for(int i = 0; i < 5; ++i){
        r = rand();
        printf("Rand %d is %d\n",i, r);
    }    
}
 

Kết quả chạy thử:
0
1
2
3
4
5
6

 
Rand 0 is 41
Rand 1 is 18467
Rand 2 is 6334
Rand 3 is 26500
Rand 4 is 19169
 

Tuy nhiên, hàm rand() này sẽ không hề random ra các số mới khi bạn chạy code ở các lần sau. Nghĩa là, kết quả của code trên ở mọi lần chạy sẽ đều random ra 5 số giống nhau. Bạn có thể thử chạy đoạn code trên nhiều lần để kiếm chứng.
Vậy làm sao để random các số ngẫu nhiên tại mọi thời điểm? Hãy đọc phần tiếp theo nào.
2. Sinh số ngẫu nhiên trong C/C++ với srand()
Để tạo ra các số ngẫu nhiên khác nhau tại mọi thời điểm chạy code, chúng ta sẽ thêm hàm srand() và truyền vào một tham số seed kiểu int. Tham số này thay đổi thì hàm srand() sẽ sinh ra các số khác nhau.
Ví dụ:
0
1
2

 
srand(123456);
 

Trong trường hợp này, giá trị a vẫn sẽ không đổi ở các lần chạy do 123456 là một hằng số. Vậy, chúng ta sẽ cần truyền vào một giá trị động chứ không phải giá trị tĩnh 😀
Có một giải pháp tốt nhất là chúng ta sẽ truyền cho seed thời gian hiện tại. Bằng cách sử dụng hàm time() trong thư viện time.h. Hàm time() trả về kiểu time_t nhưng chúng ta có thể convert về int.
0
1
2

 
srand((int) time(0));
 

Bằng cách thêm hàm này trước khi gọi hàm rand(), chúng ta đã có thể sinh số ngẫu nhiên khác nhau.
Một ví dụ cụ thể:
0
1
2
3
4
5
6
7
8
9
10
11
12
13

 
#include
#include
#include
 
int main(){
    int r;
    srand((int)time(0));
    for(int i = 0; i < 5; ++i){
        r = rand();
        printf("Rand %d is %d\n",i, r);
    }    
}
 

Kết quả chạy thử:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14

 
// Lần 1
Rand 0 is 5113
Rand 1 is 26832
Rand 2 is 11368
Rand 3 is 11635
Rand 4 is 20552
 
// Lần 2
Rand 0 is 5168
Rand 1 is 12947
Rand 2 is 20147
Rand 3 is 27496
Rand 4 is 32060
 

Ok, đã giải quyết được bài toán sinh số ngẫu nhiên cơ bản. Nhưng nếu tôi muốn sinh số ngẫu nhiên trong đoạn [min, max] thì phải làm thế nào?
3. Sinh số ngẫu nhiên trong đoạn [min, max]
Có thể các bạn thừa biết, phép toán chia dư (%) của mọi số bất kỳ(a) cho một số b cố định: a % b sẽ cho ra giá trị thuộc đoạn [0, b-1]. Ta sẽ lợi dụng tính chất này để sinh số ngẫu nhiên trong đoạn [minN, maxN] như sau:
0
1
2

 
int r = minN + rand() % (maxN + 1 - minN)
 

Như vậy, nếu bạn muốn sinh số ngẫu nhiên trong C++ trong đoạn [5,10], bạn làm như sau:
0
1
2
3
4

 
int r = 5 + rand() % (10 + 1 - 5)
// Hay viết gọn hơn
int r = 5 + rand() % 6
 

Dưới đây là một ví dụ cụ thể, tôi sẽ viết hàm random thành 1 hàm con để các bạn có thể tiện sử dụng.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

 
#include
#include
#include
 
int random(int minN, int maxN){
    return minN + rand() % (maxN + 1 - minN);
}
 
int main(){
    srand((int)time(0));
    int r;
    for(int i = 0; i < 1000; ++i){
        r = random(1,100);
        printf("%d ",r);
    }    
}
 

Kết quả chạy thử:
Kết quả sinh số ngẫu nhiên trong đoạn [minN, maxN]

https://nguyenvanhieu.vn/wp-content/uploads/2018/10/sinh-so-ngau-nhien-trong-doan-min-max-300x147.png 300w, https://nguyenvanhieu.vn/wp-content/uploads/2018/10/sinh-so-ngau-nhien-trong-doan-min-max-768x377.png 768w" data-sizes="(max-width: 977px) 100vw, 977px" title="Sinh số ngẫu nhiên trong C/C++, Sinh số random trong đoạn [a,b] 1" sizes="(max-width: 977px) 100vw, 977px" srcset="https://nguyenvanhieu.vn/wp-content/uploads/2018/10/sinh-so-ngau-nhien-trong-doan-min-max.png 977w, https://nguyenvanhieu.vn/wp-content/uploads/2018/10/sinh-so-ngau-nhien-trong-doan-min-max-300x147.png 300w, https://nguyenvanhieu.vn/wp-content/uploads/2018/10/sinh-so-ngau-nhien-trong-doan-min-max-768x377.png 768w" data-was-processed="true">Kết quả sinh số ngẫu nhiên trong đoạn [minN, maxN]
4. Sinh số thực ngẫu nhiên trong đoạn [min, max]
Dưới đây là hàm giúp các bạn sinh số thực ngẫu nhiên trong đoạn [min, max].
0
1
2
3
4
5
6

 
float float_rand( float min, float max )
{
    float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */
    return min + scale * ( max - min );      /* [min, max] */
}
 

Về cơ bản ý tưởng vẫn sử dụng hàm rand. Sau đó chia cho RAND_MAX để được số thực. Vì RAND_MAX là số lớn nhất mà hàm rand(), nên kết quả thu được sẽ là số thực trong đoạn [0, 1]. Chúng ta cần xử lý thêm một chút để thu được giá trị trong đoạn [min, max].
5. Sinh số ngẫu nhiên kiểu long long
Trong một số trường hợp, bạn có thể sẽ cần random số ngẫu nhiên lớn hơn kiểu int. Khi đó, bạn có thể sử dụng hàm random kiểu long long int này. Dưới đây là code các bạn tham khảo:
0
1
2
3
4
5
6
7
8

 
long long Rand(long long l, long long h)
{
    return l + ((long long)rand() * (RAND_MAX + 1) * (RAND_MAX + 1) * (RAND_MAX + 1) +
                (long long)rand() * (RAND_MAX + 1) * (RAND_MAX + 1) +
                (long long)rand() * (RAND_MAX + 1) +
                rand()) % (h - l + 1);
}
 

Kết luận
Bài viết này Nguyễn Văn Hiếu Blog đã hướng dẫn bạn khá đầy đủ về cách để sinh số ngẫu nhiên trong C/C++. Hi vọng bài viết đem lại nhiều kiến thức bổ ích cho tất cả các bạn.
Nếu bạn đọc quan tâm nhiều hơn về đề tài này, hãy tiếp tục đọc các bài viết có tag là sinh số ngẫu nhiên nhé. Mình sẽ còn hướng dẫn các bạn xáo trộn mảng, hay sinh một mảng các số không trùng lặp,…
time_t là kiểu dữ liệu, ko phải để đo đạc cái gì hết. Chữ _t nghĩa là “type”. time_t viết tắt cho time_type là kiểu dữ liệu “thời gian”.
biến kiểu time_t có giá trị là số giây tính từ epoch (1970-01-01 00:00:00 UTC)
time(0) là hàm trong thư viện ctime, nhận vào 1 con trỏ, thực hiện lưu giá trị x là số giây tính từ epoch vào nơi mà con trỏ đó trỏ tới, và trả về x. Nếu con trỏ đó là NULL thì chỉ trả về x.
và cuối cùng là time_t là của nợ C++ gánh từ C qua, C++ có thư viện chrono hại điện hơn
C++11 chrono tuy dài dòng nhưng rõ ràng hơn:
#include
#include
int main() {
    std::chrono::seconds secondsSinceEpoch =         std::chrono::duration_cast(             std::chrono::system_clock::now().time_since_epoch());     std::cout << secondsSinceEpoch.count(); }
  • std::chrono::system_clock là cái đồng hồ đo thời gian
  • gọi std::chrono::system_clock::now() nghĩa là lấy thời gian hiện tại của cái system_clock này, kiểu dữ liệu của nó là time_point là mốc thời gian
  • gọi tiếp .time_since_epoch() nghĩa là lấy mốc thời gian hiện tại trừ cho mốc thời gian tại epoch. Kết quả trả về là 1 khoảng thời gian duration
  • duration có thể chứa số giây, số mili giây, micro giây, hay nano giây. Muốn lấy số giây thì phải ép kiểu về kiểu seconds. Vì ở đây có bỏ qua số micro/nano giây nên phải ép kiểu tường minh bằng duration_cast,
  • cuối cùng lấy giá trị số của seconds ra thông qua .count()