G.Franzkowiak said:
Scott said:
franzkowiak wrote:
I've read some bytes from a file and just now I can't interpret 4
bytes in this dates like a real value. An extract from my program:
def l32(c):
return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) +
(ord(c[3])<<24)
...
value = l32(f.read(4)) <--- 3F 8C CC CD should be 1.11
OK, here's the skinny (I used blocks & views to get the answer):
import struct
bytes = ''.join(chr(int(txt, 16)) for txt in '3F 8C CC CD'.split())
struct.unpack('>f', bytes)
I was suspicious of that first byte, thought it might be an exponent,
since it seemed to have too many on bits in a row to be part of 1.11.
-Scott David Daniels
(e-mail address removed)
Ok, I the string exist with "mystr = f.read(4)" and the solution for
this case is in your line "struct.unpack('>f', bytes)"
But what can I do when I want the interpret the content from the Integer
myInt (*myInt = 0x3F8CCCCD) like 4-byte-real ?
This was stored with an othes system in a binary file to
CD CC 8C 3F and now is it in python in value. The conversion is not
possible. It's right... one of this bytes is an exponent.
I want copy the memory content from the "value address" to "myReal
address" and use print "%f" %myReal.
Is myReal then the right format ?
What can I do with python, in FORTH is it simple
( >f f. )
gf
If you really want to do this kind of byte fiddling:
http://members.dsl-only.net/~daniels/block.html
Then:
from block import Block, View
b = Block(4) # enough space for one float (more is fine)
iv = View('i', b) # getting to it as an integer
fv = View('f', b) # same memory as floating point
iv[0] = 0x3F8CCCCD # Here is a sample just using the integer
print fv[0]
On an Intel/Amd/Generic "PC" machine, you should get 1.1
Ok, for most bit patterns (except QNANs), you can do it in pure python:
----< i32as_single.py >------------------------------------
class NoQNAN(ValueError): pass # use to flag inability to return QNANs
def i32as_single(i):
"""
(UIAM in my interpretation of a 1995 Pentium Processor Developer's Manual)
This converts bits in a 32-bit integer as if they were bits
of a single-precision IEEE 754 floating point number to python float
+---+---+---+---+---+---+---+---+---+---+---+---+ ... +---+---+---+---+
| s | e e e e e e e eb| b b b ... b b b b0 |
+---+---+---+---^---+---+---+---^---+---+---+---^ ... ^---+---+---+---+
31 30 29 28 27 26 25 24 23 22 21 20 3 2 1 0
where s is the sign bit, and is the only thing that changes between + and -
and e..eb is an 8-bit biased (by 127) exponent, and eb is the hidden
unit 1 bit followed by 23 b..b0 significant "fraction" bits",
normalized so that the most significant bit is always 1 and therefore
doesn't have to be stored at eb, except that when all but the sign bit
are zero, eb is ignored and the value is then a signed zero value.
The binary fraction starting bit is after the hidden '1' bit eb at 23,
so viewing bits 0..23 as an integer, we have to divide by 2**23 (or
adjust the exponent) to get the 1.xxxx values when the official unbiased
exponent is zero (offset value 127). Thus 0x3f800000 is zero unbiased
exponent and no other bits, for a value of 1.0
A biased exponent of 255 signifies a NaN, and a biased exponent of
zero signifies a denormal (which doesn't have a hidden bit, and whose
unit bit is bit 22). Single precision denormals can be normalized
in python (double) float format, which is done for the return value.
"""
signbit = i&0x80000000
if not i&0x7fffffff: return signbit and -0.0 or 0.0 # if -0.0 available
biased_exp = (i>>23) & 0xff # bits 30-23
unitbit = biased_exp and 0x800000 or 0 # bit 23, or 0 for denormals
significand = i & 0x7fffff # bits 22-0
if biased_exp == 255:
if significand:
raise NoQNAN, "Sorry, can't generate QNAN from %08x" % i
return signbit and -1e9999 or 1e9999 # XXX s/b INF's for sure??
adjexp = (biased_exp or 1) - 127 - 23 # adjusted for denormal
posvalue = (significand + unitbit)*2.0**adjexp
return signbit and -posvalue or posvalue
def test():
import struct
num = 0
for sign in (0, 2*(-2**30)):
for i3 in xrange(128):
num3 = i3<<24
for i2 in xrange(256):
print '\r%08x'%(num,), # show progress
num2 = i2<<16
# skip mid byte of significand, make 0
# and twiddle only a few bits at the bottom
for num0 in xrange(8):
num = sign+num3+num2+num0
s = ''.join(map(chr,(num0, 0, i2,((sign and 0x80 or 0)+i3))))
try: ti32as = i32as_single(num)
except NoQNAN: continue
tstruct = struct.unpack('f', s)[0] # XXX '<f' => no INF ??
if ti32as != tstruct:
print '\n%x =>%r\n%r => %r' % (num, ti32as, s, tstruct)
if __name__ == '__main__':
test()
-----------------------------------------------------------
[21:47] C:\pywk\clp>i32as_single.py
C:\pywk\clp\i32as_single.py:31: FutureWarning: hex/oct constants > sys.maxint will return positi
ve values in Python 2.4 and up
signbit = i&0x80000000
7fff0007C:\pywk\clp\i32as_single.py:51: FutureWarning: %u/%o/%x/%X of negative int will return a
signed string in Python 2.4 and up
print '\r%08x'%(num,), # show progress
ff7f0007C:\pywk\clp\i32as_single.py:38: FutureWarning: %u/%o/%x/%X of negative int will return a
signed string in Python 2.4 and up
raise NoQNAN, "Sorry, can't generate QNAN from %08x" % i
fffe0007
Of course, the test() gives a clue how you might write the whole thing using struct
by just summing the four chr-ed extracted bytes from the input i ;-)
Anyway, a couple things (how to make a QNAN in python without calling struct, and '<' in struct):
-1.#INF
But I don't know how to build QNaNs:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "i32as_single.py", line 38, in i32as_single
raise NoQNAN, "Sorry, can't generate QNAN from %08x" % i
i32as_single.NoQNAN: Sorry, can't generate QNAN from 7f800001
Whereas struct does:
>>> import struct
>>> struct.unpack('f','\x00\x00\x80\x7f')[0] 1.#INF
>>> struct.unpack('f','\x01\x00\x80\x7f')[0]
1.#QNAN
BTW, your example:
>>> struct.unpack('f','\xcd\xcc\x8c\x3f')[0] 1.1000000238418579
>>> i32f(0x3f8ccccd)
1.1000000238418579
But what does this mean? (I wanted to test with little endian unpacking, since
that is what I knew I created, but that isn't what '<' means?? ...)
>>> struct.unpack('f','\x00\x00\x80\x7f')[0] 1.#INF
>>> struct.unpack('<f','\x00\x00\x80\x7f')[0]
3.4028236692093846e+038
Regards,
Bengt Richter