Last active
January 20, 2025 03:42
-
-
Save fikr4n/0e19642db8fa6bbcdddb8d47adda0e0a to your computer and use it in GitHub Desktop.
Convert float to/from string to illustrate/understand how a double precision floating-point number is encoded based on IEEE 754
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import struct | |
def to_float(bins): | |
""" | |
Convert a binary string to float. | |
""" | |
def _expand(s, length): | |
ei = s.find('..') | |
if ei == -1: return s | |
d = length - len(s) + 2 | |
return s[:ei] + (d * s[ei - 1]) + s[(ei + 2):] | |
sign, exp, mantissa = (i.replace('_', '') for i in bins.split()) | |
exp = _expand(exp, 11) | |
mantissa = _expand(mantissa, 52) | |
if len(sign) != 1 or len(exp) != 11 or len(mantissa) != 52: | |
raise ValueError((sign, exp, mantissa)) | |
int64 = (int(sign, 2) << 63) | (int(exp, 2) << 52) | int(mantissa, 2) | |
return struct.unpack('>d', struct.pack('>Q', int64))[0] | |
def to_bin(floatv, grouplen=8): | |
""" | |
Convert a float to binary string grouped per `grouplen` digits. | |
""" | |
def _group(s, w): | |
rem = len(s) % -w | |
return '_'.join(s[max(0, i):i + w] for i in range(rem, len(s), w)) | |
s = ''.join(format(i, '08b') for i in struct.pack('>d', floatv)) | |
return f"{s[0]} {_group(s[1:12], grouplen)} {_group(s[12:], grouplen)}" | |
def to_sn2(floatv): | |
""" | |
Convert a float to string representing the float in scientific notation | |
with base 2. | |
""" | |
def _superscript(s): | |
m = {'0': '⁰', '1': '¹', '2': '²', '3': '³', '4': '⁴', '5': '⁵', | |
'6': '⁶', '7': '⁷', '8': '⁸', '9': '⁹', '-': '⁻'} | |
return ''.join(m[i] for i in s) | |
int64 = struct.unpack('>Q', struct.pack('>d', floatv))[0] | |
sign = '+' if int64 >> 63 == 0 else '-' | |
mantissa = (int64 & 4503599627370495) / (1 << 52) | |
exp = (int64 >> 52) & 2047 | |
if exp == 2047: return str(floatv) | |
elif exp == 0: exp = -1022 | |
else: exp -= 1023; mantissa += 1 | |
return f"{sign}{mantissa} × 2{_superscript(str(exp))}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment