예제 #1
0
        /// <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);
        }
예제 #2
0
        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);
        }