Lottozahlen mach ich was falsch?



  • komfortable schrieb:

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

    Dafür aber Richtig. Die Variante mit Modulo x den Zahlenbereich hinzubiegen funktioniert auch nur wenn RAND_MAX ein Vielfaches von x ist. Ansonsten kommen kleinere Zahlen etwas häufiger vor.



  • 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.



  • Ist auf jeden Fall einfacher, als selbst einen korrekten Generator zu bauen. Du kannst aber gerne meinen alten Generator verwenden oder auf aktuellen Stand bringen: http://codepad.org/ceu5N7pU



  • ich habe ein wenig gegoogelt und es nun *fast* geschafft.
    Mein Problem ist, wie sage ich ihm was minumum und maximum sein soll? auf mein rd.min() %1 hört er nicht...

    #include <iostream>
    #include <random>
    
    int main()
    {
    	int lotto;
    
    	int i=0;
    	for (i = 1; i < 7; i++)
    	{
    		std::random_device rd;
    		rd.min() %1;
    		rd.max() %50;
    		int dice_roll= rd();
    		std::cout << "Lottozahl " << i << ": " << dice_roll << std::endl;
    	}
    }
    


  • Notlösung aber zumindest schnell:

    #include <iostream>
    #include <random>
    
    int main()
    {
    	int i;
    	for (i = 1; i < 7; )
    	{
    		std::random_device rd;
    		int number = rd();
    
    			while (number >= 50) {
    				number = rd() / 8689;
    			}
    			if (number <= 50 && number >= 1)
    			{
    			std::cout << "Lottozahl " << i << ": " << number << std::endl;
    			i = i++;
    		}
    		else {
    			i = i;
    		}
    	}
    }
    


  • Zuf11 schrieb:

    Notlösung

    Warum glaubst Du eine Notlösung zu brauchen?

    Zuf11 schrieb:

    aber zumindest schnell:

    Nein.

    Das ist ziemlicher Mist, den Du da aus dem Internet zusammengeklaubt und dann angepasst hast. Schnell wieder vergessen.

    Da gefällt mir die erste Lösung noch besser.
    Bau vielleicht noch eine Schleife ein, die das Array befüllt und dann lager das Befüllen in eine Funktion aus.

    Was ist eigentlich mit doppelt gezogenen Zahlen?

    PS: Stell die Warnungen Deines Compilers ein!



  • Zuf11 schrieb:

    ich habe ein wenig gegoogelt und es nun *fast* geschafft.
    Mein Problem ist, wie sage ich ihm was minumum und maximum sein soll? auf mein rd.min() %1 hört er nicht...

    Nicht raten! Programmieren ist nicht Raten, du musst genau wissen, was du tust.

    std::random_device::min()/max() liefern den minimalen Wert zurück, den std::random_device::operator()() berechnen kann.

    Die random Bibliothek unterscheidet zwei Konzepte: Generatoren und Verteilungen. Generatoren wie std::random_device liefern einfach nur zufällige Zahlen. Die Verteilungen mappen diese Zahlen dann auf ein entsprechendes Intervall.

    Du willst in deinem Fall Ganzzahlen, also nimmst du die Verteilung std::uniform_int_distribution<int>. Diese Ganzzahlen sollen im Intervall [1, 49] liegen, diese beiden Zahlen übergibst du dem Konstruktor. Anschließend rufst du den operator() der Verteilung auf und übergibst ihm irgendeinen Generator.

    Mehr Details gibts hier: http://en.cppreference.com/w/cpp/numeric/random



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

    #include <ctime>
    #include <iostream>
    #include <random>
    #include <set>
    
    int main() {
      std::minstd_rand rd(std::time(0));
      std::set<unsigned int> lottozahlen;
      while(lottozahlen.size() < 6) 
        lottozahlen.insert(1+rd()%49);
      for(auto wert : lottozahlen) 
        std::cout << wert << ' ';
      std::cout << '\n';
    }
    


  • wofür ist das Modulo 49 ??



  • 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