trunctfxf2.zig (2852B) - Raw
1 const math = @import("std").math; 2 const common = @import("./common.zig"); 3 const trunc_f80 = @import("./truncf.zig").trunc_f80; 4 5 pub const panic = common.panic; 6 7 comptime { 8 @export(&__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = common.linkage, .visibility = common.visibility }); 9 } 10 11 pub fn __trunctfxf2(a: f128) callconv(.c) f80 { 12 const src_sig_bits = math.floatMantissaBits(f128); 13 const dst_sig_bits = math.floatMantissaBits(f80) - 1; // -1 for the integer bit 14 15 // Various constants whose values follow from the type parameters. 16 // Any reasonable optimizer will fold and propagate all of these. 17 const src_bits = @typeInfo(f128).float.bits; 18 const src_exp_bits = src_bits - src_sig_bits - 1; 19 const src_inf_exp = 0x7FFF; 20 21 const src_inf = src_inf_exp << src_sig_bits; 22 const src_sign_mask = 1 << (src_sig_bits + src_exp_bits); 23 const src_abs_mask = src_sign_mask - 1; 24 const round_mask = (1 << (src_sig_bits - dst_sig_bits)) - 1; 25 const halfway = 1 << (src_sig_bits - dst_sig_bits - 1); 26 27 // Break a into a sign and representation of the absolute value 28 const a_rep = @as(u128, @bitCast(a)); 29 const a_abs = a_rep & src_abs_mask; 30 const sign: u16 = if (a_rep & src_sign_mask != 0) 0x8000 else 0; 31 const integer_bit = 1 << 63; 32 33 var res: math.F80 = undefined; 34 35 if (a_abs > src_inf) { 36 // a is NaN. 37 // Conjure the result by beginning with infinity, setting the qNaN 38 // bit and inserting the (truncated) trailing NaN field. 39 res.exp = 0x7fff; 40 res.fraction = 0x8000000000000000; 41 res.fraction |= @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))); 42 } else { 43 // The exponent of a is within the range of normal numbers in the 44 // destination format. We can convert by simply right-shifting with 45 // rounding, adding the explicit integer bit, and adjusting the exponent 46 res.fraction = @as(u64, @truncate(a_abs >> (src_sig_bits - dst_sig_bits))) | integer_bit; 47 res.exp = @truncate(a_abs >> src_sig_bits); 48 49 const round_bits = a_abs & round_mask; 50 if (round_bits > halfway) { 51 // Round to nearest 52 const ov = @addWithOverflow(res.fraction, 1); 53 res.fraction = ov[0]; 54 res.exp += ov[1]; 55 res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry 56 } else if (round_bits == halfway) { 57 // Ties to even 58 const ov = @addWithOverflow(res.fraction, res.fraction & 1); 59 res.fraction = ov[0]; 60 res.exp += ov[1]; 61 res.fraction |= @as(u64, ov[1]) << 63; // Restore integer bit after carry 62 } 63 if (res.exp == 0) res.fraction &= ~@as(u64, integer_bit); // Remove integer bit for de-normals 64 } 65 66 res.exp |= sign; 67 return res.toFloat(); 68 }