## Featured Replies in this Discussion

- by Gribouillis
- by Gribouillis

We need test cases input/correct output to help you out, if I catch your meaning, mantissa has assumed 1 as first number except when exponent is 0. What is offset of exponent. I would rewrite your nice formulas by writing one function to pop n bits out from least significant side and working only with numbers, not strings.

```
def push_bits(n, bits, value):
return value << n | bits
def pop_bits(n, value):
return value >> n, value & ((1<<n) -1)
value = 0b11
value = push_bits(3, 0b101, value)
print bin(value)
bits, rest = pop_bits(3, value)
print bin(bits), bin(rest)
```

yeh... I've tried to keep string usage to a minimum >_<

just couldn't find an easy way to do float('1.'+str(mantissa)) w/o string usage

I'm afraid I'm not quite sure of your meaning to the offset of the exponent :/

e = *length of exponent field*

shift = (byte_size*8) - (1+e)

E = (val>>shift) & int('1'*e,2)

I already know the ints returned from the input value are correct,

as the binary values are regenerated from the ints (S, E, and M).

NTM I've tested a few examples and compaired my binary values with the example's representations.

here's a few of my tests with the comparison floats:

(what the returned values should be)

# f(1,69) = 2.625

# f(1,211) = -4.75

# f(2,49152) = -2.0

# f(2,15361) = 1.0009765625

# f(4,1065353216) = 1.0

# f(4,3299092992) = -1313.3125

EDIT: only -2.0 and 1.0 are correct

if it helps you out, these were the best notes I could find as to floating-point notation and encoding.

http://en.wikipedia.org/wiki/Half-precision_floating-point_format

MAN do I hate this editor >:O

(I have a connection that cuts every 5 seconds after connecting)

^this editor sometimes misses a paragraph or 2 >_<

I have a starting point using module bitstring (from pypi) and the wikipedia page

```
import bitstring
test_data = [
("0 01111 0000000000", 1),
("0 01111 0000000001", 1.0009765625),
("1 10000 0000000000", -2),
("0 11110 1111111111", 65504),
("0 00001 0000000000", 2.0 ** (-14)),
("0 00000 1111111111", 2.0**(-14) - 2.0**(-24)),
("0 00000 0000000001", 2.0**(-24)),
("0 00000 0000000000", 0.0),
("1 00000 0000000000", -0.0),
("0 11111 0000000000", float("infinity")),
("1 11111 0000000000", -float("infinity")),
("0 01101 0101010101", 1.0/3),
]
fmt = ['uint:1', 'uint:5', 'uint:10']
for u, res in test_data:
a, b, c = (int(x, 2) for x in u.split())
s = bitstring.pack(fmt, a, b, c)
print s.bin
s, e, m = s.unpack(fmt)
if e:
v = 2 ** (e - 25) * (1024 + m)
else:
v = 2 ** (-24) * m
if s:
v = -v
print repr(v), repr(float(res))
"""my output -->
0011110000000000
1.0 1.0
0011110000000001
1.0009765625 1.0009765625
1100000000000000
-2.0 -2.0
0111101111111111
65504 65504.0
0000010000000000
6.103515625e-05 6.103515625e-05
0000001111111111
6.097555160522461e-05 6.097555160522461e-05
0000000000000001
5.960464477539063e-08 5.960464477539063e-08
0000000000000000
0.0 0.0
1000000000000000
-0.0 -0.0
0111110000000000
65536 inf
1111110000000000
-65536 -inf
0011010101010101
0.333251953125 0.3333333333333333
"""
```

Here Gribouillis data and formula for decision of value used with my push_bits and pop_bits if you need to avoid external dependencies. I also left as formulas some Gribouillis constants for easier adaption later for other lengths

```
def push_bits(n, bits, value):
return value << n | bits
def pop_bits(n, value):
return value >> n, value & ((1<<n) -1)
def b(n):
return ('0' * 16 + bin(n)[2:])[-16:]
def f(val):
bias, exp, mant = 15, 5, 10
v, m = pop_bits(mant, val)
v, e = pop_bits(exp, v)
v, s = pop_bits(1, v)
if e == (1<<exp)-1:
if m:
return float('NaN')
else:
return float('-inf') if s else float('+inf')
if e:
v = 2 ** (e - bias - mant) * ((1<<mant) + m)
else:
v = 2 ** (1 - bias - mant) * m
return -v if s else v
for t in [15360, 15361, 49152, 31743, 1024, 1023, 1, 0, 32768, 31744, 64512, 13653]:
print b(t), repr(f(t))
```

ahah!

I think I just got what I needed:

```
if e == (1<<exp)-1:
if m:
return float('NaN')
else:
return float('-inf') if s else float('+inf')
if e:
v = 2 ** (e - bias - mant) * ((1<<mant) + m)
else:
v = 2 ** (1 - bias - mant) * m
return -v if s else v
```

but hang on, lemme verify first...

EDIT:

btw, I believe 'pow(-1,s)*v' is faster than '-v if s else v'

pyTony =D

you've done it again ^_^

```
>>> f(1,69)
8bits [[1],[3],[4]]: 0 100 0101
2.625
>>> f(1,211)
8bits [[1],[3],[4]]: 1 101 0011
-4.75
>>> f(2,49152)
16bits [[1],[5],[10]]: 1 10000 0000000000
-2.0
>>> f(2,15361)
16bits [[1],[5],[10]]: 0 01111 0000000001
1.0009765625
>>> f(4,1065353216)
32bits [[1],[8],[23]]: 0 01111111 00000000000000000000000
1.0
>>> f(4,3299092992)
32bits [[1],[8],[23]]: 1 10001001 01001000010101000000000
-1313.3125
>>>
```

thank you :)

that was all I needed.

I once wrote this function to get the ieee754 representation of a float

```
def ieee754(x):
"""Return a string of 0 and 1 giving the ieee754 representation of the float x
"""
import struct
from binascii import hexlify
p = struct.pack("d", x)
s = bin(int(b"1" + hexlify(p), 16))[3:]
return " ".join(reversed([s[i:i+8] for i in xrange(0, len(s), 8)]))
```

The following test shows that the 16 bits version is very close to the 64 bits version. It means that you should be able to find the 3 numbers easily

```
0011110000000000
00111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000
1.0 1.0
0011110000000001
00111111 11110000 00000100 00000000 00000000 00000000 00000000 00000000
1.0009765625 1.0009765625
1100000000000000
11000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
-2.0 -2.0
0111101111111111
01000000 11101111 11111100 00000000 00000000 00000000 00000000 00000000
65504 65504.0
0000010000000000
00111111 00010000 00000000 00000000 00000000 00000000 00000000 00000000
6.103515625e-05 6.103515625e-05
0000001111111111
00111111 00001111 11111000 00000000 00000000 00000000 00000000 00000000
6.097555160522461e-05 6.097555160522461e-05
0000000000000001
00111110 01110000 00000000 00000000 00000000 00000000 00000000 00000000
5.960464477539063e-08 5.960464477539063e-08
0000000000000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0.0 0.0
1000000000000000
10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
-0.0 -0.0
0111110000000000
01000000 11110000 00000000 00000000 00000000 00000000 00000000 00000000
65536 inf
1111110000000000
11000000 11110000 00000000 00000000 00000000 00000000 00000000 00000000
-65536 -inf
0011010101010101
00111111 11010101 01010100 00000000 00000000 00000000 00000000 00000000
0.333251953125 0.3333333333333333
```

Apparently, removing bits `[2, 8[`

and truncating brings back the 16 bits float.

Here is something of "More than you ever wanted to know about floating point numbers" http://www.quadibloc.com/comp/cp02.htm Not helping so much at task at hand but looks really comprehensive computer science basics document for interest and fun.

To post a workin version of multiprecission code for benefit of others, here my function with bits argument instead of bytes (to avoid those 8*byte_cnt parts) Hope it is without bugs, looks to work with the test cases. (result for f(0x7ffeffffffffffffffffffffffffffff, 128) is correct but not maybe what you would expect)

```
def push_bits(n, bits, value):
return long(value << n) | long(bits)
def pop_bits(n, value):
return value >> n, value & ((1<<n) -1)
def b(n, c=16):
if n < 0:
# two's complement
n = ((2**c-1) ^ n) + 1
return ('0' * c + bin(n)[2:])[-c:]
def f(val, bits=16):
if bits == 80:
exp = 15
else:
byte_cnt = bits // 8
exp = (byte_cnt * 8 - 1)//(byte_cnt + 1) + (byte_cnt > 2) * byte_cnt // 2
mant = bits - 1 - exp
bias = (1<<(exp-1))-1
print exp, mant, bias
v, m = pop_bits(mant, val)
v, e = pop_bits(exp, v)
v, s = pop_bits(1, v)
if e == bias:
if m:
return float('NaN')
else:
return float('-inf') if s else float('+inf')
if e:
v = 2 ** (e - bias - mant) * ((1<<mant) + m)
else:
v = 2 ** (1 - bias - mant) * m
return -v if s else v
for t in [15360, 15361, 49152, 31743, 1024, 1023, 1, 0, 32768, 31744, 64512, 13653]:
print b(t), repr(f(t))
```

how does yor code calculate the length of the exponent??

you saw my code, but does yours return the same bit-fields as mine??

http://lh3.ggpht.com/-modh5yIANmA/T6CDQ-67LHI/AAAAAAAADyQ/snPDH-mtSZM/s812/floats.PNG

^just an earlier test I did while developing the equasion :P

but then again, IDK if the format standards for the bit fields may change compaired to mine >_>

(since IEEE 24bit hasn't been dev'd yet)

btw, I believe 'pow(-1,s)*v' is faster than '-v if s else v'

Interesting, but I can not reproduce this result, maybe you could send your data?

```
import random
import time
ints = [random.randint(0, 1<<62) for count in range(10**5)]
signs = [random.randint(0, 1) for count in range(10**5)]
print('starting test run')
t0= time.clock()
signed1 = [(-1)**s*v for s, v in zip(signs, ints)]
t1= time.clock()
signed2 = [-v if s else v for s, v in zip(signs, ints)]
t2 = time.clock()
print 'if', (t2-t1),'vs', t1-t0, '**'
print ((t2- t1) - (t1- t0))/(t2-t1) * 100, '% speedup'
```

**Output**

```
starting test run
if 0.094547212006 vs 0.183539248703 **
-94.1244430262 % speedup
```

80 bits has exponent of 15 bits and looks like it has one additional integer part bit in format and is not handled perfectly by the function (http://en.wikipedia.org/wiki/Extended_precision)