distribution without using of variate_generator



  • Hallo...

    Ich versuche gerade, eine Zufallszahl (mittels boost, sollte aber imho auch im tr1 zu finden sein) zu erzeugen:

    boost::geometric_distribution <> dist;
    boost::mt19937 eng;
    
    boost::variae_generator <boost::mt19337, boost::geometric_disitribution> gen (eng, dist);
    
    std::cout << gen() << std::endl;
    

    So weit, so gut - nun aber folgendes Problem:
    Wenn ich mir jetzt variate_generator angucke, wird dort nicht viel mehr gemacht, als dist(eng) aufgerufen:

    operator()
    {
     return dist(eng);
    }
    

    Wenn ich das jetzt aber selbst machen möchte, habe ich ein Problem - es kommt keine wirkliche Zufallszahl raus (nur so etwas wie NaN):

    boost::geometric_distribution <> dist;
    boost::mt19937 eng;
    
    std::cout << dist(eng) << std::endl;
    

    Womit ich zu dem Schluss komme, dass ich etwas falsch mache - auch, wenn ich den Umweg über boost::detail::pass_through_engine <boost::mt19937> gehe, kommt nichts besseres raus.

    In der Boost-Dokumentation habe ich auch keine brauchbaren Hinweise gefunden, wie ich das ganze ohne den Generator nutzen kann - was ich aber möchte, da ich unterschiedliche Verteilungen brauche - und es mir einfacher vorkommt, es so zu machen, als jedes mal einen neuen variate_generator zu erzeugen und den dann zu nutzen...
    Außerdem hoffe ich dann über boost::bind die jeweilige Funktion (operator()) binden zu können, ohne jedes mal von void* casten zu müssen (da die Verteilungen keine Basisklasse haben).

    Wenn ihr auch keine Idee habt, werde ich wohl mal in der boost-Mailinglist fragen müssen - allerdings denke ich, dass das Problem relativ einfach zu lösen ist - ich nur nicht auf die (richtige) Lösung komme -.-

    Ansonsten könnte ich die Verteilungen auch selbst implementieren (bzw mit copy&paste übernehmen) und mir eine Basisklasse dazu bauen - da ich nur Verteilungen mit gleichen result_type brauche, sollte das nicht so das Problem sein...

    Wenn ihr einen anderen Weg gehen würdet, wär es toll, ihn zu erfahren ^^

    danke scho mal 🤡



  • Du hast den "internal_engine_type" aus dem variate_generator nicht berücksichtigt.



  • Ja - den Code hatte ich hier nicht nochmals gepostet - allerdings geschrieben, dass ich nur etwas ähnlich eines NaN herausbekomme - hier der Code, den ich verwendet habe:

    #include <iostream>
    
    #define private public
    
    #include <boost/random.hpp>
    #include <boost/random/mersenne_twister.hpp>
    
    typedef boost::mt19937 Teng;
    typedef boost::normal_distribution <> Tdist;
    
    typedef boost::variate_generator <Teng, Tdist> Tvar_gen;
    
    int main()
    {
    	Teng eng;
    	Tdist dist;
    
    	Tvar_gen gen(eng, dist); //ja, ist unnötig - aber wollte die ergebnisse dann vergleichen und hab die zeile jz einfach ma drin gelassen...
    
    	Tvar_gen::internal_engine_type int_eng (Tvar_gen::decorated_engine(eng));
    
    	std::cout << dist(eng);
    
    	system("pause");
    }
    

    liefert mir (abgesehen von einer seltsamen warning) nur "-1.#IND"...
    Evtl kann die Warning da Licht ins Dunkel bringen - allerdings habe ich keine zutreffende Stelle gefunden:

    1>------ Build started: Project: test, Configuration: Debug Win32 ------
    1>Compiling...
    1>main.cpp
    1>...\test\main.cpp(20) : warning C4930: 'boost::uniform_01<UniformRandomNumberGenerator,RealType> int_eng(boost::random::detail::pass_through_engine<Engine>)': prototyped function not called (was a variable definition intended?)
    1>        with
    1>        [
    1>            UniformRandomNumberGenerator=boost::random::detail::pass_through_engine<Teng>,
    1>            RealType=double,
    1>            Engine=Teng
    1>        ]
    

    Zeile 20 ist auch hier Zeile 20 ^^ Nur find ich nichts, was die warning erklären könnte... ihr vll? Oo
    Aber wichtiger wäre noch, das Ergebnis zu erklären als die warning zu erläutern ^^

    bye



  • ich idiot...

    ich hatte natürlich in zeile 22 nen fehler gemacht - in dem ich die falsche engine verwendet hatte xD

    kommen wir also zu dem quellcode:

    #include <iostream>
    
    #define private public
    
    #include <boost/random.hpp>
    #include <boost/random/mersenne_twister.hpp>
    
    typedef boost::mt19937 Teng;
    typedef boost::normal_distribution <> Tdist;
    
    typedef boost::variate_generator <Teng, Tdist> Tvar_gen;
    
    int main()
    {
    	Teng eng;
    	Tdist dist;
    
    	Tvar_gen gen(eng, dist);
    
    	Tvar_gen::internal_engine_type int_eng (Tvar_gen::decorated_engine(eng));
    
    	std::cout << dist(int_eng) << " == " << gen() << std::endl;
    
    	system("pause");
    }
    

    und (diesmal zwei) fehlermeldungen:

    1>main.cpp
    1>...\boost\random\normal_distribution.hpp(67) : error C2198: 'boost::uniform_01<UniformRandomNumberGenerator,RealType> (__cdecl &)' : too few arguments for call
    1>        with
    1>        [
    1>            UniformRandomNumberGenerator=boost::random::detail::pass_through_engine<Teng>,
    1>            RealType=double
    1>        ]
    1>        ...\test\main.cpp(22) : see reference to function template instantiation 'double boost::normal_distribution<>::operator ()<boost::uniform_01<UniformRandomNumberGenerator,RealType>(boost::random::detail::pass_through_engine<Engine>)>(boost::uniform_01<UniformRandomNumberGenerator,RealType> (__cdecl &))' being compiled
    1>        with
    1>        [
    1>            UniformRandomNumberGenerator=boost::random::detail::pass_through_engine<Teng>,
    1>            RealType=double,
    1>            Engine=Teng
    1>        ]
    1>...\boost\random\normal_distribution.hpp(68) : error C2198: 'boost::uniform_01<UniformRandomNumberGenerator,RealType> (__cdecl &)' : too few arguments for call
    1>        with
    1>        [
    1>            UniformRandomNumberGenerator=boost::random::detail::pass_through_engine<Teng>,
    1>            RealType=double
    1>        ]
    

    allerdings versteh ich das jetzt gar nicht mehr (1. macht es boost ja auch so und 2. ist doch da ein operator () definiert?!)

    danke ^^

    PS: Boost-Version ist die 1.36: ( #define BOOST_VERSION 103600 )
    sollte zwar (lt changelog) keine unterschiede machen, aber evtl hat sich ja iwas unbedeutendes geändert und deshalb stimmen die zeilenangaben nich mehr überein oder so...
    verdammt, jz hatte ich gerade 00:00:00 als uhrzeit - aber war eben nur die vorschau und nich das absenden 😉



  • nix? -.-


  • Administrator

    Naja, ich meine dies sagt schon alles aus:

    #define private public
    

    Die Bibliothek wurde nicht auf die Verwendung in der Art ausgelegt. Was du treibst ist übelstes Hacking, was einfach Fehler verursachen muss. Am Ende wirst du auch nichts weiteres tun, als äusserst komplex die Funktion von variate_generator nachbauen.

    Du kannst allen verschiedenen variate_generator viel einfacher eine gemeinsame Basis geben:

    boost::mt19937 engine;
    boost::uniform_real<> dist0;
    boost::normal_distribution<> dist1;
    
    boost::function<double(void)> base;
    
    base = boost::variate_generator<boost::mt19937, boost::uniform_real<> >(engine, dist0);
    
    std::cout << base() << ", " << base() << ", " << base() << std::endl;
    
    base = boost::variate_generator<boost::mt19937, boost::normal_distribution<> >(engine, dist1);
    
    std::cout << base() << ", " << base() << ", " << base() << std::endl;
    

    Grüssli



  • Da in boost::variate_gen aber die engine kopiert wird und nicht nur per ref oder so gehalten wird, komme ich bei dieser möglichkeit nicht mehr an den aktuellen seed heran?!
    aber ansonsten geällt es mir scho ganz gut ^^

    klar zeigt es schon alles - ich hätte auch alle typedefs abtippen können - aber alles zu kopieren kommt aufs gleiche raus - also hab ichs einfach mal damit gemacht - die idee fand ich übrigens echt klasse - hatte volkard glaub iwann mal rausgehauen 😃

    bb


  • Administrator

    zufall schrieb:

    Da in boost::variate_gen aber die engine kopiert wird und nicht nur per ref oder so gehalten wird, komme ich bei dieser möglichkeit nicht mehr an den aktuellen seed heran?!

    Die Engines bieten überhaupt gar keine Methode an, mit welcher man wieder an den Seed kommt. Daher ist das sowieso unnötig. Du musst den Seed separat speichern.

    Grüssli



  • zufall schrieb:

    also hab ichs einfach mal damit gemacht - die idee fand ich übrigens echt klasse - hatte volkard glaub iwann mal rausgehauen 😃

    Was? #define private public ? Davon rate ich dir wirklich stark ab, denn du hebelst damit das ganze Konzept des Data Hiding aus. Mir scheint, als sähest du dieses als Feind an. Die Verbergung der Interna ist aber gut - sie bewahrt dich davor, deinen Code von der Implementierung abhängig zu machen und verringert durch enge Schnittstellen viele Fehler. Wenn in einer neueren Boost-Version plötzlich etwas geändert wird, ist dein Code ansonsten plötzlich nicht mehr kompatibel.



  • Nein - so wars doch nicht gemeint...

    Ich hätte am Ende so und so alles noch ma komplett kopiert und evtl leicht angepasst - aber zum Zeigen fand ich das bequemer weil weniger Quellcode...

    ...seed...

    stimmt - man kann ihn nur neu setzen - und damit hab ich das nächste problem: ich möchte(soll) später dafür sorgen können, dass man den status genau speichern (und laden) kann - wenn man aber wieder nicht mehr an den seed rankommt, der dem aktuellen status entspricht ists scho wieder kacke 😣

    Jemand ne Idee hierzu? 🤡
    offensichtlich ma wieder ne aufgabe, die man nicht ma eben mit ner fertigen klasse erledigen kann?! -.-

    wird also so enden, dass ich mir den zufallszahlen-algo an sich rauskopiere (effektiver werd ichs eh net hinbekommen) und ne klasse drum rum bau, wo man die verteilung rel. bequem ändern kann und der zugehörige seed irgendwie rauszubekommen ist - das wird zwar sicherlich nich ganz einfach aber hoffentlich auch nicht all zu schwer - wenn das nicht klappt, muss ich halt alle komponenten einzeln speichern und laden...

    danke schon mal : >


  • Administrator

    Wieso sollte man den aktuellen Seed eigentlich speichern wollen? Dass man den Startwert speichern will, kann ich verstehen, denn nur so kann man nochmals die gleiche Reihenfolge erzeugen. Aber welcher Zweck sollte es haben, den aktuellen Seed zu speichern? Das macht für mich irgendwie keinen Sinn.

    Grüssli



  • um ab einem gewissen zeitpunkt fortsetzen zu können - mit ner anderen verteilung beispielsweise - aber wenns nich geht, dann gibts das feature eben vorerst (^^) nicht - bis es in vergessenheit geraten ist - hoff ich mal 😉

    bb


  • Administrator

    zufall schrieb:

    um ab einem gewissen zeitpunkt fortsetzen zu können - mit ner anderen verteilung beispielsweise - aber wenns nich geht, dann gibts das feature eben vorerst (^^) nicht - bis es in vergessenheit geraten ist - hoff ich mal 😉

    Du kannst jederzeit irgendwo weitermachen, dazu musst du den Seed doch gar nicht speichern. Und du kannst auch mehrere synchron laufende Engines weitermachen lassen, musst ihnen bei neuem Begin einfach nur den gleichen Seed geben. Was für einer das ist, spielt ja keine Rolle, es sollen schliesslich Zufallszahlen sein.

    Grüssli



  • #define private public

    😮

    So irgendetwas in einer Bibliothek zu umgehen ist einfach nur böse.. 😉


Log in to reply