mirror of
https://github.com/pmret/papermario.git
synced 2024-11-08 20:12:30 +01:00
62 lines
2.3 KiB
Python
62 lines
2.3 KiB
Python
|
|
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) |