nicht lachen! 8 Bit Festkommarechnung
-
Ich möchte auf einem Microcontroller mit 8 Bit gerne in geringer Auflösung eine Kommarechnung durchführen.
Hierzu muss ich ja eine Festkommarechnung nutzen. (nen Gleitkommaindex würde mir zuviele Bits fressen). Mein Problem ist nun die Verschiebung des Kommas nach den Grundrechenarten.
Hier mal die Beispielaufteilung des Bytes:[ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ] +/-| Vorkoma | Nachkomma ]
Somit hab ich Werte zwischen 7,9375 und -8.9375.
Wohin verschieben sich nun die Kommawerte bei +-*/ ?
Will nur wissen, ob dies überhaupt praktikabel ist, oder ob es sich nicht lohnt, über so eine Lösung weiter nachzudenken..
-
DocJunioR schrieb:
Ich möchte auf einem Microcontroller mit 8 Bit gerne in geringer Auflösung eine Kommarechnung durchführen.
Das ist eine gute Idee.
Wohin verschieben sich nun die Kommawerte bei +-*/ ?
generell gilt, daß bei + und - nichts verändert wird und bei * und / muss um einen faktor korrigiert werden. den faktor kann man sich überlegen, kann ihn aber auch ausprobieren.
Will nur wissen, ob dies überhaupt praktikabel ist, oder ob es sich nicht lohnt, über so eine Lösung weiter nachzudenken..
es ist fürchterlich praktikabel. damals als nicht jeder prozessor fließkommazahlen konnte, was festkommaarithmetik einer der ganz großen tricks, wie man schnelle berechnungen schaffte.
leider war sie sehr unhandlich. aber heute haben wir ja c++.
#include <iostream> using namespace std; class TinyInt{ private: char data; public: TinyInt(){ } TinyInt(int x) :data(x<<4){ } TinyInt(double x) :data(char(x*16)){ } operator double(){ return double(data)/16; } TinyInt& operator+=(TinyInt const& b){ data+=b.data; return *this; } TinyInt& operator-=(TinyInt const& b){ data-=b.data; return *this; } TinyInt& operator*=(TinyInt const& b){ data=short(data)*b.data/16; return *this; } TinyInt& operator/=(TinyInt const& b){ data=short(data)*16/b.data; return *this; } }; TinyInt operator+(TinyInt const& a,TinyInt const& b){ TinyInt c=a; c+=b; return c; } TinyInt operator-(TinyInt const& a,TinyInt const& b){ TinyInt c=a; c-=b; return c; } TinyInt operator*(TinyInt const& a,TinyInt const& b){ TinyInt c=a; c*=b; return c; } TinyInt operator/(TinyInt const& a,TinyInt const& b){ TinyInt c=a; c/=b; return c; } #define TEST(x) cout<<#x<<'='<<x<<endl //nur, weil neulich gefragt wurde, wozu man in java einen präprozessor //brauchen könnte. int main(){ TinyInt x=1.25; TEST(x); TinyInt y=0.5; TEST(y); TEST(x+y); TEST(x-y); TEST(x*y); TEST(x/y); return 0; }
ich halte c++ für höchst geeignet für embedded systems. viel geeigneter als c, weil man gerade in c++ die möglichkeit hat, lauter solche sachen zu benutzen, die ein wenig performance bringen, ohne daß der code deswegen aufgeblasen und fehleranfällig wird.
-
#define TEST(x) cout<<#x<<'='<<x<<endl
//nur, weil neulich gefragt wurde, wozu man in java einen präprozessor
//brauchen könnte.
Das schafft man auch ohne Probleme in Java ohne hässlichen Präprozessor :p
-
java__ schrieb:
#define TEST(x) cout<<#x<<'='<<x<<endl
//nur, weil neulich gefragt wurde, wozu man in java einen präprozessor
//brauchen könnte.
Das schafft man auch ohne Probleme in Java ohne hässlichen Präprozessor :pwie?
-
volkard schrieb:
#define TEST(x) cout<<#x<<'='<<x<<endl //nur, weil neulich gefragt wurde, wozu man in java einen präprozessor //brauchen könnte.
[/cpp]
ich halte c++ für höchst geeignet für embedded systems. viel geeigneter als c...ohne daß der code deswegen aufgeblasen und fehleranfällig wird.wenn du schon so für c++ wirbst, wäre es vielleicht besser nicht so ein hässliches c macro zu nutzen, macros sind nicht typsicher, besser wäre
inline TEXT(std::string VarName,TinyInt& x) { cout... }
comments?
zum Topic:
bei fixpoint musst du besonders gut drauf achten keine overflows zu produzieren, denn wenn du zwei 8bit register multiplizierst, könnte das resultat drüberliegen, das beachten manche beim assemblercoden garnicht, so be carefull
rapso->greets();
-
rapso schrieb:
besser wäre
inline TEXT(std::string VarName,TinyInt& x) { cout... }
comments?
hallo? will ich TEST(x+y); schreiben oder TEST("x+y",x+y); ?
bemerkst du den unterschied?
wie macht man das in c++ ohne makros?
wie macht man das in java?bei fixpoint musst du besonders gut drauf achten keine overflows zu produzieren, denn wenn du zwei 8bit register multiplizierst, könnte das resultat drüberliegen, das beachten manche beim assemblercoden garnicht, so be carefull
deswegen hat jede ordentliche sprache eigentlich muldiv() anzubieten, falls sie will, daß jemand damit auch mal festkommaarithmetik betreibt (forth bietet es an, vermutlich war (ist?) forth die letze bastion der festkommaarithmetik).
hier tuts's beim op* zum glück ein mulshift (falls der prozessor so höflich ist, nen shift-befehl über zwei register anzubieten).
-
rapso schrieb:
macros sind nicht typsicher, besser wäre...
typsicher soll dieses makro doch gar nicht sein!!!
TEST(foo()); TEST(bar->faz()); TEST(1+1); TEST(x/y);
die typsicherheit (was ist das?) erledigt drunter schon der op<<, oder?
was nicht aufgeben werden kann macht nen compilerfehler.
ist wohl irgendwie sowas wie ein template.
ok, kannst ne template-funktion TEST bauen, die dann kompliziert ist, man könnte an das wort overengeneering denken, und auf jeden fall untauglich, weil sie bei weitem nicht die leistung des makros hat.
-
rapso schrieb:
bei fixpoint musst du besonders gut drauf achten keine overflows zu produzieren, denn wenn du zwei 8bit register multiplizierst, könnte das resultat drüberliegen, das beachten manche beim assemblercoden garnicht, so be carefull
tat ich darauf nicht sehr schön hinweißen (wie man das heutzutage doch schreiben tut) mit
data=short(data)*b.data/16;
?
-
volkard schrieb:
... ... TinyInt(double x) :data(char(x*16)){ } operator double(){ return double(data)/16; } ... ...
ich halte c++ für höchst geeignet für embedded systems...
mag sein, aber man sollte keine 'doubles' benutzen. viele µC's können das nicht native.
-
net schrieb:
mag sein, aber man sollte keine 'doubles' benutzen. viele µC's können das nicht native.
die doubles hier waren doch bloß zum leichteren testen in der main().
natürlich wird die keiner ernsthaft verwenden wollen.
ein konstruktor von int würde es nicht so einfach machen, eine variable mit 0.5 zu initialisieren und mit dem operator double() habe ich mir den ausgabeoperator erspart. (die anwendung braucht hoffentlich gar keinen aufgabeoperator).
-
Joa hi nochmal.
also ich hab mir Volkards Code mal angeschaut.
Sieht nicht so übel aus. Ich persönlich benutze lieber ASM für sowas, aber ich denke, dass ich das jetzt auch alleine schaffe.Die Multiplikation kann ich temporär über 2 Register laufen lassen (wozu haben die Dinger sond 32 Stück davon
) Die Speicherung erfolgt dann im 8 Bit - Format.
Festhalten will ich dann nur noch für die Allgemeinheit :
Bei Festkommazahlen ändert sich die Kommastelle folgendermaßenAddition/Subtraktion : garnicht.
Multiplikation : Die Anzahl der Nachkommastellen ergibt sich aus der Addition der Nachkommastellen (in diesem falle 4 + 4 =
der beiden Multiplikatoren.
Division : Die Anzahl Nachkommastellen subtrahiert sich. Hier sollte also vorher (in meinem Fall)4 Byte nach links geshiftet werden.
-
...Hier sollte also vorher (in meinem Fall)4 >>BIT<< nach links geshiftet werden....