2013-04-15 16 views
30

C++ 11 rasgele dağılımı (örneğin, uniform_int_distribution) tarafından üretilen değerin yalnızca operator()'a iletilen jeneratörün durumuna bağlı olduğunu düşündüm. Ancak, herhangi bir nedenle operator() imzasında const belirteci yoktur. Bunun anlamı nedir ve dağılımı bir işlev parametresi olarak nasıl iletmeliyim? Karşılıklı olmayan herhangi bir parametre olarak aktarmam gerektiğini düşündüm: const başvuru ile, ama şimdi emin değilim.Neden C++ 11 rasgele dağılımlar değişebilir?

+0

Operatörler() dağıtımlarda standart olmayan bir yapıya sahiptir ... Bu nedenle, başvuru referansı yerine başvuru kaynağı kullanın. – ForEveR

+4

Evet, bunun C++ standardında tanımlandığını anlıyorum, bunun nedenini anlamıyorum. Örneğin, üniform int dağılımı, sol ve sağ sınırlarıyla, ortalama ve standart sapma ile normal dağılımı, bireysel olasılıklar tarafından ayrık dağılım, vb. Ile tam olarak parametrelendirilebilir. Bu yüzden, inşaat anında yapılabilir. ve dağıtım örneğini değiştirmeye izin vermek için herhangi bir neden yok gibi görünüyor (özellikle 'operatör()'). – karlicoss

+0

Herhangi bir dağıtım için operatörün() işini bilmiyorum, ancak bunlardan biri bu işlevdeki öz durumu değiştirebilir mi? Dağıtım arayüzdür ve tablo 118'de req'leri karşılamalıdır (25.1.6/3) – ForEveR

cevap

17

İlk başta sorumu yanlış anladım, ancak şimdi anladığım kadarıyla, bu iyi bir soru. Bazı aşağıdaki verir ++ g için <random> uygulanmasının kaynağı haline kazma (birkaç bit netlik için dışarı bıraktı):

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; 
}; 

hepimiz _ geçmiş şaşı varsa, bunun yalnızca tek olduğunu görebilirsiniz üye parametresi, param_type _M_param, kendisinin basitçe 2 integral değeri olan bir yuva yapısıdır - aslında bir aralık. operator() sadece burada tanımlanmış, tanımlanmamıştır. Biraz daha kazma, bizi tanımlamaya getirir. Buradaki tüm kodları yayınlamak yerine, oldukça çirkin (ve oldukça uzun) olan bu işlev içinde hiçbir şeyin değişmediğini söylemek yeterlidir. Aslında, tanım ve bildirime const eklenmesi mutlu bir şekilde derlenecektir.

Bu durumda soru, diğer tüm dağıtımlar için geçerli midir? Cevap hayır.

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! 

Bunlar sadece kuramsallaştırılması, ama o const ile sınırlı değildir sebebi gerekirse uygulayıcılar bunların uygulanmasını mutasyona izin vermektir hayal: Biz std::normal_distribution için uygulamaya bakarsak bulabilirsiniz. Ayrıca, daha düzgün bir arayüz sağlar - eğer bazı operator()const ise ve bazıları const değilse, hepsi biraz dağınık olur. Bununla birlikte, neden sadece onları kurcalamadılar ve uygulayıcıların mutable kullanmasına izin vermediklerinden emin değilim. Muhtemelen, buradaki bir kişi standartlaştırma çabasının bu kısmına dahil olmadıkça, buna iyi bir cevap alamayabilirsiniz.

Düzenleme: MattieuM'in işaret ettiği gibi, mutable ve birden çok iş parçacığı birlikte güzel oynamıyor.

Sadece önemsiz bir şekilde, std::normal_distribution bir kerede iki değer üretir, bir önbelleğe alma (bu nedenle _M_saved).

#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"; 
} 

Burada, çıkış biçimi mu sigma nextval geçerli: tanımladığı operator<< aslında operator() yanındaki aramadan önce bu değeri görmenizi sağlar.

+0

Dağıtıkların mantıksal olarak sabit olmadığından, bunların yapısını yapılandırmak ve kullanabilmek için bir neden yoktur: eğer olsaydı, yeni bir numaraya her ihtiyaç duyduğunuzda yeni bir dağıtım yapabilirdiniz; çünkü yapamazsınız çünkü, mutasyona sahip olanlar için, size kötü dağılmış bir dizi verir. Düzgün olarak dağıtılmış bir dizi istiyorsanız * bu sırasındaki tüm sayıları üretmek için aynı dağıtım nesnesini kullanmanız gerekir ve const olmayan arabirim bunu yansıtır. –

+5

@ R.MartinhoFernandes std :: uniform_int_distribution' gibi bir şey için * her seferinde yeni bir dağıtım yapabildiğinizi ve uyguladığınız zaman bile mükemmel bir şekilde iyi olacağını söyleyebiliriz. Bir dağılımdan çizim yapmak, (teorik olarak) dağıtımı herhangi bir şekilde değiştirmemelidir. Eğer mu = 0 ve sigma = 1 ile normal dağılımdan bir sayı çizersem, dağılımı mu = 0 ve sigma = 1 ile normal dağılıma devam eder. – Yuushi

+3

Aynı adı paylaşmasına rağmen, C++'daki dağılımlar, matematikteki dağıtımlarla aynı varlık değildir. Bu sadece kabul etmeniz gereken bir şey. Gerçek şu ki, bazı C++ dağılımları değişebilir bir duruma * sahip ve bu durum gözlemlenebilir niteliktedir * (bunu gözlemlemek kolay değildir * çünkü rasgelelik ve olasılıklardan bahsederiz): Gözlenebilir bir durumun olmadığını varsayan bir kod yazma kötü dağıtılmış çıktıya. Ve 'mutable' asla gözlemlenebilir durumu gizlemek için kullanılmamalıdır. –