Ich möchte Festkomma-arithmetik auf einen µC implementieren. Die Umwandlung float nach fix und vice versa erfolgt über folgendende Makros: #define TOFIX(d, q) ((unsigned short)( (d)*(float)(1<<(q)) )) #define TOFLT(a, q) ( (float)(a) / (float)(1<<(q))) q gibt also die Nachkommastelle an. Eine Zahl soll als 16Bit gespeichert werden (unsigned short). Wenn ich z.b. für q = 4 einsetze bleiben also 12Bit zur Darstellung der restlichen Zahl. Jedoch ist die Rechnung selbst bei einfacher Addition sehr ungenau.Beispielsweise die Addition folgender 2er Zahlen: float d1 = 108.2f; float d2 = 200.4f; int q = 4; unsinged short f1 = TOFIX(d1,q); unsinged short f2 = TOFIX(d2,q); unsigned short f3 = f1 + f2; float flt1 = TOFLT(f3,q); printf("converted float value:%f\n",flt1); Konvertiert nach float ergibt 308.562500 statt den erwarteten 308.6. Selbst für q = 7 bekomme ich nicht den erwarteten Wert(wird natürlich genauer). Ist der Fehler bei Festkommaarithmetik üblich? Und wenn ja, wie kann ich am besten die Fehlergenauigkeit bei gegebener Nachkommastelle berechnen, z.b. für q =1,2,3... Wenn ich nun statt um q Bit zu schieben, den float Wert um 10 multipliziere und das Ergebnis der Addition wieder dividiere, erhalte ich den erwarteten Wert: 1082+2004=3086 -> 3086/10= 308,6 Intuitiv hätte ich erwartet, das das schieben um 4 bzw 7Bit genauer ist als nur 1 Kommastelle zu verschieben. Irgendwo habe ich hier einen Denkfehler ;-(
Überleg' Dir doch mal, welchen Wert jedes der 4 Bits der Nachkommastellen darstellt. Da gibt es Halbe, Viertel, Achtel und Sechzehntel. Das erklärt den Nachkommawert von 0.5625, das sind 9/16.
> Ist der Fehler bei Festkommaarithmetik üblich?
Nein. Aber Du machst keine Festkommaarithmetik sondern Rundungsfehler,
und da ist das normal.
Kevin schrieb: > 308.562500 statt den erwarteten 308.6. Es ist genauer. Mit q=4 sind bei TOFLT Resultate im 1/16 Raster möglich, also 308.5, 308.5625, 308.625, ... TOFIT rundet nicht, darum bekommst du 308.5625 als Ergebnis und nicht das nähere 308.625. LG, Sebastian
Zähle bitte alle Sechzehntel hier dezimal auf.
:
Bearbeitet durch User
Kevin schrieb: > Ich möchte Festkomma-arithmetik auf einen µC implementieren. Wozu soll das Ganze gut sein? Kevin schrieb: > Irgendwo habe ich hier einen Denkfehler Vielleicht erst mal das eigentliche Problem bzw. Ziel dar- stellen bevor hier wieder gegen Windmühlen gekämpft wird.
Kevin schrieb: > Wieso ergibt 4 Bits 9/16? <seufz> 4 Nachkomma-Bits ergeben eine Wertigkeit von 1/16 je Bit
Ähm ... also ich würde mal sagen, dass das schon Festkomma-Arithmetik ist. Ist halt Festkomma-Arithmetik im Binär-System. Und ja, in der Binär-System-Festkomma-Arithmetik ist das ein übliches Problem. Klar, es ist ein Rundungs-Problem, aber genauer gesagt würde ich es als Genauigkeits-Problem bezeichnen. Die 4 Nachkomma-Bits können nicht jede beliebige Dezimal-Zahl Nachkommastelle darstellen. Alleine von 0,0 - 0,9 gibt es nur die 0,0 und die 0,5, die wirklich genau nach Binär-Festkomma umgewandelt werden können. Insgesamt gibt es bei 4 Bit naturgemäß nur 16 exakt darstellbare dezimale Nachkomma-Zahlen. (Alle Kombinationen von 0,5 0,25 0,125 0,0625 und die 0) Float hat im übrigen das gleiche Problem. Es tritt nur eben nicht so schnell auf, weil bei Float die Genauigkeit flexibler gehandhabt wird. Sprich, bei kleinen Zahlen kann Float genauer sein, als bei sehr hohen Zahlen. Und trotzdem gibt es auch Dezimalzahlen mit 2 Nachkomma-Stellen, wo Float bei wiederholten Rechnungen in Ungenauigkeiten läuft. Eine andere Alternative wäre, die Festkomma-Arithmetik mit BCD-Zahlen (Binary Coded Decimal) zu machen. Dann gibt es bei der Genauigkeit keinen Unterschied mehr zur dezimalen Festkomma-Arithmetik. Allerdings ist dann die Umwandlung nach Float nicht mehr so einfach und auch die Operatoren funktionieren so nicht mehr (in standard C jedenfalls). In C++ könnte man die entsprechend überladen. Aber wie schon erwähnt, wenn man nicht genau weiß, was die Zielsetzung ist, stochert man im Trüben.
MagIO2 schrieb: > Ähm ... also ich würde mal sagen, dass das schon Festkomma-Arithmetik > ist. Ist halt Festkomma-Arithmetik im Binär-System. Das ist doch Geschwurbel. Ist doch klar, dass wir hier vom Binärsystem reden. Was denn sonst? Von BCD war nie die Rede. Ich möchte behaupten, der TO kennt weder Festkomma noch BCD wirklich.
Beitrag #6725044 wurde von einem Moderator gelöscht.
Moin, die Vorredner haben die Problematik ja gut erklärt, mehr ist unter diesen Umständen nicht rauszuholen. Solltest Du allerdings meistens mit einer Nachkommastelle arbeiten, wäre statt des Shifts um 4 ein Teilen bzw. Multiplizieren mit 10 eine Lösung. Oder mit einer anderen Zahl, die Deine Vorstellung von Genauigkeit besser trifft. 50 z.B. würde 0,02 als Auflösung liefern... Gruß Jens
MagIO2 schrieb: > Es tritt nur eben nicht so schnell auf, weil bei Float die Genauigkeit > flexibler gehandhabt wird. Sprich, bei kleinen Zahlen kann Float genauer > sein, als bei sehr hohen Zahlen. Die relative Genauigkeit wird durch die Anzahl der Bits in der Mantisse bestimmt und ist auch bei Float für kleine und große Zahlen gleich. Böse wird es bei der Addition/Subtraktion von stark unterschiedlichen Float Zahlen, weil die Operanden vor der Rechenoperation auf den gleichen Exponent gebracht werden müssen.
Andreas S. schrieb: > MagIO2 schrieb: >> Ähm ... also ich würde mal sagen, dass das schon Festkomma-Arithmetik >> ist. Ist halt Festkomma-Arithmetik im Binär-System. > > Das ist doch Geschwurbel. Ist doch klar, dass wir hier vom Binärsystem > reden. Was denn sonst? Von BCD war nie die Rede. Ich möchte behaupten, > der TO kennt weder Festkomma noch BCD wirklich. Sorry .. hab vergessen das in den richtigen Bezug zu setzen: g457 schrieb: > Nein. Aber Du machst keine Festkommaarithmetik sondern Rundungsfehler, > und da ist das normal. Dachte, dass g457 möglicherweise die Festkomma-Arithmetik im Binär-System nicht erkannt hat. ;o)
Ich arbeite immer auch mit Festkomma Arithemtik. Der ADC hat vielleicht 16-20Bit, und dann kommt oft ein Regler hinten dran. Der rechnet immer in 32bit Ganzzahl. Irgendwo benoetige ich dann eine skalierung. zB ein Thermoelement an einem 20 Bit Wandler. Der Benutzer moechte Celsius eingebem, der Regler rechnet in hardware Werten, vom ADC her. Ein ADC Wert von vielleicht 72623 waeren zB 279 Grad. Ich moechte zB eine Aufloesung der Konstanten von vielleicht 1/1000 haben, also 4 Stellen. Die division (62623/279) ergibt 260.297. So waehle ich meine Konstante als 1041, mit implizit div 4. Das ergibt dann bei 1040-> 279.31, resp 1041->279.05 Grad, Etwa 0.3 Grad bei 300Grad. Der Benutzer gibt seine 279 Grad als Vorgabewert ein und der Kalibriertwert 1040 als Multiplikator gefolgt von den Div 4 ergibt des Vorgabewert fuer den ADC.
MagIO2 schrieb: > Ähm ... also ich würde mal sagen, dass das schon Festkomma-Arithmetik > ist. Ist halt Festkomma-Arithmetik im Binär-System. Und ja, in der > Binär-System-Festkomma-Arithmetik ist das ein übliches Problem. Das "Problem" existiert ebenso im Dezimalsystem. Wenn mein Thermometer 21°C anzeigt muss ich ebenso davon ausgehen, dass das nicht die wirkliche Temperatur ist. Es könnte genau so gut 21,34°C sein, aber das Thermometer kann nur in 1° Schritten anzeigen.
> aber das Thermometer kann nur in 1° Schritten anzeigen.
Schon seit droellfzig Jahren schaffen es dickethale Thermometer
auch die Zehntel aufzuloesen. Ob die stimmen lassen wir mal
dahingestellt.
Stammt das vllt aus Wehrmachtsbestaenden?
Schwaetzer schrieb: > Schon seit droellfzig Jahren schaffen es dickethale Thermometer > auch die Zehntel aufzuloesen. Ob die stimmen lassen wir mal > dahingestellt. Das ändert nichts am Sachverhalt. Dann zeigt es halt 21,0°C an und ich muss damit rechnen, dass es in Wirklichkeit 21,0451353464213°C gemessen hat.
Schwaetzer schrieb: > Schon seit droellfzig Jahren schaffen es dickethale Thermometer > auch die Zehntel aufzuloesen. Nimm einen DS18B20. Der löst nicht Zehntel auf, sondern 1/16 Grad auf. Wenn du die Werte als 1/10 Grad darstellst, sehen Temperaturverläufe trotz der höheren Auflösung sehr merkwürdig aus.
Kevin schrieb: > Ich möchte Festkomma-arithmetik auf einen µC implementieren. Die > Umwandlung float nach fix und vice versa.... Wo zu eigentlich dies hin und her Gehample?
Stefan ⛄ F. schrieb: > Das "Problem" existiert ebenso im Dezimalsystem. Das "Problem" existiert in jedem Zahlensystem, egal ob die Basis jetzt 2 oder 10 ... oder (warum nicht?) 5 ist.
Andreas S. schrieb: > Das "Problem" existiert in jedem Zahlensystem, Ja, das ist der Punkt auf den ich hinaus wollte.
Kevin schrieb: > Wieso ergibt 4 Bits 9/16? 4 Bit nach dem Komma bedeuten, dass du deine Werte mit einer Schrittweite von 1/16 angeben kannst. Was dich vielleicht verwirrt: Eine Zahl, die in Dezimal sehr einfach aussieht, wie 0,6, muss im Dualsystem nicht genauso einfach sein. Tatsächlich ist 0,6 im Dualsystem eine periodische Zahl. 0,6 = 1/2 + 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + … Oder wenn man es direkt als duale Kommazahl schreiben würde: 0,1001100110011001100… Wie du siehst, kannst du mit 4 Bit nur die ersten beiden der Summanden darstellen, der Rest geht verloren. Schwaetzer schrieb: > Schon seit droellfzig Jahren schaffen es dickethale Thermometer Das ist genau die Art von Aufsatz, unter die der Lehrer dann "Thema verfehlt" schreibt.
Mir ist diese Festkomma Umrechnung viel zu kompliziert. In meinen Programmen verschiebe ich einfach nur das Komma. Temperaturen werden intern in 10tel-Grad gespeichert. Da reicht die Genauigkeit, die Umwandlung ist einfach un schnell, und selbst ein Mensch kann mit den Rohwerten etwas anfangen. Spannungen speichere ich in in Millivolt. Genauer ist der AD-Wandler oft nicht, und bei uin16_t habe ich noch einen Bereich bis 65 Volt. Und für Berechnungen brauche ich keine Macros, die über float gehen und auf einem Arm-M0 wegen fehlender FP-Einheit noch simuliert werden müssen.
PittyJ schrieb: > In meinen Programmen verschiebe ich einfach nur das Komma. > Temperaturen werden intern in 10tel-Grad gespeichert. Viel Spaß, wenn die Werte aus einem DS18B20 stammen. Jede vernünftige Auswertung von Temperaturänderungen wird damit dann zur Farce, wenn man sich nicht gerade auf "so um ± 0.2" beschränkt.
Wolfgang schrieb: > Viel Spaß, wenn Er schrieb "gespeichert" nicht angezeigt. Evtl. will man damit ja auch noch a wengerl rum rechnen.
Teo schrieb: > Er schrieb "gespeichert" nicht angezeigt. Eben - und wenn jemand mit den gespeichert Werten irgendetwas tut, z.B. einen Verlauf graphisch darstellen, sieht er den Salat. Dann meint er, plötzlich ungleichmäßige Temperaturänderungen zu haben, obwohl der Verlauf eigentlich völlig gleichmäßig war.
PittyJ schrieb: > Mir ist diese Festkomma Umrechnung viel zu kompliziert. > In meinen Programmen verschiebe ich einfach nur das Komma. Das hatte ich auch im Anfangsthread erwähnt. Einfach um 10,100,1000... multiplizieren. Wenn man den un-skalierten Wert haben möchte entsprechend dividieren.Viel einfacher als Festkomma und genauer.Darum wundere ich mich schon, das Festkomma-Rechnungen so verbreitet sind. Man könnte nun für bessere Genauigkeit einen 32Bit Wert reservieren d.h. 16Bit für Ganzzahl und 16Bit für die Nachkommastelle. Aber ich möchte auch Werte miteinander multiplizieren. Und 64Bit stehen nicht zur Verfügung als Wortlänge. Leider weiß ich nicht wie ich Überlaufe dann handeln soll.So die Idee mich auf 2Byte zu beschränken,mit 4Bit als Nachkomma und 12Bit für die Ganzzahl.
Kevin schrieb: > Das hatte ich auch im Anfangsthread erwähnt. Einfach um 10,100,1000... > multiplizieren. Wenn man den un-skalierten Wert haben möchte > entsprechend dividieren.Viel einfacher als Festkomma und genauer. Das IST Festkommaarithmetik! Niemand sagt, daß man mit 1/2^n Auflösung arbeiten MUSS!!
Falk B. schrieb: > Kevin schrieb: >> Das hatte ich auch im Anfangsthread erwähnt. Einfach um 10,100,1000... >> multiplizieren. Wenn man den un-skalierten Wert haben möchte >> entsprechend dividieren.Viel einfacher als Festkomma und genauer. > > Das IST Festkommaarithmetik! Niemand sagt, daß man mit 1/2^n > Auflösung arbeiten MUSS!! Es ist aber weit verbreitet, vermutlich um shiften zu können.
Kevin schrieb: > Einfach um 10,100,1000... > multiplizieren. Wenn man den un-skalierten Wert haben möchte > entsprechend dividieren.Viel einfacher als Festkomma und genauer.Darum > wundere ich mich schon, das Festkomma-Rechnungen so verbreitet sind. Weil früher generell und heute auch noch je nach Mikrocontroller Multiplikation und insbesondere Division sehr langsame Operationen waren. Shiften war sehr viel schneller aber halt nur mit Zweierpotenzen möglich. Heutzutage sind Mikrocontroller allgemein viel schneller und Multiplikation meistens genau so schnell wie Shiften.
Kevin schrieb: > Das hatte ich auch im Anfangsthread erwähnt. Einfach um 10,100,1000... > multiplizieren. Wenn man den un-skalierten Wert haben möchte > entsprechend dividieren.Viel einfacher als Festkomma und genauer. "Genauer" ist es dann (und NUR dann), wenn es einzig darum geht, diesen einen Wert später zu einer dezimalen Anzeige zu verwursten. > Darum > wundere ich mich schon, das Festkomma-Rechnungen so verbreitet sind. Weil es immer DANN genauer wird, wenn man mit dem Kram irgendwas rechnen muss. Gerechnet wird nämlich im Binärsystem (Ausnahme: BCD-Arithmetik). Und gerechnet wird in vielen Anwendungen. Regler, digitale Filter usw. usf. > Man könnte nun für bessere Genauigkeit einen 32Bit Wert reservieren Natürlich, umso mehr Bits, umso genau wird's. Aber auch umso langsamer. Spätestens, wenn man den Datenbereich der nativen Typen des Zielsystems verlassen muss, um eine hinreichende Genauigkeit für die konkrete Anwendung zu erzielen. Und blöderweise ist es ausgerechnet dort, wo gerechnet werden muss oft auch so, dass die Rechnerei ziemlich flott sein muss, damit die Anwendung noch funktionieren kann. Bei einem Regler nützt es garnix, wenn du den nächsten Stellwert auf dreißig Stellen nach dem Komma ausrechnest, wenn der Aktor überhaupt nur mit 12 Bit angesteuert werden kann. Was aber u.U. viel nützt, ist wenn das Ergebnis dieser Berechnung 20000mal pro Sekunde zu verfügung steht und nicht nur alle zwei Sekunden. Genau sowas ist der Anwendungsbereich von Ganzzahl-Arithmetik. > 16Bit für Ganzzahl und 16Bit für die Nachkommastelle. Aber ich möchte > auch Werte miteinander multiplizieren. Und 64Bit stehen nicht zur > Verfügung als Wortlänge. Dann muss man halt diese Möglichkeit schaffen. Die Grundrechenarten sind easy. > Leider weiß ich nicht wie ich Überlaufe dann > handeln soll Vorzugsweise richtig.
Blechbieger schrieb: > Weil früher generell und heute auch noch je nach Mikrocontroller > Multiplikation und insbesondere Division sehr langsame Operationen > waren. Früher (tm) hat man oft einfach in der Anzeige die LED für den Dezimalpunkt an der passende Stelle aktiviert. Das kostete den µC einen einzigen IO-Zugriff, ganz ohne Multiplikation, Float-Rechnerei oder Binär-Dezimal-Diskussion.
Kevin schrieb: > PittyJ schrieb: >> Mir ist diese Festkomma Umrechnung viel zu kompliziert. >> In meinen Programmen verschiebe ich einfach nur das Komma. > > Das hatte ich auch im Anfangsthread erwähnt. Einfach um 10,100,1000... > multiplizieren. Wenn man den un-skalierten Wert haben möchte > entsprechend dividieren.Viel einfacher als Festkomma und genauer. Es ist nicht einfacher. Ob ich durch 10 oder durch 16 teile, macht theoretisch keinen Unterschied. In der Praxis ist das Teilen durch 16 viel einfacher, weil durch einen simplen Bit-Shift lösbar. Und genauer (besser gesagt höher auflösend) ist es auch nicht, wenn du Werte in einer Schrittweite von 1/10 statt 1/16 speicherst. Im Gegenteil. Und es sind eben einfach andere Werte, die damit exakt darstellbar sind. Bei 1/10 wären deine 0,6 exakt darstellbar, da das ein ganzzahliges Vielfaches von 1/10 ist. Dafür ist bei 1/16 eben z.B. 0,4375 exakt darstellbar, da das ein ganzzahliges Vielfaches von 1/16 ist. Das müsstest du bei 1/10-Schritten auf 0,4 runden. Aber 16 Schritte sind mehr als 10, also ist die Auflösung höher. > So die Idee mich auf 2Byte zu beschränken,mit 4Bit als Nachkomma und > 12Bit für die Ganzzahl. Damit kannst du dann Werte bis maximal 4095,9375 darstellen mit einer Auflösung von 1/16. Würdest du durch 10 teilen, hättest du eben einen Maximalwert von 6553,5, dafür nur noch eine Auflösung von 1/10.
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.