DoxigAlpha

binaryToDecimal

Convert a binary float representation to decimal.

Function parameters

Parameters

#
T:type
bits:T
mantissa_bits:std.math.Log2Int(T)
exponent_bits:u5
explicit_leading_bit:bool
tables:anytype

Type definitions in this namespace

Types

#

Returns the minimum buffer size needed to print every float of a specific type and format.

Functions

#
bufferSize
Returns the minimum buffer size needed to print every float of a specific type and format.
render
Format a floating-point value and write it to buffer.
formatScientific
Write a FloatDecimal to a buffer in scientific form.
formatDecimal
Write a FloatDecimal to a buffer in decimal form.
binaryToDecimal
Convert a binary float representation to decimal.

Error sets in this namespace

Error Sets

#

Any buffer used for `format` must be at least this large.

Values

#
min_buffer_size
Any buffer used for `format` must be at least this large.

Source

Implementation

#
pub fn binaryToDecimal(comptime T: type, bits: T, mantissa_bits: std.math.Log2Int(T), exponent_bits: u5, explicit_leading_bit: bool, comptime tables: anytype) FloatDecimal(T) {
    if (T != tables.T) {
        @compileError("table type does not match backend type: " ++ @typeName(tables.T) ++ " != " ++ @typeName(T));
    }

    const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
    const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
    const ieee_mantissa = bits & ((@as(T, 1) << mantissa_bits) - 1);
    const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(T, 1) << exponent_bits) - 1));

    if (ieee_exponent == 0 and ieee_mantissa == 0) {
        return .{
            .mantissa = 0,
            .exponent = 0,
            .sign = ieee_sign,
        };
    }
    if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
        return .{
            .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(T, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
            .exponent = special_exponent,
            .sign = ieee_sign,
        };
    }

    var e2: i32 = undefined;
    var m2: T = undefined;
    if (explicit_leading_bit) {
        if (ieee_exponent == 0) {
            e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
        } else {
            e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
        }
        m2 = ieee_mantissa;
    } else {
        if (ieee_exponent == 0) {
            e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
            m2 = ieee_mantissa;
        } else {
            e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
            m2 = (@as(T, 1) << mantissa_bits) | ieee_mantissa;
        }
    }
    const even = (m2 & 1) == 0;
    const accept_bounds = even;

    // Step 2: Determine the interval of legal decimal representations.
    const mv = 4 * m2;
    const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(T, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));

    // Step 3: Convert to a decimal power base using 128-bit arithmetic.
    var vr: T = undefined;
    var vp: T = undefined;
    var vm: T = undefined;
    var e10: i32 = undefined;
    var vm_is_trailing_zeros = false;
    var vr_is_trailing_zeros = false;
    if (e2 >= 0) {
        const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
        e10 = cast_i32(q);
        const k: i32 = @intCast(tables.POW5_INV_BITCOUNT + pow5Bits(q) - 1);
        const i: u32 = @intCast(-e2 + cast_i32(q) + k);

        const pow5 = tables.computeInvPow5(q);
        vr = tables.mulShift(4 * m2, &pow5, i);
        vp = tables.mulShift(4 * m2 + 2, &pow5, i);
        vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, i);

        if (q <= tables.bound1) {
            if (mv % 5 == 0) {
                vr_is_trailing_zeros = multipleOfPowerOf5(mv, if (tables.adjust_q) q -% 1 else q);
            } else if (accept_bounds) {
                vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
            } else {
                vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
            }
        }
    } else {
        const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
        e10 = cast_i32(q) + e2;
        const i: i32 = -e2 - cast_i32(q);
        const k: i32 = cast_i32(pow5Bits(@intCast(i))) - tables.POW5_BITCOUNT;
        const j: u32 = @intCast(cast_i32(q) - k);

        const pow5 = tables.computePow5(@intCast(i));
        vr = tables.mulShift(4 * m2, &pow5, j);
        vp = tables.mulShift(4 * m2 + 2, &pow5, j);
        vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, j);

        if (q <= 1) {
            vr_is_trailing_zeros = true;
            if (accept_bounds) {
                vm_is_trailing_zeros = mm_shift == 1;
            } else {
                vp -= 1;
            }
        } else if (q < tables.bound2) {
            vr_is_trailing_zeros = multipleOfPowerOf2(mv, if (tables.adjust_q) q - 1 else q);
        }
    }

    // Step 4: Find the shortest decimal representation in the interval of legal representations.
    var removed: u32 = 0;
    var last_removed_digit: u8 = 0;

    while (vp / 10 > vm / 10) {
        vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
        vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
        last_removed_digit = @intCast(vr % 10);
        vr /= 10;
        vp /= 10;
        vm /= 10;
        removed += 1;
    }

    if (vm_is_trailing_zeros) {
        while (vm % 10 == 0) {
            vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
            last_removed_digit = @intCast(vr % 10);
            vr /= 10;
            vp /= 10;
            vm /= 10;
            removed += 1;
        }
    }

    if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
        last_removed_digit = 4;
    }

    return .{
        .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
        .exponent = e10 + cast_i32(removed),
        .sign = ieee_sign,
    };
}