Hi Leute, ich versuche gerade eine Fixed-Point Bibliothek zu coden. Mein Ansatz ist derzeit, dass ich die float-Werte ins Qm.n-Format formatiere. Sprich ich habe dann m Vorkomma-Bits und n Nachkomma-Bits. Der Faktor, zum Umrechnen der Float Werte in fixe Werte, ist 2^n. Der Exponent des Faktors und die mit dem Faktor verrechente Zahl werden jeweils in einem Integer gespeichert. Der Faktor wird durch den Exponent immer so gewählt, dass die Vorkomma-Stellen gerade so dargestellt werden können. Code ich gerade meinen eigenen Float-Datentype neben dem eigentlichen Datentyp oder ist das Beschriebene Vorgehen richtig ????
:
Verschoben durch Moderator
Also ich würde das wieder als float definieren was Du da machst. Fixed point ist eigentlich Integer wo Du Dir das Komma dazu denkst. Sprich, bei der Textausgabe das Komma einfügst. Oder was schwebt Dir vor?
Wenn du m änderst, ist es nicht mehr Festkomma. Sind deine Zahlenbereiche so dynamisch, daß sich der Aufwand lohnt, oder ist es nicht sinnvoller wirklich bei Festkomma zu bleiben? Dann wäre der der Rechenaufwand deutlich kleiner, auch wenn man deswegen vielleicht ein paar Bits mehr nehmen muß, die nicht immer genutzt werden. Fließkomma ist nicht umsonst zu haben.
Das ganze soll dann auf eine dsPIC33 laufen. Ich würde gerne float umgehen, sofern das möglich ist. An sich reichen mir (für dieses Projekt) Werte von 9999,99 bis 0,00. Ich wollte mir nur Arbeit für die Zukunft sparen und eine möglichst universelle Bibliothek schreiben. Iwann kam mir dann der Gedanke, dass das ja gar nicht mehr so verschieden von einem Float ist... Ich denke es ist nicht verkehrt die Stelle des Kommas frei wählen zu können, jedoch sollte die Werte, die miteinander verrechnet werden, denselben Faktor besitzen, sodass diese schnell miteinander verrechnet werden können. Ihr habt schon recht, wenn der Controller jedes mal den Exponenten anpassen muss, ist es im Grunde Gleitkomma darstellung und wahrscheinlich noch langsamer als mit Float zu rechnen. Die Frage ist, ob es schneller ist, wenn das Komma fest steht und nicht weiter angepasst werden muss. Das muss ich mal austesten...
Aaron K. schrieb: > 9999,99 Du willst aber nicht mit dezimalen Stellen rechnen, hoffe ich? Mit 14 Bits Vorkommastellen geht es bis über 16000. 13 Bits reichen nicht bis 9999. Eine Genauigkeit von Hundertstel (oder besser) hätte man mit 7 Bits Nachkomma (1/128). Macht zusammen 21 Bits mindestens. Das ist jetzt wohl keine günstige Größe auf einem Rechner mit Bytes zu 8 Bit, also würde man 24 Bits insgesamt nehmen. Z.B. 17.7 oder 16.8... (binär, nicht dezimal). Du musst natürlich den Wertebereich so einstellen, daß es auch für Zwischenergebnisse reicht.
Aaron K. schrieb: > eine möglichst universelle Bibliothek schreiben es soll auch schon fertiges geben, übrigens :-)
Aaron K. schrieb: > Iwann kam mir dann der Gedanke, dass das ja gar nicht mehr so > verschieden von einem Float ist... Allerdings ;-). Multipliziere die Zahl mit 100 und rechne mit 32bit Integer. Bei der Ausgabe machst Du halt das Komma wieder rein. Klaus W. schrieb: > es soll auch schon fertiges geben, übrigens :-) Ja, die 32-bit Integer Arithmetik. (Hab ich mal gehört ;-) ) 24-Bit dürfte dagegen schwieriger als fertige lib zu bekommen sein.
Aaron K. schrieb: > Ich wollte mir nur Arbeit für die > Zukunft sparen und eine möglichst universelle Bibliothek schreiben. Möglichst universell ist halt Gleitkomma. Deswegen ist Schwachsinn, Gleitkomma durch Gleitkomma einer eigenen Bibliothek ersetzen zu wollen. Und für Festkomma braucht man keine Bibliothek. Für Festkomma braucht man nur Disziplin. Man muss sich halt an jeder Stelle des Codes im Klaren sein, wo die aktuelle Kommaposition ist. Idealerweise schreibt man den Code sogar so, dass die immer möglichst günstig für die nächste anzuwendende Operation liegt. Das Ziel ist dabei immer, möglichst nicht "breiter" werden zu müssen, aber trotzdem die angestrebte Genauigkeit bezüglich der Gesamtoperation einzuhalten. Ja, man muss dazu den umzusetzenden Algorithmus betrachten. Und ja, man muss auch die Wertebereiche der Eingangsgrößen betrachten. Allein daraus ergibt sich, dass es keine universelle Bibliothek für das Problem geben kann. Wäre sie wirklich unversell, wäre sie mit an Sicherheit grenzender Wahrscheinlichkeit auch gleich wieder suboptimal bezüglich des Durchsatzes (jedenfalls bei der überwiegenden Mehrheit der Probleme). So einfach ist das.
c-hater schrieb: > Allein daraus ergibt sich, dass es keine universelle Bibliothek für das > Problem geben kann. Wäre sie wirklich unversell, wäre sie mit an > Sicherheit grenzender Wahrscheinlichkeit auch gleich wieder suboptimal > bezüglich des Durchsatzes (jedenfalls bei der überwiegenden Mehrheit der > Probleme). So einfach ist das. Da muss ich intervenieren... Man kann ja auch verschiedene Zahlenbereiche schaffen, in welchen sich das Komma immer an der selben Stelle befindet. Wäre dem nicht so, was wäre wenn in einem Bereich des Programms eine Auflösung bis in die 1000stel von nöten ist, in einem anderen jedoch eine einzige Nachkommastelle ausreichend genau ist? In so einem Fall wäre es praktisch die Variablen welche im selben Zahlenbereich liegen miteinander verrechnen zu können. Gerade bei Division oder Multiplikation können die fixed-point-Zahlen nicht einfach miteinander verrechnet werden. Da:
Was man aber eig. möchte ist:
Also muss jedes Produkt durch den gemeinsamen Faktor geteilt werden um das erwünschte Ergebnis zu erhalten. Ebenso muss jeder Quotient mit dem gemeinsamen Skalierungsfaktor multipliziert werden, da:
Was man aber eig. möchte ist:
Diese Operationen jedesmal im Code "diskret" durchzuführen ist unübersichtlich und verschlechtert sowohl les- als auch wartbarkeit des Codes. Aus diesem Grund ist es Meiner Meinung nach besser sich eine kleine aber feine Bibliothek für die fixed-point-Arithmetik zu basteln. Addition und Subtraktion sind wie gewohnt durchführbar, da gilt:
Der Übersichtlichkeit wegen bietet sich aber auch hier an Funktionen zu schreiben, sodass alle 4 Grundrechenoperationen im Code ähnlich aussehen. Wenn man so möchte kann man diese kleine Bibliothek sicherlich auch so gestalten dass es verschiedene Skalierungsfaktoren gibt. Mann muss jedoch dafür sorgen dass Variablen, welche miteinander verrechnet werden, denselben Skalierungsfaktor besitzen. Den Skalierungsfaktor der Zahlen bei jeder Rechen-Operation anzupassen ist zwar gut für die Auflösung und die Code-Redundanz, jedoch begeht man dann denselben Fehler, aus welchem ich diesen Thread geöffnet habe und baut sich seinen eigenen Float-Datentype zusamenn. Die Berechnung des DIY-floats ist dabei höchst wahrscheinlich noch langsamer als den c-typischen float-Datentype zu verwenden. Für meinen Code habe ich mich an dem hier inspiriert: https://www.allaboutcircuits.com/technical-articles/fixed-point-representation-the-q-format-and-addition-examples/ Nach dieser Quelle berechnet sich die fixed-point-Zahl wie folgt:
Bit:
Anzahl der Bits:
Anzahl der Vorkomma-Bits:
Anzahl der Nachkomma-Bits/Skalierungs Faktor:
Um die fixed-point Zahl zu berechnen muss lediglich die float-Zahl mit dem Skalierungsfaktor multipliziert werden und am die restlichen Nachkommastellen "abgeschnitten" werden. Dimensioniert man den Faktor auf 2^15, so ergibt sich eine Auflösung von:
und einen Wertebereich von:
Den Faktor kann man wie bereits erwähnt frei wählen, er sollte sich jedoch nachdem die Variable einmal in die fixed-point Darstellung konvertiert wurde, nur noch selten oder besser gar nicht mehr ändern. Also nochmal zusammenfassend. Ja wenn an den Faktor bei jeder Operation anpasst, so hat man sich im Grunde einen eignenen float-Datentype gebastelt (weil ich deisen Fehler gemacht habe und mir nicht 100% sicher war habe ich diesen Thread geöffnet). Aber man kann sich sehr wohl eine Universelle Bibliothek basteln, welche für verschiedene Zahlenbereiche passend ist, basteln, so auch z.B. Für Zahlen zwischen 1 und -1, mit möglichst hoher Auflösung. Man sollte dabei jedoch aufpassen, dass man den Faktor eben gleich lässt und nicht anpasst, weil man dann besagtes Problem hat, dass man im Grunde erneut in float rechnet. Bitte verbessert mich, wenn ich flasch liege, aber ich denke dass das Grundsätzlich mal nicht flasch ist was ich hier geschrieben habe. :D Danke für alle bisher und alle die noch kommen eure Antworten ;-)
Klaus W. schrieb: > Du musst natürlich den Wertebereich so einstellen, daß es auch für > Zwischenergebnisse reicht. Kleiner Hinweis: Jein. Wenn bspw. bei der Implementierung digitaler Filter sichergestellt ist, dass Eingangs- und Ausgangsgrößen im darstellbaren Bereich sind, können innendrin auch mal Sachen überlaufen, ohne dass etwas schiefgeht. Das ist mitunter einer der Vorteile von Fixed-Point Arithmetik. Voraussetzung dafür ist, dass die Operationen alle linear sind und eben wie oben geschrieben, Eingangs- und Ausgangsgrößen garantiert immer im Wertebereich liegen
>Code ich gerade meinen eigenen Float-Datentype neben dem eigentlichen >Datentyp Ja. Bei der Festkomma-Arithmetik führst Du ausschließlich Integer-Operationen aus. Das ist der Clou an der Sache. Fließkommazahlen haben einen variablen Exponenten, aber Festkommazahlen haben keinen festen Exponenten, sondern gar keinen. Verabschiede Dich von der Idee, Deine Festkomma-Zahlen könnten irgendwie als Exponent-behaftet interpretiert oder mit einem Exponenten aufgepeppt werden. Sobald Du daran auch nur denkst, bist Du im Float-Datentyp unterwegs. Fällt Deine Entscheidung auf Fließkomma, benutze die eingebauten Single-/Double-Typen. Ist Dir Festkomma-Arithmetik lieber, rechne mit ausreichend großen Integer.
Ich habe das ganze jetzt mal gemessen und nochmal ein wenig dazu recherchiert. Also kurz um... Addition und Subtraktion sind auf meiner Platform (dsPIC33CK) ca. um Faktor 10 schneller. Sie benötigen 25 statt wie beim Float 325 Schritte. Multiplikation ist etwa gleich schnell. Fixed-Point benötigt hier 325 und floating-point benötigt 147 Schritte. Bei der Division wirds dann krass... Die Division mit floats benötigt cs. 480 Schritte. Da ich in meinem fixed-point code 32-Bit verwende und ich diesen Bereich für die Division auf 64 erweitern muss, dauert die Division hier 9550 Zyklen... Das Erweitern ist notwendig, da der erste fixed-point Wert mit dem Skalierungsfaktor multipliziert wird, sodass man auch Ergebniss kleiner 1 oder kleiner -1 erhält. Mir fällt kein Weg das zu umgehen, vlt. wisst ihr ja weiter :) Schlussendlich denke ich, dass ich wieder auf Float umsteige. Die Division dauert einfach deutlich zu lang nach der Erweiterung auf 64Bit. Bei der Multiplikation wird ebenfalls auf 64Bit erweitert um einem Überlauf vorzubeugen. Diese ist jedoch vergleichbar mit einer floating-point Operation, was die Zyklen angeht.
c-hater schrieb: > Allein daraus ergibt sich, dass es keine universelle Bibliothek für das > Problem geben kann. https://github.com/MikeLankamp/fpm Also das Ding kommt einer universellen Bibliothek schön sehr nahe. Kann auch trigonometrische Funktionen. Aber... UPS... C++, Sorry C-Hater.
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.