zig

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

addf3.zig (6348B) - Raw


      1 const std = @import("std");
      2 const math = std.math;
      3 const common = @import("./common.zig");
      4 const normalize = common.normalize;
      5 
      6 /// Ported from:
      7 ///
      8 /// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc
      9 pub inline fn addf3(comptime T: type, a: T, b: T) T {
     10     const bits = @typeInfo(T).float.bits;
     11     const Z = std.meta.Int(.unsigned, bits);
     12 
     13     const typeWidth = bits;
     14     const significandBits = math.floatMantissaBits(T);
     15     const fractionalBits = math.floatFractionalBits(T);
     16     const exponentBits = math.floatExponentBits(T);
     17 
     18     const signBit = (@as(Z, 1) << (significandBits + exponentBits));
     19     const maxExponent = ((1 << exponentBits) - 1);
     20 
     21     const integerBit = (@as(Z, 1) << fractionalBits);
     22     const quietBit = integerBit >> 1;
     23     const significandMask = (@as(Z, 1) << significandBits) - 1;
     24 
     25     const absMask = signBit - 1;
     26     const qnanRep = @as(Z, @bitCast(math.nan(T))) | quietBit;
     27 
     28     var aRep: Z = @bitCast(a);
     29     var bRep: Z = @bitCast(b);
     30     const aAbs = aRep & absMask;
     31     const bAbs = bRep & absMask;
     32 
     33     const infRep: Z = @bitCast(math.inf(T));
     34 
     35     // Detect if a or b is zero, infinity, or NaN.
     36     if (aAbs -% @as(Z, 1) >= infRep - @as(Z, 1) or
     37         bAbs -% @as(Z, 1) >= infRep - @as(Z, 1))
     38     {
     39         // NaN + anything = qNaN
     40         if (aAbs > infRep) return @bitCast(@as(Z, @bitCast(a)) | quietBit);
     41         // anything + NaN = qNaN
     42         if (bAbs > infRep) return @bitCast(@as(Z, @bitCast(b)) | quietBit);
     43 
     44         if (aAbs == infRep) {
     45             // +/-infinity + -/+infinity = qNaN
     46             if ((@as(Z, @bitCast(a)) ^ @as(Z, @bitCast(b))) == signBit) {
     47                 return @bitCast(qnanRep);
     48             }
     49             // +/-infinity + anything remaining = +/- infinity
     50             else {
     51                 return a;
     52             }
     53         }
     54 
     55         // anything remaining + +/-infinity = +/-infinity
     56         if (bAbs == infRep) return b;
     57 
     58         // zero + anything = anything
     59         if (aAbs == 0) {
     60             // but we need to get the sign right for zero + zero
     61             if (bAbs == 0) {
     62                 return @bitCast(@as(Z, @bitCast(a)) & @as(Z, @bitCast(b)));
     63             } else {
     64                 return b;
     65             }
     66         }
     67 
     68         // anything + zero = anything
     69         if (bAbs == 0) return a;
     70     }
     71 
     72     // Swap a and b if necessary so that a has the larger absolute value.
     73     if (bAbs > aAbs) {
     74         const temp = aRep;
     75         aRep = bRep;
     76         bRep = temp;
     77     }
     78 
     79     // Extract the exponent and significand from the (possibly swapped) a and b.
     80     var aExponent: i32 = @intCast((aRep >> significandBits) & maxExponent);
     81     var bExponent: i32 = @intCast((bRep >> significandBits) & maxExponent);
     82     var aSignificand = aRep & significandMask;
     83     var bSignificand = bRep & significandMask;
     84 
     85     // Normalize any denormals, and adjust the exponent accordingly.
     86     if (aExponent == 0) aExponent = normalize(T, &aSignificand);
     87     if (bExponent == 0) bExponent = normalize(T, &bSignificand);
     88 
     89     // The sign of the result is the sign of the larger operand, a.  If they
     90     // have opposite signs, we are performing a subtraction; otherwise addition.
     91     const resultSign = aRep & signBit;
     92     const subtraction = (aRep ^ bRep) & signBit != 0;
     93 
     94     // Shift the significands to give us round, guard and sticky, and or in the
     95     // implicit significand bit.  (If we fell through from the denormal path it
     96     // was already set by normalize( ), but setting it twice won't hurt
     97     // anything.)
     98     aSignificand = (aSignificand | integerBit) << 3;
     99     bSignificand = (bSignificand | integerBit) << 3;
    100 
    101     // Shift the significand of b by the difference in exponents, with a sticky
    102     // bottom bit to get rounding correct.
    103     const @"align": u32 = @intCast(aExponent - bExponent);
    104     if (@"align" != 0) {
    105         if (@"align" < typeWidth) {
    106             const sticky = if (bSignificand << @intCast(typeWidth - @"align") != 0) @as(Z, 1) else 0;
    107             bSignificand = (bSignificand >> @truncate(@"align")) | sticky;
    108         } else {
    109             bSignificand = 1; // sticky; b is known to be non-zero.
    110         }
    111     }
    112     if (subtraction) {
    113         aSignificand -= bSignificand;
    114         // If a == -b, return +zero.
    115         if (aSignificand == 0) return @bitCast(@as(Z, 0));
    116 
    117         // If partial cancellation occurred, we need to left-shift the result
    118         // and adjust the exponent:
    119         if (aSignificand < integerBit << 3) {
    120             const shift = @as(i32, @intCast(@clz(aSignificand))) - @as(i32, @intCast(@clz(integerBit << 3)));
    121             aSignificand <<= @intCast(shift);
    122             aExponent -= shift;
    123         }
    124     } else { // addition
    125         aSignificand += bSignificand;
    126 
    127         // If the addition carried up, we need to right-shift the result and
    128         // adjust the exponent:
    129         if (aSignificand & (integerBit << 4) != 0) {
    130             const sticky = aSignificand & 1;
    131             aSignificand = aSignificand >> 1 | sticky;
    132             aExponent += 1;
    133         }
    134     }
    135 
    136     // If we have overflowed the type, return +/- infinity:
    137     if (aExponent >= maxExponent) return @bitCast(infRep | resultSign);
    138 
    139     if (aExponent <= 0) {
    140         // Result is denormal; the exponent and round/sticky bits are zero.
    141         // All we need to do is shift the significand and apply the correct sign.
    142         aSignificand >>= @intCast(4 - aExponent);
    143         return @bitCast(resultSign | aSignificand);
    144     }
    145 
    146     // Low three bits are round, guard, and sticky.
    147     const roundGuardSticky = aSignificand & 0x7;
    148 
    149     // Shift the significand into place, and mask off the integer bit, if it's implicit.
    150     var result = (aSignificand >> 3) & significandMask;
    151 
    152     // Insert the exponent and sign.
    153     result |= @as(Z, @intCast(aExponent)) << significandBits;
    154     result |= resultSign;
    155 
    156     // Final rounding.  The result may overflow to infinity, but that is the
    157     // correct result in that case.
    158     if (roundGuardSticky > 0x4) result += 1;
    159     if (roundGuardSticky == 0x4) result += result & 1;
    160 
    161     // Restore any explicit integer bit, if it was rounded off
    162     if (significandBits != fractionalBits) {
    163         if ((result >> significandBits) != 0) result |= integerBit;
    164     }
    165 
    166     return @bitCast(result);
    167 }
    168 
    169 test {
    170     _ = @import("addf3_test.zig");
    171 }