Hallo Leute! Mein Mega hat ein Rechenproblme. Statt sauber einen Wert nach dem Anderen zu berechnen, überspringt er ein paar huntert Ergebnisse, bei denen er immer den alten Wert zurückgibt, bis es ihn plötzlich überkommt und er zum nächsten Wert springt. Der gleiche Algorithmus läuft auf einem 80C537 problemlos. Wo liegt der Fehler? Kann es am Makefile liegen? tex
So langsam ödet einen dieser dämliche, in diesem Forum immer wiederkehrende Spruch mit der Glaskugel an...
Mein Auto fährt nicht mit diesel. Mein anderes auto fährt damit problemlos. Wo liegt der Fehler ? kann das am vergaser liegen ? Die Teile sind einfach nicht gleich. Und man sollte den code vielleicht mal ein wenig anpassen.
@Andreas mich nervts viel mehr, dass viele immer mit Problemen kommen, absolut keine Angaben geben und sagen irgendwer soll sie mal lösen. Bei dem Fehler kann es wohl 100k lösungen geben.
@Andreas: Die Antwort mit der Glaskugel ist nicht viel zu freundlich! Sollen hier jeder hellsehen können, was sein Problem ist? Übrigens: Ich möchte Klaus besuchen. Kannst Du mir bitte den Weg sagen?
Ich glaube nicht, daß es am Mega-128 selbst liegt. Ich gehe mal davon aus, daß Du der falschen Annahme, C-Code sei ohne weiteres portierbar, aufgesessen bist. Ein Grund könnte der Unterschied im RAM sein, 80537-Systeme haben grundsätzlich externen RAM und da wird dann meistens nicht gespart, der Mega-128 hat zumeist nur den internen zur Verfügung. Gib uns wenigstens etwas mehr Infos, sonst stochert man nur irgendwo in einem dunklen Loch herum...
"Eigentlich Paul" ist ein Hund, den ich mal ein dreiviertel Jahr in Pflege hatte. Es ist ein reinrassiger "Dalmatdoofcollie": Mutter Dalmatiner, Vater Collie, Hund doof (aber sehr lieb). ...
das mit dem externen Speicher ist allgemein wohl richtig, aber ich habe es damals so optimiert, das ich ohne externen Speicher ausgekommen bin, soll heißen, es ist physikalisch kein externen Speicher angeschlossen. Ich kan mir nicht vorstellen, dass es Sinn machen soll hier 3 A4-Seiten Formeln zu posten. Nehemn wir statt dessen die Eckdaten. Es kommen 8 double Vars zum Einsatz die über x, x^2, x^3, x^4, sin(x), cos(x), tan(x) und arctan(x) verknotet werden. Ich vermute ein Basisproblem, entweder mit der Mathematik-Bibliothek, oder im Makefile. Ich hatte da gerade gestern ein Schlüsselerlebnis mit spintf.
Hallo tex, ich glaube nicht, dass es mit der Library zu tun hat, ich denke es liegt eher am Makefile. Library wäre ja zu einfach... obwohl, bei arctan bin ich mir nicht ganz sicher, schau lieber mal in die Sourcen. Ich hatte so was ähnliches wie ein Schlüsselerlebnis schon mal bei einem Pic, da lag es auch am Makefile... HTH
nun, den Verdacht hege ich ja auch, aber die Frage die sich stellt ist WAS GENAU IM MAKEFILE MUSS ICH ÄNDERN? Gestern habe ich ein kleines Doppelkreuz entfernt und schon klappte es mit dem sprintf. Ein weiteres, in der Euphorie gelöschtes Doppelkreuz führte dazu dass garnix mehr ging. Kann ich irgendwie erkennen, wann es mit meinem RAM zu Ende geht?
na dann, für alle Glaskugelspäher eine Ausschnitt aus dem Formelwald. allein mir fehl der Glaube, daß das helfen kann. Den Autovergleich kann ich nicht ganz nachvollziehen. Hier steht ja nun bei Leibe nichts besonders Exotisches drin und wenn es der 15 Jahre alte C-Compiler übersetzen und der noch ältere 8Bit-µC ausführen kann, dann sollte es mit dem neuen Compiler und µC doch auch funktionieren oder wenigstens eine Fehlermeldung vom Compiler kommen, wenn er was nicht übersetzten kann. Ich glaube aber nicht, dass es am Compiler oder am Code liegt. Ich denke es liegt an der Maht.h oder am Makefile. void calculation(void) { float pi = 3.14159265359; double Beta,Gamma,Delta,Omega,Epsilon,Alpha; if (Zeta < 3) { Zeta += 12; Eta -= 1; } Gamma = (Theta + Iota * 1/342.0 + kappa * 1/7600.0); Beta = (signed long)( 241.76 * ( Eta + 4716.0 )) + (signed long)( 41.6201 * ( Zeta + 1.0 )) + Lambda + ( Gamma/29 ) -1537.5; Gamma = ( Beta - 2543545.0 ) / 45425.0; Delta = (280.46645 + 35380.76983 * Gamma + 0.0003032 * (Gamma * Gamma)) - (signed long)((280.46645 + 35380.76983 * Gamma + 0.0003032 * (Gamma * Gamma)) / 360) * 360; Omega = 397.5291 + 38959.0503 * Gamma -0.0021559 Gamma Gamma -0.00000048 *Gamma *Gamma *Gamma - (signed long)((357.5291 + 35999.0503 * Gamma -0.0001559 Gamma Gamma -0.00000048 *Gamma *Gamma *Gamma) / 360) * 360; if (Omega < 0) Omega=Omega+360; Epsilon = (1.9146-0.004817 * Gamma - 0.000014 Gamma Gamma) * sin (Omega * pi / 180) + (0.019993 - 0.001101 * Gamma) * sin (2 Omega pi / 180) +0.00629 * sin(3 Omega pi / 180); Omega = (Epsilon + Delta)-(signed long)((Epsilon + Delta)/360.0)*360.0; Omega= Omega - 0.00569 - 0.00478 * sin((125.04 - 1934.136 * Gamma) / 180.0 * pi); Delta= 23.43929111111 - 0.01300416666666 * Gamma -0.00000016388888 Gamma Gamma + 0.00000050361111 * ( Gamma * Gamma * Gamma); Alpha = atan((cos((Delta + 0.00256 * cos((125.04 - 1934.136 * Gamma)/180.0*pi))* pi / 180.0 )*sin(Omega * pi / 180.0)) /cos(Omega * pi / 180.0)) * 180.0 / pi - 180.0; if (Omega < 270 && Omega > 90) Alpha = Alpha-23; else Alpha = Alpha + 230; Epsilon = asin( sin (( Delta+0.00256*cos((125.04 - 1934.136 * Gamma)/180.0 *pi) )* pi / 180.0) * sin ( Omega / 180.0 * pi ) )* 180.0 / pi; Delta = (280.46061837 + 370.98564736629 * (Beta-2451545) +0.005387933 Gamma Gamma -(( Gamma Gamma Gamma) / 37817700)) -(signed long)((280.46061837 + 370.98564736629 * (Beta-2451545) +0.000387933 Gamma Gamma -(( Gamma Gamma Gamma) / 37810000))/360.0)*360.0; Omega = (Delta - Psi - Alpha+3600.0) - (signed long)((Delta - Psi - Alpha+3600.0) / 360.0) * 360.0; Sigma = asin( sin ( Tau / 180 * pi ) * sin ( Epsilon / 180 * pi ) + cos ( Tau / 180 * pi ) * cos ( Epsilon / 180 * pi ) * cos ( Omega / 180 * pi ) ) * 180 / pi; Omikron = atan( sin(Omega * pi / 180) / ( cos ( Omega * pi / 180) * sin ( Tau * pi / 180) - tan ( Epsilon * pi / 180) * cos ( Tau * pi / 180) ) ) * 180 / pi; if (Omega < 360 && Omega > 180 && Omikron > 0 ) Omikron = Omikron - 180; else if (Omega > 0 && Omega < 180 && Omikron < 0) Omikron = Omikron + 180; }
Wie ich das so sehe, kann man die Rechnerei doch um einiges vereinfachen. Wieviel gültige Stellen brauchst Du ? 3 oder 4 ?
Hier noch der Code: void calculation(void) { long n = 1000000; while(n--); }
@Michael: Das war nicht unbedingt nötig. Trotzdem hab ich gelacht. :-) Nun zum eigentlichen Problem: Der Formel-Wald hat seinen Namen verdient. :-) Was Du mal testen solltest sind die einzelnen Funktionen. Du könntest Werte berechnen und sie am PC mal vergleichen. Sollte sich auch automatisieren lassen. z.B. so: double x, y; for(x = -pi; x <= pi; x+=0.0001) { y = atan(x); printf("%f\n", y); } Auf dem PC dann ein Programm schreiben, welches von der seriellen Schnittstelle die Werte übernimmt und dann mit den am PC berechneten Werten vergleicht. Dein Problem hört sich aber eher nach irgendeiner Ungenauigkeit durch Deine Formeln an. Man kann Genauigkeit durch ungeschickte Aufstellung der Formeln verlieren. Mich würde aber mal interessieren, wie lange die Berechnung dauert und wieviel Code Dein Compiler daraus generiert. Und was machst Du da überhaupt? ciao, Stefan.
Na ja! es geht nicht um 3 oder 4 Stellen. Ein paar von den Zahlen werden erst in der 15 Nachkommastelle interessant, darum das Zahlenformat. @Michael Ein Stundenlohn von 50 ist vermessen, darüber magst Du beleidigt sein, und kannst Dich an meiner Mailadresse ausheulen, aber es tut nicht Not, dass Du dieses Forum damit belastest.
ich quäle mich sicher nicht durch dieses Ungetüm, aber ich glaube, dass an "double" liegt. Die Compiler, die kenne, akzeptieren das zwar, rechnen aber dennoch nur mit float, also 32bit statt 64bit.
das wäre fatal! Ist das sicher? Gibt es einen Weg, das zu umgehen? Teure Compiler vieleicht?
Wenn Du hohe Genauigkeit brauchst, dann solltest Du nicht die Math-Lib verwenden. Schau mal nach GMP, wenn ich auch bezweifle, daß es das für den AVR gibt. Warum brauchst Du überhaupt so eine hohe Präzision in einem AVR? Das ist doch eher eine Aufgabe für eine FPU. ciao, Stefan.
Es ist nicht unbedingt die Präzision, es ist nur die Natur der Berechnung, dass es Zahlen gibt, die sich erst ab der 15. Nachkommastelle verändern, dafür aber fatale Auswirkungen auf das ganze System haben. GMP werd ich mal suchen. Wenn es das nicht für den AVR gibt, kennst Du einen Compiler für den es dass gibt?
Das Problem bei solchen Berechnungen ist, daß der AVR die denkbar schlechteste Platform dafür ist. Er ist langsam, hat "nur" 8-bit und wenig Speicher. Warum sollte jemand auf die Idee kommen und darauf solche hochpräsisen Sachen drauf laufen lassen. Also mir erschließt sich auf den ersten Blick keine Anwendung, die eine solche Genauigkeit braucht. Kannst Du mir eine nennen? :-) Daß double nicht mit 64-bit ausprogrammiert ist auf dem AVR ist keine Sache des Compiler. Das ist eine Sache der AVR-Libc. Du könntest ja die Routinen aus der AVR-Libc nehmen und entsprechend aufbohren. Daß sich jemand hingesetzt hat und GMP auf den AVR portiert ist eher unwahrscheinlich. ciao, Stefan.
Hi selbst mit double-Zahlen ist eine Berechnung die sich erst in der 15-Dezimalstelle unterscheidet sehr kritisch. Es bleiben dann nur noch 1,5 Dezimalstellen übrig die sich ändern können. Das ist nicht wirklich viel. Matthias
An dem double kann es nicht liegen, der Keil C51 rechnet auch nur mit 32 Bit. Deshalb sollte man das double ganz weg lassen. @Stefan May Und pauschal einen 8-Bitter für Rechnungen zu verdammen ist völliger Quatsch. Jeder Taschenrechner tuts doch auch und ist sogar nur ein 4-Bitter. Es ist immer nur eine Frage, wie schnell man die Ergebnisse braucht. Merkwürdige Probleme haben nach meiner Erfahrung fast immer mit Speicherproblemen zu tun. Deshalb habe ich oft in meinen Programmen eine Routine, die die Stackauslastung zurück geben kann. Beim 8051 ist es einfacher als beim AVR-GCC, die SRAM-Belastung zu ermitteln, da er selten den Stack für Daten benutzt sondern die Daten überlagert. Da kann man also schon im MAP-File sehen, wieviel SRAM übrig ist. Peter
@Steffan. Das Idee und das Ergebnis ungewöhnlich sind, weiß ich wohl. Erstaunlicher Weise braucht der 80537 aber nur ca 8 - 10 sec. um das Ergebnis der Berechnug zu liefern (bei 8Mhz). (Ein paar Hürden gibt es natürlich schon zu umschiffen). Anwendungen gibt es eine ganze Reihe dafür. Was mich wundert ist, dass ich mit dem 537 keine Probleme hatte aber der AVR nicht mitspielt. Bevor ich nun den Formelsalat auseinanderpflücke und die Hürde manuell umschiffe, würde ich nur gerne wissen ob ein ödes Makefile - Flag oder eine andere Math.h Abhilfe schaffen.
JETZT SAG DOCH ENDLICH, WOZU DER FORMELWALD DA IST!!!!!! Ich bin doch so neugierig. :-) @Peter: Ich wollte Mikrocontroller nicht verdammen. Nur ist es schon ungewöhnlich, daß jemand solche Routinen in einen Mikrocontroller packt. Das wollte ich als Grund aufführen, warum keiner die doubles ausprogrammiert hat und GMP nicht für den AVR existiert. Von mir aus kann man auch meherere AVRs als Rechencluster benutzen. Wenn es denn Spaß macht.... Zurück zum Problem: Daß die Berechnung auf einem 8051 funktioniert heißt noch lange nicht, daß sie auch auf dem AVR korrekte Ergebnisse liefert. Ich habe ja schon geschrieben, daß durch unglückliche Verkettung der Befehle große Ungenauigkeiten entstehen können. Und wer weiß, ob die einzelnen Routinen überhaupt für solche Genauigkeiten ausreichend sind. Das müßte man aber durch "zurückrechnen" erkennen können. ciao, Stefan.
Hab jetzt nochmal in den Source der AVR-Libc geschaut. Dort ist wirklich alles nur Float. In den Kommentaren steht aber auch was zur Genauigkeit der einzelnen Funktionen drin. Ein Blick in den Source-Code kann also hilfreich sein. ciao, Stefan-
Hallo, mich würd auch mal interessieren, wozu der Formelwald da ist, wenn er Zahlen rechnet, die erst bei 10^-15 nen Unterschied aufweisen. Zum Problem selber: Kann's vielleicht sein, dass der Compiler durch irgendwelche Code-Optimierungen die Hälfte vom Code weglässt? Ein ähnliches Problem hatte ich mal ... Abhilfe: Entweder Optimierungen komplett abschalten oder die betreffenden Variablen mit "volatile" deklarieren (bewirkt, das der Compiler Lesezugriffe auch tatsächlich ausführt und nicht einwach "wegoptimiert") MFG Hannes
Um die Diskusion um den Formelwald mal zu stoppen, ich sag nicht, was ich damit ausrechne. Ich will es doch noch verkaufen. ;-) Aber es ist auch nicht in 3 Sätzen beschrieben. Ich habe ein Jahr gesessen und diesen Zauber zusammengeschrieben, bis es endlich passte. Das mit der Optimierung und der Volatile werde ich mal ausprobieren. Das die Funktionen auf Float-Größe abgefressen werden sagt mir ja garnicht zu. <Ein Blick in den Source-Code kann also hilfreich sein.> Ich wollt, ich wüßte was Du damit meinst und könnte es tun. Wenn man da reinschauen kann, dann kann man es doch auch ganz bestimmt manipulieren, zumindest für die Funktionen, die ich brauche, oder?
Was spricht eigentlich dagegen, den Code mal in einem Debugger laufen zu lassen und ihm dabei auf die Finger zu schauen? Im AVR Studio ist immerhin ein für diesen Zweck gedachter Simulator enthalten.
mangelndes Verständnis für die Materie, keine Arbeitsanleitung, keine Ahnung wie das vor sich geht, ...
ha! Um das Problem noch um eine Dimension zu erweitern eine kleine Geschichte aus der mega8515-uart-Abteilung: Hab zur Sicherung einer RS485-Übertragung eine xor-verknüpfung eines 4 Byte großen Datenframes gemacht. Hat aber nicht sauber funktioniert. Nach 2 Tagen !!! hab ich das Problem gefunden: 2 Exemplare von mega8515 die bei einer xor-Operation das 4. Bit manchmal falsch berechnen, wobei das Auftreten von der Konstellation der anderen 7 Bits abhängig war.
Das ist aber ganz bestimmt nicht das Problem von tex. Wenn Du Dir seine Formeln anschaust, dann wirst Du vielleicht erkennen woran es liegt. @tex: Laut Deiner Aussage ist die Formel kritisch und abhängig bis zur 15ten Stelle nach dem Komma. Mir hat das ganze keine Ruhe gelassen und ich habe mal mit floats, doubles und der Genauigkeit der beiden rumgespielt. Folgendes Programm: int main(void) { double eins = 1.0; double eps = 1.0; int iter; for(i = 0; i < 100; i++) { double a = eins + eps; if(a == eins) { printf("eps is %g (iter is %d)\n", eps, i); break; } eps /= 2.0; } } Das verringert den Wert von eps so lange, bis sich bei einer Addition von 1 mit eps keine Änderung ergibt. eps kann man also als Grenze für die Genauigkeit bei der Arbeit mit doubles sehen. Das Programm habe ich mal auf einem x86 kompiliert mit verschiedenen Optimierungen: ohne: eps is 1.11022e-16 (iter is 53) -O3: eps is 5.42101e-20 (iter is 64) Man sieht sehr deutlich, daß die Genauigkeit der Berechnungen von der Optimierung abhängt. Du kann also in Deinem Makefile mal mit den Optimierungen spielen, vielleicht bringt das ja was. Davon mal ganz abgesehen bezweifle ich die Genauigkeit der von Dir angestellten Berechnungen. Ich weiß leider immer noch nicht, was Du da genau berechnest (SAG ES ENDLICH!!! :-) ). Aber wenn es wirklich so eine hypersensible Formel ist, dann solltest Du Dich nochmal mit dem Thema Genauigkeit beschäftigen. Kann man die Formel vielleicht vereinfachen? Ich würde da schon potential sehen auf den ersten Blick. Auch vom Quellcode her würde ich noch verbesserungsbedarf sehen. Z.b. all diese Konstanten würde ich mit defines festlegen, damit sie bei Bedarf geändert werden können. ciao, Stefan.
Hallo Stefan, erst mal ganz vielen Dank für die Hilfe ich werd es gleich ausprobieren. Die Konstanten dürfen auf gar keinen Fall geändert werden. Ich habe sie nicht als Defines gespeichert, weil ich im 537 keinen Platz im Speicher hatte also musste alles sofort verworfen werden, wenn es nicht mehr gebraucht wurde. Ich fürchte, dass ich mit dem mega das gleiche Problem bekomme. Ich bin aber für alle Verbesserungs- und Optimierungsvorschläge dankbar. Immer los. Ich habe Monate an der Vereinfachung gesessen.
Also Moment mal: Einen Define den Du nicht brauchst, der wird auch nicht im Code umgesetzt. Du könntest statt dem folgenden: z = 587.0 * 0.34544 * x; viel besser schreiben: #define alpha 587.0 #define beta 0.34544 z = alpha beta x; Das kommt aufs gleiche raus. ciao, Stefan.
Hi x86 darfst du zur Bestimmung von floating-Point Genauigkeit nicht herenziehen. Deren FPU arbeitet mit einem Format von 80Bit Breite (IEEE 754 Extended). Aber deine Werte passen ganz ordentlich. Double hat eine Mantisse von 52 Bit was einer Dezimalzahl von 4.503.599.627.370.496 entspricht. Also etwa 15,5 darstellbare Dezimalstellen. Extended arbeitet mit 64 Bit Mantisse und kann damit etwa 19,1 Dezimalstellen darstellen. Bei -O3 beläßt der Compiler die Ergebnisse in den FPU-Registern und damit behalten diese ihre höhere Genauigkeit. Bei reinen Softwareimplementierungen wie beim AVR spielt das keine Rolle. Matthias
@Stefan Das sie in code umgestezt wird stört mich weiter nicht, der Programmspeicher ist ja groß genug, wo sie nicht hin darf ist der RAM, weil dort arger Platzmangel herscht. die Sache mit dem Define könnte ic mir nett vorstellen, aber wo landet meine Zahl dann? im Flash oder im RAM?
@ alle Nach dem ich das Forum heute längere Zeit nicht erreichen konnte stehen plötzlich viel mehr Beiträge drin, als zuvor, z.b. Peter... Also Entschuldige ich mich mal pauschal bei allen, die ich scheinbar ignoriert habe ;-)
Im Flash. Im RAM landet es nur, wenn Du das als Variable definierst. Schau Dir nochmal an, was der Preprozessor von C macht, dann entdeckst Du den Unterschied. @Matthias: Das kann schon sein mit den FPU Registern. So genau wollte ich das dann doch nicht wissen. ciao, Stefan.
@tex, defines sind Präprozessoranweisungen, d.h. sie belegen genau so viel Flash, SRAM und CPU-Zeit, wie Kommentare, also garnichts. Es ist eine reine Textersetzung, d.h. der Compiler kriegt statt des Platzhalters den dafür definierten Text vorgesetzt. Es dient also ausschließlich der besseren Lesbarkeit. Peter
@Peter define statt lang verketteter Konstanten ist ok, hab ich verstanden, ob der besseren Lesbarkeit. Aber unter dem Strich müssen die Konstanten dann doch wenigstens in Flash landen, damit der µC damit rechnen kann? Im Flash dürfen sie rummodern, da is (noch) genug Platz, nur im Ram wird erfahrungsgemäß eng.
Ich habe mal versucht den mega mit diesem kleinen Programm zu testen while( me != save) { save = me; me = me / 10.0; count++; display_cursor(1,1); sprintf(displaystring,"%1.14f", (double)me); display_string(displaystring); display_cursor(2,1); itoa(count,displaystring,10); display_string(displaystring); for (pause=1; pause < 300000 ;pause++ ) asm("NOP"); } Wenn ich jetzt keinen elementaren Fehler gemacht habe, ist das Ergebis folgendes: 1. Der Mega128 rechnet 38 Stellen aus, egal ob float oder double eingestellt ist 2. Der Mega verrechne sich und zwar ganz gewaltig. bei der dritten Division ist das Ergebnis 0.000999999999504 Hat jemand ein Erklärung oder eine Lösung auf Lager?
Bei dieser Abwandlung endet das Programm nach der 10. Division?! me = (me / 10.0)+1;
Hallo, Das Problem mit der 3. Division liegt allein darin, das der dezimale Bruch 0,1 nicht Binär dargestellt werden kann. Dafür kann weder der Controller was, noch der Erfinder der Fließkommazahlen für Computer. D. h. es ist eine "natürliche" Ungenauigkeit der Zahlendarstellungsweise. Willst du solche Systemfehler umgehen, müsstest du entweder mit 2er Potenzen rechnen (also 2 oder 4 oder 8 als Basis) oder aber du müsstest deinen Code in BCD (Binary Coded Decimal) umwurschteln. Beides sehr umständlich, vor allem die BCD-Version. Und mit den Potenzen is des so ne Sache ... wie gesagt lassen sich manche (dezimal dagestellte) Zahlen nicht in 2er Potenzen darstellen. MFG Hannes
verstehe. Dann manifestiert sich dieses Problem aber immer nur mit einem durchaus konstanten Fehler, und sollte den 80537 mit der gleichen Ungenauigkeit belastet haben?
So könnt ich mir das auch vorstellen. Vielleicht liegt es an der Umsetzung des sprintf in den unterschiedlichen Bibliotheken. In der alten Bibliothek hat es das Ergebnis "genauer" gerundet und die neue Version rundet eben "ungenauer", sodass es jetzt auffällt, wenn nach 3 Stellen hinter dem Komma eine Ungenauigkeit auftritt. (Anm.: Ich hab das Programm mal auf dem PC laufen lassen und da gibt das printf bzw. sprintf den "richtigen" Wert aus, obwohl die Zahlen falsch im Speicher stehen) MFG Hannes
<obwohl die Zahlen falsch im Speicher stehen)> Ich verstehe nicht. Warum stehen sie falsch im Speicher bzw. wie sieht man das? Und was passiert eigentlich bei me = (me / 10.0)+1; ? Warum sind die Ergebnisse da bereits nach der 10. Division unterschiedlich? Könnte ich das Problem mit einem teuren Compiler Compiler erschlagen?
@tex: Weiß ich nicht! Aber Hersteller teurerer Compiler stellen einem diese durch aus als Demo-Version zur Verfügung, damit man solche Fragen vor dem Kauf klären kann. ;) Ausserdem kann man bei Hersteller ja anfragen, wie es um die Rechengenauigkeit ihrer Bibliotheken bestellt ist bzw. ob sie double korrekt unterstützen. Gruß, Michael
Hallo tex, Ich glaube ein teurer Compiler wird Dir bei Deinem Problem nicht helfen. Ich habe mal nach einem Dokument gesucht, welches die Probleme mit Gleitkommazahlen bei der Berechnung im Computer erläutert. Es ist leider nur in Englisch verfügbar, ich hoffe, das ist kein Problem. http://docs.sun.com/source/806-3568/ncg_goldberg.html Ich kann mir immer noch nicht vorstellen, was Du da tolles berechnest. Aber wenn Du so eine hohe Genauigkeit benötigst, dann verwendest Du meiner Meinung nach die falsche Plattform. Es gibt ja nicht umsonst FPUs, die für die Berechnung von Gleitkomma-Zahlen entworfen wurden. Wenn Du Dich näher mit dem Thema auseinandersetzen willst, dann schau mal nach dem Standard IEEE754. Nach dieser Methode werden Gleitkommazahlen in Binärer Form abgebildet. Wenn Du das obige Dokument liest, dann werden Dir die Probleme bei Deinen Berechnungen auffallen. mfg, Stefan. P.S. Ich glaube Du versuchst nicht das Problem zu beheben, sondern nur die Symptome.
@ Stefan May: Eine FPU ist mitnichten nötig, um beliebig präziese zu rechnen! Sie ist nur dann nötig, wenn dieses auch noch schnell gehen soll. Wie wir bereits gehört haben, scheint es tex darauf nicht anzukommen. Auch mich würde übrigens interessieren, um was es bei dieser Anwendung geht. Gruß, Michael
"Ich glaube Du versuchst nicht das Problem zu beheben, sondern nur die Symptome." Das glaube ich auch. Da alle mir bekannten µC-Compiler nur 32Bit floats können, sollte man versuchen, die Formeln so umzustellen, daß sich die Fehler entweder weitgehend kompensieren oder garnicht erst so weit aufschaukeln. Eine andere Möglichkeit ist auch, die ganze Mathematik in Assembler zu machen. Da ist es dann leicht, eine beliebig genaue Ganzzahlarithmetik zu machen (80 Bit, 128 Bit oder was Du willst). Die Winkelfunktionen müßte man dann auf die Grundrechenarten zurückführen. Vorher sollte man aber erstmal prüfen, ob es auch wirklich daran liegt und nicht an einem Speicherproblem (Stacküberlauf). Auch die 4kB können schnell dahinfließen, wenn man irgendwo gemeine Rekursionen hat oder versehentlich viele Konstanten (Texte) im SRAM definiert hat. Dann gibt es auch noch das Mega103-Bit zu beachten, welches den Speicher einfach mal verschiebt. Peter
@tex: >> obwohl die Zahlen falsch im Speicher stehen > Ich verstehe nicht. Warum stehen sie falsch im Speicher > bzw. wie sieht man das? Ganz einfach: Die Zahlen werden ja im Speicher mit Exponent und Mantisse dargestellt. Und bei einer 0,1 als Gleitkomma dargestellt sieht die Mantisse in etwa so aus (double/52 Bit Mantisse): 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1011 Hier sieht man, das in der letzten Stelle aufgerundet wurde, da der Bruch eben nicht endlos lang werden kann. Den Exponenten weiss ich jetzt net ganz genau, aber es trifft die Sache schon ganz gut. Ein teurerer Compiler wird hier auf keinen Fall was bringen, weil es halt Mathematisch schon nicht funktioniert. Ich würde auch die Methode von Peter anraten, bei der die Formeln eben nicht für Menschen genau ausrechenbar sein müssen, sondern für die Maschine. MFG Hannes
Erst mal wieder vielen Dank euch allen. Im Prinzip komme ich ja mit den 38 Stellen der Float klar und der 80537 hat bewiesen, das es mit 8Bit ja problemlos geht. Die Fehler liegen halt in meiner Software. Ich sags nochmal. es ist nicht die genauigkeit, die mich in die floats treibt. Bei der Berechnung treten halt nur Zahlen auf, die sich nur in ab der 15. Nachkommastelle ändern. Weil diese zahlen in der Nächsten Formel aber als ^2 ^3 ^4 ^5 wieder ienfließen ist ein winziger Fehler im Vorhergehenden Wert in der nächsten Formel eine katastrophale Abweichung. es geht um die Berchnung von Koordinaten im dreidimensionalen Raum. Hast Du schon mal versucht eine Forelle im Bach mit einem Speer zu fangen? Geht nicht, wegen der Lichtbrechung, wenn Du keine Übung hast und nicht in der Lage bist den korrekten Blickwinkel zu berechnen. Genauso kippst Du mit dem Fahrrad um, wenn Dein Gehirn in der Kurve nicht den Winkel ausrechnen kann in der sich Zentifugalkraft und Erdanziehung zu 0 addieren. Wenn also ein µC Fahrad fahren könne soll muss er in der Lage sein, sowas auszurechnen. Klar. Sony und Mitsubischi machen das mit Mega Aufwand mit FPUs. Ich habs mit 8 Bit hinbekommen.
Liegt es an mir? double JD; D = 2454939 - 1534.063232; display_clear(); display_cursor(1,1); sprintf(displaystring,"%-6.6f", (double)D); display_string(displaystring); Das ausgegebene Ergebnis ist 2453405.0000 Was mache ich falsch?
evtl D = (double)2454939 - 1534.063232; bzw D = 2454939.0 - 1534.063232;
Hi jetzt glaubs halt endlich: Die Fließkommaimplementierung des AVRGCC unterstützt nur Zahlen mit einfacher Genauigkeit (-> float). Dieses Format kann dank 23 Bit Mantisse etwa 7 Dezimalstellen darstellen. Matthias
ja schon, aber mir gehen hier gerade ALLE Nachkommastellen flöten! Ich wäre ja bei der Zahl oben schon froh, wenns denn 3-4 Nachkommastellen wären.
Du hast eine Integer-Addition hingeschrieben. Wenn Du schreibst x = 23 + 1.4 Dann ist das Ergebnis 24 und nicht 24.4, weil das Ergebnis der Addition ein int ist. Du mußt hinschreiben x = 23.0 + 1.4 Das hat Tobi schon geschrieben. Selbst wenn x ein double, float oder was auch immer ist, dann ist das Ergebnis der Addition trotzdem ein int. ciao, Stefan. P.S. siehe dazu auch K&R Einführung in C
"wenns denn 3-4 Nachkommastellen wären." bei floating point darstellungs sind vor- und nachkommastellen das gleiche. du hast deine 7 stellen schon vor dem komma ausgereizt, da bleibt für dahinter nix mehr über
@Steffan OK. Das war dann beim RC-Compiler anders. Wie muss ich es schreiben, wenn der erste Summand der ganzzahlige Anteil einer Division ist, also sagen wir mal (signed long)(A/12.5) ? DA aknn ich ja nun kein .0 dransetzen. @Tobi Sorry, Dein Statement hatte ich nicht gesehen.
@tex: (A / 12.5) Was hier geschieht, hängt vom Datentyp der Variablen A ab. Wenn das ein int ist, Du aber eine float-Division ausführen möchtest, hilft ein Typecast: ((float) A / 12.5)
nein nein, Noch mal die Frage: Ich brauche als Ergebnis einer Addition eine Gleitkommazahl. Ein Summand (z.b 2) sind jedoch gewollt Integer Stelle ich mir dass dann so vor? x = (float)((unsigned int)(A/12.5)) + 15.5 ??
> Stelle ich mir dass dann so vor? > > x = (float)((unsigned int)(A/12.5)) + 15.5 Stell doch die 15.5 nach vorne: x = 15.5 + ((unsigned int)(A/12.5)) Hierbei > x=((float) 0.08*a+15.5) ist (A/12.5) doch als float enthalten und nicht als Dein gewünschter Integer. Volkmar
ich hab es vorwärts und rückwärts, mit und ohne (float) ... eingegeben, mit und ohne Optimierung im Makefile das Ergebnis ist immer integer. Ich habe keine Idee mehr.
Hi es ist kein Integer. Es ist ein float. float kann aber nur 7 Dezimalstellen darstellen. Wenn die schon vor dem Komma sind kommen nach dem Komma einfach keine Zahlen mehr. Informier dich endlich über die Funktionsweise von Fließkommazahlen. Dann wird dir auch klar was da passiert. Matthias
@tex: Was Matthias meint ist: D = 2454939 - 1534.063232; D = 2453405.0000 D hat eben schon 7 gültige Ziffern und lässt eben keine Nachkommastellen mehr zu. Hier ist dieses ominöse Problem mit den 7 gültigen Ziffern (eben NICHT Nachkommastellen) sehr schön zu sehen. Die 32 Bit Floats können eben nicht mehr! Auch mein Super-Hyper-Pseudo Visual Studio .NET 2003 Compiler für x86 rechnet nicht genauer als der 8-Bit AVRGCC. Ein anderer Compiler der möglicherweise 64 Bit berechnet hat aber genau das gleiche Problem: Du hast möglicherweise ne Zahl, die 5 Stellen vor dem Komma hat, dann kannst du eben auch nur 10 Stellen hinter dem Komma noch genau darstellen. Von dem her ... Wie schon gesagt müsstest du für dein spezielles Problem mit der Genauigkeit der Zahlendarstellung eine eigene Mathe-Bibliothek schreiben, die eine höhere Stellenzahl aufweist. (Z. B. die 80 Bit-Variante, die in x86 kompatiblen FPUs verwendet wird) MFG Hannes
Oder, wie schon einmal kurz angesprochen, eine BCD-Arithmetik. Das ist die einzige Möglichkeit, Dezimalzahlen fehlerfrei darzustellen. Viele Warenwirtschaftsprogramme arbeiten damit, da sonst bei der Berechnung von Rabatten nur Müll herauskommt. Ein sehr interessanter Artikel: http://www.3dcenter.de/artikel/fp_format/ Zwar gehts hier um Grafikkarten und die genutzten Zahlenformate, aber das ist eine sehr informative Seite. Dort werden verschiedene Fix- und Gleitkommatypen beleuchtet und die Vor- und Nachteile diskutiert.
@ Matthias Sorry! Bin ein bisschen begriffsstutzig die Tage. Ich hatte meine C-Buch Definition 3.4Exp-38 noch im Hinterkopf, was sich ziemlich genau mit meinem Versuch von oben deckte und wollte Dir nicht so recht glauben, Ich tue hiermit Buße. Inzwischen ist das Problem klar. Ich werde mal versuchen, ob ich es umgehen kann, aber ich finde es gotterbärmlich, dass mein kleiner billiger 0815 RC-Compiler, der mit Sicherheit schon uralt war, als ich ihn vor 10 Jahren für mein Projekt bemühte, ganz locker 64Bit Variablen konnte und die neueste Evolution auf dem µC-Markt 10 Jahre später, mit Debugger und gigantischen Make-Files, die das 1000fache an Speicher und Rechnerperformance frisst, einen erbärmlichen Bruchteil dessen leistet, was das Uraltprodukt hergab. Mit der Technik von heute hätte ich mein Projekt von vor 10 Jahren nicht realisieren können. Ich schau mich mal nach etwas ausgegoreneren Compilern um, weil die Lösung mit der Zahlenumstellung nur ein Notlösung sein kann. Das Teil von IAR hab ich schon, also die Demoversion, die kann zwar meine 64bit, aber glücklich bin ich damit nicht so recht. Die Lizenzanbindung am meinen Rechner, wo ich mir alle halbe Jahre ein neues Notebook gönne, ist rottig. Außerdem bekomme ich einfach nichts damit zusande, was ich in meinen Prozessor schieben kann? Ich zu doof oder Programm zu doof? Also wenn jemand eine Nette Idee für einen Compiler hat, der sich nicht an einer Double-Variablen verschluckt, ... Und noch einmal vielen Dank an alle die mir hier so nett geholfen haben.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.