import math import struct # From mips_to_c: https://github.com/matt-kempster/mips_to_c/blob/d208400cca045113dada3e16c0d59c50cdac4529/src/translate.py#L2085 def format_f32_imm(num: int) -> str: packed = struct.pack(">I", num & (2 ** 32 - 1)) value = struct.unpack(">f", packed)[0] if not value or value == 4294967296.0: # Zero, negative zero, nan, or INT_MAX. return str(value) # Write values smaller than 1e-7 / greater than 1e7 using scientific notation, # and values in between using fixed point. if abs(math.log10(abs(value))) > 6.9: fmt_char = "e" elif abs(value) < 1: fmt_char = "f" else: fmt_char = "g" def fmt(prec: int) -> str: """Format 'value' with 'prec' significant digits/decimals, in either scientific or regular notation depending on 'fmt_char'.""" ret = ("{:." + str(prec) + fmt_char + "}").format(value) if fmt_char == "e": return ret.replace("e+", "e").replace("e0", "e").replace("e-0", "e-") if "e" in ret: # The "g" format character can sometimes introduce scientific notation if # formatting with too few decimals. If this happens, return an incorrect # value to prevent the result from being used. # # Since the value we are formatting is within (1e-7, 1e7) in absolute # value, it will at least be possible to format with 7 decimals, which is # less than float precision. Thus, this annoying Python limitation won't # lead to us outputting numbers with more precision than we really have. return "0" return ret # 20 decimals is more than enough for a float. Start there, then try to shrink it. prec = 20 while prec > 0: prec -= 1 value2 = float(fmt(prec)) if struct.pack(">f", value2) != packed: prec += 1 break if prec == 20: # Uh oh, even the original value didn't format correctly. Fall back to str(), # which ought to work. return str(value) ret = fmt(prec) if "." not in ret: ret += ".0" return ret def format_f64_imm(num: int) -> str: (value,) = struct.unpack(">d", struct.pack(">Q", num & (2 ** 64 - 1))) return str(value)