Beispiel #1
0
 public static bool AreEqualExactUnums(Unum left, Unum right) =>
 left.IsZero() && right.IsZero() ? true : left.UnumBits == right.UnumBits;
Beispiel #2
0
 public static Unum SubtractExactUnums(Unum left, Unum right) => AddExactUnums(left, NegateExactUnum(right));
Beispiel #3
0
 public static Unum NegateExactUnum(Unum input) => input.Negate();
Beispiel #4
0
        public static Unum AddExactUnums(Unum left, Unum right)
        {
            // It could be only FractionSizeMax + 2 long if that would be Hastlayer-compatible (it isn't due to static
            // array sizes).
            var scratchPad = new BitMask(left._environment.Size);

            // Handling special cases first.
            if (left.IsNan() || right.IsNan())
            {
                return(new Unum(left._environment, left.QuietNotANumber));
            }

            if ((left.IsPositiveInfinity() && right.IsNegativeInfinity()) ||
                (left.IsNegativeInfinity() && right.IsPositiveInfinity()))
            {
                return(new Unum(left._environment, left.QuietNotANumber));
            }

            if (left.IsPositiveInfinity() || right.IsPositiveInfinity())
            {
                return(new Unum(left._environment, left.PositiveInfinity));
            }

            if (left.IsNegativeInfinity() || right.IsNegativeInfinity())
            {
                return(new Unum(left._environment, left.NegativeInfinity));
            }

            var exponentValueDifference = left.ExponentValueWithBias() - right.ExponentValueWithBias();
            var signBitsMatch           = left.IsPositive() == right.IsPositive();
            var resultSignBit           = false;
            var biggerBitsMovedToLeft   = 0;
            var smallerBitsMovedToLeft  = 0;
            var resultExponentValue     = 0;


            if (exponentValueDifference == 0) // Exponents are equal.
            {
                resultExponentValue = left.ExponentValueWithBias();

                // We align the fractions so their Most Significant Bit gets to the leftmost position that the
                // FractionSize allows. This way the digits that won't fit automatically get lost.
                biggerBitsMovedToLeft  = left.FractionSizeMax + 1 - (left.FractionSize() + 1);
                smallerBitsMovedToLeft = left.FractionSizeMax + 1 - (right.FractionSize() + 1);
                // Adding the aligned Fractions.
                scratchPad = AddAlignedFractions(
                    left.FractionWithHiddenBit() << biggerBitsMovedToLeft,
                        right.FractionWithHiddenBit() << smallerBitsMovedToLeft,
                        signBitsMatch);


                if (!signBitsMatch)
                {
                    // If the value of the Hidden Bits match we just compare the fractions,
                    // and get the Sign of the bigger one.
                    if (left.HiddenBitIsOne() == right.HiddenBitIsOne())
                    {
                        resultSignBit = left.Fraction() >= right.Fraction()
                            ? !left.IsPositive()   // Left Fraction is bigger.
                            : !right.IsPositive(); // Right Fraction is bigger.
                    }
                    // Otherwise we get the Sign of the number that has a Hidden Bit set.
                    else
                    {
                        resultSignBit = left.HiddenBitIsOne() ? !left.IsPositive() : !right.IsPositive();
                    }
                }
                else
                {
                    resultSignBit = !left.IsPositive();
                }
            }
            else if (exponentValueDifference > 0) // Left Exponent is bigger.
            {
                // We align the fractions according to their exponent values so the Most Significant Bit  of the bigger
                // number gets to the leftmost position that the  FractionSize allows.
                // This way the digits that won't fit automatically get lost.
                resultSignBit          = !left.IsPositive();
                resultExponentValue    = left.ExponentValueWithBias();
                biggerBitsMovedToLeft  = left.FractionSizeMax + 1 - (left.FractionSize() + 1);
                smallerBitsMovedToLeft = left.FractionSizeMax + 1 - (right.FractionSize() + 1) - exponentValueDifference;

                scratchPad = left.FractionWithHiddenBit() << biggerBitsMovedToLeft;
                // Adding the aligned Fractions.
                scratchPad = AddAlignedFractions(scratchPad,
                                                 right.FractionWithHiddenBit() << smallerBitsMovedToLeft, signBitsMatch);
            }
            else // Right Exponent is bigger.
            {
                // We align the fractions according to their exponent values so the Most Significant Bit  of the bigger
                // number gets to the leftmost position that the  FractionSize allows.
                // This way the digits that won't fit automatically get lost.
                resultSignBit          = !right.IsPositive();
                resultExponentValue    = right.ExponentValueWithBias();
                biggerBitsMovedToLeft  = left.FractionSizeMax + 1 - (right.FractionSize() + 1);
                smallerBitsMovedToLeft = left.FractionSizeMax + 1 - (left.FractionSize() + 1) + exponentValueDifference;

                scratchPad = right.FractionWithHiddenBit() << biggerBitsMovedToLeft;
                // Adding the aligned Fractions.
                scratchPad = AddAlignedFractions(scratchPad,
                                                 left.FractionWithHiddenBit() << smallerBitsMovedToLeft, signBitsMatch);
            }

            // Calculating how the addition changed the exponent of the result.
            var exponentChange = scratchPad.GetMostSignificantOnePosition() - (left.FractionSizeMax + 1);
            var resultExponent = new BitMask(left._environment.Size) +
                                 ExponentValueToExponentBits(resultExponentValue + exponentChange, left.Size);
            // Calculating the ExponentSize needed to the excess-k notation of the results Exponent value.
            var resultExponentSize = (byte)(ExponentValueToExponentSize(resultExponentValue + exponentChange) - 1);

            var resultUbit = false;

            if (smallerBitsMovedToLeft < 0)
            {
                resultUbit = true;                             // There are lost digits, so we set the ubit to 1.
            }
            // If there are no lost digits, we can shift out the least significant zeros to save space.
            else
            {
                scratchPad = scratchPad.ShiftOutLeastSignificantZeros();
            }

            ushort resultFractionSize = 0;

            //Calculating the results FractionSize.
            if (scratchPad.GetMostSignificantOnePosition() == 0) // If the Fraction is zero, so is the FractionSize.
            {
                resultExponent     = scratchPad;                 // 0
                resultExponentSize = 0;                          // If the Fraction is zero, so is the ExponentSize.
            }
            else
            {
                resultFractionSize = (ushort)(scratchPad.GetMostSignificantOnePosition() - 1);
            }


            if (resultExponent.GetMostSignificantOnePosition() != 0) // Erase the hidden bit if it is set.
            {
                scratchPad         = scratchPad.SetZero((ushort)(scratchPad.GetMostSignificantOnePosition() - 1));
                resultFractionSize = (ushort)(resultFractionSize == 0 ? 0 : resultFractionSize - 1);
            }

            // This is temporary, for the imitation of float behaviour. Now the Ubit works as a flag for rounded values.
            // When Ubounds will be implemented this should be handled in the addition operator.
            if ((!left.IsExact()) || (!right.IsExact()))
            {
                resultUbit = true;
            }

            // Setting the parts of the result Unum to the calculated values.
            var resultBitMask = left.AssembleUnumBits(resultSignBit, resultExponent, scratchPad,
                                                      resultUbit, resultExponentSize, resultFractionSize);

            return(new Unum(left._environment, resultBitMask));
        }