public static bool AreEqualExactUnums(Unum left, Unum right) => left.IsZero() && right.IsZero() ? true : left.UnumBits == right.UnumBits;
public static Unum SubtractExactUnums(Unum left, Unum right) => AddExactUnums(left, NegateExactUnum(right));
public static Unum NegateExactUnum(Unum input) => input.Negate();
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)); }