Lottozahlen mach ich was falsch?



  • heavylotto schrieb:

    C++11 bietet einen komfortablen Zufallsgenerator. Versuch mal dieses kleine Programm. Wegen set gibt es keine Zahl doppelt.

    Das ist kein bisschen besser als rand().



  • mod_? schrieb:

    wofür ist das Modulo 49 ??

    damit nur Zahlen von 0 bis 48 erzeugt werden. +1 macht dann einen Bereich von 1 bis 49.



  • Wenn dann bitte so:

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dist(1, 49);
    
    std::set<int> lottozahlen;
    while(lottozahlen.size() < 6)
      lottozahlen.insert(dist(gen));
    

    Ist zwar etwas umständlich, aber so gibts vernünftig verteilte Zufallszahlen.



  • komfortable schrieb:

    sebi707 schrieb:

    komfortable schrieb:

    lol, der PRNG von C++11 ist alles, aber nicht komfortabel.

    Dafür aber Richtig.

    Sagen wir besser. Die kleine Abweichung spielt hier keine Rolle, daher würde ich bei Anfängern weiterhin zu rand und srand(time(nullptr)) raten.

    Warum etwas empfehlen, was von C++ 11 als deprecated eingestuft und ab c++17 vermutlich nicht mehr teil von C++ sein wird?
    Abgesehen davon, ist bei MS der Wertebereich auf 32767 beschränkt, siehe https://msdn.microsoft.com/en-us/library/2dfe3bzd.aspx.



  • sebi707 schrieb:

    Wenn dann bitte so:

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dist(1, 49);
    
    std::set<int> lottozahlen;
    while(lottozahlen.size() < 6)
      lottozahlen.insert(dist(gen));
    

    Ist zwar etwas umständlich, aber so gibts vernünftig verteilte Zufallszahlen.

    Ja. Ist umständlich. Aber wieso das besser verteilte Zufallszahlen als

    minstd_rand
    

    , das

    std::linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>
    

    entspricht, geben soll, musst du erstmal zeigen. Nur behaupten reicht nicht.



  • LCGs gibts schon ewig und ist quasi der einfachste Zufallszahlengenerator den man so bauen kann. Ein tolles "Feature" ist z.B. das sich Ebenen ergeben wenn man die Zufallszahlen entsprechend aufträgt (https://en.wikipedia.org/wiki/Linear_congruential_generator). Aber allein wegen dem Modulo disqualifiziert sich deine Lösung. Man rechne mal die Anzahl der Möglichen Werte von minstd_rand (2147483647) Modulo 49 und erhält 43. Damit kommen in deiner Lösung die Zahlen <=43 leicht häufiger vor als die Zahlen >43.


  • Mod

    sebi707 schrieb:

    Damit kommen in deiner Lösung die Zahlen <=43 leicht häufiger vor als die Zahlen >43.

    Und zwar 0.000002% häufiger. Absolut unbrauchbar.



  • SeppJ schrieb:

    Und zwar 0.000002% häufiger. Absolut unbrauchbar.

    Klar ist natürlich nicht besonders viel. Mit rand() unter Windows wo RAND_MAX=32767 ist sieht das schon wieder schlechter aus. Jedenfalls ist meine Lösung nicht wesentlich komplizierter als die von heavylotto. Außerdem sehe ich irgendwie keinen Sinn darin absichtlich einen schlechteren Zufallszahlengenerator zu nehmen, wenn man schon die neuen C++11 Teile nutzt. Ob ich minstd_rand oder mt19937 schreibt macht nicht so den Unterschied.

    Wers noch nicht kennt: Ein Vortrag warum man besser nicht rand() benutzt und was man stattdessen besser nimmt: https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful


  • Mod

    Die Wahl des Zufallsgenerators und die Berechnung der richtigen Verteilung sind zwei getrennte Probleme.

    rand ist gut genug für Spielereien, wie hier. rand ist nicht gut genug für einige professionelle Anwendungen, wie beispielsweise wissenschaftliches Rechnen. Da es nicht wirklich einen Unterschied macht, ob man nun rand oder mt19937 schreibt, kann und sollte man auch für Spielereien etwas besseres als rand benutzen.

    Eine "Gleichverteilung" mittels modulo ist gut genug für Spielereien. Eine modulo-Verteilung ist sogar gut genug für sehr viele professionelle Anwendungen, mir fallt spontan kein Gegenbeispiel ein, außer man hat wirklich eine Verteilung, die sich über einen signifikanten Bereich des Zufallszahlenraums erstreckt. Die Verteilungsfunktionen sind komplizierter in der Benutzung (und theoretisch etwas langsamer) als ein einfaches Modulo. Die Modulo-Verteilung würde ich daher nicht so negativ darstellen.



  • Ich benutze immer noch gerne mein altes völlig transparentes System:

    class Random_spezial // siehe: http://www.math.keio.ac.jp/home2/matumoto/public_html/mt19937int.c 
    {
    private:
    	unsigned seed_;
    	const int N;
    	const int M;
    	const unsigned MATRIX_A;
    	const unsigned UPPER_MASK;
    	const unsigned LOWER_MASK;
    	const unsigned TEMPERING_MASK_B;
    	const unsigned TEMPERING_MASK_C;
    	unsigned TEMPERING_SHIFT_U(unsigned y) { return (y >> 11); }
    	unsigned TEMPERING_SHIFT_S(unsigned y) { return (y << 7); }
    	unsigned TEMPERING_SHIFT_T(unsigned y) { return (y << 15); }
    	unsigned TEMPERING_SHIFT_L(unsigned y) { return (y >> 18); }
    	static unsigned mt[624];
    	static int mti;
    
    public:
    	Random_spezial() :N(624), M(397), MATRIX_A(0x9908b0df),
    		UPPER_MASK(0x80000000), LOWER_MASK(0x7fffffff),
    		TEMPERING_MASK_B(0x9d2c5680), TEMPERING_MASK_C(0xefc60000),
    		seed_(static_cast<unsigned>(time(0)))
    	{
    		static bool seed_flag = 0;
    		if (!seed_flag)
    		{
    			sgenrand(seed_);
    			seed_flag = true;
    		}
    	}
    
    	void sgenrand(unsigned seed_)
    	{
    		mt[0] = seed_ & 0xffffffff;
    		for (mti = 1; mti<N; mti++) mt[mti] = (69069 * mt[mti - 1]) & 0xffffffff;
    	}
    
    	unsigned getNum() { return genrand() % (RAND_MAX + 1); }
    
    	unsigned genrand()
    	{
    		unsigned y;
    		static unsigned mag01[2] = { 0x0, MATRIX_A };
    
    		if (mti >= N)
    		{
    			int kk;
    			//if (mti == N+1) sgenrand(seed_); 
    			for (kk = 0;kk<N - M;kk++)
    			{
    				y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
    				mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1];
    			}
    			for (;kk<N - 1;kk++)
    			{
    				y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
    				mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1];
    			}
    			y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
    			mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1];
    
    			mti = 0;
    		}
    		y = mt[mti++];
    		y ^= TEMPERING_SHIFT_U(y);
    		y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
    		y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
    		y ^= TEMPERING_SHIFT_L(y);
    		return y;
    	}
    };
    
    unsigned Random_spezial::mt[624];
    int Random_spezial::mti = 625;
    
    template<typename T_Generator> class Wuerfel
    {
    private:
    	const int maxzahl_;
    	const int maxrandom_;
    	T_Generator zahlengenerator_; // Template-Typ 
    
    public:
    	Wuerfel(int maxzahl) :maxzahl_(maxzahl), maxrandom_(RAND_MAX - (RAND_MAX%maxzahl)) {}
    
    	int wuerfelt()
    	{
    		int r;
    		do { r = zahlengenerator_.getNum(); } while (r >= maxrandom_);
    		return (r % maxzahl_ + 1);
    	}
    };
    
    int n = ...; // your choice  
    Wuerfel<Random_spezial> w(n);
    

    Im Code:

    Car myCar(w.wuerfelt() - 1, w.wuerfelt() - 1);
    

    Der Link ist übrigens inzwischen tot. 🙂



  • Erhard Henkes schrieb:

    Ich benutze immer noch gerne mein altes völlig transparentes System:

    Wozu? Es sieht völlig kaputt aus, da es von RAND_MAX abhängt. Abgesehen davon gibt keinen Grund, es zu verwenden, wenn wir seit C++11 eine bessere Alternative haben.


Anmelden zum Antworten