Seite 1 von 1

IEEE 754, single precision in Python

Verfasst: Montag 30. März 2009, 17:41
von ChrisGTJ
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?

Verfasst: Montag 30. März 2009, 17:57
von b.esser-wisser
- 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"?

Verfasst: Montag 30. März 2009, 18:54
von derdon
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).

Verfasst: Montag 30. März 2009, 19:23
von b.esser-wisser
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

Verfasst: Montag 30. März 2009, 23:17
von Trundle
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]

Verfasst: Dienstag 31. März 2009, 14:58
von ChrisGTJ
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

Verfasst: Dienstag 31. März 2009, 15:02
von ChrisGTJ
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

Verfasst: Dienstag 31. März 2009, 17:27
von str1442
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;
}