Exemple #1
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));
        }
Exemple #2
0
        /// <summary>
        /// Creates a Unum initialized with a value that is defined by the bits in a uint array.
        /// </summary>
        /// <param name="environment">The Unum environment.</param>
        /// <param name="value">
        /// The uint array which defines the Unum's value as an integer.
        /// To use with Hastlayer this should be the same size as the BitMasks in the given environment.
        /// </param>
        /// <param name="negative">Defines whether the number is positive or not.</param>
        public Unum(UnumEnvironment environment, uint[] value, bool negative = false)
        {
            _environment = environment;

            UnumBits = new BitMask(value, environment.Size);
            if (UnumBits == _environment.EmptyBitMask)
            {
                return;
            }

            // Handling the case when the number wouldn't fit in the range of the environment.
            if (UnumHelper.LargestExpressablePositiveInteger(environment) != environment.EmptyBitMask)
            {
                if (UnumBits > UnumHelper.LargestExpressablePositiveInteger(environment))
                {
                    UnumBits = negative ? environment.LargestNegative | environment.UncertaintyBitMask
                        : environment.LargestPositive | environment.UncertaintyBitMask;
                    return;
                }
            }
            var uncertainityBit = false;

            // Putting the actual value in a BitMask.
            var exponent = new BitMask(value, Size);

            // The value of the exponent is one less than the number of binary digits in the integer.
            var exponentValue = new BitMask((uint)(exponent.GetMostSignificantOnePosition() - 1), Size);

            // Calculating the number of bits needed to represent the value of the exponent.
            var exponentSize = exponentValue.GetMostSignificantOnePosition();

            // If the value of the exponent is not a power of 2,
            // then one more bit is needed to represent the biased value.
            if ((exponentValue.GetLowest32Bits() & exponentValue.GetLowest32Bits() - 1) > 0)
            {
                exponentSize++;
            }

            // Handling input numbers that don't fit in the range of the given environment.
            if (exponentSize > ExponentSizeMax)
            {
                UnumBits = negative ? (environment.LargestNegative | environment.UncertaintyBitMask) - 1
                    : (environment.LargestPositive | environment.UncertaintyBitMask) - 1;
                return;
            }
            // Calculating the bias from the number of bits representing the exponent.
            var bias = exponentSize == 0 ? 0 : (1 << exponentSize - 1) - 1;

            // Applying the bias to the exponent.
            exponent = exponentValue + (uint)bias;

            // Putting the actual value in a BitMask.
            var fraction = new BitMask(value, Size);

            // Shifting out the zeros after the least significant 1-bit.
            fraction = fraction.ShiftOutLeastSignificantZeros();

            // Calculating the number of bits needed to represent the fraction.
            var fractionSize = fraction.GetMostSignificantOnePosition();


            /* If there's a hidden bit and it's 1,
             * then the most significant 1-bit of the fraction is stored there,
             * so we're removing it from the fraction and decreasing fraction size accordingly. */
            if (exponent.GetLowest32Bits() > 0)
            {
                fractionSize--;
                fraction = fraction.SetZero(fractionSize);
            }
            // Handling input numbers that fit in the range, but are too big to represent exactly.
            if (fractionSize > FractionSizeMax)
            {
                fraction        = fraction >> FractionSizeMax - fractionSize;
                uncertainityBit = true;
            }

            UnumBits = AssembleUnumBits(negative, exponent, fraction,
                                        uncertainityBit, (byte)(exponentSize > 0 ? --exponentSize : 0), (ushort)(fractionSize > 0 ? --fractionSize : 0));
        }