zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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 }