Dezimalwert binär in Datei schreiben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

Hallo,

ich würde gerne den Dezimalwert "9.57" binäre in eine Datei schreiben.

Mein Ansatz bis dato

Code: Alles auswählen

value = "9.57"
dec_val = decimal.Decimal(value)
_tmp = str.split(value,'.')
_exponent = len(_tmp[1])
bytes = []
bytes.append( pack('<l', int(dec_val * pow(10, _exponent))))
bytes.append( pack('<B', 256 - len(_tmp[1])))
f = open("c:\\temp\\test.dat", "wb") 
f.write(''.join(bytes))
Schreibt leider BD 03 00 00 FE und nicht BD 03 FE. Wie kann vernünftig die genutzt Bytes der Mantisse ermitteln und dann mit dem Exponenten schreiben?

Danke
Claudia
BlackJack

@myxin: Vielleicht solltest Du erst einmal genau spezifizieren wie die binäre Darstellung aussehen soll. Und wie sieht der Wertebereich aus, der kodiert werden soll? Wenn Du nur die „benutzen“ Bytes der Mantisse speichern möchtest, dann müsstest Du ja auch noch speichern wie viele das sind. Es sei denn du schränkst das ganze auf eine Zahl pro Datei ein.

Man käme übrigens ohne `decimal` aus. Statt zu rechnen, könntest Du einfach den Dezimalpunkt entfernen und die Zeichenkette in eine ganze Zahl umwandeln.

Die benötigten Bytes bekommst Du mittels Logarithmus heraus. Der zur Basis 2 verrät Dir zum Beispiel wieviele Bits benötigt werden.
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

Vielen Dank für die Antwort.

>Vielleicht solltest Du erst einmal genau spezifizieren wie die binäre Darstellung aussehen soll. Und wie sieht der Wertebereich aus, der kodiert werden soll?
Die Mantissa liegt im Bereich -2139062143 bis 2147483647 und der Exponent im Bereich von -127 bis 127.
Der Typ ist ein Dec32 (ich denke, das kennt python nicht, oder?)
Wichtig ist, das in der Datei nicht die führenden Nullen der Mantissa geschrieben werden.
Heisst am Beispiel von 9.57 soll BD 03 FE und nicht BD 03 00 00 FE stehen,
oder am Beispiel 1.0 soll in der Datei 0A FF nicht aber 0A 00 00 00 FF wie es bei mir der Fall ist.

>Wenn Du nur die „benutzen“ Bytes der Mantisse speichern möchtest, dann müsstest Du ja auch noch speichern wie viele das sind. Es sei denn du schränkst das ganze auf eine Zahl pro Datei ein.
Genauer gesagt pro Zeile, ja. Damit werden Schwankungen ermittelt bzw. festgelegt und das festlegen ist das Problem.
Die Schnittstelle schmeisst einen Fehler wenn führend 0x0 0x0 der Mantissa geliefert werden. Beim Exponent ist es einfach, der ist immer nur ein Byte, bei der Mantissa leider nicht.
Aktuell sehe ich nicht, wie ich das gelöst bekomme.

>Man käme übrigens ohne `decimal` aus. Statt zu rechnen, könntest Du einfach den Dezimalpunkt entfernen und die Zeichenkette in eine ganze Zahl umwandeln.
Stimmt, danke :-)

>Die benötigten Bytes bekommst Du mittels Logarithmus heraus. Der zur Basis 2 verrät Dir zum Beispiel wieviele Bits benötigt werden.
OK, kannst Du mir das ein bisschen genauer erklären was Du da meinst?

Danke
Claudia
deets

Gibt es einen Grund, warum du nicht einfach die ueberfluessigen Null-Bytes aus dem String rausfilterst, nachdem du konvertiert hast?
BlackJack

@myxin: Was meinst Du mit „pro Zeile“? Wir reden hier von *Binärdaten*, da gibt es keine Zeilen. Woran würdest Du eine Zeile erkennen wollen? Oder anders formuliert, ist Dir klar, dass in der Darstellung der Zahl in dieser Form *jeder* Bytewert vorkommen kann?
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

Was meinst Du mit „pro Zeile“? Wir reden hier von *Binärdaten*, da gibt es keine Zeilen.
Woran würdest Du eine Zeile erkennen wollen?
Oder anders formuliert, ist Dir klar, dass in der Darstellung der Zahl in dieser Form *jeder* Bytewert vorkommen kann?
Sorry, anscheinend verwirre ich mehr als es deutlicher zu machen.

Zeile deswegen, da jeder Wert der an die Schnittselle übergeben wird base64 encodiert ist.
Heisst, 1.0 wird bei mir als
CgAAAP8= (entspricht base64 dekodiert den Hexwerten A0 00 00 00 FF)
übergeben, brauchen tue ich aber
Cv8= (entspricht base64 dekodiert den Hexwerten A0 FF)

Das mit base64 en/de-codieren habe ich weggelassen, da es mit dem eigentlich Problem nichts zu tun hat.

Danke
Claudia
BlackJack

@myxin: Ah, okay. Du meintest übrigens 0A FF und nicht A0 FF. *Das* müsste dann 16.0 sein. :-)
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

BlackJack hat geschrieben:@myxin: Ah, okay. Du meintest übrigens 0A FF und nicht A0 FF. *Das* müsste dann 16.0 sein. :-)
ahhhhh - natürlich 0A FF :-)

Claudia
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

deets hat geschrieben:Gibt es einen Grund, warum du nicht einfach die ueberfluessigen Null-Bytes aus dem String rausfilterst, nachdem du konvertiert hast?
ooppss - hab Dich überlese, sorry.
Wie soll das gehen? Wenn ich 957 als int packe, kann ich dann auf die Nullbytes zugreifen? Wenn ja, wie?

Danke
Claudia
BlackJack

@myxin: Schau mal was Zeichenkette, was ja in Python 2.x eigentlich Byteketten sind, für Methoden haben. Da ist auch eine dabei, mit der man bestimmte Zeichen/Bytewerte von einem Ende der Zeichenkette entfernen kann.
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

Vielen Dank an Alle

Code: Alles auswählen

    b = ''.join(pack('<l', int(dec_val * pow(10, _exponent)))).rstrip(chr(0))
    b += ''.join( pack('<B', 256 - len(_tmp[1])))
    return b
tut was es soll.

Gruß
Claudia
BlackJack

@myxin: Tut vielleicht was es soll, ist aber umständlich. Die `join()`\s sind zum Beispiel total sinnfrei. Damit setzt Du eine Zeichenkette aus den Buchstaben der übergebenen Zeichenketten zusammen. Da kommt also exakt das selbe heraus wie man rein steckt. `decimal.Decimal` würde ich auch nicht für so etwas einfaches bemühen. Und Du solltest es mal mit negativen Zahlen testen.

Code: Alles auswählen

def convert(value):
    exponent = len(value) - value.index('.') - 1
    mantissa = int(value.replace('.', ''))
    return struct.pack('<l', mantissa).rstrip('\0\xff') + chr(256 - exponent)
Edit: Zahlen die grösser als der Wertebereich der Mantisse sind, funktionieren damit allerdings auch nicht.
myxin
User
Beiträge: 47
Registriert: Dienstag 10. Januar 2012, 16:57

@BlackJack

nicht nur das dein Code übersichtlicher und eher zu verstehen ist wie meiner, nein, er ist auch noch 10 Mal schneller ;-)
Allerdings hat er ein kleines Problem, wenn ich richtig verstehe.

Code: Alles auswählen

pack('<l', mantissa).rstrip('\0\xff') + chr(256 - exponent)
das heisst, dass nicht nur Nullbytes sondern auch Bytes mit Wert 255 gelöscht würden, oder?
Dann würde aber ein Decimal von z. B. 6528.1 als 01 FF und nicht als 01 FF FF codiert.
Oder war das eine Denksportaufgabe (negative Werte) für mich?? ;-)

Danke
Claudia
BlackJack

@myxin: Das mit den 0xff hat tatsächlich mit negativen Zahlen zu tun, denn die werden im Zweierkomplement dargestellt und folglich mit gesetzten Bits „aufgefüllt”. Aber Du hast auch gleich eine Schwachstelle gefunden — meine Schnellschusslösung funktioniert nicht mit allen Werten. Man müsste positive und negative Werte dort tatsächlich getrennt behandeln. Und man müsste irgendwie kodieren wie das Vorzeichen aussieht. Denn man kann nach dem `rstrip()` den Daten nicht mehr ansehen ob nun 0- oder 1-Bits entfernt wurden.
Antworten