Generieren Sie Zufallszahlen mit der C++11-Zufallsbibliothek

Lesezeit: 11 Minuten

Generieren Sie Zufallszahlen mit der C11 Zufallsbibliothek
smac89

Wie der Titel schon sagt, versuche ich, eine Möglichkeit zu finden, Zufallszahlen mit dem neuen C++11 zu generieren <random> Bücherei. Ich habe es mit diesem Code versucht:

std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);

Das Problem mit dem Code, den ich habe, ist, dass er jedes Mal, wenn ich ihn kompiliere und ausführe, immer dieselben Zahlen generiert. Meine Frage ist also, welche anderen Funktionen in der Zufallsbibliothek dies erreichen können, während sie wirklich zufällig sind?

Für meinen speziellen Anwendungsfall habe ich versucht, einen Wert innerhalb des Bereichs zu erhalten [1, 10]

  • Diese Frage grenzt gefährlich an „primär meinungsbasiert“. Wenn Sie die Meinungsaufforderung loswerden können, sehe ich diese Frage als sehr nützlich an (falls sie nicht bereits gestellt wurde).

    – Johannes Dibling

    29. Oktober 2013 um 18:03 Uhr


  • Ich schlage vor, a zu verwenden std::mt19937 wie der Motor, es sei denn, Sie haben einen guten Grund, dies nicht zu tun. Und die Verteilung ist an beiden Enden ein geschlossenes Intervall.

    – Chris

    29. Oktober 2013 um 18:04 Uhr

  • Siehe stackoverflow.com/q/7114043/420683 und stackoverflow.com/q/16536617/420683 und stackoverflow.com/q/11817493/420683 und channel9.msdn.com/Events/GoingNative/2013/…

    – dyp

    29. Oktober 2013 um 18:13 Uhr


  • @chris Die Verteilung ist nicht an beiden Enden geschlossen, überprüfen Sie dies Verknüpfung oder dieses Verknüpfung

    – Notiz1288

    29. Oktober 2013 um 18:29 Uhr


  • @ memo1288, Danke, ich dachte, das OP verwendet a std::uniform_int_distributionwelcher ist an beiden Enden geschlossen.

    – Chris

    29. Oktober 2013 um 20:54 Uhr

Generieren Sie Zufallszahlen mit der C11 Zufallsbibliothek
Bill Lynch

Stephan T. Lavavej(stl) von Microsoft hat bei Going Native einen Vortrag darüber gehalten, wie man die neuen C++11-Zufallsfunktionen verwendet und warum man sie nicht verwenden sollte rand(). Darin hat er eine Folie eingefügt, die Ihre Frage im Grunde löst. Ich habe den Code von dieser Folie unten kopiert.

Sie können seinen vollständigen Vortrag sehen Hier:

#include <random>
#include <iostream>

int main() {
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution<double> dist(1.0, 10.0);

    for (int i=0; i<16; ++i)
        std::cout << dist(mt) << "\n";
}

Wir gebrauchen random_device einmal, um den benannten Zufallszahlengenerator zu starten mt. random_device() ist langsamer als mt19937aber es muss nicht geseedet werden, da es zufällige Daten von Ihrem Betriebssystem anfordert (die von verschiedenen Orten stammen, wie z RdRand zum Beispiel).


Wenn man sich diese Frage / Antwort ansieht, scheint es so uniform_real_distribution gibt eine Zahl im Bereich zurück [a, b), where you want [a, b]. Dazu unsere uniform_real_distibution sollte eigentlich so aussehen:

std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));

  • Da die Frage nach der allgemeinsten Methode zum Generieren von Zufallszahlen fragt, möchten Sie vielleicht einfach verwenden default_random_engineist es laut C++ Primer derjenige, den die Implementierung als am nützlichsten erachtet hat

    – Aaronmann

    29. Oktober 2013 um 18:56 Uhr

  • @aaronman: Ich gehe von STLs Vortrag aus, wo er das ausdrücklich nicht mag default_random_engine existiert.

    – Bill Lynch

    29. Oktober 2013 um 18:57 Uhr


  • @chris wir alle kennen den Unterschied zwischen einem Vektor und einer Karte, nicht jeder kennt den Unterschied zwischen mt19937 und ranlux24, wenn jemand es geschafft hat, Programmierer zu werden, ohne zu wissen, was ein Vektor und ein Wörterbuch sind, sollten sie vielleicht einen haben std::default_containerhoffentlich gibt es keine Leute, die sich selbst als Programmierer betrachten, die die Unterschiede nicht kennen, viele Skriptsprachen haben eine Standard-Map-Typ-Struktur, die auf eine ganze Reihe von Arten implementiert werden könnte, die der Benutzer möglicherweise nicht kennt

    – Aaronmann

    29. Oktober 2013 um 21:04 Uhr


  • Die nextafter Anruf ist für die meisten Anwendungen übertrieben. Die Chancen einer zufälligen double Landung genau auf dem Endpunkt sind so winzig, dass es keinen praktischen Unterschied zwischen Ein- und Ausschluss gibt.

    – Markieren Sie Lösegeld

    27. Juni 2014 um 17:00 Uhr

  • @chris Unrelated (aber du hast die Tür geöffnet), dein std::vector Analogie funktioniert hier nicht, weil std::vector ist Eigentlich ein guter Standard aufgrund des CPU-Cachings. Es übertrifft sogar std::list zum Einstecken in die Mitte. Das gilt selbst dann, wenn Sie alle Container verstehen und basierend auf algorithmischer Komplexität eine fundierte Entscheidung treffen könnten.

    – void.pointer

    23. Oktober 2014 um 22:53 Uhr

Was ist der beste Weg um Zufallszahlen in C zu
Ilja Polishchuk

Meine ‘Random’-Bibliothek bietet einen sehr praktischen Wrapper um zufällige C++11-Klassen. Sie können fast alle Dinge mit einer einfachen ‘get’-Methode erledigen.

Beispiele:

  1. Zufallszahl in einem Bereich

    auto val = Random::get(-10, 10); // Integer
    auto val = Random::get(10.f, -10.f); // Float point
    
  2. Zufälliger boolescher Wert

    auto val = Random::get<bool>( ) // 50% to generate true
    auto val = Random::get<bool>( 0.7 ) // 70% to generate true
    
  3. Zufälliger Wert aus einer std::initilizer_list

    auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
    
  4. Zufälliger Iterator aus dem Iteratorbereich oder allen Containern

    auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
    auto it = Random::get( vec ); // return random iterator
    

Und noch mehr Dinge! Schauen Sie sich die Github-Seite an:

https://github.com/effolkronium/random

Ich habe das ganze Zeug oben gelesen, etwa 40 andere Seiten mit c++ darin, so und mir die angeschaut Video von Stephan T. Lavavej “STL”
und war mir immer noch nicht sicher, wie Zufallszahlen in der Praxis funktionieren, also nahm ich mir einen ganzen Sonntag Zeit, um herauszufinden, worum es geht und wie es funktioniert und verwendet werden kann.

Meiner Meinung nach hat STL Recht damit, “keinen Srand mehr zu verwenden”, und er hat es im Video gut erklärt 2. Er empfiehlt auch zu verwenden:

ein) void random_device_uniform() — für verschlüsselte Generierung, aber langsamer (aus meinem Beispiel)

b) die Beispiele mit mt19937 — schneller, Fähigkeit, Seeds zu erstellen, nicht verschlüsselt


Ich habe alle beanspruchten c++11-Bücher herausgeholt, auf die ich Zugriff habe, und festgestellt, dass deutsche Autoren wie Breymann (2015) immer noch einen Klon davon verwenden

srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or

nur mit <random> anstatt <time> and <cstdlib> #inklusive – also achte darauf, nur aus einem Buch zu lernen :).

Bedeutung – das sollte seit c ++ 11 nicht mehr verwendet werden, weil:

Programme benötigen oft eine Quelle für Zufallszahlen. Vor dem neuen Standard stützten sich sowohl C als auch C++ auf eine einfache C-Bibliotheksfunktion namens rand. Diese Funktion erzeugt pseudozufällige ganze Zahlen, die im Bereich von 0 bis zu einem systemabhängigen Maximalwert von mindestens 32767 gleichmäßig verteilt sind. Die rand-Funktion hat mehrere Probleme: Viele, wenn nicht die meisten Programme benötigen Zufallszahlen in einem anderen Bereich als der eine von rand produziert. Einige Anwendungen erfordern zufällige Gleitkommazahlen. Einige Programme benötigen Zahlen, die eine ungleichmäßige Verteilung widerspiegeln. Programmierer führen häufig Nicht-Zufälligkeiten ein, wenn sie versuchen, den Bereich, Typ oder die Verteilung der von rand generierten Zahlen zu transformieren. (Zitat aus Lippmans C++ Primer 5. Auflage 2012)


Die beste Erklärung von 20 Büchern fand ich schließlich in Bjarne Stroustrups neueren – und er sollte sich auskennen – in “A tour of C++ 2019”, “Programming Principles and Practice Using C++ 2016” und “The C++ Programming Language 4th edition 2014” und auch einige Beispiele in “Lippmans C++ Primer 5. Auflage 2012”:

Und es ist wirklich einfach, denn ein Zufallszahlengenerator besteht aus zwei Teilen:
(1) eine Maschine, die eine Folge zufälliger oder pseudozufälliger Werte erzeugt. (2) eine Verteilung, die diese Werte einer mathematischen Verteilung in einem Bereich zuordnet.


Trotz der Meinung von Microsofts STL-Mann schreibt Bjarne Stroustrups:

In stellt die Standardbibliothek Zufallszahlenmaschinen und -verteilungen bereit (§24.7). Verwenden Sie standardmäßig die default_random_engine , die aufgrund ihrer breiten Anwendbarkeit und geringen Kosten ausgewählt wird.

Die void die_roll() Beispiel ist von Bjarne Stroustrups – gute Idee, Engine zu generieren und mit zu verteilen using (mehr dazu hier).


Um die von der Standardbibliothek in bereitgestellten Zufallszahlengeneratoren praktisch nutzen zu können <random> Hier ein paar ausführbare Codes mit verschiedenen Beispielen, die auf das Nötigste reduziert sind und euch hoffentlich Zeit und Geld sparen:

    #include <random>     //random engine, random distribution
    #include <iostream>   //cout
    #include <functional> //to use bind

    using namespace std;


    void space() //for visibility reasons if you execute the stuff
    {
       cout << "\n" << endl;
       for (int i = 0; i < 20; ++i)
       cout << "###";
       cout << "\n" << endl;
    }

    void uniform_default()
    {
    // uniformly distributed from 0 to 6 inclusive
        uniform_int_distribution<size_t> u (0, 6);
        default_random_engine e;  // generates unsigned random integers

    for (size_t i = 0; i < 10; ++i)
        // u uses e as a source of numbers
        // each call returns a uniformly distributed value in the specified range
        cout << u(e) << " ";
    }

    void random_device_uniform()
    {
         space();
         cout << "random device & uniform_int_distribution" << endl;

         random_device engn;
         uniform_int_distribution<size_t> dist(1, 6);

         for (int i=0; i<10; ++i)
         cout << dist(engn) << ' ';
    }

    void die_roll()
    {
        space();
        cout << "default_random_engine and Uniform_int_distribution" << endl;

    using my_engine = default_random_engine;
    using my_distribution = uniform_int_distribution<size_t>;

        my_engine rd {};
        my_distribution one_to_six {1, 6};

        auto die = bind(one_to_six,rd); // the default engine    for (int i = 0; i<10; ++i)

        for (int i = 0; i <10; ++i)
        cout << die() << ' ';

    }


    void uniform_default_int()
    {
       space();
       cout << "uniform default int" << endl;

       default_random_engine engn;
       uniform_int_distribution<size_t> dist(1, 6);

        for (int i = 0; i<10; ++i)
        cout << dist(engn) << ' ';
    }

    void mersenne_twister_engine_seed()
    {
        space();
        cout << "mersenne twister engine with seed 1234" << endl;

        //mt19937 dist (1234);  //for 32 bit systems
        mt19937_64 dist (1234); //for 64 bit systems

        for (int i = 0; i<10; ++i)
        cout << dist() << ' ';
    }


    void random_seed_mt19937_2()
    {
        space();
        cout << "mersenne twister split up in two with seed 1234" << endl;

        mt19937 dist(1234);
        mt19937 engn(dist);

        for (int i = 0; i < 10; ++i)
        cout << dist() << ' ';

        cout << endl;

        for (int j = 0; j < 10; ++j)
        cout << engn() << ' ';
    }



    int main()
    {
            uniform_default(); 
            random_device_uniform();
            die_roll();
            random_device_uniform();
            mersenne_twister_engine_seed();
            random_seed_mt19937_2();
        return 0;
    }

Ich denke, das summiert sich und wie gesagt, ich brauchte eine Menge Lesen und Zeit, um es auf diese Beispiele zu reduzieren – wenn Sie weitere Sachen zur Nummerngenerierung haben, freue ich mich über eine Nachricht per PN oder im Kommentarbereich und werde es bei Bedarf hinzufügen oder diesen Beitrag bearbeiten. Bool

Hier ist etwas, das ich gerade in diese Richtung geschrieben habe:

#include <random>
#include <chrono>
#include <thread>

using namespace std;

//==============================================================
// RANDOM BACKOFF TIME
//==============================================================
class backoff_time_t {
  public:
    random_device                      rd;
    mt19937                            mt;
    uniform_real_distribution<double>  dist;

    backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}

    double rand() {
      return dist(mt);
    }
};

thread_local backoff_time_t backoff_time;


int main(int argc, char** argv) {
   double x1 = backoff_time.rand();
   double x2 = backoff_time.rand();
   double x3 = backoff_time.rand();
   double x4 = backoff_time.rand();
   return 0;
}

~

Hier ist eine Ressource, die Sie über den Pseudozufallszahlengenerator lesen können.

https://en.wikipedia.org/wiki/Pseudorandom_number_generator

Grundsätzlich benötigen Zufallszahlen im Computer einen Startwert (diese Zahl kann die aktuelle Systemzeit sein).

Ersetzen

std::default_random_engine generator;

Durch

std::default_random_engine generator(<some seed number>);

Generieren Sie Zufallszahlen mit der C11 Zufallsbibliothek
Malcolm McLean

Sie haben zwei häufige Situationen. Der erste ist, dass Sie Zufallszahlen wollen und sich nicht zu sehr um die Qualität oder Ausführungsgeschwindigkeit kümmern. Verwenden Sie in diesem Fall das folgende Makro

#define uniform() (rand()/(RAND_MAX + 1.0))

das gibt Ihnen p im Bereich von 0 bis 1 – Epsilon (es sei denn, RAND_MAX ist größer als die Genauigkeit eines Doubles, aber machen Sie sich darüber Sorgen, wenn Sie dazu kommen).

int x = (int) (uniform() * N);

Gibt nun eine zufällige ganze Zahl von 0 bis N -1 aus.

Wenn Sie andere Distributionen benötigen, müssen Sie p transformieren. Oder manchmal ist es einfacher, uniform() mehrmals aufzurufen.

Wenn Sie wiederholbares Verhalten wünschen, starten Sie mit einer Konstante, andernfalls mit einem Aufruf von time().

Wenn Sie sich nun über Qualität oder Laufzeitleistung Gedanken machen, schreiben Sie uniform() neu. Aber sonst berühren Sie den Code nicht. Halten Sie uniform() immer auf 0 bis 1 minus Epsilon. Jetzt können Sie die C++-Zufallszahlenbibliothek umschließen, um ein besseres uniform() zu erstellen, aber das ist eine Art Option auf mittlerer Ebene. Wenn Sie sich an den Eigenschaften des RNG stören, lohnt es sich auch, ein wenig Zeit zu investieren, um zu verstehen, wie die zugrunde liegenden Methoden funktionieren, und stellen Sie dann eine bereit. Sie haben also die vollständige Kontrolle über den Code und können garantieren, dass die Sequenz mit demselben Startwert immer genau gleich ist, unabhängig von der Plattform oder der Version von C++, auf die Sie verlinken.

988860cookie-checkGenerieren Sie Zufallszahlen mit der C++11-Zufallsbibliothek

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy