float Genauigkeit



  • Hallo, ich beschäftige mich zurzeit mit der Programmierung von Mikrocontrollern und benutze den C Compiler PICC von HITech.
    Bei C gibts ja den Datentyp float. Aus dem Internet hab ich rausgekriegt, dass dieser Datentyp 4 byte lang ist.
    In meinem Programm möchte ich mit diesem Datentyp eine Zahl speichern, welche vor dem Komma genau zwei byte lang ist und der Rest der Variabel hinter dem Komma verwenden.
    Kann ich die Variabel so deklarieren, oder ist die Aufteilung der Genauigkeit und Länge gar nicht möglich ?
    Wenn dies nicht gehen sollte, gäbe es da noch eine andere Möglichkeit eine solche Zahl zu speichern. Wichtig ist einfach dass ich vor dem Komma zwei byte zur Verfügung habe, der Rest sollte einfach so genau wie möglich sein.



  • Meines Wissens ist es nicht möglich den float selber so umzubiegen, dass er deinen Anforderungen gerecht wird. Deshalb würde ich dir folgende Struktur empfehlen:

    struct MyFloat
    {
        short vor;
        unsigned double nach;
    }
    
    MyFloat Add(MyFloat param1, MyFloat param2)
    {
        MyFloat temp;
        short uebertrag = 0;
        temp.nach = param1.nach + param2.nach;
    
        if(temp.nach>1.0)
        {
            uebertrag = (int)temp.nach;
            temp.nach = temp.nach - uebertrag;
        }
    
        temp.vor = param1.vor + param2.vor + uebertrag;
    
        return temp;
    }
    

    Frag mich jetzt allerdings nicht, wie man multipliziert bzw. dividiert ;). Ausserdem muss noch irgendwie das Vorzeichen beachtet werden. Dafür bin ich aber definitiv zu müde :xmas1: (Ich missbrauche die Nikolausmütze mal als Schlafmütze 😉 )

    btw.: short ist mit seiner grösse vom Compiler abhängig. Unter 32-Bit ist short 2 Byte gross.



  • ein float hat 6.92 dezimalstellen (23 bit) an genauigkeit. der rest ist vorzeichen und exponent (1 und 8 bit).

    ist nur eine idee, aber du wuerdest besser wegkommen, einen long int oder ein packed struct fuer die zwecke zu missbrauchen. die oberen 1+7 bits waeren dann vorzeichen und vorkommateil, die restlichen 24 bits koenntest du dir als zaehler eines n/2**24 bruches denken. dann haettest du 2.1 + 7.22 dezimalstellen genauigkeit.
    damit haettest du aber nur 2 stellen rausgequetscht und so zu rechnen ist umstaendlich, weil du dir fuer jede rechenoperation ne funktion schreiben muesstest.

    kleines beispiel, was ich mit genauigkeit meine:
    3 bits bedeuten 3*log(2)/log(10) = 0.9 dezimalstellen genauigkeit.
    wenn man es sich vorstellt, kann ich mit 3 bits nur 8 von 10 zustaenden erreichen.
    6 bits haben 1.8 dezimalstellen genauigkeit, da 64 von 100 zustaende.
    7 bits haben 2.1 stellen, weil 128 zustaende (uebergenau fuer 2 stellen).



  • cin schrieb:

    struct MyFloat
    {
        short vor;
        unsigned double nach;
    }
    

    Das geht so nicht ganz - es gibt kein "unsigned double".

    Frag mich jetzt allerdings nicht, wie man multipliziert bzw. dividiert ;).

    geeignet ausmultiplizieren 😉



  • Auf Mikrocontrollern ist float eh selten wirklich brauchbar. Wenn das Teil keine FPU hat (was imho eher üblich ist), dann muss das ganze emuliert werden. Und das ist gähnend langsam.



  • Um mal konret zu werden poste ich den Code mal hier rein.

    bit dimm_dlevel = 0;
    unsigned char a;  // Rechenvariabel
    float b;  // Rechenvariabel
    unsigned short c;  // Rechenvariabel
    
    unsigned char dmath_schrl(unsigned char start,unsigned char end,unsigned char mainvalue){
    
      dimm_dlevel = 0;  // Dimmlevel reset
    
      a = end - start;
      b = (float)255 / (float)mainvalue;
      c = (unsigned short)b * (unsigned short)a;
    
      if(c > (unsigned short)255){  // Wenn Schritt zu gross
    
        dimm_dlevel = 1;  // Höheres Level
    
        b = (float)c / (float)255;  // Auf höheres Level rechnen
        c = (unsigned short)b;  // Resultat schreiben
    
      }
    
      return (unsigned char)c;
    
    }
    

    Also wahrscheinlich lache sich einige kaputt über meinen Code, kann leider nicht besser. 😞
    Also die Funktion muss eine Schrittlänge für einen PWM Dimmer berechnen.
    Die Variabeln start und end beschreiben den Startpunkt und den Endpunkt des Dimmvorganges.
    mainvalue beschreibt die Anzahl Schritte die ausgeführt werden sollen.
    Hab das Ganze jetzt so gelöst, dass sobald das Ergebniss nicht mehr in eine char Variabel passt, eine bitvariable auf 1 gesetzt wird um dann nur noch einen ungenaueren Wert auszugeben.
    So funktioniert es zwar einigermassen nur leider ist es wegen dem Wandeln der float in eine short Variable enorm ungenau. Die Rechnung c = (unsigned short)b * (unsigned short)a; ergiebt ein sehr ungenaues Resultat. Leider kann ich als C keine float Variable nehmen, da diese ja vor dem Komma nur 8 bit speichern kann.
    Was würde ein Profi in der Situation machen ? (Bitte keine Antworten ala "Lern am besten mal richtig C", ich bin ja schliesslich gerade dabei 😉 )Wäre auch noch genial wenn ich das Endergebnis am Schluss noch sauber runden könnte.



  • wie der name fließkommazahl schon sagt ist die position des kommas variabel. die paßt sich automatisch an. um dein ziel zu erreichen brauchst du nur sicher zu stellen, daß die zahl im bereich 100.0>x>-100.0 liegt.


Anmelden zum Antworten