Zufallszahlen im Wertebereich



  • Hi zusammen:

    Bin gerade dabei mir einen Zufallszahlengenerator zu schreiben, der mir innerhalb von einem zweidimensionalem Wertebereich Zufallszahlen ausspuckt.

    Die Zufallszahl soll dabei vom Typ double sein, zudem kann der Wertebereich auch negativ sein.

    Bisher verwende ich die folgende Funktion zum erstellen von Zufallszahlen.

    double rnd()
     {
       const unsigned long a = 65539; // 2**31-1
       const unsigned long m = 2147483647; // 2**31-1
       static unsigned long xi = 7;
       xi = ( a * xi ) % m;
       return ( (double) xi / (double) m );
     }
    

    Gibt es hier eine Möglichkeit den Wertebereich festzulegen in der die Zahl gezogen werden kann?
    Kann ich also zb.: Zufallszahlen vom Typ double im Bereich von -2.0 bis + 3.0 zulassen?

    Alle zufallszahlengeneratoren die ich gefunden haben nur Zufallszahlen im positiven Wertebereich erzeugt, zudem meist nur Werte vom Typ Integer.



  • redbomber schrieb:

    Alle zufallszahlengeneratoren die ich gefunden haben nur Zufallszahlen im positiven Wertebereich erzeugt, zudem meist nur Werte vom Typ Integer.

    Du könntest die positiven ganzen Zahlen manipulieren um auf z.b. Negative und floating point Zahlen zu kommen

    EDIT:
    Hier stand Blödsinn...
    Glatt das static übersehen...bin wohl zu müde.. 😃

    Hier gibt es allerdings schon einen guten Artikel zum Thema Zufallszahlen...sieh dir den mal an http://c-plusplus.net/forum/viewtopic-var-t-is-172876-and-start-is-0.html



  • redbomber schrieb:

    Hi zusammen:

    Bin gerade dabei mir einen Zufallszahlengenerator zu schreiben, der mir innerhalb von einem zweidimensionalem Wertebereich Zufallszahlen ausspuckt.

    Die Zufallszahl soll dabei vom Typ double sein, zudem kann der Wertebereich auch negativ sein.

    Bisher verwende ich die folgende Funktion zum erstellen von Zufallszahlen.

    double rnd()
     {
       const unsigned long a = 65539; // 2**31-1
       const unsigned long m = 2147483647; // 2**31-1
       static unsigned long xi = 7;
       xi = ( a * xi ) % m;
       return ( (double) xi / (double) m );
     }
    

    Gibt es hier eine Möglichkeit den Wertebereich festzulegen in der die Zahl gezogen werden kann?
    Kann ich also zb.: Zufallszahlen vom Typ double im Bereich von -2.0 bis + 3.0 zulassen?

    Alle zufallszahlengeneratoren die ich gefunden haben nur Zufallszahlen im positiven Wertebereich erzeugt, zudem meist nur Werte vom Typ Integer.

    Du kannst auch die ganz normale rand()-Funktion aus der cstdlib benutzen:

    double a = static_cast<double>(std::rand()) / RAND_MAX; // Werte von 0.0..1.0
    double b = 2.0 * (a - 0.5); //von -1.0..1.0#
    //usw.
    

    Richtig gut ist boost.random, weil man da noch zwischen verschiedenen Algorithmen wählen kann. Der Mersenne Twister ist z.B. sehr gut, was Widerholungen und Performance betrifft.
    Außerdem kann man die Verteilung und den Wertebereich direkt angeben.



  • redbomber schrieb:

    Bisher verwende ich die folgende Funktion zum erstellen von Zufallszahlen.

    double rnd()
     {
       const unsigned long a = 65539; // 2**31-1
       const unsigned long m = 2147483647; // 2**31-1
       static unsigned long xi = 7;
       xi = ( a * xi ) % m;
       return ( (double) xi / (double) m );
     }
    

    der Ausdruck 'a * xi' führt recht schnell zu einem Overflow, da das Ergebnis größer wird als numeric_limits<unsigned long>::max() - vorausgesetzt, Dein long ist 32 Bit breit.

    D.h. im Grunde steht da

    xi = (( a * xi ) & 0xFFFFFFFF) % m;
    

    Das führt dazu, dass die Periode Deines Generators bei knapp über 100000 liegt. Wenn Du aus a einen long long machst (64 Bit breit) so steigert dass die Periode auf 1073741822 (=(m-1)/2) - also ein Vielfaches.

    redbomber schrieb:

    Gibt es hier eine Möglichkeit den Wertebereich festzulegen in der die Zahl gezogen werden kann?
    Kann ich also zb.: Zufallszahlen vom Typ double im Bereich von -2.0 bis + 3.0 zulassen?

    Sicher - der Generator liefert Zahlen im Intervall (0.0, 1.0). Das kannst Du natürlich auf (-2.0, 3.0) aufblasen.

    return ( (double) xi / (double) m ) * 5.0 - 2.0;
    

    Eleganter und flexibler geht das ganze, wenn Du aus der Funktion zunächst mal einen Funktor machst, der die 'Roh'-Zufallszahlen liefert.

    struct Rnd
    {
        explicit Rnd( long xi = 7 )
            : m_xi( xi )
        {}
        static long min() { return 0; }
        static long max() { return m; }
    
        long operator()()
        {
            m_xi = ( a * m_xi ) % m;
            return m_xi;
        }
    private:
        long m_xi;
    
        // Periode: 1073741822
        // Bereich: [3; 2147483646]
        static const long long a = 65539;; // 2**16+3
        static const long m = 2147483647; // 2**31-1
    };
    

    Dieser Funktor liefert seine Grenzen mit min() und max() und daraus lässt sich ähnlich wie oben jeder beliebige Bereich durch eine lineare Transformation einstellen.
    Code braucht man dazu auch nicht viel schreiben, denn das liefert bereits boost.random. Hier die Verteilung 'uniform_real'.

    #include <boost/random/uniform_real.hpp>
    
    struct Rnd {/* s.o. */};
    
    int main()
    {
        using namespace std;
    
        boost::uniform_real< double > verteilung( -2.0, +3.0 );
        Rnd rnd;
        for( int n = 10; n; --n )
            cout << verteilung( rnd ) << endl;
        return 0;
    }
    

    Gruß
    Werner



  • und

    verteilung( -2.0, +3.0 )
    

    ist dann letztendlich welche Funktion?



  • Das ist keine Funktion, sondern der Konstruktoraufruf eines Objekts vom Typ boost::uniform_real<double> .



  • irgendwie funktioniert das noch immer nicht so ganz:

    1. woran sehe ich hier die Grenzen:

    return ( (double) xi / (double) m ) * 5.0 - 2.0;
    

    Ok, mit -2 verschiebe ich den Wertebereich einfach wieder in Richtung der negativen Zahlen. Aber was bewirkt die 5?

    DIe Methode von Werner Salomon habe ich versucht einzubauen, jedoch erscheint bei mir immer die Fehlermeldung "boost hast not been declared"
    Die benötigte uniform_real.hpp habe ich aber includiert.



  • redbomber schrieb:

    Ok, mit -2 verschiebe ich den Wertebereich einfach wieder in Richtung der negativen Zahlen. Aber was bewirkt die 5?

    Deine Zufallszahlen können ja zwischen 0 und 1 sein, also hast du eine Spannweite von 1. Durch die Multiplikation mit 5 erweiterst du das Intervall, sodass die Spannweite 5 beträgt.

    redbomber schrieb:

    DIe Methode von Werner Salomon habe ich versucht einzubauen, jedoch erscheint bei mir immer die Fehlermeldung "boost hast not been declared"
    Die benötigte uniform_real.hpp habe ich aber includiert.

    Du bist dir aber bewusst, dass der Namensraum boost für die Bibliothek Boost steht? Ansonsten schau mal hier, Boost ist eine gute Erweiterung der Standardbibliothek und besitzt sehr mächtige Instrumente.


Anmelden zum Antworten