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?
cevap
İ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.
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. –
@ 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
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. –
- 1. Rasgele veri kaynağına dayalı rapor (sütunların adedi ve adları değişebilir)
- 2. C++ 11
- 3. C++ 11
- 4. C++ 11
- 5. Python'da rasgele sayıları nasıl oluşturabilirim?
- 6. C++ 11 Regex Eşleşmesi
- 7. Temperlenmiş sendikalar C++ 11
- 8. C++ 11 - sıralama işlevini
- 9. C++ 11 tuple performansı
- 10. C++ 11: C++ ile 11 yeni rastgele kütüphane, egzersiz am <random>
- 11. En ++ C++ 11 sınıfı C++ 11 referans veya değer olarak
- 12. hızlı aralığı (C++ 11)
- 13. elle istream C++ 11
- 14. Eşleştirme (C++ 11)
- 15. C++ 11 kapatma shared_ptr
- 16. clang ++ C++ 11 çağırma
- 17. C++ 11 operatörü ""
- 18. boost :: C++ 11
- 19. C++ 11 haritayı başlat
- 20. C++ 11 özel varsayılan yapıcı
- 21. C++ 11: std :: function :: target()
- 22. Erişim değerleri C++ 98 ve C++ 11
- 23. C++ 11/Boost `unordered_map` silme sırasında neden geri dönmez?
- 24. Neden C++ 11 CAS işlemleri iki işaretçi parametresi alır?
- 25. Bir değişkenin tanımı neden C++ 11'in gelişimi sırasında değişti?
- 26. Yöntemler rasgele sırada çağırılıyor (C#)
- 27. C++ 11 sınıfının <random> sınıfındaki dağılımları, temeldeki jeneratörü nasıl dönüştürür?
- 28. bağlama işlevi sonucu C++ C++ 11
- 29. sıfırlara bir vektör başlatmak C++/C++ 11
- 30. C++ sarmalayıcı için boost/C++ 11
Operatörler() dağıtımlarda standart olmayan bir yapıya sahiptir ... Bu nedenle, başvuru referansı yerine başvuru kaynağı kullanın. – ForEveR
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
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