public static UFix16 Lerp(UFix16 left, UFix16 right, ushort fraction) { var tempOut = left._value * ((1 << 16) - fraction); tempOut += (long)right._value * fraction; tempOut >>= 16; var result = (uint)tempOut; return(*(UFix16 *)&result); }
public static UFix16 Lerp(UFix16 left, UFix16 right, uint fraction) { var tempOut = (long)left._value * (0 - fraction); tempOut += (long)right._value * fraction; tempOut >>= 32; var result = tempOut; return(*(UFix16 *)&result); }
private static UFix16 Divide(UFix16 left, UFix16 right, out bool overflow) { overflow = false; if (right == Zero) { throw new DivideByZeroException(); } uint a = *(uint *)&left, b = *(uint *)&right; //var result = ((ulong)a <<16) / ((ulong)b<<16); //result >>=16; ulong remainder = a; ulong divider = b; ulong quotient = 0u; var bitPos = 17; while ((divider & 0xF) is 0 && bitPos >= 4) { divider >>= 4; bitPos -= 4; } while (remainder is not 0 && bitPos >= 0) { // Shift remainder as much as we can without overflowing var shift = (int)Clz((uint)remainder); if (shift > bitPos) { shift = bitPos; } remainder <<= shift; bitPos -= shift; var div = remainder / divider; remainder %= divider; quotient += div << bitPos; var mask = 0x1FFFFFFFFu >> bitPos--; if ((div & ~mask) is not 0) { overflow = true; } remainder <<= 1; } quotient++; var result = quotient >> 1; return(overflow ? MaxValue : *(UFix16 *)&result); }
private static UFix16 Subtract(UFix16 left, UFix16 right, out bool overflow) { overflow = false; var l = *(uint *)&left; var r = *(uint *)&right; var result = l - r; if (r > l) { overflow = true; } return(overflow ? MinValue : Raw(result)); }
private static UFix16 Add(UFix16 left, UFix16 right, out bool overflow) { overflow = false; var l = *(uint *)&left; var r = *(uint *)&right; var result = l + r; if (result < l || result < r) { overflow = true; } return(overflow ? MaxValue : Raw(result)); }
private static UFix16 Multiply(UFix16 left, UFix16 right, out bool overflow) { overflow = false; var product = (ulong)*(uint *)&left * *(uint *)&right; // The upper 16 bits should all be the same (the sign). var upper = product >> 48; if (upper is not 0) { overflow = true; } var result = (int)(product >> 16); var temp = *(UFix16 *)&result; result += (int)(product & 0x8000) >> 15; return(overflow ? MaxValue : *(UFix16 *)&result); }
public static UFix16 Sqrt(UFix16 value) { var num = *(uint *)&value; var result = 0u; var bit = 0u; byte n; // Many numbers will be less than 15, so // this gives a good balance between time spent // in if vs. time spent in the while loop // when searching for the starting value. bit = (num & 0xFFF00000) != 0 ? 1u << 30 : 1u << 18; while (bit > num) { bit >>= 2; } // The main part is executed twice, in order to avoid // using 64 bit values in computations. for (n = 0; n < 2; n++) { // First we get the top 24 bits of the answer. while (bit != 0) { if (num >= result + bit) { num -= result + bit; result = (result >> 1) + bit; } else { result >>= 1; } bit >>= 2; } if (n == 0) { // Then process it again to get the lowest 8 bits. if (num > 65535) { // The remainder 'num' is too large to be shifted left // by 16, so we have to add 1 to result manually and // adjust 'num' accordingly. // num = a - (result + 0.5)^2 // = num + result^2 - (result + 0.5)^2 // = num - result - 0.5 num -= result; num = (num << 16) - 0x8000; result = (result << 16) + 0x8000; } else { num <<= 16; result <<= 16; } bit = 1 << 14; } } // Finally, if next bit would have been 1, round the result upwards. if (num > result) { result++; } return(new UFix16() { _value = result }); }
public static UFix16 Divide(UFix16 left, UFix16 right) => Divide(left, right, out _);
public static UFix16 Multiply(UFix16 left, UFix16 right) => Multiply(left, right, out _);
public static UFix16 Subtract(UFix16 left, UFix16 right) => Subtract(left, right, out _);
public static UFix16 Add(UFix16 left, UFix16 right) => Add(left, right, out _);
public static UFix16 CheckedDivide(UFix16 left, UFix16 right) { var value = Divide(left, right, out var overflow); return(overflow ? throw new OverflowException() : value); }