Mein Typumwandler arbeitet fehlerhaft
-
Ich hab mir eine kleine Klasse geschrieben die brüche bearbeiten soll.
Für diese Klasse habe ich einen Typumwandler geschrieben der double in einen Bruch umwandeln kann.class brueche { private: int m_zaehler; int m_nenner; void kuerzen() { int ggtVar=ggt(m_zaehler,m_nenner); m_zaehler/=ggtVar; m_nenner/=ggtVar; }; public: brueche(int zaehler,int nenner) { m_zaehler=zaehler; m_nenner=nenner; kuerzen(); }; brueche(double zahl) { int temp=(int) zahl; int nenner=10; m_nenner=1; m_zaehler=temp; while(zahl-temp>0) { m_nenner*=nenner; zahl*=10.0; temp=(int) zahl; m_zaehler=temp; }; kuerzen(); cout<<"Ergebniss "<<m_zaehler<<"/"<<m_nenner<<endl; }; }; void main() { double a=1.999; brueche b(a); };Die Funktion ggt befindet sich in eienr extra Datei und ermittelt den größten gemeinsammen Teiler.
Die Funktion soll solange die Zahl*10 nehmen bis hinter dem Komma keine Zahl mehr steht die >0 ist. Das problem das ich habe ist das werte wie 1,25 oder 1,9 richtig berechnet werden aber enige werte wie 1,999 zB eine art endlosschleife auslösen obwohl sie rein logisch funktionieren müsten. Ich popel jetzt schon geraume Zeit dranrum und finde keinen Fehler. Weiß einer vone euch weiter?
-
Dein cast auf int
int temp=(int) zahl;sorgt bei Zahlen <1 dafür, dass temp zu 0 wird und dann bricht deine Schleife nicht mehr ab, weil du immer 0 von zahl abziehst.
while(zahl-temp>0)Edit: Sorry, war Blödsinn, du änderst es ja nochmal innerhalb der Schleife.
-
Nanuq schrieb:
Dein cast auf int
int temp=(int) zahl;sorgt bei Zahlen <1 dafür, dass temp zu 0 wird und dann bricht deine Schleife nicht mehr ab, weil du immer 0 von zahl abziehst.
while(zahl-temp>0)Ne dann müste sie das ja imemr tun, tut sie aber nicht wenn ich zb 1,99 eingebe gibt er correct 199/100 aus, wenn ich aber 1,999, also eine 9 mehr, angebe dann bleibt er scheinbar ewig in der Schleife.
Der cast auf int soll lediglich ausgeben wieviel vor der Klammer ist und die Schleife ausführen solange das Ergebniss größer 0 ist.
Bsp 1.99:
Vor der Schleife nimtm int den Wert 1 an.
Die Schleife startet und schaut 1,99-1.
Durchlauf 1:
Zahl+10=19,9
int nimmt den wert 19 an
Schleife schaut 19,9-19.
usw
am ende ist int 199 und es wird 199,0-199 gerechnet da der wert nichtmehr>0 ist endet die Schleife. wenn ich aber 1,999 angebe, müste theoretisch nur 1e weitere Schleife durchlaufen werden aber die Stopt aus einem mir unerklärlichen Grund nicht. 1,99 gibt 199/100 und 1,909 gibt 1909/1000 aus. Nur 1,999 gibt den Fehler. Besteht die Möglichkeit das er bei 3mal der selben Zahl am ende der Eingabe davon ausgeht das es ne Periodische zahl ist? Also statt wie gemeint 1,999 1, Periode9?
-
Hast Recht, war ein Fehler von mir.
Denke, das liegt an der Ungenauigkeit eines double (15 Stellen Genauigkeit). Wenn du an der 16-ten Nachkommastelle einen Wert != 0 stehen hast (sieht man beim debuggen), ziehst du diese Ungenauigkeit auch bei den folgenden Multiplikationen mit 10 die ganze Zeit mit. Irgendwann wird der Wertebereich von deinem int temp überschritten (wird negativ) und die Schleife bricht nicht mehr ab. Warum das nur manchmal so ist, kann ich dir aber auch nicht sagen.
Schau mal hier, vielleicht hilft das:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-170600.html
-
Mmh das is interessant aber solte die Multiplikation mit 10,0 solche Rechenfehler nich umgehen?
Ne erklärung warum das Programm bei einigen zahlen zu keinem Ergebniss komtm wäre es auf jedenfall, es würde bedeuten das die Zahl nach irgendeienr Multiplikation mit 10,0 einfach einige Stellen mehr hat die sich wie ne Seuche ausbreiten.
Ok habs probiert es scheint tatsächlich eine Rechenungenauigkeit zu sein.
Hab den Typumwandlungskonstruktor so umgeschrieben.int temp=(int) zahl; int nenner=10; double rechner=10.0; double tempzahl=zahl; m_nenner=1; m_zaehler=temp; while(tempzahl-temp>0) { m_nenner*=nenner; tempzahl=zahl*rechner; temp=(int) tempzahl; m_zaehler=temp; rechner=rechner*10,0; };Er verwendet jetzt zum Abgleich eine Kopie der Originalzahl. Und rechnet auch immer bei jeder neuen Runde den Wert komplett neu aus statt ihn imemr *10 zu nehmen.
Danke für den Denkanstoß.
-
Algemein hat das Produkt zweier Zahlen mit jeweils a bzw. b signifikanten Stellen in einem beliebigen Zahlensystem a+b signifikante Stellen. Da Gleitkommazahlen für gewöhnlich intern in Binärdarstellung vorliegen, ist das Ergebnis der Multiplikation mit einer Zahl, die keine Potenz der Basis 2 ist, im allgemeinen nicht exakt, weil Stellen abgeschnitten werden. Statt 10 solltest du daher numeric_limits<double>::radix benutzen, um diese Art von Fehler zu vermeiden.