zwei gleiche doubles falsch?



  • Moin. Schönes Wochenende (oder was davon über ist) an euch alle.

    Ich hab gestern Abend ein kleines Kopfrechenprogramm geschrieben und wollte es eben gerade noch um prozente erweitern. Nun klappt das auch, nur schein ich irgendwas zu übersehen. Manchmal wenn man das richtige Ergebniss eingibt, dann kommt tatsächlich falsch raus, aber öfter eben richtig und da es kein Sinn macht, muss ich wohl irgendwas dämliches übersehen haben. Ich weiß nur nicht was.
    Hier ein paar Stücke vom Code:

    #include <iostream>
    #include <string>
    #include <conio.h>
    #include <random>
    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::string;
    
    int random(int zahl1, int zahl2) {
    	std::random_device rd;
    	std::mt19937 mt(rd());
    	std::uniform_int_distribution<int> dist(zahl1, zahl2);
    	return dist(mt);
    }
    
    int main(int argc, char **argv) {
    	double input = 0;
    	double zahl = 0;
    	double zahl2 = 0;
    	double ergebnis = 0;
    	std::string operation;
    
    	while (true) {
    		system("cls");
    		// hier wird die aufgabe generiert
    		zahl = random(1, 100);
    		zahl2 = random(1, 100);
    		while (zahl > zahl2) zahl = random(1, 100);
    		ergebnis = (zahl2 / 100) * zahl;
    		operation = "prozent von";
    
    		cout << "Aufgabe : " << zahl << " " << operation << " " << zahl2 << endl << endl;
    		cout << "Das Ergebniss ist :" << ergebnis << endl; // nur zum testen
    		cin >> input;
    		cout << "Dein Input:" << input << endl << endl; // nur zum testen
    
    		if (input == ergebnis) {
    			cout << "Richtig!";
    		}
    		else {
    			cout << "Falsch" << endl;
    			cout << ergebnis;
    		}
    		_getch();
    	}
    }
    

    das alles wird in einer schleife ausgeführt und sieht am ende natürlich etwas anders aus, aber das grundlegende ist gleich. müsste sich auch so compilen lassen, wenn man noch eine kurze zufallsfunktion dazu schreibt. wollte es nur kurz halten

    EDIT: Ich hab doch nochmal alles in eine ausführbare schleife gepackt

    EDIT 2: So ich habe eine nicht ganz befriedigende Lösung gefunden, weil ich sie nicht ganz verstehe, aber es funktioniert nun. Ich musste input und ergebnis in ein string umwandeln. Also wenn zufällig jemand lust hat mir das zu erklären, dann würde ich mich freuen. Ansonsten funktioniert wenigstens mein Programm 😃



  • Fließkommazahlen sind nicht immer exakt sondern Näherungswerte.
    Dadurch entstehen bei der Verarbeitung Rundungsfehler.

    Darum sollte man auch keine Fließkommazahlen auf Gleichheit testen.

    I.A. schaut man nach, ob der Betrag der Differenz kleiner als ein Schwellwert ist (oft mit Epsilon bezeichnet)

    Durch deine Umwandlung in ein String bekommst du nur eine begrenzte Anzahl an Stellen und simulierst so das Epsilon.

    Die Größe vom Epsilon hängt aber auch von der Größe der beiden Vergleichswerte ab, denn die Stellenanzahl ist begrenzt. Bei double sind es meist 16 Dezimalstellen ( ⚠ nicht Nachkommastellen)



  • Abgesehen von dem Rundungsproblem ist deine random-Funktion merkwürdig.

    Du solltest std::mt19937 mt(rd()); nicht jedes Mal neu initialisieren, um dann nur einmal eine Zahl rauszuholen - das ist sinnlos und du könntest dann auch gleich das rd direkt an die uniform_int_distribution übergeben. Die Idee ist ja gerade, dass man die random number engine (hier: mt19337) einmalig initialisiert und danach von ihr die Werte bezieht statt vom random_device. Außerdem ist das Erzeugen eines mt19337-Objektes recht aufwendig - also besser nur einmal machen.



  • @wob: hab das gerade mal getestet bei 1 Million wiederholungen brauch meine Zufallsfunktion auf meinem PC ca 11 Sekunden und mit deinem Tipp nichtmal 1. Das ist natürlich schon ein großer unterschied. Danke für den Tipp 🙂

    @DirkB: Huh, oke. Auch gut zu wissen. Ebenso danke.


Log in to reply