Poster pour @FlopSetxk qui se bat avec l'éditeur d'OC :
Bonjour a tous ! Excusez moi de vous deranger, mais j'aurais besoin d'un petit peu d'aide (Ca fait quatre jours que je pietine...) Je voudrais implementer un generateur de nombres aleatoires a la compilation, repondant aux criteres suivants: - Supporte differents "Engines" (Linear congruential, subtract with carry...) - Supporte tout type de nombre (Unsigned int, unsigned short...) - Permet d'obtenir un nombre compris entre un maximum et un minimum - Check la validite des parametres a la compilation
Et dans les trefonds de Github, j'ai trouver ca: https://github.com/cr-lupin/metarand Ce code est base sur ce document: https://pdfs.semanticscholar.org/da32/da4c2b972693fc50e28518d9d44111f7d31c.pdf (Que j'ai du lire une bonne vingtaine de fois)
Le probleme de ce code, c'est que non seulement il ne permet pas de definir un encradrement min/max pour le resultat (Je pense pouvoir regler cela facilement avec un macro, mais une solution directement avec les templates ne serait-elle pas plus "propre" ?), mais surtout il ne verifie ni la valeur des parametres, ni le resultat des operations performees, ni la capacite des type arbitraires passes ! Ce qui conduit le compilateur (MSVC, Visual Studio 2017, C++ 17), a me signaler deux jolis "Integer overflow", dont le plus notable est ici:
static const UIntType value = (a * seed + c) % m;
J'ai donc mit les main dans le cambouis, et essayer de regler ca. Sauf que vous vous en doutez, si je suis la, c'est parce que j'ai pas reussi... en fait, les warnings disparaissent en baissant la valeur des parametres a, c et m, et de la graine, mais apres les resultats ne sont plus aleatoires. Et je suis pas assez bon en meta-programmation pour fixer ca. Si quelqu’un pouvez m’expliquer comment régler ca... merci par avance !
PS: Desole pour l'orthographe et l'abscence d'accents, mais je suis sur un clavier QWERTY...
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Les opérations sur les non signés sont parfaitement définit et ne causent pas de problème. Est-ce un avertissement ou une erreur ? Car il est possible de désactiver localement des avertissements avec des pragma. Après, c'est toujours possible de faire l'opération sur des uint64_t avant de les remettre dans le type demandé par l'utilisateur.
Pour l'intervalle de valeur, c'est aux distributions de le faire en se basant sur le min/max du générateur de nombre, eux même définit par l'algorithme du générateur et les valeurs initiales dans le template.
Poster pour @FlopSetxk qui se bat avec l'éditeur d'OC :
Salut et merci de la réponse. C’est des warnings, pas des erreurs. D’ailleurs le code compile et fonctionne tel quel. Mais je trouve qu’utiliser #pragma ça fait un peu “on planque les cigarettes sous le tapis”. Si le compilo sort des wanings, y doit bien y avoir une raison. Par ailleurs, je suis pas certain que GCC ou Clang soit aussi permissif.
Pour l’histoire du min/max j’ai pas compris ce que tu veux dire... Qu’est-ce que tu appelles distribution ?
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
> Par ailleurs, je suis pas certain que GCC ou Clang soit aussi permissif.
Si. Ils le sont pour les non-signés. Dans le cas de nombre signé, se sera une erreur. Pour msvc, les 2 sont des avertissements.
> Qu’est-ce que tu appelles distribution ?
si tu regardes ce que propose le standard pour les nombres aléatoires, il y a 2 choses:
les générateurs
les distributions
Les générateurs produisent un nombre en fonction d'une formule mathématique. Les limites du résultat sont imposés par les paramètres de l'algorithme, la formule utilisée et le type du résultat (u32, u64, etc). Le nombre généré est ensuite utilisé dans l'itération suivante. La graine utilisée comme valeur de départ correspond à la première itération, ou est une dérivée.
Si je prends std::mt19937, la limite et de 2**32-1. Pour linear_congruential_engine, la limite est du paramètre m qui sert de modulo. On pourrait se dire que le paramètre m sert à définir un intervalle, mais comme le résultat est utilisé pour l'itération suivante, une mauvaise valeur corrompt le générateur qui retourne alors toujours la même valeur ou un nombre très restreint.
#include <random>
#include <iostream>
int main()
{
std::linear_congruential_engine<unsigned, 4, 11, 28> engine(1);
for (int i = 0; i < 22; ++i)
std::cout << engine() << "\n"; // toujours 15
}
Du coup, la plage de valeur est calculée par des lois de probabilité: les distributions qui s'occupent de répartir les valeurs du générateur dans les limites imposées. Par exemple, on peut trouver la loi normale qui donne une courbe en cloche. Ou comme dans metarand, la loi de Bernoulli qui définit la probabilité d'avoir 1 par rapport à 0.
Poster pour @FlopSetxk qui se bat avec l'éditeur d'OC :
Ok, donc concretement tu me conseil de faire quoi ? Implemeter la loi normale (Que je ne connais absolument pas) par dessus les congruences lineaires ? N'est-il pas simplement possible de reutiliser l'implementation de la STL, mais lors de la compilation au lieu de l'execution ?
De plus, voici la sortie de visual studio:
1>main.cpp 1>f:\test\meta_number.h(86): warning C4307: '*': integral constant overflow 1>f:\tetst\meta_number.h(71): note: see reference to class template instantiation 'Eval<MetaRandomNumbersGenerator>' being compiled 1> with 1> [ 1> MetaRandomNumbersGenerator=X 1> ] 1>f:\test\main.cpp(50): note: see reference to class template instantiation 'MetaRandomNumberNext<X>' being compiled
> Ok, donc concretement tu me conseil de faire quoi ? (1) Implemeter la loi normale (Que je ne connais absolument pas) par dessus les congruences lineaires ? (2) N'est-il pas simplement possible de reutiliser l'implementation de la STL, mais lors de la compilation au lieu de l'execution ?
Oui et oui. Par contre, il faut recopier l'implémentation pour la mettre dans des fonctions constexpr...
Tu peux regarder les sources de msvc qui sont sur ton système ou celle de libc++ (clang) (dans random et algorithm).
> si je modifie [...] par [...], les Warnings disparaissent, mais la sortie n'est plus aleatoire !
C'est ce que je disais dans mon message précédent, jouer avec les valeurs des générateurs est très risqué et c'est facile de tourner sur les mêmes valeurs.
msvc compile avec un avertissement pour unsigned et int (même s'il n'affiche que le premier avertissement car la ligne est la même)
gcc/clang ne donne pas d'avertissement pour les non signés, mais une erreur pour les signés (avec en plus un avertissement).
Le plus simple reste de désactiver localement les avertissements, il ne faut pas croire que tous les avertissements sont légitimes quel que soit le contexte.
Poster pour @FlopSetxk qui se bat avec l'éditeur d'OC :
Réutiliser le code de la STL est tentant, mais rien que dans <random> il doit y avoir... quoi... 5500 lignes de code ? Au bas mot ? Dont une partie qui repose sur des implementations de la STL qui ne sont pas sensé être exposées au code utilisateur je suppose... Comment je suis censé utiliser ça ?
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Les seules fonctions inintéressante sont les operator() des distributions. Après, ce n'est qu'une bête implémentation d'une suite mathématique qui se trouve sur Wikipédia.
Poster pour @FlopSetxk qui se bat avec l'éditeur d'OC :
Je suis desole, mais la tu me parles chinois... ou au minimum vietnamien. Meme si je copie les operateurs, ca veut dire que je doit reecrire tout le reste du code a la main non ? J'ai bien compris que je peut pas faire un copier-coller de la STL, mais dans le lien que tu m'a donne, le fichier <random> commence par un commentaire. Celui-ci (Attention, c'est long):
/* random synopsis
#include <initializer_list>
namespace std {
// Engines
template <class UIntType, UIntType a, UIntType c, UIntType m> class linear_congruential_engine { public: // types typedef UIntType result_type;
// constructors and seeding functions explicit linear_congruential_engine(result_type s = default_seed); template<class Sseq> explicit linear_congruential_engine(Sseq& q); void seed(result_type s = default_seed); template<class Sseq> void seed(Sseq& q);
// generating functions result_type operator()(); void discard(unsigned long long z); };
template <class UIntType, UIntType a, UIntType c, UIntType m> bool operator==(const linear_congruential_engine<UIntType, a, c, m>& x, const linear_congruential_engine<UIntType, a, c, m>& y);
template <class UIntType, UIntType a, UIntType c, UIntType m> bool operator!=(const linear_congruential_engine<UIntType, a, c, m>& x, const linear_congruential_engine<UIntType, a, c, m>& y);
template <class charT, class traits, class UIntType, UIntType a, UIntType c, UIntType m> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const linear_congruential_engine<UIntType, a, c, m>& x);
template <class charT, class traits, class UIntType, UIntType a, UIntType c, UIntType m> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, linear_congruential_engine<UIntType, a, c, m>& x);
template <class UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, UIntType d, size_t s, UIntType b, size_t t, UIntType c, size_t l, UIntType f> class mersenne_twister_engine { public: // types typedef UIntType result_type;
// constructors and seeding functions explicit mersenne_twister_engine(result_type value = default_seed); template<class Sseq> explicit mersenne_twister_engine(Sseq& q); void seed(result_type value = default_seed); template<class Sseq> void seed(Sseq& q);
// generating functions result_type operator()(); void discard(unsigned long long z); };
template <class UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, UIntType d, size_t s, UIntType b, size_t t, UIntType c, size_t l, UIntType f> bool operator==( const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& x, const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& y);
template <class UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, UIntType d, size_t s, UIntType b, size_t t, UIntType c, size_t l, UIntType f> bool operator!=( const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& x, const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& y);
template <class charT, class traits, class UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, UIntType d, size_t s, UIntType b, size_t t, UIntType c, size_t l, UIntType f> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& x);
template <class charT, class traits, class UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, UIntType d, size_t s, UIntType b, size_t t, UIntType c, size_t l, UIntType f> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, mersenne_twister_engine<UIntType, w, n, m, r, a, u, d, s, b, t, c, l, f>& x);
template <class charT, class traits, class Engine, size_t w, class UIntType> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const independent_bits_engine<Engine, w, UIntType>& x);
template <class charT, class traits, class Engine, size_t w, class UIntType> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, independent_bits_engine<Engine, w, UIntType>& x);
template <class charT, class traits> friend basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>& is, piecewise_linear_distribution& x); };
} // std */
Au-dela du fait que je comprends pas ce que cette implementation fait commentee, je reve ou une majorite des methodes sont declarees en constexpr ? Ne puis-je pas utiliser ce code ?
Sinon, j'ai trouver ca: https://github.com/effolkronium/random Je vois pas pourquoi trois implementations, mais ne puis-je pas utiliser la premiere, (random static), pour parvenir a mes fin ?
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
> Je suis desole, mais la tu me parles chinois... ou au minimum vietnamien. Meme si je copie les operateurs, ca veut dire que je doit reecrire tout le reste du code a la main non ?
Tout se trouve les fonctions operator(), le reste du code ne te sert pas.
> J'ai bien compris que je peut pas faire un copier-coller de la STL
Si, 90% de copier/coller, 10% de glus pour déplacer les variables membres en paramètre template.
> mais dans le lien que tu m'a donne, le fichier <random> commence par un commentaire. Celui-ci (Attention, c'est long): [...]
C'est l'interface publique qu'on retrouve sur cppreference.com, il n'y aucune implémentation dans le commentaire.
> je reve ou une majorite des methodes sont declarees en constexpr ?
Oui, tu rêves. Seulement min()/max() sont constexpr, les autres sont des variables membres statiques initialisées avec les paramètres de template.
> Je vois pas pourquoi trois implementations, mais ne puis-je pas utiliser la premiere, (random static), pour parvenir a mes fin ?
Il utilise les objets random de la STL qui ne fonctionnent pas dans un contexte compile-time, donc non.</random>
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.