Negative Zahl in Bytes prüfen

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
Benutzeravatar
Dennis89
User
Beiträge: 1699
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo zusammen,

dieses mal geht es bei mir wieder um Bytes.
Ich bekomme zum Beispiel:

Code: Alles auswählen

b'qX\x1b\x00\x00\xff\xff\xff'
`b'q'`ist zur Prüfung, ob es sich um die Nachricht handelt, die ich erwarte. Die 3 `xff` werden immer zum Schluss gesendet und dazwischen befindet sich meine Zahl im little Endian.

Code: Alles auswählen

>> value = b'qX\x1b\x00\x00\xff\xff\xff'
>> int.from_bytes(value[1:5], 'little')
7000
Die Zahl -7000 wird mir so zurück gegeben:

Code: Alles auswählen

b'q\xa8\xe4\xff\xff\xff\xff\xff']/code]

[code="python"]>> value = b'q\xa8\xe4\xff\xff\xff\xff\xff'
>> int.from_bytes(value[1:5], 'little')
4294960296
Wenn ich das richtig verstanden habe, dann beginnt eine negative Zahl mit `xff` und da ich little Endian habe und "alle" negativen Zahlen, die ich getestet habe, mit `xff` enden, bin ich auf dem richtigen Weg(denke ich).
Es wäre doch aber falsch, nur dieses Byte gegen `xff` zu prüfen? Denn dasss ist ja grundsätzlich erst mal valide, weil ich vielleicht die Zahl 4294967295 benötige. Oder sagt man, dass man mit der Anzahl an Bytes nur eine gewisse größe an Zahl darstellen kann und wenn es größer ist, ist es negativ?


Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 18370
Registriert: Sonntag 21. Oktober 2012, 17:20

Negative Zahlen werden durch das Zweierkomplement dargestellt. Du mußt Dich also entscheiden, ob Du vorzeichenbehaftete Zahlen hast, oder nicht. Und wenn das feststeht, ist auch eindeutig klar, ob Du eine sehr große Zahl oder eine negative Zahl hast.

Code: Alles auswählen

int.from_bytes(value[1:5], 'little', signed=True)
Benutzeravatar
__blackjack__
User
Beiträge: 14326
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Auf 0xFF prüfen wäre auch deshalb falsch, weil es ja nicht zwingend dieser Wert sein muss, auch bei einer negativen Zahl nicht:

Code: Alles auswählen

In [5]: value = b'q\xa8\xe4\xff\xf0\xff\xff\xff'

In [6]: value[1:5]
Out[6]: b'\xa8\xe4\xff\xf0'

In [7]: int.from_bytes(value[1:5], "little", signed=True)
Out[7]: -251665240
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Benutzeravatar
Dennis89
User
Beiträge: 1699
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für die Erklärungen, hat mir sehr weitergeholfen!


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
Dennis89
User
Beiträge: 1699
Registriert: Freitag 11. Dezember 2020, 15:13

Es wird nicht besser bei mir. Hatte das alles nur am PC getestet. MicroPython ist da etwas anders:

https://docs.micropython.org/en/latest/ ... -parameter
Das gilt auch für `from_bytes()`

Habe mich gefragt, ob ich das mit dem Zweierkomplement jetzt selbst schreiben muss, dann habe ich das auf Github entdeckt:
https://github.com/micropython/micropython/issues/15399

Wenn ich das selbst schreiben könnte, dann wäre es vermutlich schon längst implementiert.

Sollte das meine Programmierkenntnisse überschreiten, dann würde ich die Hex-Darstellung an den Server senden, da wandeln und wenn es negativ ist, eine entsprechende Antwort an den ESP senden.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 14326
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Zweierkomplement negieren ist einfach. Alle Bits ”kippen” und dann 1 addieren. Für die -7000 aus dem Beispiel:

Code: Alles auswählen

>>> 4294960296 ^ 0xFFFFFFFF
6999

>>> (4294960296 ^ 0xFFFFFFFF) + 1
7000

>>> -((4294960296 ^ 0xFFFFFFFF) + 1)
-7000
Und testen ob das umrechnen nötig ist, also ob man eine negative Zahl hat, ist ein einfacher Test ob das höchstwertige Bit gesetzt ist (negativ) oder nicht (positiv).

Code: Alles auswählen

>>> (4294960296 & 0x80000000) != 0
True
Alles Operationen die MicroPython können sollte.

Code: Alles auswählen

    data = ...
    value = int.from_bytes(data[1:5], "little")
    if value & 0x80000000:
        value = -((value ^ 0xFFFFFFFF) + 1)
    print(value)
Edit: Wenn man Zahlen haben kann die grösser sein können, als das was man mit den hier vier Bytes darstellen kann, dann kann man auch auch das hier machen:

Code: Alles auswählen

    value = int.from_bytes(data[1:5], "little")
    if value >= 0x80000000:
        value -= 0x100000000
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
Sirius3
User
Beiträge: 18370
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn micropython das Argument nicht kennt, dann benutze statt dessen struct:

Code: Alles auswählen

struct.unpack_from("<i", value, 1)[0]
Antworten