11 Stimmen

Verwendung von boost::random als RNG für std::random_shuffle

Ich habe ein Programm, das den Zufallszahlengenerator mt19937 aus boost::random verwendet. Ich muss einen random_shuffle durchführen und möchte, dass die dafür generierten Zufallszahlen aus diesem gemeinsamen Zustand stammen, damit sie in Bezug auf die zuvor generierten Zahlen des Mersenne-Twisters deterministisch sein können.

Ich habe etwas Ähnliches versucht:

void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
    struct bar {
        boost::mt19937 &_state;
        unsigned operator()(unsigned i) {
            boost::uniform_int<> rng(0, i - 1);
            return rng(_state);
        }
        bar(boost::mt19937 &state) : _state(state) {}
    } rand(state);

    std::random_shuffle(vec.begin(), vec.end(), rand);
}

Aber ich bekomme eine Vorlage Fehler Aufruf random_shuffle mit Rand. Dies funktioniert jedoch:

unsigned bar(unsigned i)
{
    boost::mt19937 no_state;
    boost::uniform_int<> rng(0, i - 1);
    return rng(no_state);
}
void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
    std::random_shuffle(vec.begin(), vec.end(), bar);
}

Wahrscheinlich, weil es sich um einen tatsächlichen Funktionsaufruf handelt. Aber offensichtlich wird der Zustand des ursprünglichen Mersenne-Twisters nicht beibehalten. Woran liegt das? Gibt es eine Möglichkeit, das zu tun, was ich versuche, ohne globale Variablen zu tun?

0 Stimmen

Könnten Sie bitte den korrekten Code für die Nachwelt posten, sobald Sie ihn getestet haben? Danke

0 Stimmen

Greg: Ich habe deine Änderung rückgängig gemacht. Sie müssen keine HTML-Zeichen in Ihrem Code auslassen, wenn Sie bereit sind, Markdown-Codeblöcke zu verwenden (jede Zeile 4 Leerzeichen einrücken).

0 Stimmen

Markieren Sie einfach den Code, und klicken Sie auf die Schaltfläche "010 101".

13voto

Chris Jester-Young Punkte 212385

In den Kommentaren bat Robert Gould um eine Arbeitsversion für die Nachwelt:

#include <algorithm>
#include <functional>
#include <vector>
#include <boost/random.hpp>

struct bar : std::unary_function<unsigned, unsigned> {
    boost::mt19937 &_state;
    unsigned operator()(unsigned i) {
        boost::uniform_int<> rng(0, i - 1);
        return rng(_state);
    }
    bar(boost::mt19937 &state) : _state(state) {}
};

void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
    bar rand(state);
    std::random_shuffle(vec.begin(), vec.end(), rand);
}

0 Stimmen

Übrigens ist dies nicht die Art und Weise, wie ich Code formatiere (ich bevorzuge "foo&bar", nicht "foo &bar"), aber ich dachte, ich sollte es so lassen, nur für Leute, die denken, dass solche Änderungen "einen Unterschied machen könnten".

0 Stimmen

Aus Neugierde, welchen Nutzen die Vererbung von unary_function hat? Aus operator() ist ersichtlich, was die Eingabe und die Ausgabe sind...

0 Stimmen

Es macht die Funktoren komponierbarer, d.h. es stellt einige Typendefinitionen zur Verfügung, die es einfacher machen, andere Funktoren aus Ihrem Funktor zu erstellen. Lassen Sie mich einen Link für Sie auftreiben....

11voto

coppro Punkte 14158

In C++03 können Sie keine Schablone instanziieren, die auf einem funktionslokalen Typ basiert. Wenn Sie die Klasse rand aus der Funktion auslagern, sollte es gut funktionieren (Haftungsausschluss: nicht getestet, es könnte andere unheilvolle Fehler geben).

Diese Anforderung wurde in C++0x gelockert, aber ich weiß nicht, ob diese Änderung im C++0x-Modus von GCC bereits implementiert wurde, und es würde mich sehr überraschen, sie in einem anderen Compiler zu finden.

1 Stimmen

Wenn Sie die Struktur auf die globale Ebene verlagern, können Sie sie auch von std::unary_function erben lassen :-)

5voto

baol Punkte 4236

Ich verwende hier tr1 anstelle von boost::random, aber das sollte nicht viel ausmachen.

Das Folgende ist ein bisschen kompliziert, aber es funktioniert.

#include <algorithm>
#include <tr1/random>

std::tr1::mt19937 engine;
std::tr1::uniform_int<> unigen;
std::tr1::variate_generator<std::tr1::mt19937, 
                            std::tr1::uniform_int<> >gen(engine, unigen);
std::random_shuffle(vec.begin(), vec.end(), gen);

0 Stimmen

Dies funktioniert aufgrund eines Fehlers, der sich nicht auf eine Person bezieht, nicht. Wie geschrieben, gen erzeugt ganze Zahlen aus 0 über N 代わりに 0 über N - 1 wie verlangt von std::random_shuffle() .

0 Stimmen

@Spire: uniform_int::operator(engine, N) liefert eine Zahl in [0,N) (d.h. zwischen 0 und N-1). Das funktioniert also, wenn auch trickreich, tatsächlich.

1voto

Eliot Punkte 5051

Ich dachte, es lohnt sich, darauf hinzuweisen, dass dies jetzt in C++11 ziemlich einfach ist, wenn man nur die Standardbibliothek verwendet:

#include <random>
#include <algorithm>

std::random_device rd;
std::mt19937 randEng(rd());
std::shuffle(vec.begin(), vec.end(), randEng);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X