64 bit signed little endian integer

Die Scriptsprache PHP fĂŒr die Gestaltung von dynamischen Websites.

64 bit signed little endian integer

Beitragvon Neptunus » Mi 07 Dez, 2005 10:33

Hallo,

ich brÀuchte eine effiziente Routine, die mir einen 64 bit signed little endian integer Wert erzeugt. Ich brÀuchte eine solche Routine, um ein Netzwerkprotokoll zu implementieren.

Ein 32-bittiger Wert stellt ja nicht wirklich ein Problem dar, es ist sogar recht simpel, da man mit chr() jeweils 8 Bit erhĂ€lt und diese zu einem String zusammenklebt - fĂŒr 64 bit habe ich derzeit aber keine konkrete Idee, da PHP-intern nur 32-bittige Integers verwendet werden.

Weiß hier vielleicht jemand, wie eine solche Routine zu erstellen wĂ€re, oder wie in PHP am Besten mit großen Zahlen umzugehen ist?

lg & danke,
Neptunus
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon superracer » Mi 07 Dez, 2005 11:18

einen wert erzeugen? ne zufallszahl oder wie?
superracer
Board-User Level 3
Board-User Level 3
 
BeitrÀge: 1073
Registriert: So 04 Jul, 2004 11:18

Beitragvon Neptunus » Mi 07 Dez, 2005 11:25

Nein, keine Zufallszahl.

Ich implementiere ein Netzwerkprotokoll, welches voraussetzt, dass gewisse Angaben eben als 64 bit signed little endian integer vom Client (=mein PHP-Script) an den Server gesendet werden.

Angenommen, in dieser Art wird die Zahl 254 an den Server gesendet, so muss die Uwandlungsroutine eine Folge von 8 Byte erzeugen, deren BITS wie folgt aussehen:

11111110 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon ulrich » Mi 07 Dez, 2005 11:35

in c oder c++ wĂŒrde ich ein feld von 8 characters verwenden, oder ein feld von 2 integers, oder auch eine struktur, die 2 integers enthĂ€lt.
weiters könnte man den speicherplatz, den ein double (8 byte fließkommawert) liefert, mißbrauchen.
was von den vorgeschlagenen datenstrukturen in php analog und verwendbar zur verfĂŒgung steht, entzieht sich leider meiner kenntnis ;)
ulrich
Senior Board-Mitglied
Senior Board-Mitglied
 
BeitrÀge: 287
Registriert: Do 13 Nov, 2003 14:27

Beitragvon superracer » Mi 07 Dez, 2005 11:35

wenn du intern nur 32-bit zahlen verwendest, dann so:

pack("VV", $zahl, 0)

und mit vorzeichen:

pack("VV", $zahl, $zahl >= 0 ? 0 : -1)

wenn du 64-bit zahlen verwenden willst, mußt du wohl oder ĂŒbel diese in einen high order und einen low order teil spalten:

pack("VV", $zahl_low, $zahl_high)

mit dem vorzeichen mußt du dich dann ein bissl spielen...
superracer
Board-User Level 3
Board-User Level 3
 
BeitrÀge: 1073
Registriert: So 04 Jul, 2004 11:18

Beitragvon Neptunus » Mi 07 Dez, 2005 12:57

ulrich hat geschrieben:in c oder c++ wĂŒrde ich ein feld von 8 characters verwenden, oder ein feld von 2 integers, oder auch eine struktur, die 2 integers enthĂ€lt.
weiters könnte man den speicherplatz, den ein double (8 byte fließkommawert) liefert, mißbrauchen.
was von den vorgeschlagenen datenstrukturen in php analog und verwendbar zur verfĂŒgung steht, entzieht sich leider meiner kenntnis ;)


Ja, in C wÀrs wirklich schön zu machen :-)

In PHP könnte man sich im Kreis drehen, dort gibt es nÀmlich keine Datentypen und -strukturen, so wie es sie in C gibt.

Man kann auch keine Variable eines bestimmten Typs definieren.

Wenn man eine Variable benötigt, verwendet man sie einfach. Im Hintergrund fĂŒhrt PHP wie wild implizite Typkonvertierungen durch.

Beispiel: man legt eine Variable an und weist ihr den Int-Wert 10 zu:
$var = 10;

Jetzt ist jemand so kreativ und addiert das Zeichen '1':
$var += '1';

In $var steht dann nicht wie in C 10 + der ASCII-Code von '1', sondern 11.

Von welchem Typ $var dann nun ist, weiß ich nicht. Vielleicht ists noch ein int, vielleicht aber auch inzwischen ein String, in dem "11" steht.

Normalerweise spielt das aber auch keine Rolle in PHP, da die Datentypen sowieso immer implizit hin und her konvertiert werden, wie sie eben gerade benötigt werden.

Ich kann einer Methode, die einen String erwartet eine Gleitkommazahl mitgeben --> es wird daraus implizit ein String; oder man kann einer mathem. Funktion einen String "123.45" mitgeben -> es wird implizit ein float oder double daraus.

Auch interessant ist die Zuweisung von ganzzahligen Zahlen zu einer Variable: Ist die Zahl nĂ€mlich "klein", wird die Variable PHP-intern ein Integer. (Integers sind intern 32-bit-Werte). Weise ich aber eine grĂ¶ĂŸere Zahl einer Variable zu, sodass ein Buffer-Overflow entsteht, wird die Variable implizit ein double.

Und als User (oder besser gesagt PHP-Code-Eintippser) merkt man absolut nichts von diesen mysteriösen Dingen, die die ganze Zeit im Hintergrund ablaufen.

Will man nichts mit Datentypen zu tun, mag das alles ja praktisch sein - braucht man aber einen bestimmten Typen, der einen Wert in einer bestimmten Form speichert, könnte man fast verzweifeln.

In solchen FĂ€llen muss man dann auf Tricks wie pack() zurĂŒckgreifen, wie hier schon jemand geschrieben hat.

Ein anderer Trick, ist die Verwendung von chr(int val). Diese Funktion liefert nÀmlich zu einem numerischen Wert das dazugehörige ASCII-Zeichen.
PHP-intern sind ASCII-Zeichen mangels nativer UTF8-UnterstĂŒtzung immer genau 8 Bit groß.
Ruft man zB chr(8 ) auf, bekommt man das entsprechende ASCII-Zeichen zurĂŒck - es ist aber genau 1 Byte lang und hat den Bit-Inhalt 0001000 :-)

Um einen 32 Bit Wert zu erzeugen, kann man sich auf diesem Weg die 4 einzelnen Bytes generieren lassen, hÀngt sie zum Schluss zu einem String zusammen, und fertig ist das, was man in anderen Sprachen einfach als unsigend int kennt (oder long) :-)

Ich hoffe ich hab dich jetzt nicht zu sehr verwirrt, aber PHP ist so.
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon Neptunus » Mi 07 Dez, 2005 13:29

superracer hat geschrieben:pack("VV", $zahl, 0)

[...]


Danke fĂŒr den Tipp, ich kanns allerdings leider frĂŒhestens erst morgen ausprobieren, vorausgesetzt ich mag mich dazu ĂŒberwinden :-)

pack("VV", 1, 0) sieht ja recht gut aus.

Bei obigem Beispiel erhalte ich so 32 bit in denen der Wert 1 steht, dazu 32 fĂŒhrende Nullen und gut ists.

Nur funktioniert die Sache auch bei negativen Zahlen? 'V' weist pack ja schließlich an, unsigned 32 Bit zu erzeugen. Wird in diesem Fall auch richtig mit dem 2er-Komplement umgegangen, sodass es ĂŒber alle 64 Bit erzeugt wird?

Bei pack ("VV", -2, -1) (also Umwandlung der Zahl -2) mĂŒsste das Ergebnis so aussehen:
1. 32 Bit: 1........100
2. 32 Bit: 1...........1

Kommt es denn wirklich zu diesem Ergebnis? Denn gedanklich schaffe ich es nicht, diese Anweisung so durchzurechnen.
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon Neptunus » Mi 07 Dez, 2005 13:39

Hier sind schon wieder die Zeiten falsch, der Beitrag von superracer steht vor meinem.


Du hast natĂŒrlich recht, ich hab gleich 2 Dinge verwechselt :-)

Die 2 32-Bit-Paare hab ich jeweils big endian dargestellt und bei der signed-Darstellung hab ich schon vor dem Invertieren 1 addiert :-)

Sehr gut, wenn pack so funktioniert, das macht es fĂŒr mich um Vieles einfacher.

Nur wie funktioniert die Sache bei einer Zahl, bei der auch die vorderen 32 Bit benutzt werden? Kannst du da vielleicht weiter helfen?

zB das Umwandeln der Zahl 1,8 * 10^19

Ich wĂŒrde die Zahl der Umwanldungsfunktion als String ĂŒbergeben (da man sonst einen Gleitkommawert hat), diese Zahl dann in einen String umwandeln bestehend aus 0en und 1en, diesen String dann in StĂŒcken zu je 8 Zeichen zerlegen, diese Blöcke dann in die entsprechende Zahl zwischen 0 und 255 umwandeln und so die einzelnen Bytes zusammenkleben.

Hat jemand eine bessere Idee, denn mein Weg ist sicher nicht der performanteste?
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon superracer » Mi 07 Dez, 2005 13:51

Neptunus hat geschrieben:Bei pack ("VV", -2, -1) (also Umwandlung der Zahl -2) mĂŒsste das Ergebnis so aussehen:
1. 32 Bit: 1........100
2. 32 Bit: 1...........1

-2 ist aber 11111...110. und pack("VV",-2,-1) gibt aus (im hexdump): feff ffff ffff ffff
also richtig.
superracer
Board-User Level 3
Board-User Level 3
 
BeitrÀge: 1073
Registriert: So 04 Jul, 2004 11:18

Beitragvon Neptunus » Mi 07 Dez, 2005 22:46

Die Lösung meines Problems ist folgende:
http://java.sun.com/j2se/1.4.2/docs/api ... teger.html

Ich werde eine entsprechende Klasse fĂŒr PHP bauen, die im Großen und Ganzen die FunktionalitĂ€t dieser Java-Klasse besitzen wird (bis auf vielleicht die Methode zum SchĂ€tzen, ob es sich um eine Primzahl handelt :-)

Schwierig ist das hĂ€ndische binĂ€re Dividieren, das ich zwangsweise in dieser Klasse implementieren muss, denn ich kann auch keine Divisionen im 10er-System mit Stift und Papier durchfĂŒhen, aber von solchen Problemen darf man sich nicht abhalten lassen ;-)
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon superracer » Do 08 Dez, 2005 10:28

etwas overkill wenn du mich fragst, du wolltest ja eigentlich nur eine binÀre reprÀsentation einer 64-bit zahl? und vor allem das ganze auch noch selbst zu schreiben...?? wenn du schon sowas komplexes brauchst, wieso nicht mal eines hiervon anschaun?

http://www.php.net/manual/en/ref.gmp.php
http://www.php.net/manual/en/ref.bc.php
http://pear.php.net/package/Math_Integer

das ganze wird dir aber nicht dabei helfen, die zahl in binÀre form zu kriegen...
superracer
Board-User Level 3
Board-User Level 3
 
BeitrÀge: 1073
Registriert: So 04 Jul, 2004 11:18

Beitragvon Neptunus » Do 08 Dez, 2005 16:28

Ja overkill, aber man weiß ja nie fĂŒr was man so etwas gebrauchen kann, und schließlich mache ich es sowieso nur zu meinem privaten VergnĂŒngen, wenn man so sagen will :-)

Man braucht nur eine Methode zu machen, die das BigInteger-Objekt als 64-bit-Wert 128-bit oder was auch immer zurĂŒckliefert, und schon hĂ€tte man genau das, was ich brauche - nur eben viel komplexer, umfangreicher und auch ganz sauber, ohne irgendwelche wackligen Umwandlungen, die eben zufĂ€llig funktionieren.
Neptunus
Board-User Level 1
Board-User Level 1
 
BeitrÀge: 691
Registriert: Do 26 Jun, 2003 16:43

Beitragvon superracer » Do 08 Dez, 2005 16:37

Neptunus hat geschrieben:... ohne irgendwelche wackligen Umwandlungen, die eben zufÀllig funktionieren.

diese umwandlungen sind weder wackelig, noch funktionieren sie nur zufÀllig, sondern die funktionieren, weil die arithmetik eben so ist wie sie ist.
aber gut, wenn sich jemand unbedingt unnötig arbeiten machen will... :)
superracer
Board-User Level 3
Board-User Level 3
 
BeitrÀge: 1073
Registriert: So 04 Jul, 2004 11:18

Beitragvon ulrich » Fr 09 Dez, 2005 16:43

Neptunus hat geschrieben:
ulrich hat geschrieben:in c oder c++ wĂŒrde ich ein feld von 8 characters verwenden, oder ein feld von 2 integers, oder auch eine struktur, die 2 integers enthĂ€lt.
weiters könnte man den speicherplatz, den ein double (8 byte fließkommawert) liefert, mißbrauchen.
was von den vorgeschlagenen datenstrukturen in php analog und verwendbar zur verfĂŒgung steht, entzieht sich leider meiner kenntnis ;)


Ja, in C wÀrs wirklich schön zu machen :-)

In PHP könnte man sich im Kreis drehen, dort gibt es nÀmlich keine Datentypen und -strukturen, so wie es sie in C gibt.

Man kann auch keine Variable eines bestimmten Typs definieren.

Wenn man eine Variable benötigt, verwendet man sie einfach. Im Hintergrund fĂŒhrt PHP wie wild implizite Typkonvertierungen durch.

Beispiel: man legt eine Variable an und weist ihr den Int-Wert 10 zu:
$var = 10;

Jetzt ist jemand so kreativ und addiert das Zeichen '1':
$var += '1';

In $var steht dann nicht wie in C 10 + der ASCII-Code von '1', sondern 11.

Von welchem Typ $var dann nun ist, weiß ich nicht. Vielleicht ists noch ein int, vielleicht aber auch inzwischen ein String, in dem "11" steht.

Normalerweise spielt das aber auch keine Rolle in PHP, da die Datentypen sowieso immer implizit hin und her konvertiert werden, wie sie eben gerade benötigt werden.

Ich kann einer Methode, die einen String erwartet eine Gleitkommazahl mitgeben --> es wird daraus implizit ein String; oder man kann einer mathem. Funktion einen String "123.45" mitgeben -> es wird implizit ein float oder double daraus.

Auch interessant ist die Zuweisung von ganzzahligen Zahlen zu einer Variable: Ist die Zahl nĂ€mlich "klein", wird die Variable PHP-intern ein Integer. (Integers sind intern 32-bit-Werte). Weise ich aber eine grĂ¶ĂŸere Zahl einer Variable zu, sodass ein Buffer-Overflow entsteht, wird die Variable implizit ein double.

Und als User (oder besser gesagt PHP-Code-Eintippser) merkt man absolut nichts von diesen mysteriösen Dingen, die die ganze Zeit im Hintergrund ablaufen.

Will man nichts mit Datentypen zu tun, mag das alles ja praktisch sein - braucht man aber einen bestimmten Typen, der einen Wert in einer bestimmten Form speichert, könnte man fast verzweifeln.

In solchen FĂ€llen muss man dann auf Tricks wie pack() zurĂŒckgreifen, wie hier schon jemand geschrieben hat.

Ein anderer Trick, ist die Verwendung von chr(int val). Diese Funktion liefert nÀmlich zu einem numerischen Wert das dazugehörige ASCII-Zeichen.
PHP-intern sind ASCII-Zeichen mangels nativer UTF8-UnterstĂŒtzung immer genau 8 Bit groß.
Ruft man zB chr(8 ) auf, bekommt man das entsprechende ASCII-Zeichen zurĂŒck - es ist aber genau 1 Byte lang und hat den Bit-Inhalt 0001000 :-)

Um einen 32 Bit Wert zu erzeugen, kann man sich auf diesem Weg die 4 einzelnen Bytes generieren lassen, hÀngt sie zum Schluss zu einem String zusammen, und fertig ist das, was man in anderen Sprachen einfach als unsigend int kennt (oder long) :-)

Ich hoffe ich hab dich jetzt nicht zu sehr verwirrt, aber PHP ist so.

nein, eigentlich nicht - und danke fĂŒr den netten vortrag :)
ulrich
Senior Board-Mitglied
Senior Board-Mitglied
 
BeitrÀge: 287
Registriert: Do 13 Nov, 2003 14:27


ZurĂŒck zu PHP

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 25 GĂ€ste

cron