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)); }
/// <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)); }