Function binaryToDecimal [src]
Convert a binary float representation to decimal.
Prototype
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)
Parameters
T: type
bits: T
mantissa_bits: std.math.Log2Int(T)
exponent_bits: u5
explicit_leading_bit: bool
Source
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,
};
}