/// <summary> /// Raise a to the b power. Special cases: /// * 1^NA => 1 /// * NA^0 => 1 /// </summary> public static IX Pow(IX a, IX b) { var av = a.RawValue; var bv = b.RawValue; if (av == 1) { return(1); } switch (bv) { case 0: return(1); case 1: return(av); case 2: return(a * a); case RawNA: return(RawNA); } if (av == -1) { return((bv & 1) == 0 ? 1 : -1); } if (bv < 0) { return(RawNA); } if (av == RawNA) { return(RawNA); } // Since the abs of the base is at least two, the exponent must be less than 31. if (bv >= 31) { return(RawNA); } bool neg = false; if (av < 0) { av = -av; neg = (bv & 1) != 0; } Contracts.Assert(av >= 2); // Since the exponent is at least three, the base must be <= 1290. Contracts.Assert(bv >= 3); if (av > 1290) { return(RawNA); } // REVIEW: Should we use a checked context and exception catching like I8 does? ulong u = (ulong)(uint)av; ulong result = 1; for (; ;) { if ((bv & 1) != 0 && (result *= u) > RawIX.MaxValue) { return(RawNA); } bv >>= 1; if (bv == 0) { break; } if ((u *= u) > RawIX.MaxValue) { return(RawNA); } } Contracts.Assert(result <= RawIX.MaxValue); var res = (RawIX)result; if (neg) { res = -res; } return(res); }
public static IX operator *(IX a, IX b) { var av = a._value; var bv = b._value; bool neg = (av ^ bv) < 0; if (av < 0) { if (av == RawNA) { return(RawNA); } av = -av; } if (bv < 0) { if (bv == RawNA) { return(RawNA); } bv = -bv; } // Deal with the low 32 bits. ulong lo1 = (ulong)av & 0x00000000FFFFFFFF; ulong lo2 = (ulong)bv & 0x00000000FFFFFFFF; RawIX res = (RawIX)(lo1 * lo2); if (res < 0) { return(RawNA); } // Get the high 32 bits, including cross terms. ulong hi1 = (ulong)av >> 32; ulong hi2 = (ulong)bv >> 32; if (hi1 != 0) { // If both high words are non-zero, overflow is guaranteed. if (hi2 != 0) { return(RawNA); } // Compute the cross term. ulong tmp = hi1 * lo2; if ((tmp & 0xFFFFFFFF80000000) != 0) { return(RawNA); } res += (long)(tmp << 32); if (res < 0) { return(RawNA); } } else if (hi2 != 0) { // Compute the cross term. ulong tmp = hi2 * lo1; if ((tmp & 0xFFFFFFFF80000000) != 0) { return(RawNA); } res += (long)(tmp << 32); if (res < 0) { return(RawNA); } } // Adjust the sign. if (neg) { res = -res; } return(res); }