C ++ 11 cung cấp cho bạn rất nhiều tùy chọn mới với random
. Bài viết kinh điển về chủ đề này sẽ là N3551, Tạo số ngẫu nhiên trong C ++ 11
Để biết lý do tại sao việc sử dụng rand()
có thể có vấn đề, hãy xem tài liệu trình bày có hại của rand () được coi là có hại của Stephan T. Lavavej được đưa ra trong sự kiện Đi 2013 . Các slide trong các ý kiến nhưng đây là một liên kết trực tiếp .
Tôi cũng bao gồm boost
cũng như sử dụng rand
vì mã kế thừa vẫn có thể yêu cầu hỗ trợ của nó.
Ví dụ dưới đây được chắt lọc từ trang web cppreference và sử dụng công cụ std :: mersenne_twister_engine và std :: thống_real_distribution tạo ra các số trong [0,10)
khoảng, với các công cụ và phân phối khác được nhận xét ( xem nó trực tiếp ):
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
int main()
{
std::random_device rd;
//
// Engines
//
std::mt19937 e2(rd());
//std::knuth_b e2(rd());
//std::default_random_engine e2(rd()) ;
//
// Distribtuions
//
std::uniform_real_distribution<> dist(0, 10);
//std::normal_distribution<> dist(2, 2);
//std::student_t_distribution<> dist(5);
//std::poisson_distribution<> dist(2);
//std::extreme_value_distribution<> dist(0,2);
std::map<int, int> hist;
for (int n = 0; n < 10000; ++n) {
++hist[std::floor(dist(e2))];
}
for (auto p : hist) {
std::cout << std::fixed << std::setprecision(1) << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
}
đầu ra sẽ tương tự như sau:
0 ****
1 ****
2 ****
3 ****
4 *****
5 ****
6 *****
7 ****
8 *****
9 ****
Đầu ra sẽ thay đổi tùy thuộc vào phân phối bạn chọn, vì vậy nếu chúng tôi quyết định sử dụng std :: normal_distribution với giá trị 2
cho cả trung bình và stddev, ví dụ dist(2, 2)
thay vì đầu ra sẽ tương tự như vậy ( xem trực tiếp ):
-6
-5
-4
-3
-2 **
-1 ****
0 *******
1 *********
2 *********
3 *******
4 ****
5 **
6
7
8
9
Sau đây là phiên bản sửa đổi của một số mã được trình bày trong N3551
( xem trực tiếp ):
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
std::default_random_engine & global_urng( )
{
static std::default_random_engine u{};
return u ;
}
void randomize( )
{
static std::random_device rd{};
global_urng().seed( rd() );
}
int main( )
{
// Manufacture a deck of cards:
using card = int;
std::array<card,52> deck{};
std::iota(deck.begin(), deck.end(), 0);
randomize( ) ;
std::shuffle(deck.begin(), deck.end(), global_urng());
// Display each card in the shuffled deck:
auto suit = []( card c ) { return "SHDC"[c / 13]; };
auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };
for( card c : deck )
std::cout << ' ' << rank(c) << suit(c);
std::cout << std::endl;
}
Kết quả sẽ tương tự như:
5H 5S NHƯ 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QĐ JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C 7S 6S
Tăng cường
Tất nhiên Boost.Random luôn là một tùy chọn, ở đây tôi đang sử dụng boost :: Random :: thống_real_distribution :
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>
int main()
{
boost::random::mt19937 gen;
boost::random::uniform_real_distribution<> dist(0, 10);
std::map<int, int> hist;
for (int n = 0; n < 10000; ++n) {
++hist[std::floor(dist(gen))];
}
for (auto p : hist) {
std::cout << std::fixed << std::setprecision(1) << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
}
rand ()
Nếu bạn phải sử dụng rand()
thì chúng ta có thể truy cập Câu hỏi thường gặp về C để được hướng dẫn về Cách tạo số ngẫu nhiên dấu phẩy động? , về cơ bản đưa ra một ví dụ tương tự như điều này để tạo một khoảng [0,1)
:
#include <stdlib.h>
double randZeroToOne()
{
return rand() / (RAND_MAX + 1.);
}
và để tạo một số ngẫu nhiên trong phạm vi từ [M,N)
:
double randMToN(double M, double N)
{
return M + (rand() / ( RAND_MAX / (N-M) ) ) ;
}