fork download
  1. #!/usr/bin/env python3
  2. import math
  3. import re
  4. import sys
  5. from string import hexdigits
  6. from types import SimpleNamespace
  7.  
  8.  
  9. def float_to_bin_hex(f,
  10. hex2bin={ord(h): '{:04b}'.format(int(h, 16)) for h in hexdigits}):
  11. if math.isinf(f) or math.isnan(f):
  12. return repr(f) # inf nan
  13. # abuse .hex()
  14. h = f.hex()
  15. prefix, suffix = h.find('.'), h.rfind('p')
  16. return (h[:prefix].replace('x', 'b')
  17. + h[prefix:suffix].translate(hex2bin)
  18. + h[suffix:])
  19.  
  20.  
  21. def float_to_bin(f):
  22. # NOTE: the implementation closely follows float.hex()
  23. if not math.isfinite(f):
  24. return repr(f) # inf nan
  25.  
  26. sign = '-' * (math.copysign(1.0, f) < 0)
  27. if f == 0: # zero
  28. return sign + '0b0.0p+0'
  29.  
  30. # f = m * 2**e
  31. m, e = math.frexp(math.fabs(f))
  32. shift = 1 - max(sys.float_info.min_exp - e, 0)
  33. m = math.ldexp(m, shift) # m * (2**shift) -- make *im* 0 or 1
  34. e -= shift
  35.  
  36. fm, im = math.modf(m)
  37. assert im == 1.0 or im == 0.0
  38. n, d = fm.as_integer_ratio()
  39. assert d & (d - 1) == 0 # power of two
  40. return '{sign}0b{i}.{frac:0{width}b}p{e:+}'.format(
  41. sign=sign, i=int(im), frac=n, width=d.bit_length() - 1, e=e)
  42.  
  43.  
  44. def bin_to_float(bin_float):
  45. if bin_float in ['nan', 'inf', '-inf']: # special
  46. return float(bin_float)
  47.  
  48. d = SimpleNamespace(**re.fullmatch(
  49. r'(?P<sign>-?)0b(?P<integer>[01])\.(?P<frac>[01]+)p(?P<esign>[-+]?)(?P<exp>\d+)',
  50. bin_float).groupdict())
  51. m = d.integer + d.frac # mantissa
  52. n = math.ldexp(int(m, 2), (-1 if d.esign else 1) * int(d.exp) - len(m))
  53. return math.copysign(n, (-1 if d.sign else 1))
  54.  
  55.  
  56. for f in [-123.45, -0.0, 0.0, math.nan, math.inf, -math.inf, 0.5, 2**-1074,
  57. 0.1, 0.01, 0.001, 10.1, 100.1, 1000.1]:
  58. print(f, float_to_bin(f), sep='\t')
  59. got = bin_to_float(float_to_bin(f))
  60. expected = bin_to_float(float_to_bin_hex(f))
  61. assert got == expected or (math.isnan(got) and math.isnan(expected)), (f, got, expected,
  62. float_to_bin(f), float_to_bin_hex(f))
  63.  
Success #stdin #stdout 0.01s 28640KB
stdin
Standard input is empty
stdout
-123.45	-0b1.1110110111001100110011001100110011001100110011001101p+6
-0.0	-0b0.0p+0
0.0	0b0.0p+0
nan	nan
inf	inf
-inf	-inf
0.5	0b1.0p-1
5e-324	0b0.0000000000000000000000000000000000000000000000000001p-1022
0.1	0b1.100110011001100110011001100110011001100110011001101p-4
0.01	0b1.0100011110101110000101000111101011100001010001111011p-7
0.001	0b1.00000110001001001101110100101111000110101001111111p-10
10.1	0b1.0100001100110011001100110011001100110011001100110011p+3
100.1	0b1.100100000110011001100110011001100110011001100110011p+6
1000.1	0b1.1111010000001100110011001100110011001100110011001101p+9