Пример #1
0
        /// <summary>
        /// Determines whether the integer is equal to the provided integer.
        /// </summary>
        /// <param name="other">The other integer.</param>
        /// <returns><c>true</c> if the integers are equal, <c>false</c> if not, and
        /// <c>null</c> if the conclusion of the comparison is not certain.</returns>
        public virtual Trilean IsEqualTo(IntegerValue other)
        {
            if (!IsKnown || !other.IsKnown)
            {
                // We are dealing with at least one unknown bit in the bit fields.
                // Conclusion is therefore either false or unknown.

                if (Size != other.Size)
                {
                    return(Trilean.False);
                }

                // Check if we definitely know this is not equal to the other.
                // TODO: this could probably use performance improvements.
                for (int i = 0; i < Size * 8; i++)
                {
                    Trilean a = GetBit(i);
                    Trilean b = other.GetBit(i);

                    if (a.IsKnown && b.IsKnown && a.Value != b.Value)
                    {
                        return(Trilean.False);
                    }
                }

                return(Trilean.Unknown);
            }

            return(Equals(other));
        }
Пример #2
0
        /// <summary>
        /// Subtracts a second (partially) known integer from the current integer.
        /// </summary>
        /// <param name="other">The integer to subtract.</param>
        /// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match.</exception>
        public virtual void Subtract(IntegerValue other)
        {
            // The following implements a ripple full-subtractor.

            AssertSameBitSize(other);

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

            maskBuffer.Fill(0xFF);

            var difference = new BitField(differenceBuffer);
            var mask       = new BitField(maskBuffer);

            Trilean borrow = false;

            for (int i = 0; i < differenceBuffer.Length * 8; i++)
            {
                var a = GetBit(i);
                var b = other.GetBit(i);

                // Implement full-subtractor logic.
                var d    = a ^ b ^ borrow;
                var bOut = (!a & borrow) | (!a & b) | (b & borrow);

                difference[i] = d.ToBooleanOrFalse();
                mask[i]       = d.IsKnown;
                borrow        = bOut;
            }

            SetBits(differenceBuffer, maskBuffer);
        }
Пример #3
0
        /// <summary>
        /// Adds a second (partially) known integer to the current integer.
        /// </summary>
        /// <param name="other">The integer to add.</param>
        /// <exception cref="ArgumentException">Occurs when the sizes of the integers do not match.</exception>
        public virtual void Add(IntegerValue other)
        {
            // The following implements a ripple full-adder.

            AssertSameBitSize(other);

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

            maskBuffer.Fill(0xFF);

            var sum  = new BitField(sumBuffer);
            var mask = new BitField(maskBuffer);

            Trilean carry = false;

            for (int i = 0; i < sumBuffer.Length * 8; i++)
            {
                var a = GetBit(i);
                var b = other.GetBit(i);

                // Implement full-adder logic.
                var s = a ^ b ^ carry;
                var c = (carry & (a ^ b)) | (a & b);

                sum[i]  = s.ToBooleanOrFalse();
                mask[i] = s.IsKnown;
                carry   = c;
            }

            SetBits(sumBuffer, maskBuffer);
        }
Пример #4
0
        /// <summary>
        /// Performs a bitwise exclusive or operation with another (partially) known integer value.
        /// </summary>
        public virtual void Xor(IntegerValue other)
        {
            AssertSameBitSize(other);

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

            GetBits(bits);

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

            GetMask(mask);

            if (IsKnown && other.IsKnown)
            {
                // Catch common case where everything is known.
                Span <byte> otherBits = stackalloc byte[Size];
                other.GetBits(otherBits);
                new BitField(bits).Xor(new BitField(otherBits));
            }
            else
            {
                // Some bits are unknown, perform operation manually.
                var bitField  = new BitField(bits);
                var maskField = new BitField(mask);

                for (int i = 0; i < mask.Length * 8; i++)
                {
                    var result = GetBit(i) ^ other.GetBit(i);
                    bitField[i]  = result.ToBooleanOrFalse();
                    maskField[i] = result.IsKnown;
                }
            }

            SetBits(bits, mask);
        }
Пример #5
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)
                {
Пример #6
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);
        }