// This doesn't work for all cases yet. //public Unum(UnumEnvironment environment, float number) //{ // _environment = environment; // // Handling special cases first. // if (float.IsNaN(number)) // { // UnumBits = _environment.QuietNotANumber; // return; // } // if (float.IsPositiveInfinity(number)) // { // UnumBits = _environment.PositiveInfinity; // return; // } // if (float.IsNegativeInfinity(number)) // { // UnumBits = _environment.NegativeInfinity; // return; // } // UnumBits = new BitMask(_environment.Size); // var floatExponentBits = (BitConverter.ToUInt32(BitConverter.GetBytes(number), 0) << 1) >> 24; // // These are the only uncertain cases that we can safely handle without Ubounds. // if (ExponentSizeMax < ExponentValueToExponentSize((int)floatExponentBits - 127)) // { // // The exponent is too big, so we express the number as the largest possible signed value, // // but the Unum is uncertain, meaning that it's finite, but too big to express. // if (floatExponentBits - 127 > 0) // UnumBits = IsPositive() ? LargestPositive : LargestNegative; // else // If the exponent is too small, we will handle it as a signed uncertain zero. // { // UnumBits = new BitMask(Size); // if (!IsPositive()) Negate(); // } // SetUncertainityBit(true); // return; // } // var floatFractionBits = (BitConverter.ToUInt32(BitConverter.GetBytes(number), 0) << 9) >> 9; // uint resultFractionSize = 23; // uint floatFractionBitsSize = 23; // if (floatFractionBits == 0) resultFractionSize = 0; // else // while (floatFractionBits % 2 == 0) // { // resultFractionSize -= 1; // floatFractionBits >>= 1; // floatFractionBitsSize = resultFractionSize; // } // var uncertainty = false; // if (FractionSizeMax + 1 < resultFractionSize) // { // resultFractionSize = ((uint)FractionSizeMax - 1); // uncertainty = true; // } // else if (resultFractionSize > 0) resultFractionSize = (resultFractionSize - 1); // var resultFraction = uncertainty ? // new BitMask(new uint[] { floatFractionBits >> (int)floatFractionBitsSize - FractionSizeMax }, Size) : // new BitMask(new uint[] { floatFractionBits }, Size); // var resultExponent = ExponentValueToExponentBits((int)(floatExponentBits - 127), Size); // var floatBits = BitConverter.ToUInt32(BitConverter.GetBytes(number), 0); // var resultSignBit = (floatBits > uint.MaxValue / 2); // var resultExponentSize = (ExponentValueToExponentSize((int)floatExponentBits - 127) - 1); // AssembleUnumBits(resultSignBit, resultExponent, resultFraction, // uncertainty, resultExponentSize, resultFractionSize); //} /// <summary> /// Creates a Unum of the given environment initialized with the value of the uint. /// </summary> /// <param name="environment">The Unum environment.</param> /// <param name="value">The uint value to initialize the new Unum with.</param> public Unum(UnumEnvironment environment, uint value) { _environment = environment; // Creating an array of the size needed to call the other constructor. // This is necessary because in Hastlayer only arrays with dimensions defined at compile-time are supported. var valueArray = new uint[environment.EmptyBitMask.SegmentCount]; valueArray[0] = value; UnumBits = new Unum(environment, valueArray).UnumBits; }
/// <summary> /// Shifts the BitMask to the right by the number of trailing zeros. /// </summary> /// <returns>A BitMask where the trailing zeros are shifted out to the right.</returns> public BitMask ShiftOutLeastSignificantZeros() { var leastSignificantOnePosition = GetLeastSignificantOnePosition(); var mask = new BitMask(this); if (leastSignificantOnePosition == 0) { return(mask); } return(mask >> leastSignificantOnePosition - 1); }
public static BitMask ExponentValueToExponentBits(int value, ushort size) { var exponent = new BitMask((uint)((value < 0) ? -value : value), size); var exponentSize = ExponentValueToExponentSize(value); exponent += (uint)(1 << (exponentSize - 1)) - 1; // Applying bias if (value < 0) // In case of a negative exponent the { exponent -= (uint)(-2 * value); } return(exponent); }
public static BitMask AddAlignedFractions(BitMask left, BitMask right, bool signBitsMatch) { var mask = new BitMask(left.Size); if (signBitsMatch) { mask = left + right; } else { mask = left > right ? left - right : right - left; } return(mask); }
// This doesn't work for all cases yet. //public Unum(UnumEnvironment environment, double x) //{ // _environment = environment; // UnumBits = _environment.EmptyBitMask; // // Handling special cases first. // if (double.IsNaN(x)) // { // UnumBits = QuietNotANumber; // return; // } // if (double.IsPositiveInfinity(x)) // { // UnumBits = PositiveInfinity; // return; // } // if (double.IsNegativeInfinity(x)) // { // UnumBits = NegativeInfinity; // return; // } // var doubleBits = BitConverter.ToUInt64(BitConverter.GetBytes(x), 0); // SetSignBit((doubleBits > ulong.MaxValue / 2)); // var doubleFractionBits = (BitConverter.ToUInt64(BitConverter.GetBytes(x), 0) << 12) >> 12; // uint resultFractionSize = 52; // if (doubleFractionBits == 0) resultFractionSize = 0; // else // { // while (doubleFractionBits % 2 == 0) // { // resultFractionSize -= 1; // doubleFractionBits >>= 1; // } // } // var uncertainty = false; // if (FractionSizeMax < resultFractionSize - 1) // { // SetFractionSizeBits((uint)(FractionSizeMax - 1)); // uncertainty = true; // } // else SetFractionSizeBits(resultFractionSize - 1); // var doubleExponentBits = (BitConverter.ToUInt64(BitConverter.GetBytes(x), 0) << 1) >> 53; // // These are the only uncertain cases that we can safely handle without Ubounds. // if (ExponentSizeMax < ExponentValueToExponentSize((int)doubleExponentBits - 1023)) // { // // The exponent is too big, so we express the number as the largest possible signed value, // // but the Unum is uncertain, meaning that it's finite, but too big to express. // if (doubleExponentBits - 1023 > 0) // UnumBits = IsPositive() ? LargestPositive : LargestNegative; // else // If the exponent is too small, we will handle it as a signed uncertain zero. // { // UnumBits = _environment.EmptyBitMask; // if (!IsPositive()) Negate(); // } // SetUncertainityBit(true); // return; // } // var exponentSizeBits = ExponentValueToExponentSize((int)doubleExponentBits - 1023) - 1; // SetExponentSizeBits(exponentSizeBits); // var doubleFraction = new uint[2]; // doubleFraction[0] = (uint)((doubleFractionBits << 32) >> 32); // doubleFraction[1] = (uint)((doubleFractionBits >> 32)); // if (uncertainty) // { // SetFractionBits(Size > 32 ? // // This is necessary because Hastlayer enables only one size of BitMasks. // new BitMask(doubleFraction, Size) >> ((int)resultFractionSize - (int)FractionSize()) : // // The lower 32 bits wouldn't fit in anyway. // new BitMask(new uint[] { doubleFraction[1] }, Size) >> ((int)resultFractionSize - FractionSizeMax)); // SetUncertainityBit(true); // } // else // SetFractionBits(Size > 32 ? // // This is necessary because Hastlayer enables only one size of BitMasks. // new BitMask(doubleFraction, Size) : // // The lower 32 bits wouldn't fit in anyway. // new BitMask(new uint[] { doubleFraction[1] }, Size)); // SetExponentBits(ExponentValueToExponentBits((int)(doubleExponentBits - 1023), Size)); //} #endregion #region Methods to set the values of individual Unum structure elements /// <summary> /// Assembles the Unum from its pre-computed parts. /// </summary> /// <param name="signBit">The SignBit of the Unum.</param> /// <param name="exponent">The biased notation of the exponent of the Unum.</param> /// <param name="fraction">The fraction of the Unum without the hidden bit.</param> /// <param name="uncertainityBit">The value of the uncertainity bit (Ubit).</param> /// <param name="exponentSize">The Unum's exponent size, in a notation that is one less than the actual value.</param> /// <param name="fractionSize">The Unum's fraction size, in a notation that is one less than the actual value.</param> /// <returns>The BitMask representing the whole Unum with all the parts set.</returns> private BitMask AssembleUnumBits(bool signBit, BitMask exponent, BitMask fraction, bool uncertainityBit, byte exponentSize, ushort fractionSize) { var wholeUnum = new BitMask(exponentSize, Size) << FractionSizeSize; wholeUnum += fractionSize; if (uncertainityBit) { wholeUnum += UncertaintyBitMask; } wholeUnum += fraction << UnumTagSize; wholeUnum += exponent << (UnumTagSize + fractionSize + 1); if (signBit) { wholeUnum += SignBitMask; } return(wholeUnum); }
public BitMask(BitMask source) { Size = source.Size; SegmentCount = source.SegmentCount; Segments = source.Segments; }
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)); }
public BitMask ExponentMask() { var exponentMask = new BitMask(1, Size); return(((exponentMask << ExponentSize()) - 1) << (FractionSize() + UnumTagSize)); }
public BitMask FractionMask() { var fractionMask = new BitMask(1, Size); return(((fractionMask << FractionSize()) - 1) << UnumTagSize); }
/// <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)); }
public BitMask MinRealU => _environment.MinRealU; // "minrealu" #endregion #region Unum constructors public Unum(UnumEnvironment environment) { _environment = environment; UnumBits = new BitMask(_environment.Size); }