IEEE 754, single precision in Python

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
ChrisGTJ
User
Beiträge: 105
Registriert: Mittwoch 22. August 2007, 15:45

Hallo zusammen,

IEEE 754 schreibt vor, wie eine Gleitkommazahl mit einfacher Genauigkeit zu bilden ist. Die Frage ist, ob Python schon mit entsprechenden Zahlen arbeitet und wie das Datenformat ist.

Hintergund: Ein Stückchen Hardware liefert genau solche Werte und ich muß diese Werte lesen, verstehen und ggf. verändert wieder schreiben können. Das heißt, ich lese 4 Bytes und schreibe 4 Bytes. Mein Python läuft auf Windows.

Ich habe mir mal das Beispiel aus Wikipedia hergenommen:

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

und einwenig Codiert, um an die Byterepräsentation einer Fließkommazahl zu kommen:

Code: Alles auswählen

>>> from ctypes import c_float, c_uint8, cast, POINTER
>>> pFloat = (c_float*1)()
>>> byteArray = cast(pFloat, POINTER(c_uint8))

>>> pFloat[0] = 18.4
>>> [byteArray[i] for i in range(0,4)]
[51, 51, 147, 65]
>>> pFloat[0]
18.399999618530273
So, wenn man sich die 4 Bytes [0x33, 0x33, 0x93, 0x41] anguckt und sie binär aufschreibt, erhält man:

Code: Alles auswählen

0011 0011 0011 0011 1001 0011 0100 0001
  6    7    4    5    2    3    0    1
etwas umsortieren hilft und man kommt zu der Darstellung im wiki-Beispiel:

Code: Alles auswählen

0_100 0001 1_001 0011 0011 0011 0011 0011
Vorzeichen _ Exponent _ Mantisse
Jetzt frage ich mich nun: Wie liddle- oder big-endian ist das, was ich da sehe, eigentlich? Ist meine Interpretation der Zahlen richtig?

Gruß und Danke,

Christoph

PS: Gibt es eine elegantere Methode, um an die Bytes zu kommen?

PPS: Kann mir jemand sagen, warum im obigen Beispiel

Code: Alles auswählen

>>> [a for a in byteArray]
zu einem Absturz der Python-Konsole führt?
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

- Das Modul struct (aus der Standard-library) hilft dir bestimmt weiter.
- Das ist alles little endian.
- ich hab keine Ahnung, ob dein gecastetes Bytearray eine Größenbeschränkung hat (wenn Nein, ergibt die list comprehension natürlich 'ne Schutzverletzung/segfault).
edit: Da ist wohl keine Beschränkung (Willkommen in C ;) )

Code: Alles auswählen

Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import c_float, c_uint8, cast, POINTER
>>> pFloat = (c_float*1)()
>>> byteArray = cast(pFloat, POINTER(c_uint8))
>>> pFloat[0] = 18.4
>>> byteArray
<ctypes.LP_c_ubyte object at 0x00B55710>
>>> byteArray[:]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError
>>> byteArray[:4]
[51, 51, 147, 65]
>>> byteArray[:5]
[51, 51, 147, 65, 0]
>>> byteArray[:15]
[51, 51, 147, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> byteArray[:100]
[51, 51, 147, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 192, 48, 30, 30, 50, 0, 0, 0,
255, 255, 255, 255, 0, 0, 0, 0, 68, 58, 92, 80, 114, 111, 103, 114, 97, 109, 109, 101, 92, 112, 121, 116, 104, 111, 110,
 92, 108, 105, 98, 92, 115, 105, 116, 101, 45, 112, 97, 99, 107, 97, 103, 101, 115, 92, 114, 101, 97, 100, 108, 105, 110
, 101, 46, 112, 121, 99, 0, 0, 0, 0, 0, 0]
>>>
hth, Jörg

ps.: was ist "die Python-Konsole"?
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

b.esser-wisser hat geschrieben:ps.: was ist "die Python-Konsole"?
Damit ist vermutlich die Python-Shell gemeint (Das Programm, das aufgerufen wird, wenn du python in einer Shell eintippst).
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

derdon hat geschrieben:
b.esser-wisser hat geschrieben:ps.: was ist "die Python-Konsole"?
Damit ist vermutlich die Python-Shell gemeint (Das Programm, das aufgerufen wird, wenn du python in einer Shell eintippst).
"Vermutlich" ist der springende Punkt, da es ja noch eine ganze Reihe von "Python-Shells" gibt (IPython, PyCrust und manch ein Editor/IDE hat wieder was eigenes).

hth, Jörg
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Das [mod]struct[/mod]-Modul wurde ja schon erwähnt, wenn es viele Floats sind würde sich auch noch das [mod]array[/mod]-Modul anbieten.

Und wenn man schon mit ctypes rumfrickelt, dann vllt so, dass das Ganze kein Glücksspiel ist.

Code: Alles auswählen

>>> import ctypes as c
>>> f = c.c_float(18.399999618530273)
>>> f.value
18.399999618530273
>>> c.c_char * c.sizeof(f)
<class '__main__.c_char_Array_4'>
>>> _.from_address(c.addressof(f))
<__main__.c_char_Array_4 object at 0x1fa2408>
>>> _.raw
'33\x93A'
>>> map(ord, _)
[51, 51, 147, 65]
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
ChrisGTJ
User
Beiträge: 105
Registriert: Mittwoch 22. August 2007, 15:45

b.esser-wisser hat geschrieben:
derdon hat geschrieben:
b.esser-wisser hat geschrieben:ps.: was ist "die Python-Konsole"?
Damit ist vermutlich die Python-Shell gemeint (Das Programm, das aufgerufen wird, wenn du python in einer Shell eintippst).
"Vermutlich" ist der springende Punkt, da es ja noch eine ganze Reihe von "Python-Shells" gibt (IPython, PyCrust und manch ein Editor/IDE hat wieder was eigenes).

hth, Jörg
Genau, ich hatte einfach ein cmd-Tool geöffnet, also nix besonderes.

Das mit der fehlenden Begrenzung des Arrays ist einleuchtend. Danke. :)

Christoph
ChrisGTJ
User
Beiträge: 105
Registriert: Mittwoch 22. August 2007, 15:45

b.esser-wisser hat geschrieben:- Das Modul struct (aus der Standard-library) hilft dir bestimmt weiter.
- Das ist alles little endian.
Buaahhh, ich Trottel, natürlich. Hab's sogar schon mal genutzt! :oops:

Littleendian ist auch klar, mich hat die nibbleweise Umsortiererei gegenübern dem Beispiel verwirrt.

Danke für die Hilfe!

Christoph
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Das erste Beispiel direkt in C umgesetzt, für alle Interessierten:

Code: Alles auswählen

#include <stdio.h>

int main(void) {
	float a = 18.4;
	unsigned char *byte_pointer = &a;

	int i;
	for(i = 0; i <= 3; ++i) {
		printf("Value %d: %d.\n", i, *(byte_pointer + i));
               // oder *byte_pointer++
	}

	printf("%f\n", a);

	return 0;
}
Antworten