Exemple #1
0
        /// <summary>
        /// Determines whether the integer is greater than the provided integer.
        /// </summary>
        /// <param name="other">The other integer.</param>
        /// <param name="signed">Indicates the integers should be interpreted as signed or unsigned integers.</param>
        /// <returns><c>true</c> if the current integer is greater than the provided integer, <c>false</c> if not, and
        /// <c>null</c> if the conclusion of the comparison is not certain.</returns>
        public virtual Trilean IsGreaterThan(IntegerValue other, bool signed)
        {
            if (signed)
            {
                var thisSigned  = GetLastBit();
                var otherSigned = other.GetLastBit();
                if (thisSigned.IsUnknown || otherSigned.IsUnknown)
                {
                    return(Trilean.Unknown);
                }

                // If the signs do not match, we know the result
                if (thisSigned ^ otherSigned)
                {
                    return(otherSigned);
                }

                if (thisSigned)
                {
                    return(IsLessThan(other, false));
                }
            }

            // The following implements the "truth" table:
            // "-" indicates we do not know the answer yet.
            //
            //    | 0 | 1 | ?
            // ---+---+---+---
            //  0 | - | 0 | 0
            //  --+---+---+---
            //  1 | 1 | - | ?
            //  --+---+---+---
            //  ? | ? | 0 | ?

            AssertSameBitSize(other);

            for (int i = Size * 8 - 1; i >= 0; i--)
            {
                Trilean a = GetBit(i);
                Trilean b = other.GetBit(i);

                switch (a.Value, b.Value)
                {
Exemple #2
0
        /// <summary>
        /// Multiplies the current integer with a second (partially) known integer.
        /// </summary>
        /// <param name="other">The integer to multiply with.</param>
        /// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match.</exception>
        public virtual void Multiply(IntegerValue other)
        {
            AssertSameBitSize(other);

            // We implement the standard multiplication by adding and shifting, but instead of storing all intermediate
            // results, we can precompute the two possible intermediate results and shift those and add them to an end
            // result to preserve time and memory.

            // First possible intermediate result is the current value multiplied by 0. It is redundant to compute this.

            // Second possibility is the current value multiplied by 1.
            var multipliedByOne = (IntegerValue)Copy();

            // Third possibility is thee current value multiplied by ?. This is effectively marking all set bits unknown.
            // TODO: We could probably optimise the following operations for the native integer types.
            var multipliedByUnknown = (IntegerValue)Copy();

            Span <byte> maskBuffer = stackalloc byte[Size];

            multipliedByOne.GetMask(maskBuffer);

            Span <byte> bitsBuffer = stackalloc byte[Size];

            multipliedByOne.GetBits(bitsBuffer);

            var mask = new BitField(maskBuffer);
            var bits = new BitField(bitsBuffer);

            mask.Not();
            mask.Or(bits);
            mask.Not();

            Span <byte> unknownBits = stackalloc byte[Size];

            multipliedByUnknown.GetBits(unknownBits);

            multipliedByUnknown.SetBits(unknownBits, maskBuffer);

            // Final result.
            var result = new IntegerNValue(Size);

            int lastShiftByOne     = 0;
            int lastShiftByUnknown = 0;

            for (int i = 0; i < Size * 8; i++)
            {
                Trilean bit = other.GetBit(i);

                if (!bit.IsKnown)
                {
                    multipliedByUnknown.LeftShift(i - lastShiftByUnknown);
                    result.Add(multipliedByUnknown);
                    lastShiftByUnknown = i;
                }
                else if (bit.ToBoolean())
                {
                    multipliedByOne.LeftShift(i - lastShiftByOne);
                    result.Add(multipliedByOne);
                    lastShiftByOne = i;
                }
            }

            Span <byte> resultBits = stackalloc byte[Size];
            Span <byte> resultMask = stackalloc byte[Size];

            result.GetBits(resultBits);
            result.GetMask(resultMask);

            SetBits(resultBits, resultMask);
        }
Exemple #3
0
        /// <summary>
        /// Divides the current integer with a second (partially) known integer and returns remainder of division.
        /// </summary>
        /// <param name="other">The integer to divide with</param>
        /// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match or there is dividing by zero.</exception>
        public virtual void Remainder(IntegerValue other)
        {
            AssertSameBitSize(other);

            // Throw exception because of dividing by zero
            if (other.IsZero == Trilean.True)
            {
                throw new ArgumentException("Divisor is zero and dividing by zero is not allowed.");
            }

            // There are 2 possibilities
            // First is that both numbers are known. In this possibility remainder is counted as usual.
            // Second possibility is that some of numbers are unknown.
            // Remainder in second possibility is count as shorter number of this two numbers with all bits set to unknown.

            var firstNum  = (IntegerValue)Copy();
            var secondNum = (IntegerValue)other.Copy();
            var result    = (IntegerValue)Copy();

            // Possibilities of count
            if (firstNum.IsKnown && secondNum.IsKnown)
            {
                // Remainder is count by classic way
                while (firstNum.IsGreaterThan(secondNum, false) || firstNum.IsEqualTo(secondNum))
                {
                    firstNum.Subtract(secondNum);
                }

                result = firstNum;
            }
            else
            {
                // Setting all unknown bits to True because of finding out smaller number
                for (int i = 0; i < Size * 8; i++)
                {
                    if (firstNum.GetBit(i) == Trilean.Unknown)
                    {
                        firstNum.SetBit(i, Trilean.True);
                    }

                    if (secondNum.GetBit(i) == Trilean.Unknown)
                    {
                        secondNum.SetBit(i, Trilean.True);
                    }
                }

                // Result is shorter number
                result = (firstNum.IsGreaterThan(secondNum, false))
                    ? (IntegerValue)secondNum.Copy()
                    : (IntegerValue)firstNum.Copy();

                // Setting all bits to unknown in result
                bool isZeroBit = false;
                for (int i = Size * 8 - 1; i >= 0; i--)
                {
                    // Jumping through zeros
                    if (result.GetBit(i) != Trilean.False || isZeroBit)
                    {
                        isZeroBit = true;
                        result.SetBit(i, Trilean.Unknown);
                    }
                }
            }

            Span <byte> resultBits = stackalloc byte[Size];
            Span <byte> resultMask = stackalloc byte[Size];

            result.GetBits(resultBits);
            result.GetMask(resultMask);

            SetBits(resultBits, resultMask);
        }
Exemple #4
0
        /// <summary>
        /// Divides the current integer with a second (partially) known integer.
        /// </summary>
        /// <param name="other">The integer to divide with</param>
        /// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match or there is dividing by zero.</exception>
        public virtual void Divide(IntegerValue other)
        {
            AssertSameBitSize(other);

            // Throw exception because of dividing by zero
            if (other.IsZero == Trilean.True)
            {
                throw new ArgumentException("Divisor is zero and dividing by zero is not allowed.");
            }

            // There is only one possibility to cover all possible result
            // The solution is to get first number as big as possible by changing all Uknown bits to True
            // And second number needs to be as small as possible by changing all Unknown bits to false

            // First possibility
            var firstNum  = (IntegerValue)Copy();
            var secondNum = (IntegerValue)other.Copy();
            var oneNum    = (IntegerValue)Copy();
            var result    = (IntegerValue)Copy();

            for (int i = 0; i < Size * 8; i++)
            {
                if (firstNum.GetBit(i) == Trilean.Unknown)
                {
                    firstNum.SetBit(i, Trilean.True);
                }

                if (secondNum.GetBit(i) == Trilean.Unknown)
                {
                    secondNum.SetBit(i, Trilean.False);
                }

                oneNum.SetBit(i, Trilean.False);
                result.SetBit(i, Trilean.False);
            }

            oneNum.SetBit(0, Trilean.True);

            // Adding 1 to second number if it is zero
            if (secondNum.IsZero)
            {
                secondNum.Add(oneNum);
            }

            while ((firstNum.IsGreaterThan(secondNum, false) == Trilean.True || firstNum.IsEqualTo(secondNum)))
            {
                result.Add(oneNum);
                firstNum.Subtract(secondNum);
            }

            // Changing all known bits to unknown in greater result
            if (!IsKnown || !other.IsKnown)
            {
                bool isZeroBit = false;
                for (int i = Size * 8 - 1; i >= 0; i--)
                {
                    // Jumping through zeros
                    if (result.GetBit(i) != Trilean.False || isZeroBit)
                    {
                        isZeroBit = true;
                        result.SetBit(i, Trilean.Unknown);
                    }
                }
            }

            Span <byte> resultBits = stackalloc byte[Size];
            Span <byte> resultMask = stackalloc byte[Size];

            result.GetBits(resultBits);
            result.GetMask(resultMask);

            SetBits(resultBits, resultMask);
        }