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