Zufallszahl generieren, aber wie?



  • & ist bitweise UND-Verknüpfung
    % ist modulo
    http://www.cplusplus.com/reference/clibrary/cstdlib/rand/



  • icarus2 schrieb:

    Oder ist das erlaubt, bedeutet aber etwas anderes?

    Ja, wie immer in C++.
    & ist bitweises AND.



  • Alles klar.

    Vielen Danke für die Hilfe 🙂



  • volkard schrieb:

    Ich kenne viel Code, der sich drauf verläßt, daß rand() immer >=0 liefert.

    Upps, bin jetzt vom int in seinem Code ausgegangen. 😃



  • Ich habe immer noch ein Problem... die Zufallszahlen werden zwar generiert, aber es kommt immer ein falsches Ergebnis raus. (Die Problemstellung steht im Classenkommentar, des geposteten Java-Codes.

    Hier mal den Code:

    #include <iostream>
    #include <ctime>
    
    int get_random_car_door();
    int get_random_player_choice();
    int get_opened_door(int car_door, int chosen_door);
    int get_changed_door(int opened_door, int chosen_door);
    
    const int Amount_of_doors = 3;
    
    int main()
    {	
    	using namespace std;
    
    	cout << "Enter the amount of games the computer shall play: ";
    	int loops;
    	cin >> loops;
    	cout << endl << endl << endl;
    
    	int chosen_door;
    	int opened_door;
    	int car_door;
    
    	int wins = 0;
    	int losses = 0;
    
    	for(int i = 0; i < loops; i++){
    
    		car_door = get_random_car_door();
    		chosen_door = get_random_player_choice();
    		opened_door = get_opened_door(car_door, chosen_door);
    
    		chosen_door = get_changed_door(opened_door, chosen_door);
    
    		if(chosen_door == car_door){
    			wins++;
    		} else {
    			losses++;
    		}
    
    	}
    
    	cout << "Wins:   " << wins << endl;
    	cout << "Losses: " << losses << endl;
    
    	int exit;
    	cin >> exit;
    	return 0;
    }
    
    int get_random_car_door(){
    
    	return ( rand() % ( Amount_of_doors - 1 ) );
    
    }
    
    int get_random_player_choice(){
    
    	return ( rand() % ( Amount_of_doors - 1 ) );
    
    }
    
    int get_opened_door(int car_door, int chosen_door){
    
    	int opened_door;
    
    	while(true){
    		opened_door = ( rand() % ( Amount_of_doors - 1 ) );
    
    		if(opened_door != car_door && opened_door != chosen_door){
    			return opened_door;
    		}
    	}
    
    }
    
    int get_changed_door(int opened_door, int chosen_door){
    
    	for(int i = 0; i < Amount_of_doors; i++){
    
    		if(i != opened_door && i != chosen_door){
    			return i;
    		}
    	}
    
    	return -1;
    }
    

    Ich habe das Gefühl, dass vor alem in der Funktion get_opened_door(int car_door, int chosen_door) etwas nicht stimmt, denn wenn ich mehr als 2 Eingebe am Anfang, bleibt das Programm irgendwie wie in einer Endlosschleiffe.

    Da ich zuerst dachte, dass ich einfach etwas falsch programmiert habe, habe ich es noch in Java, da kenne ich mich recht gut aus, geschrieben und da funktioniert alles.

    import javax.swing.JOptionPane;
    
    /**
     * This program demonstrates a mathematical probability problem, called 
     * "car and the goat".
     * 
     * The Car and the Goat
     * We assume that you are the winner in a TV-show. You get either a luxury car or a goat
     * as the prize. The presenter of the show takes you to three closed doors behind which
     * there is the car and two goats. First you choose one door at random. Then, to increase
     * the excitement, the presenter opens a door with a goat behind, and he asks you if 
     * you still want to change the door or not. What will you do?
     * 
     * Of course, you should change the door.
     * 
     * The program simulates the result, for a player who always changes doors, and prints
     * the ratio between wins and losses.
     * 
     * @author Urs Müller (17.12.09)
     *
     */
    public class CarGoat {
    
    	private final static int AMOUNT_OF_DOORS = 3; //total amount of doors
    
    	protected CarGoat(){
    
    		int chosenDoor; 	//stores which door the player chooses (it is chosen randomly by the computer)
    		int openedDoor; 	//the door, the presenter opens
    		int carDoor; 		//the door, behind which the car is
    
    		long startTime, endTime;
    
    		int wins = 0;
    		int losses = 0;
    
    		//determines how many games the computer shall simulate
    		String input = JOptionPane.showInputDialog(null, "Enter the amount of games \nthe computer shall play.");
    		int loops = Integer.valueOf(input);
    		startTime = System.currentTimeMillis();
    
    		//loops through all games
    		for(int i = 0; i < loops; i++){
    
    			carDoor = getRandomCarDoor();
    			chosenDoor = getRandomPlayerChoice();
    			openedDoor = getOpenedDoor(carDoor, chosenDoor);
    
    			chosenDoor = getChangedDoor(openedDoor, chosenDoor);
    
    			if(chosenDoor == carDoor){
    				wins++;
    			}else{
    				losses++;
    			}
    		}
    
    		endTime = System.currentTimeMillis();
    		System.out.println(endTime - startTime);
    
    		//round to 3 decimal places
    		double ratio = (double)wins / (double)losses;
    		final int DECIMAL_PLACES = 3;
    		double factor = Math.pow(10, DECIMAL_PLACES);
    		ratio = Math.round(ratio * factor) / factor;
    
    		//shows the result
    		JOptionPane.showMessageDialog(null, "Wins:   " + wins + "\n" +
    											"Losses: " + losses + "\n" +
    											"Ratio:  " + wins + " / " + losses + " = " + ratio + " : 1");
    
    	}
    
    	public int getRandomCarDoor(){
    
    		return (int)( Math.random() * 3 );
    
    	}
    
    	public int getRandomPlayerChoice(){
    		return (int)( Math.random() * 3 );
    	}
    
    	/**
    	 * Calculates which door is opened by the presenter.
    	 * 
    	 * @param carDoor - the door behind which the car is
    	 * @param chosenDoor - the door, the player has chosen
    	 * @return the door, the presenter opens
    	 */	
    	public int getOpenedDoor(int carDoor, int chosenDoor){
    
    		int openedDoor;
    
    		while(true){
    
    			openedDoor = (int) ( Math.random() * 3 );
    
    			if(openedDoor != carDoor && openedDoor != chosenDoor){
    				return openedDoor;
    			}
    		}
    
    	}
    
    	/**
    	 * Changes the door
    	 * 
    	 * @param carDoor - the door behind which the car is
    	 * @param openedDoor - the door the presenter has opened
    	 * @param chosenDoor - the door, the player has chosen
    	 * @return
    	 */
    	public int getChangedDoor(int openedDoor, int chosenDoor){
    
    		for(int i = 0; i < AMOUNT_OF_DOORS; i++){
    
    			if(i != openedDoor && i != chosenDoor){
    				return i;
    			}
    
    		}
    
    		return -1;
    	}
    
    	public static void main(String[] args) {
    
    		new CarGoat();
    
    	}
    
    }
    

    Ich wäre sehr froh, wenn mir jemand einen Unteschied sagen kann. Auch wenn mein C++ Programmierstil schlecht ist, könnt ihr es mich ruhig wissen lassen 🙂

    Danke schon im voraus



  • Wenn Du eine Zufallszahl aus der Menge {0,1,...,Amount_of_doors-1} haben möchtest, ist sowohl
    rand() % Amount_of_doors - 1
    als auch
    rand() % ( Amount_of_doors - 1 )
    falsch.

    Das -1 hat hier nichts zu suchen. Im ersten Fall bekommst Du Zahlen -1,0,1 und im zweiten Fall bekommst Du nur 0 und 1.

    Das mit dem & klappt auch nur für Zweierpotenzen. Wenn also x und y positiv sind, und y eine Zweierpotenz ist, dann gilt
    x % y == x & (y-1)
    aber auch nur dann.

    Gruß,
    SP



  • Schonmal <random> (bzw <tr1/random>) angeguckt?
    z.B.:

    template<typename T>
    class random_generator
    {
    public:
    	random_generator(T min, T max)
    		: m_ui(min, max)
    	{	}
    	T operator()()
    	{
    		return m_ui(m_eng);
    	}
    private:
    	std::tr1::uniform_int<T> m_ui;
    	std::tr1::mt19937 m_eng;
    };
    
    int main()
    {
        random_generator<int> ig(0,100);
        for(int i=0; i<10; ++i)
            std::cout << ig() << "\n";
        return 0;
    }
    




  • @ Sebastian Pizer
    Aso, jetzt ist natürlich klar, wiso es nicht funktioniert hat.

    @ brotbernd
    Sieht interessant aus, aber atm überfordert mich der Code noch etwas. Ich werde mal noch ein bisschen in meinem C++ Buch lesen.

    @ FreakY<3Cpp
    Der Link sieht sehr interessant aus. Ich werde das ganze mal lesen, brauche allerdings etwas Zeit dafür, der ganze Post ist ja zimlich lange ^^

    Vielen Danke für eure Antworten. Ich hoffe, dass ich das mit Hilfe eurer Posts hinbekomme. Wenn nicht schreib ichs wieder hier rein 😉



  • icarus2 schrieb:

    atm überfordert mich der Code noch etwas.

    #include <random>
    // #include <tr1/random> // gcc
    
    int main()
    {
       using namespace std::tr1;
    
       const int Amount_of_doors = 3;
       uniform_int<int> get_random_car_door(0, Amount_of_doors-1);
       mt19937 engine;
    
       int car_door = get_random_car_door(engine);
       int nochmal = get_random_car_door(engine);
       ...
    }
    

    einfacher? 😉



  • Hehe, ja das ist schon besser 🙂

    Vielen Dank.

    Hab ich nur das Gefühl, dass C++ komplizierter ist als Java, oder ist das wirklich so? Ich habe das Gefühl, dass dem Programmierer bei sehr vielen Sachen sehr viel mehr Freiheiten gelassen werden?
    (Muss natürlich nicht heissen, dass C++ schlechter ist, ich will hier keine Java vs. C++ Diskussion 😉 )



  • Ja, das kann man wohl so sagen.
    Über besser oder schlechter kann man sowieso nur im Zusammenhang mit einer konkreten Aufgabenstellung diskutieren. Es gibt viele Aufgaben für die C++ sicherlich eine schlechte Wahl ist.



  • icarus2 schrieb:

    Hab ich nur das Gefühl, dass C++ komplizierter ist als Java, oder ist das wirklich so? Ich habe das Gefühl, dass dem Programmierer bei sehr vielen Sachen sehr viel mehr Freiheiten gelassen werden?

    Komplizierter ist Ansichtssache, aber sicher komplexer.

    In C++ wird eher die Philosophie vertreten, dass 1. der Benutzer das letzte Wort hat und 2. man für nichts zahlen möchte, das man nicht braucht. Punkt 1 sieht man daran, dass dem Programmierer sehr viele Freiheiten – darunter auch gefährliche – geboten werden. Wenn er einen Zeiger als int ansprechen möchte, okay, reinterpret_cast macht es möglich. Das erfordert natürlich eine gewisse Verantwortung, im Normalfall braucht man diese Mittel auch nicht. Dennoch ist es praktisch, in den anderen Fällen nicht von der Sprache daran gehindert zu werden. Bei Punkt 2 geht Java den sichereren Weg. Es nimmt für viele Dinge einen Laufzeitoverhead in Kauf, um gewisse Fehler über Exceptions mitzuteilen (Array-Indizes, Klassen-Casts, Nullzeiger).

    Es spielt halt eine Rolle, wie man die Prioritäten legt. Ich würde C++ nicht prinzipiell als unsicher ansehen: Man kann sehr gut programmieren, ohne dauernd Low-Level-Rumgehacke zu betreiben. Dank Techniken wie RAII muss man sich nur noch sehr selten wirklich manuell um Speicher kümmern. In gewissen Aspekten ist C++ sogar sicherer, weil es sehr mächtige Metaprogrammierung zur Compilezeit und damit statische Typsicherheit ermöglicht. Dafür fällt es einem als Anfänger in C++ schwerer, sich mit Zeigern und solchen Dingen zurechtzufinden, weil es eben etwas mehr Fehlerquellen gibt.



  • Wenn man aber erst mal einige Jahre Erfahrung hat, alle Regeln und Idiome verinnerlicht hat, seinen Stil entwickelt hat ist C++ alles andere als unsicher, eben weil man genau weiss was man da macht. Ich glaube ich habe schon ewig kein explizites delete irgendwo hingeschrieben. Und wenn mal was sehr optimiertes benötigt oder sich mit einer C Biblitothek rumschlagen muss, wird jede Ekligkeit in eine Klasse gekabselt und Ruhe.
    Das Problem ist, dass "gutes" Programmieren meist erst in fortgeschrittener Literatur behandelt wird, obwohl diese Dinge für Anfänger viel wichtiger sind.



  • Volle Zustimmung, brotbernd. 👍

    Leider ist der Markt auch heute noch überschwemmt von Büchern, die mit char* -Frickeleien beginnen und einen solchen Stil angewöhnen. Kein Wunder denken immer noch so viele Leute, dass man sich in C++ wahnsinnige Mühe für grundlegende Dinge wie Speicherverwaltung oder Stringverarbeitung machen müsse.



  • Also ich lese gerade den C++ Primer Plus.

    Der enthält schon solche Dinge wie char *. Im Moment kämpfe ich mich gerade durch das Kapitel "Memory Models and namespaces". Ist etwas mühsam, aber ich freue mich auf das Kapitel "Objects and Classes" 🙂



  • icarus2 schrieb:

    Also ich lese gerade den C++ Primer Plus. Der enthält schon solche Dinge wie char *.

    Das ist überhaupt kein Problem, der Primer gehört auch zur guten Anfängerliteratur. Natürlich darf man schon wissen, dass es char -Arrays gibt und man damit Strings verwalten kann. Es schadet auch nicht, es anwenden zu können. Aber wenn einem von Anfang an ausschliesslich solche Dinge gezeigt werden, sodass man effektiv das Gefühl bekommt, die Sprache ermögliche keine besseren Wege, ist das etwas anderes.



  • Wie sieht es bei C++ eigentlich mit naming convetions aus?

    Ich habe schon verschiedenes gelesen. camel_case, camelCase und noch anderes. Im Primer steht, es gibt verschiedene Dinge. Gibt es aktuelle naming conventions für C++ oder nicht?



  • icarus2 schrieb:

    Ich habe schon verschiedenes gelesen. camel_case, camelCase und noch anderes. Im Primer steht, es gibt verschiedene Dinge. Gibt es aktuelle naming conventions für C++ oder nicht?

    Es gibt verschiedene Namenskonventionen in C++.

    Die Standardbibliothek und Boost verwenden unter_striche , aber selbst bist du frei. Sei einfach einheitlich, mindestens innerhalb eines Projekts.



  • So, ich habs hinbekommen... alles funktioniert 🙂

    Ich habe es so gelöst:

    Ich habe alles in dem geposteten Link gelesen und anschliessend diese Klasse hier übernommen:

    //Datei: random.cpp
    
    #ifndef _RANDOM_H
    #define _RANDOM_H
    
    #include <cstdlib>
    #include <ctime>
    #include <cassert>
    
    class Random
    {
    private:
    	Random()
    	{
    		std::srand(static_cast<int>(std::time(NULL)));
    	}
    public:
    	static int rnd(int lowerbounds, int upperbounds)
    	{
    		static Random dummy;
    		assert(upperbounds - lowerbounds < RAND_MAX);
    		return lowerbounds + std::rand() % (upperbounds - lowerbounds + 1);
    	}
    };
    
    #endif
    

    Das hier ist anschliessend das file, von dem aus das Prog gestartet wird:

    #include <iostream>
    #include <cmath>
    #include "random.cpp"
    
    int get_random_car_door();
    int get_random_player_choice();
    int get_opened_door(int car_door, int chosen_door);
    int get_changed_door(int opened_door, int chosen_door);
    double round(double number, int places);
    
    static const int Amount_of_doors = 3;
    
    int main()
    {
    
    	using std::cin;
    	using std::cout;
    	using std::endl;
    
    	int games;
    	cout << "Enter the amount of games the computer shall simulate: ";
    	cin >> games;
    	cout << endl << endl;
    
    	int wins = 0;
    	int losses = 0;
    
    	int car_door;
    	int chosen_door;
    	int opened_door;
    
    	for(int i = 0; i < games; i++){
    
    		car_door = get_random_car_door();
    		chosen_door = get_random_player_choice();
    		opened_door = get_opened_door(car_door, chosen_door);
    
    		chosen_door = get_changed_door(opened_door, chosen_door);
    
    		if(chosen_door = car_door){
    			wins++;
    		} else {
    			losses++;
    		}
    
    	}
    
    	double ratio = (float)wins / (float)losses;
    	ratio = round(ratio, 3);
    
    	cout << "Wins:   " << wins << endl;
    	cout << "Losses: " << losses << endl;
    	cout << "Ratio:  " << wins << " / " << losses << " = " << ratio << " : 1" << endl;
    
    	int exit;
    	cin >> exit;
    	return 0;
    }
    
    int get_random_car_door(){
    	return Random::rnd(0, Amount_of_doors - 1);
    }
    
    int get_random_player_choice() {
    	return Random::rnd(0, Amount_of_doors - 1);
    }
    
    int get_opened_door(int car_door, int chosen_door){
    
    	int opened_door;
    
    	while(true){
    
    		opened_door = Random::rnd(0, Amount_of_doors - 1);
    
    		if(opened_door != car_door && opened_door != chosen_door){
    			return opened_door;
    		}
    	}
    
    }
    
    int get_changed_door(int opened_door, int chosen_door){
    
    	for(int i = 0; i < Amount_of_doors; i++){
    
    		if(i != opened_door && i != chosen_door){
    			return i;
    		}
    	}
    }
    
    double round(double number, const int places){
    
    	int factor = pow(10.0, places);
    	number = (int) ( number * factor );
    	number = number / factor;
    
    	return number;
    }
    

    Falls was im Code sehr hässlich ist, gebt mir bescheid 😉

    Ansonsten nochmals vielen Dank für eure Hilfe.


Anmelden zum Antworten