from .math_round_float import round_float POW10 = [1.0, 10.0, 100.0, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12] def format_decimal(value: float, decimals: int, trim_zeros: bool, group_separator: str) -> str: """A float as decimal text, never in exponent form and never "-0". str(), String() and Rust's Display disagree about floats (1e-07, 1e-7, 0.0000001), so the number is rounded once, turned into a whole count of 10^-decimals units, and the digits of that integer are laid out by hand. """ rounded = round_float(value, decimals) scaled = abs(rounded) * POW10[decimals] if scaled >= 1e15: raise ValueError("value is too large to format at %d decimal places, received %r" % (decimals, value)) units = int(round_float(scaled, 0)) digits = str(units).rjust(decimals + 1, "0") whole = digits[: len(digits) - decimals] fraction = digits[len(digits) - decimals:] if trim_zeros: fraction = fraction.rstrip("0") grouped = "" for i, ch in enumerate(whole): if i > 0 and (len(whole) - i) % 3 == 0: grouped += group_separator grouped += ch body = grouped + "." + fraction if fraction else grouped return "-" + body if units > 0 and rounded < 0 else body