Zwei Int16-Werte zu einem double zusammenbauen



  • Hallo Leute,

    ich bekomme über eine Kommunikationsschnittstelle zwei Int16 Werte.
    Diese zwei Werte bilden ein double Wert.
    Das Problem ist, dass ich sie nicht zusammengebaut bekomme.

    Mein Quellcode sieht so aus:

    short Variable_1; // Highword
    short Variable_2; // Lowword
    
    UInt16 Highword = (UInt16)Variable_1;
    UInt16 Lowword = (UInt16)Variable_2;
    double Ergebnis = Convert.ToDouble(((Highword  << 16) + Lowword));
    

    Hat jemand von euch Ahnung, was ich falsch mache?
    Danke



  • Servus,

    zuerst musst du wissen, mit welcher Bitwertigkeit die Bytes bei dir ankommen. Stichwort MSB / LSB. Je nachdem müssen die bytes in sich selbst nochmal gedreht werden.

    Dein Ansatz des Shiften ist schon richtig, allerdings macht dir das Convert.ToDouble einen Strich durch die Rechnung. Denk mal genau drüber nach 😉

    Hast du ein Byte Array? Dann verwende den BitConverter. In deinem Fall sind 2 x 16 Bit (2 x 2 Byte) = 4 Byte (32 Bit) ==> Typ float bzw. Single

    gruß
    Hellsgore



  • hallo Hellsgore,

    na ja, Variable_1 ist dabei das "MSB". Aus diesem Grund habe ich sie auch um 16 Bit nach links verschoben.
    Variable_1 und Variable_2 werden direkt von der über die Schnittstelle mit Werten gefüllt. Ich verwende also kein Bytearray.

    Welche Konvertierungsfunktion würdest du verwenden, wenn die Ergebnisvariable ein float wäre?



  • Das Variable_1 das Highword von den beiden ist, hast du ja schon geschrieben. Ich meinte aber die Wertigkeit innerhalb der beiden "Variablen".

    BitConverter würde ich verwenden oder du bastelst dir den ganzen Kram zu Fuß. Allerdings fällt mir spontan nur ein, unsafe code zu verwenden.

    Von daher macht dir das Leben einfach und verwende folgendes:

    byte[] bitTest = new byte[] { (byte)(high >> 8), (byte)(high & 0xFF), (byte)(low >> 8), (byte)(low & 0xFF) };
    
    float f = BitConverter.ToSingle(bitTest, 0);
    

    Sollte deine Wertigkeit nicht stimmen, dann drehe die Reihenfolge.



  • Danke für die ausführliche Antwort.
    Werde ich ausprobieren.



  • double Ergebnis = Convert.ToDouble(Variable_1) * 65536.0 + Convert.ToDouble(Variable_2);
    

    Das ist mein Weg.



  • Servus,

    Hoppelmoppel schrieb:

    double Ergebnis = Convert.ToDouble(Variable_1) * 65536.0 + Convert.ToDouble(Variable_2);
    

    Das ist mein Weg.

    Wo sind die Nachkommastellen bei 2 x 2 Byte unsinged integern? 😉

    EDIT:
    Zum weiteren Verständnis von Gleitkommazahlen finde ich folgenden Artikel sehr schön beschrieben:

    http://de.wikipedia.org/wiki/IEEE_754



  • So zum Feierabend hin habe ich mir gerade ein paar Minütchen gegönnt und ein Beispiel erstellt, dass die Berechnung nun verdeutlichen sollte:

    // 0 10000011 00100110011001100110011
    // 1100165939
    // High: 16787
    // Low: 13107
    
    ushort high = 16787;
    ushort low = 13107;
    
    short bias = GetSingleBias();
    
    uint value = (uint)high << 16 | (uint)low;
    
    // x 10000011 00100110011001100110011
    byte sign = (byte)(value >> 31);
    
    // 0 xxxxxxxx 00100110011001100110011
    uint exponent = (uint)((value >> 23) & 0xFF);
    
    // 0 10000011 xxxxxxxxxxxxxxxxxxxxxxx
    uint fraction = value & 0x7FFFFF;
    
    // 0010011001100110011001x
    // Immer ein Bit von rechts betrachten
    // Ist das Bit gesetzt dann 2^-(BitPosition)
    // Stichwort: binary fractional number convention
    float fractionPart = 0.0f;
    for (int i = 1; i <= 23; i++)
    {
        if ((fraction & 0x01) == 0x01)
        {
            fractionPart += (float)Math.Pow(2, -(24 - i));
        }
    
        fraction >>= 1;
    }
    
    float result = 0.0f;
    
    // r = s * 1.f * 2^(e-127)
    if (exponent > 0)
    {
        result = Convert.ToSingle((sign > 0 ? -1.0f : 1.0f) * (1.0f + fractionPart) * (float)Math.Pow(2, exponent - (uint)bias));
    }
    else // r = s * 0.f * 2^(1-127)
    {
        result = Convert.ToSingle((sign > 0 ? -1.0f : 1.0f) * (0.0f + fractionPart) * (float)Math.Pow(2, 1 - (uint)bias));
    }
    
    private static short GetSingleBias()
    {
        // Bias bezeichnet die Anzahl der Bits im Exponenten
        short singleExponent = 8;
    
        return (short)(Math.Pow(2, (8 - 1)) - 1);
    }
    

    Die Werte sind aus dem Wiki Artikel. Sollte sich Fehler finden, dann bitte berichtigen.



  • Hallo Hellsgore,

    danke für deine Mühe. Jetzt wird einiges klar 👍


Anmelden zum Antworten