Ho pensato che il valore generato dalla distribuzione casuale di C++ 11 (uniform_int_distribution
, ad esempio), dipende solo dallo stato del generatore che viene passato allo operator()
. Tuttavia, per qualche ragione non esiste uno specificatore const
nella firma di operator()
. Che cosa significa e come devo passare la distribuzione come parametro di funzione? Ho pensato di doverlo passare come parametro non reciproco: per riferimento const, ma ora non ne sono sicuro.Perché le distribuzioni casuali di C++ 11 sono modificabili?
risposta
Ho frainteso la domanda in un primo momento, tuttavia, ora che ho capito, è una buona domanda. Alcuni scavare nella fonte dell'attuazione <random>
per g ++ dà la seguente (con alcuni bit tralasciato per chiarezza):
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;
};
Se strabismo passato tutta la _
, possiamo vedere che ha solo un singolo parametro membro, param_type _M_param
, che a sua volta è semplicemente una struttura nidificata che contiene 2 valori interi, in effetti un intervallo. operator()
è dichiarato solo qui, non definito. Qualche altro scavo ci porta alla definizione. Invece di postare tutto il codice qui, che è piuttosto brutto (e piuttosto lungo), è sufficiente dire che nulla è mutato all'interno di questa funzione. Infatti, aggiungendo const
alla definizione e alla dichiarazione si compileranno felicemente.
La domanda diventa, è vero per ogni altra distribuzione? La risposta è no. Se guardiamo alla realizzazione per std::normal_distribution
, troviamo:
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!
tutto questo è solo teorizzare, ma immagino la ragione per cui non è limitato a const
è quello di consentire gli esecutori di mutare la loro attuazione, se necessario. Inoltre, mantiene un'interfaccia più uniforme - se alcuni operator()
sono const
e alcuni non sono const
, tutto diventa un po 'disordinato.
Tuttavia, perché non li hanno semplicemente resi costanti e consentono agli implementatori di utilizzare mutable
Non ne sono sicuro. Probabilmente, a meno che qualcuno non sia coinvolto in questa parte dello sforzo di standardizzazione, potresti non ottenere una buona risposta a questo.
Modifica: come sottolineato da MattieuM, mutable
e più thread non funzionano bene insieme.
Altrettanto poco interessante, std::normal_distribution
genera due valori contemporaneamente, memorizzandone uno uno (da cui lo _M_saved
). Il operator<<
che definisce permette effettivamente di vedere questo valore prima della prossima chiamata a 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";
}
Qui, il formato di output è mu sigma nextval
.
Non vi è alcun motivo per renderli const e use mutable perché le distribuzioni non sono logicamente const: se fossero si potrebbe semplicemente creare una nuova distribuzione ogni volta che è necessario un nuovo numero; come non puoi perché, per quelli che hanno una mutazione, ti dà una sequenza mal distribuita. Se si desidera una sequenza correttamente distribuita, * è necessario * utilizzare lo stesso oggetto di distribuzione per generare tutti i numeri in tale sequenza e l'interfaccia non-const lo riflette. –
@ R.MartinhoFernandes Per qualcosa come 'std :: uniform_int_distribution' tu * potresti * farne una nuova distribuzione ogni volta, e sarebbe perfetto, anche se implementato. Disegnare i numeri da una distribuzione dovrebbe (teoricamente) non modificare la distribuzione stessa in alcun modo. Se disegno un numero da una distribuzione normale con mu = 0 e sigma = 1, la distribuzione rimane una distribuzione normale con mu = 0 e sigma = 1 dopo quello. – Yuushi
Nonostante condividano lo stesso nome, le distribuzioni in C++ non sono la stessa entità delle distribuzioni dalla matematica. Questo è qualcosa che devi solo accettare. La verità è che alcune distribuzioni C++ hanno uno stato mutabile * e che lo stato è osservabile * (potrebbe non essere * facile * osservarlo perché stiamo parlando di casualità e probabilità, però): scrivere codice che presuppone che non ci siano conduttori di stato osservabili a output mal distribuito. E 'mutabile' non dovrebbe mai essere usato per nascondere lo stato osservabile. –
- 1. C++ 11 numeri casuali
- 2. Le stringhe C++ sono modificabili con le stringhe Java UNLIKE?
- 3. Le stringhe in argv sono modificabili?
- 4. In che modo le distribuzioni della classe C++ 11 <random> trasformano il generatore sottostante?
- 5. Le sessioni sono modificabili dal client/utente?
- 6. Genera numeri casuali in base alle distribuzioni
- 7. C++ 11 generatore di numeri casuali UIntType contraddizione
- 8. Tracciare le normali distribuzioni
- 9. C++ 11 Sicurezza filo dei generatori di numeri casuali
- 10. Perché le mie distribuzioni di app MDB in cluster WebLogic sono in stato di avviso?
- 11. Generazione di numeri casuali efficiente con C++ 11 <random>
- 12. Di cosa è composta una distribuzione casuale di C++ 11?
- 13. Genera numeri casuali tra 0 e 1 con distribuzioni gaussiane
- 14. Perché New-AzureReservedIP restituisce ResourceNotFound: non sono state rilevate distribuzioni?
- 15. Perché le proprietà di un oggetto immutabile sono modificabili in Swift?
- 16. Generare numeri casuali correlati dalle distribuzioni binomiali in R
- 17. I container standard C++ 11 sono "final"?
- 18. compatibilità binaria tra le distribuzioni Linux
- 19. Perché le operazioni CAS C++ 11 richiedono due parametri puntatore?
- 20. Quali sono le differenze tra -std = C++ 11 e -std = gnu ++ 11?
- 21. Lo standard C++ 11 garantisce numeri casuali identici per gli stessi seed attraverso le implementazioni?
- 22. atomico C++ 11: perché funziona questo codice?
- 23. Come posso automatizzare le distribuzioni di Node.js?
- 24. Perché le espressioni vuote sono legali in C/C++?
- 25. I numeri casuali di Java non sono casuali?
- 26. C/JSON Library nelle diffuse distribuzioni Linux?
- 27. Quali sono le implicazioni dell'uso di _GLIBCXX_CXX11_ABI per utilizzare l'ABI pre-5.1 C++ con le caratteristiche di C++ 11/14?
- 28. variabili membro modificabili statiche in C++?
- 29. Perché non c'è `static_if` in C++ 11
- 30. CSS: i pulsanti sono di volta in volta non modificabili?
Gli operatori() nelle distribuzioni sono non-const per standard ... Quindi, utilizzare il riferimento anziché il riferimento const. – ForEveR
Sì, ho capito che questo è definito nello standard C++, non ne capisco il motivo. Ad esempio, la distribuzione uniforme di int può essere completamente parametrizzata dai suoi limiti sinistro e destro, dalla distribuzione normale per la media e dalla deviazione standard, dalla distribuzione discreta da parte delle probabilità individuali, ecc. Così può essere fatto al momento della costruzione, e sembra che non ci sia ragione di permettere di cambiare l'istanza di distribuzione (specialmente per 'operator()'). – karlicoss
Non conosco il lavoro di operator() per qualsiasi distribuzione, ma uno di questi potrebbe cambiare stato autonomo in questa funzione? La distribuzione è un'interfaccia e dovrebbe soddisfare le richieste nella tabella 118 (25.1.6/3) – ForEveR