Viele Zufallszahlen schnell generieren, aber wie?



  • Hallo,

    mein Problem ist, dass ich über folgende Funktion zwar viele Zufallszahlen generieren kann, aber jedesmal eine Sekunde auf eine neue warte müsste.

    Get_random_value(int max) 
    {
    	srand( (int)(time(NULL)) );
    	return ((rand() % max) + 1);
    }
    

    Gibt es einen einfachen Algorythmus mit dem ich schneller neue Werte erzeugen kann.

    Danke für alle Antworten,

    Moritz



  • Lass einfach das srand() aus deiner Funktion weg, und führe es am besten nur einmal pro Programm aus.

    Du kannst dir auch mal den Artikel über Zufallszahlen im Magazin anschauen, da steht alles nochmal genau beschrieben.



  • Sorry...Falscher Beitrag... 😮



  • int RandInt(int iMin, int iMax)
    {
        return(iMin+(static_cast<int>(rand())%(iMax-iMin)));
    }
    ...
    srand((int)time(NULL));
    int iZahl=RandInt(0,9);
    


  • struct randome
    {
    	inline static unsigned long generate(unsigned long min = 0, unsigned long max = (RAND_MAX - 1)) 
    	{ 
    		static randome _inst; 
    		if (max - min >= RAND_MAX) throw std::out_of_range("RAND_MAX");
    		return min + std::rand() % (max - min + 1);
    	}
    
    private:
        randome() { std::srand(static_cast<unsigned>(std::time(NULL))); }
    };
    

    hast dann aber keine Multithreadingsicherheit ...

    randome::generate(10, 15);
    

    ...
    Wollte es erst mit operator()(unsigned long min, unsigned lon max) machen ... geht aber nicht, da es sich dann mit dem Konstruktor schneiden würde!



  • Wieso sollte das mit dem operator() nicht gehen, klar geht das:

    class rng
    {
    public:
        rng();
        long operator()(long min_val, long max_val);
        // ...
    };
    
    void foo()
    {
       long v1 = rng()(1, 10);
       rng r;
       long v2 = r(1,10);
    }
    


  • Nee 😛 Du solltest dir vllt. angucken was ich geschrieben habe 😛 Bei mir ist der Konstruktor private, da der nur einmal (d.h. auch static randome _inst; ) aufgerufen werden soll ...



  • Wie viele Primzahlen brauchst du denn? Wenns viele sind, solltest du dir überlegen, ob du nicht auf std::rand verzichten willst und z. B. lieber eine Mersenne-Twister-Implementierung benutzt. std::rand ist nämlich meist nur ein linearer Kongruenzgenerator mit schlecht gewählten Variablen.

    Außerdem würde ich nicht Modulo benutzen, um die Zufallszahlen auf deinen passenden Bereich einzugrenzen. Such lieber nach einer Funktion, die dir Zahlen im Intervall [0;1[ liefert (geht notfalls auch mit /(rand_max + 1) ).



  • Michael E. schrieb:

    Wie viele Primzahlen brauchst du denn?

    Hallo, ich brauche keine Primzahlen (oder habe ich da jetzt was nicht verstanden?).
    Der Verzicht auf srand() tuts natürlich... danke.
    Ist ja auch klar, nach Srand nimmt er ich doch immer wider den ersten eintrag aus der Liste. Srandet man mehrmals mit dem gleich Wert, nimmt er immer wieder den ersten, folglich den gleichen Wert.

    Danke, Moritz



  • rand() verwendet keine Liste - sondern eine (relativ primitve) Rechenvorschrift, um einen neuen Zufallswert zu ermitteln 😉 Aber natürlich kommt jedes Mal der selbe Wert heraus, wenn du den Zufallsgenerator mit dem selben Startwert fütterst.



  • (D)Evil schrieb:

    Nee 😛 Du solltest dir vllt. angucken was ich geschrieben habe 😛 Bei mir ist der Konstruktor private, da der nur einmal (d.h. auch static randome _inst; ) aufgerufen werden soll ...

    Richtig.

    Was aber wohl überhaupt keinen Sinn macht.
    Wozu eine Klasse wenn man doch nur eine Funktion exportiert, und State global ist.

    Es hat schon einen Sinn dass man Zufallszahlen-Generatoren als normale konstruierbare, kopierbare etc. Objekte implementiert.



  • hustbaer schrieb:

    (D)Evil schrieb:

    Nee 😛 Du solltest dir vllt. angucken was ich geschrieben habe 😛 Bei mir ist der Konstruktor private, da der nur einmal (d.h. auch static randome _inst; ) aufgerufen werden soll ...

    Richtig.

    Was aber wohl überhaupt keinen Sinn macht.
    Wozu eine Klasse wenn man doch nur eine Funktion exportiert, und State global ist.

    Es hat schon einen Sinn dass man Zufallszahlen-Generatoren als normale konstruierbare, kopierbare etc. Objekte implementiert.

    Das eine schließt das andere nicht aus. Wenn man kann die Erstellung des Zufallsobjekts von der Erzeugung von Zufallswerten trennt, hat man den Zufall als Singleton und kann neue Methoden hinzufügen, um an Zufallswerte heranzukommen.

    Beispiel:

    Zufall.h

    #ifndef ZUFALL_H_
    #define ZUFALL_H_
    
    #include <ctime>
    
    class Zufall
    {
    public:
    	static Zufall &Objekt(unsigned long min = 0, unsigned long max = (RAND_MAX - 1));
    
    	void setzeBereich(unsigned long min = 0, unsigned long max = (RAND_MAX - 1));
    
    	unsigned long operator()() const;
    	unsigned long operator()(unsigned long min, unsigned long max) const;	
    
    private:
    	Zufall();
    
    	unsigned long m_min;
    	unsigned long m_max;
    };
    
    //Implementierung
    
    inline Zufall::Zufall()
    {
    	std::srand(static_cast<unsigned>(std::time(NULL)));
    }
    
    inline Zufall &Zufall::Objekt(unsigned long min, unsigned long max)
    {
        static Zufall z;
        z.setzeBereich(min, max);
        return z;
    }
    
    inline void Zufall::setzeBereich(unsigned long min, unsigned long max)
    {
    	m_min = min;
    	m_max = max;
    }
    
    inline unsigned long Zufall::operator()() const
    {
    	return m_min + std::rand() % (m_max - m_min + 1); 
    }
    
    inline unsigned long Zufall::operator ()(unsigned long min, unsigned long max) const
    {
    	return min + std::rand() % (max - min + 1); 
    }
    
    #endif /*ZUFALL_H_*/
    

    main.cpp

    #include <iostream>
    #include "Zufall.h"
    using namespace std;
    
    ostream &operator<<(ostream &ausgabe, const Zufall &einZufall)
    {
    	return ausgabe << einZufall();
    }
    
    int main()
    {	
    	cout << Zufall::Objekt(0, 12)() << "\n";
    	cout << Zufall::Objekt()(8, 12) << "\n";
    
    	Zufall &z = Zufall::Objekt(12, 24);
    	for (size_t i = 0; i < 10; ++i)
    		cout << z << "\n";
    }
    


  • Zufallskonstruktör schrieb:

    hustbaer schrieb:

    ...
    Es hat schon einen Sinn dass man Zufallszahlen-Generatoren als normale konstruierbare, kopierbare etc. Objekte implementiert.

    Das eine schließt das andere nicht aus. Wenn man kann die Erstellung des Zufallsobjekts von der Erzeugung von Zufallswerten trennt, hat man den Zufall als Singleton und kann neue Methoden hinzufügen, um an Zufallswerte heranzukommen.

    Es gibt Stellen an den ein Singleton sinnvoll ist. Gerade in deinem Beispiel finde ich aber beileibe eine schlechte Idee, oder zumindestens eine schlechte Schnittstelle. Nehmen wir einfach mal an wir haben ein paar Klassen die Zufallszahlen verwenden, allesamt mit unterschiedlichen Wertebereich: Deine Klasse läd zum falschen Bedienen ein (man kann zwar bei der Übergabe den Wertebereich eingeben, aber man kann auch über Methoden gehen die sich gegenseitig von mehreren Stellen "verbiegen" lassen.

    Zumal ich keinen einzigen Grund an der Stelle für ein Singleton sehe.

    cu André



  • Ich sehe auch keinen Grund für ein Singleton.

    Bei einigen Anwendungsfällen ist es sogar erforderlich 2 oder mehrere Generatoren zu haben die ihren eigenen State haben, also so dass die Zahlen die Generator Instanz A ausspuckt unabhängig davon sind wie oft man dazwischen auf Generator Instanz B Zahlen gezogen hat.

    Genauso gibt es Anwendungsfälle wo es Sinn macht wenn ein Generator serialisierbar ist (und Kopierbarkeit und Zuweisbarkeit sind dann eine Folge der Serialisierbarkeit).

    Zumindest sollte also ein Generator ganz normale Instanzen erlauben. Wenn man dann unbedingt ein Singleton daraus basteln will kann man das immer noch "drüberstülpen".



  • Moritz06 schrieb:

    Michael E. schrieb:

    Wie viele Primzahlen brauchst du denn?

    Hallo, ich brauche keine Primzahlen (oder habe ich da jetzt was nicht verstanden?).

    Klar, ich meinte Zufallszahlen. Einfach im Kopf ersetzen.



  • hustbaer schrieb:

    Zumindest sollte also ein Generator ganz normale Instanzen erlauben.

    genau - und wir hatten doch schon mal einen Thread mit Zufallszahlengenerator. Der geht für Integer und Fließkommazahlen und erlaubt mehrere Instanzen für verschiedene Intervalle.

    Gruß
    Werner


Anmelden zum Antworten