[c++]quadratische gleichungen fehlersuche

DarkSean

Erfahrenes Mitglied
Hi,ich hab folgendes Problem.
Ich hab ein Programm geschrieben um quadratische Gleichungen zu lösen. Es funktioniert im Prinzip so wie es soll. Es löst jede Gleichung richtig und zeigt auch die Diskriminante an. Doch gebe ich die Gleichung 5x² + 14x+ 9,8 = 0 ein, zeigt das Prog etwas völlig falsches an. Die Diskriminante ist bei der Gleichung 0, doch es wird -1,0... angezeigt. Ich weiß nicht ob bei anderen Gleichungen der gleiche Fehler auftritt, denn bis jetzt klappte es nur bei der Gleichung nicht. Hat jemand eine Lösung für mein Problem? Ich bin auch schon mein Code durchgegangen aber ich kann meinerseits keinen Fehler entdecken.
Code:
#include <iostream>
#include <conio.h>
#include <cmath>

using namespace std;

long double a,a1,p,p1,q,q1,d,x1,x2;

int main()
{
    while (bool i = 1)
    {
	cout << "Programm zur L\x94sung quadratischer Gleichungen der Form"
		 << endl << "a x ^ 2 + b x + c = 0";
	cout << endl
		 << endl
		 << "© 2006 Oliver Sabiniarz"	 
		 << endl
		 << endl << " Geben sie a ein: "
		 << endl << " a = ";
	cin  >> a;//5
	cout << endl
		 << endl << " Geben sie b ein: "
		 << endl << " b = ";
	cin  >> p;//14
	cout << endl
		 << endl << " Geben sie c ein: "
		 << endl << " c = ";
	cin  >> q;//9.8
	a1 = a;//a1=5
	a = a / a1;//a=1
	p1 = p / a1;//p1=2.8
	q1 = q / a1;//q1=1.96
	d = pow((p1 / 2), 2)-q1;//d=0
	if (a1 != 1)//true
	{
	cout 
		 << endl << a1 << " x ^ 2 + " << p << " x + " << q << " = 0  <=>  " << "x ^ 2 + " << p1 << " x + " << q1 << " = 0";//Ausgabe: 5x^2+14x+9.8=0<=>x^2+2.8+1.96=0
	}
	cout << endl <<"Diskriminante = " << d << endl;//Diskriminante = 0
	if (d > 0)
	{
		x1 = -p1 / 2 - sqrt(d);
		x2 = -p1 / 2 + sqrt(d);
		cout << endl <<"x1 = " << x1
	         << endl <<"x2 = " << x2;
	}	
	else if (d==0)
	{	
	    x2 = -p1 / 2 + sqrt(d);
	    cout << endl << "x = " << x2;
	}
	else if (d < 0)
	{
		d=-d;
        cout << endl <<"x1 = " << -p1 / 2 << " + " << sqrt(d) << " i"
             << endl <<"x2 = " << -p1 / 2 << " - " << sqrt(d) << " i";
	}
	cout << endl << endl << "Auf Wiedersehen!" << endl << endl << endl;
	getch();	
	}	
}
 
Hi.

Ich hab dein Programm mal ausprobiert und es wurde als Diskriminante -1.42139e-016 == -1.42139 * 10 ^ -16 == -0.000000000000000142139 berechnet.

Also ein Wert der "fast" 0 ist, aber eben nur fast.

Gleitkommazahlen (double, float) sind immer ungenau. Manche "einfache" gebrochen rationale Zahlen lassen sich mitunter nicht genau als Gleitkommazahl speichern. D.h. wenn du mit Gleitkommazahlen rechnest kannst du nicht erwarten ein genaues Ergebnis zu bekommen. Desweiteren ist es somit eine relativ schlechte Idee bei Gleitkommazahlen auf Gleichheit (z.B. == 0) zu prüfen.

Was man machen kann ist zu prüfen ob eine Gleitommazahl eben "fast" gleich einer anderen ist oder man verwendet eine Bibliothek die mit beliebiger Genauigkeit rechnet.

Gruß
 
Na ja, aber probier mal den Fall mit der oben angegebenen Gleichung, da kommt nämlich genau 0 raus, und trotzdem wird ein falscher wert ausgegeben.
 
moin


Na ja, aber probier mal den Fall mit der oben angegebenen Gleichung, da kommt nämlich genau 0 raus, und trotzdem wird ein falscher wert ausgegeben.
Genau das hat er gemacht! Und er hat ganz genau beschrieben warum der Fehler so auftritt!

Gebe mal ein "(int)" in die Ausgabe ein, also so::
Code:
cout << endl <<"Diskriminante = " << (int)d << endl;//Diskriminante = 0

So wird diese Ungenauigkeit "abgeschnitten".


mfg
umbrasaxum
 
Wenn ich die Diskriminante als Integer speicher, wird das Ergebnis meist ungenauer (unbrauchbar), und das will ich auch nicht. Was kann ich denn machen damit die Genauigkeit erhalten wird, aber solche Fehler nicht auftreten, außer auf ganze Zahlen zu runden? Wie geht das denn mit dem ungefähr 0? MIr wär das mit der "Bibliothek" noch lieber, nur habe ich damit keine Erfahrung. Wie geht das?
Mir ist gerade auch bei VB aufgefallen, das wenn ich 100 mit 99.99 subtrahiere kommt auch nicht 0.01 raus. Es wäre mir lieber gewesen, dass das ein Programmierfehler meinerseits gewesen wäre :(
 
Zuletzt bearbeitet:
DarkSean hat gesagt.:
Wenn ich die Diskriminante als Integer speicher, wird das Ergebnis meist ungenauer (unbrauchbar), und das will ich auch nicht. Was kann ich denn machen damit die Genauigkeit erhalten wird, aber solche Fehler nicht auftreten, außer auf ganze Zahlen zu runden?
Das geht nicht mit den Gleitkommatypen von C++. Das Problem hier ist das schon 9,8 als long double nicht genau gespeichert werden kann.
Code:
cout.precision(20); cout << (9.8l) << endl;
Wenn man mit einer solchen ungenau gespeicherten Zahl rechnet, setzt sich der Fehler der in dieser Zahl steckt fort und vervielfacht sich dementsprechend (je nach Operation).
DarkSean hat gesagt.:
Wie geht das denn mit dem ungefähr 0?
Naja, du brauchst nur zu schauen ob der Absolutwert kleiner als eine ganz kleine Zahl ist. Es gibt einen Wert Epsilon, der angibt wie genau man eine Zahl als Gleitkommazahl speichern kann.
Code:
#include <limits>

cout << numeric_limits<long double>::epsilon() << endl;
DarkSean hat gesagt.:
MIr wär das mit der "Bibliothek" noch lieber, nur habe ich damit keine Erfahrung. Wie geht das?
Vor ein paar Tagen war schonmal ein solches Thema hier im Forum, da ging es um die genaue Berechnung von Pi bis auf einige hundert Stellen genau. Da wurden einige Vorschläge zu Bibliotheken gemacht - MAPM (http://www.tc.umn.edu/~ringx004/mapm-main.html) sollte dafür ganz gut geeignet sein.

Gruß
 
Das gefäält mir schonmal, nur ich bin ein ziemlicher Anfänger im Programmieren und habe wirklich KEINEN Schimmer wie ich das einbauen soll. Wäre nett wenn mir einer eine Schritt-für-Schritt-Beschreibung geben könnte. Ich beherrsche Englisch zwar ziemlich gut, aber um die Seite zu verstehen reicht es dann doch wieder nicht.
Euer recht verzweifelter
Sean
 
Also, als erstes solltest du dir mal die mapm-492.zip Datei runterladen und entpacken. Da gibt's dann eine README Datei - die sollte man lesen. Da steht drin
DOS / Win NT/9x (in a DOS window for NT/9x):

see the file 'README.DOS' for instructions.
In der README.DOS steht dann drin
========================
Microsoft Visual C++ 6.0
========================
run : mkallmsc.bat (builds library + 4 executables)
(Du mußt vorher evtl. VCVARS32.BAT im VC++ \bin Verzeichnis ausführen)

Damit du die Bibliothek dann in deinem Programm verwenden kannst mußt du einerseits die Header Dateien inkludieren wie es in den Beispielprogrammen die dabei sind vorgemacht ist (dafür mußt du auch das Verzeichnis wo die Header Dateien liegen irgendwo unter Projekt->Einstellungen: C/C++ hinzufügen) und andererseits die Bibliothek selbst unter Projekt->Einstellungen: Linker hinzufügen.

Da ich kein VC++ 6.0 habe kann ich dir das leider nicht genau sagen wie die Einstellungen heißen. Da mußt du einfach nochmal in der Hilfe nachschauen.

Gruß
 
Achso, das ich ich dann wohl verwechselt. Ich war irgendwie davon überzeugt das du VC++ 6.0 geschrieben hattest - war aber wohl ein anderes Thema ;)

Mit Dev-Cpp kann ich dir besser helfen. Als erstes lädst du dir diesmal die Datei für Unix Systeme runter. (http://www.tc.umn.edu/~ringx004/mapm-4.9.2.tar.gz) und entpackst die (z.B. mit 7-zip oder einem anderen fähigen Entpackprogramm)

Ich werde mal annehmen das du Dev-C++ im Standardpfad c:\dev-cpp installiert hast - wenn nicht mußt du das folgende jeweils für deinen Pfad anpassen.

Dann öffnest du eine DOS-Box und setzt erstmal den Pfad damit die Tools von Dev-C++ gefunden werden:
Code:
set PATH=%PATH%;c:\dev-cpp\bin
Dann wechselst du in das Verzeichnis wo du MAPM ausgepackt hast und rufst das Programm make folgendermaßen auf:
Code:
cd c:\build\mapm_4.9.2
make -f makefile.unx
Das sollte dann problemlos durchlaufen und eine Bibliothek "libmapm.a" und ein paar Beispielprogramme erstellen.

Um die Bibliothek zu verwenden mußt du sie nur unter Projekt->Optionen: Parameter: "Bibliothek/Objekt hinzufügen" -> libmapm.a Datei auswählen hinzufügen.

Außerdem mußt du wie gesagt noch die Header Dateien einbinden. Dazu kannst du entweder die .h Dateien vom MAPM Verzeichnis in dein Projektverzeichnis kopieren, oder du fügst das MAPM Verzeichnis unter Projekt->Optionen: Verzeichnisse: Include Verzeichnisse hinzu.

Gruß
 
Zurück