crc-32 signed int mit python 3?

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
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

Hallo,

ich müsste einen string in eine checksum umwandeln.
Vorgegeben wird mir, dass es "crc-32 signed int" sein soll.

Also bin ich beim googlen auf folgendes gestoßen:
https://docs.python.org/3.6/library/binascii.html

Leider ist das was mir binascii.crc32(string.encode()) ausgibt, aber offenbar ein "unsigned long". In Python 2 war es wohl noch ein signed int.
In der Doku steht, man müsse " & 0xffffffff" dranhängen, damit es unter allen Python Versionen gleich ist.
Doch damit komme ich auf dnselben Wert, weshalb ich mal davon ausgehe, dass dieses " & 0xffffffff" etwas in einen unsigned long umwandelt.

Doch wie komme ich unter python 3 nun auf eine "signed int"?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist ja immer noch eine 32-bit-checksumme. Nur der Datentyp in Python, der die dann am Ende aufnimmt, ist halt ein long. Wie willst du das denn weiterverarbeiten?
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

__deets__ hat geschrieben:Das ist ja immer noch eine 32-bit-checksumme. Nur der Datentyp in Python, der die dann am Ende aufnimmt, ist halt ein long. Wie willst du das denn weiterverarbeiten?
Ich bekomme eine checksum und muss diese mit meiner selbstgebildeten checksum vergleichen.
Den "checkstring" dafür muss ich selbst bilden, könnte also theoretisch schon dort der fehler stecken.

Ich bekomme nämlich zb als Vorgabe:
-2066223162
Während meine Berechnug dies ausspuckt:
2228744134
Und auf Nachfrage warum meine checksum falsch ist, bekam ich die Antwort:
checksum is a signed int
you're calculating it as an unsigned long
Leider wurde bisher nicht weiter darauf eingegangen, weshalb ich nun hier nachgefragt habe.
Mich verwundert aber auch, dass die vorgegebene checksum negativ ist. Gibts das?

Ich werde nochmal überprüfen, ob mein checkstring selbst richtig ist...

PS:
Nur nochmal zum Verständnis:
unsigned long und signed int sind vom wert her identisch, es muss also an meinem checkstring liegen?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da die CRC auf einem *signed* int stattfindet, klar gibt's da negative checksummen.

Ich bekomme das konvertiert mit struct:

Code: Alles auswählen

>>> v = 2228744134
>>> struct.pack("I", v)
b'\xc6\xef\xd7\x84'
>>> struct.unpack("i", struct.pack("I", v))
(-2066223162,)
Insofern stimmt deine Berechnung, du musst nur tatsaechlich das Vorzeichen reparieren. Das hab' ich dir ja jetzt gezeigt :)
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

ah vielen dank :)
In einer Zeile vom checkstring zur checksum also:

mychecksum = struct.unpack("i", struct.pack("I", binascii.crc32(checkstring.encode())))[0]

funktioniert :)
Allein oder auch mit Google wäre ich da nie drauf gekommen... =/
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja, da stecken schon ein paar fortgeschrittene Grundlagen drin. Da hilft man auch gerne mit aus :D
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

__deets__ hat geschrieben:Ja, da stecken schon ein paar fortgeschrittene Grundlagen drin. Da hilft man auch gerne mit aus :D
:)

der checkstring besteht aus zahlen, welche ich aus einer Liste beziehe, die ich im json format erhalten habe.
Also wenn ich es printe, sieht die Liste zb so aus: [1, 1.234, 0.23, 0.0002348]
Der checkstring wird dann über
":".join(liste)
gebildet.
Nun ist das Problem, dass "join" einen string will und keine Zahl.
Deswegen hab ich vorher jede Zahl der Liste vorher mit "str()" in einen string umgewandelt.

Nun gibt es dabei aber das Problem, dass eine Zahl wie 0.0000x in die "e-5" schreibweise umgewandelt wird, wodurch die checksum aber natürlich falsch wird.
Ich hatte das e-5 Problem schonmal und hatte als Lösung das hier verwendet:
'%.8f' % zahl
Doch in diesem Fall funktioniert das natürlich nicht, weil "0.0000x00" als string etwas anderes ist als "0.0000x". Wieviele Nachkommastellen die Zahl jeweils hat, kann ich nicht im voraus sagen, nur dass es maximal 8 sind.
Also wie packe ich diese Zahlen nun in einen checkstring?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Auch da hilf struct. Schau mal nach den float-Formaten. Du musst das entsprechend umwandeln. Ich kann mir nicht vorstellen, dass du da auf eine formatierte Zahldarstellung rausmusst. Würde ich zumindest denjenigen welchen um die Ohren hauen. Oder du musst den originalen JSON String nehmen. Was ich auch wieder um die Ohren hauen würde :twisted:
Scholastik
User
Beiträge: 53
Registriert: Freitag 7. Juli 2017, 12:35

__deets__ hat geschrieben:Auch da hilf struct. Schau mal nach den float-Formaten. Du musst das entsprechend umwandeln. Ich kann mir nicht vorstellen, dass du da auf eine formatierte Zahldarstellung rausmusst. Würde ich zumindest denjenigen welchen um die Ohren hauen. Oder du musst den originalen JSON String nehmen. Was ich auch wieder um die Ohren hauen würde :twisted:
danke :)

bei googlen nach dem Problem stößt man meistens auf diese % f Lösung.
Habe jetzt aber eine Lösung gefunden, welche scheinbar prüft wieviele nachkommastellen gebraucht werden:
https://stackoverflow.com/questions/388 ... 1#38847691
Das funktioniert und werde ich dann für alle Zahlen anwenden, die kleiner als 0.0001 sind :)
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich halte das für die falsche Herangehensweise, weil du dich damit darauf verlässt, das du und der JSON Encoder die gleiche Zahldastellung haben. Und zwar *alle* JSON Encoder. Die Sender Seite hat ja auch einen. Ob das garantiert ist, das solltest du zumindest überprüfen. Oder zb den JSON Encoder benutzten.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Scholastik: crc-Checksummen werden über Bits gebildet, es gibt also soetwas wie Vorzeichen nicht, das ist nur eine Darstellung. Das sinnvolle Vorgehen ist also die Checksummen vor dem Vergleich auf 32bit zu beschneiden:

Code: Alles auswählen

checksumme1 = 2228744134
checksumme2 = -2066223162
if (checksumme1-checksumme2) & 0xffffffff == 0:
    print("identisch")
Zweiter Punkt: es gibt keine eindeutige Dezimaldarstellung für Fließkommazahlen. Diese für eine Checksumme zu benutzen ist also von vornherein zum Scheitern verurteilt. Wer kommt auf solch eine Idee? Woher kommen diese Zahlen? Wer bildet die Checksumme? Wie kann man das ändern?
Antworten