Tôi nghĩ rằng giá trị được tạo ra bởi phân phối ngẫu nhiên C++ 11 (ví dụ: uniform_int_distribution
), chỉ phụ thuộc vào trạng thái của bộ tạo được chuyển đến operator()
. Tuy nhiên, vì một lý do nào đó không có số tham chiếu const
trong chữ ký của operator()
. Điều đó có nghĩa là gì và tôi nên chuyển giao phân phối như một tham số chức năng như thế nào? Tôi nghĩ rằng tôi đã phải vượt qua nó như là bất kỳ tham số không lẫn nhau: bởi tham chiếu const, nhưng bây giờ tôi không chắc chắn.Tại sao C++ 11 phân phối ngẫu nhiên có thể thay đổi?
Trả lời
Tôi đã hiểu sai câu hỏi lúc đầu, tuy nhiên, bây giờ tôi hiểu, đó là một câu hỏi hay. Một số đào sâu vào nguồn gốc của việc thực hiện <random>
cho g ++ cho phép như sau (với một vài bit trái ra cho rõ ràng):
template<typename _IntType = int>
class uniform_int_distribution
{
struct param_type
{
typedef uniform_int_distribution<_IntType> distribution_type;
explicit
param_type(_IntType __a = 0,
_IntType __b = std::numeric_limits<_IntType>::max())
: _M_a(__a), _M_b(__b)
{
_GLIBCXX_DEBUG_ASSERT(_M_a <= _M_b);
}
private:
_IntType _M_a;
_IntType _M_b;
};
public:
/**
* @brief Constructs a uniform distribution object.
*/
explicit
uniform_int_distribution(_IntType __a = 0,
_IntType __b = std::numeric_limits<_IntType>::max())
: _M_param(__a, __b)
{ }
explicit
uniform_int_distribution(const param_type& __p)
: _M_param(__p)
{ }
template<typename _UniformRandomNumberGenerator>
result_type
operator()(_UniformRandomNumberGenerator& __urng)
{ return this->operator()(__urng, this->param()); }
template<typename _UniformRandomNumberGenerator>
result_type
operator()(_UniformRandomNumberGenerator& __urng,
const param_type& __p);
param_type _M_param;
};
Nếu chúng ta nheo mắt qua tất cả các _
, chúng ta có thể thấy rằng nó chỉ có một đơn tham số thành viên, param_type _M_param
, mà chính nó chỉ đơn giản là một cấu trúc lồng nhau giữ 2 giá trị tích phân - có hiệu lực, một phạm vi. operator()
chỉ được khai báo ở đây, không được xác định. Một số chi tiết đào mang chúng ta đến định nghĩa. Thay cho việc đăng tất cả mã ở đây, điều này khá xấu (và khá dài), nó đủ để nói rằng không có gì bị đột biến bên trong hàm này. Thực tế, việc thêm const
vào định nghĩa và khai báo sẽ biên dịch một cách vui vẻ.
Câu hỏi sau đó trở thành, điều này có đúng với mọi phân phối khác không? Câu trả lời là không. Nếu chúng ta nhìn vào thực hiện cho std::normal_distribution
, chúng ta thấy:
template<typename _RealType>
template<typename _UniformRandomNumberGenerator>
typename normal_distribution<_RealType>::result_type
normal_distribution<_RealType>::
operator()(_UniformRandomNumberGenerator& __urng,
const param_type& __param)
{
result_type __ret;
__detail::_Adaptor<_UniformRandomNumberGenerator, result_type>
__aurng(__urng);
//Mutation!
if (_M_saved_available)
{
_M_saved_available = false;
__ret = _M_saved;
}
//Mutation!
Đây là tất cả chỉ là lý thuyết, nhưng tôi tưởng tượng là lý do nó không bị hạn chế để const
là cho phép người thực hiện để biến việc thực hiện nếu có yêu cầu. Hơn nữa, nó giữ một giao diện thống nhất hơn - nếu một số operator()
là const
và một số không phải là const
, tất cả sẽ trở thành một chút lộn xộn.
Tuy nhiên, tại sao chúng không đơn giản khiến chúng trở thành const và cho phép người triển khai sử dụng mutable
Tôi không chắc chắn. Có khả năng, trừ khi một người nào đó ở đây tham gia vào phần này của nỗ lực tiêu chuẩn hóa, bạn có thể không nhận được câu trả lời hay cho điều này.
Chỉnh sửa: Như MattieuM đã chỉ ra, mutable
và nhiều chuỗi không phát cùng nhau.
Cũng như một điều thú vị nhỏ sang một bên, std::normal_distribution
tạo hai giá trị cùng một lúc, lưu vào bộ nhớ cache một (do đó _M_saved
). Các operator<<
mà nó định nghĩa thực sự cho phép bạn nhìn thấy giá trị này trước khi cuộc gọi bên cạnh operator()
:
#include <random>
#include <iostream>
#include <chrono>
std::default_random_engine eng(std::chrono::system_clock::now().time_since_epoch().count());
std::normal_distribution<> d(0, 1);
int main()
{
auto k = d(eng);
std::cout << k << "\n";
std::cout << d << "\n";
std::cout << d(eng) << "\n";
}
Ở đây, định dạng đầu ra là mu sigma nextval
.
Không có lý do gì để làm cho chúng const và sử dụng mutable vì các bản phân phối không phải là const hợp lý: nếu chúng là bạn chỉ có thể tạo một bản phân phối mới mỗi lần bạn cần một số mới; như bạn không thể vì, đối với những người có đột biến, nó mang lại cho bạn một chuỗi phân phối kém. Nếu bạn muốn một chuỗi được phân phối đúng, bạn * phải * sử dụng cùng một đối tượng phân phối để tạo tất cả các số trong chuỗi đó và giao diện không const phản ánh điều đó. –
@ R.MartinhoFernandes Đối với một cái gì đó như 'std :: uniform_int_distribution' bạn * có thể * có nó làm cho một phân phối mới mỗi lần, và nó sẽ là hoàn toàn tốt, ngay cả khi thực hiện. Vẽ các con số từ một phân phối nên (theo lý thuyết) không sửa đổi bản thân phân phối theo bất kỳ cách nào. Nếu tôi vẽ một số từ phân bố chuẩn với mu = 0 và sigma = 1, phân phối vẫn là phân bố chuẩn với mu = 0 và sigma = 1 sau đó. – Yuushi
Mặc dù chia sẻ cùng tên, bản phân phối trong C++ không phải là thực thể giống như phân phối từ toán học. Đó là điều bạn phải chấp nhận. Sự thật là một số bản phân phối C++ có trạng thái có thể thay đổi * và trạng thái đó có thể quan sát được * (có thể không * dễ dàng quan sát vì chúng ta đang nói về tính ngẫu nhiên và xác suất): viết mã giả định không có các trạng thái dẫn xuất quan sát được đến đầu ra phân phối kém. Và 'mutable' không bao giờ được sử dụng để ẩn trạng thái quan sát được. –
- 1. C++ 11 số ngẫu nhiên
- 2. Trình tạo số ngẫu nhiên phân phối ngẫu nhiên
- 3. Số ngẫu nhiên từ bản phân phối Beta, C++
- 4. Tại sao RUnit thay đổi số ngẫu nhiên của tôi?
- 5. Phân phối số ngẫu nhiên thế hệ
- 6. phân phối ngẫu nhiên Gaussian trong PostgreSQL
- 7. Trình tạo số ngẫu nhiên có phân phối beta
- 8. Tại sao không ngẫu nhiên() ngẫu nhiên?
- 9. phát sinh số ngẫu nhiên được phân phối đồng đều
- 10. Liệu ngẫu nhiên() có thay đổi không?
- 11. Bias trong ngẫu nhiên số phân phối bình thường (javascript)
- 12. Trình tạo số giả ngẫu nhiên - Phân phối số mũ
- 13. Điều gì sẽ xảy ra khi bạn sao chép công cụ số ngẫu nhiên và phân phối số ngẫu nhiên?
- 14. Phân phối ngẫu nhiên (Monte-Carlo) trên quả cầu đơn
- 15. PHP: số ngẫu nhiên từ một phân phối chuẩn
- 16. Tạo các số ngẫu nhiên theo các bản phân phối
- 17. Mẫu ngẫu nhiên từ phân phối riêng biệt bivariate
- 18. VS2010 thay đổi cổng cụ thể một cách ngẫu nhiên
- 19. C++ 11 An toàn chủ đề của các trình tạo số ngẫu nhiên
- 20. Hiểu phân bố Poisson của trình tạo số ngẫu nhiên
- 21. Tại sao facebook có ID phần tử ngẫu nhiên?
- 22. Tại sao nó xuất hiện máy phát số ngẫu nhiên của tôi không phải ngẫu nhiên trong C#?
- 23. Phân tích số ngẫu nhiên
- 24. ngẫu nhiên chuỗi C#
- 25. C# Ngẫu nhiên (Dài)
- 26. Chuyển đổi phân phối đồng đều thành phân phối chuẩn
- 27. số C# ngẫu nhiên không là "ngẫu nhiên"
- 28. Tạo Số ngẫu nhiên Dựa trên Phân phối Beta bằng cách sử dụng Boost
- 29. Tạo một tệp nhị phân ngẫu nhiên
- 30. Tạo số ngẫu nhiên giữa 0 và 1 với phân phối gaussian
Toán tử() trong phân phối không phải là const theo tiêu chuẩn ... Vì vậy, hãy sử dụng tham chiếu thay vì tham chiếu const. – ForEveR
Vâng, tôi hiểu điều này được định nghĩa trong tiêu chuẩn C++, tôi không hiểu lý do cho việc này. Ví dụ, phân bố int thống nhất có thể được tham số đầy đủ bởi giới hạn bên trái và bên phải của nó, phân phối chuẩn theo giá trị trung bình và độ lệch chuẩn, phân bố riêng biệt theo xác suất riêng lẻ, v.v. Vì vậy, nó có thể được thực hiện tại thời điểm xây dựng, và có vẻ như không có lý do gì để cho phép thay đổi cá thể phân phối (đặc biệt là đối với toán tử '()'). – karlicoss
Tôi không biết về công việc của toán tử() cho bất kỳ phân phối nào, nhưng có thể một trong số họ thay đổi trạng thái tự trong hàm này? Phân phối là giao diện và nó sẽ đáp ứng các yêu cầu trong bảng 118 (25.1.6/3) – ForEveR