From 410d3057d201496518ec822fdd4529e48cd59bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Leh=C3=B3czky?= Date: Sun, 27 Mar 2022 14:51:51 +0200 Subject: [PATCH 1/3] Targeting .NET 6 --- Lombiq.Arithmetics.Tests/Lombiq.Arithmetics.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lombiq.Arithmetics.Tests/Lombiq.Arithmetics.Tests.csproj b/Lombiq.Arithmetics.Tests/Lombiq.Arithmetics.Tests.csproj index 7b4b6be..c88831b 100644 --- a/Lombiq.Arithmetics.Tests/Lombiq.Arithmetics.Tests.csproj +++ b/Lombiq.Arithmetics.Tests/Lombiq.Arithmetics.Tests.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net6.0 Library false From 1de112d1b7242bcd3ebd1d1dd08b3d42517f4c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Leh=C3=B3czky?= Date: Sun, 27 Mar 2022 15:58:51 +0200 Subject: [PATCH 2/3] File scoped namespaces --- BitMask/BitMask.cs | 723 ++++--- Lombiq.Arithmetics.Tests/BitMaskTests.cs | 393 ++-- .../CompatibilityAssert.cs | 29 +- .../PositTests/Posit32Tests.cs | 765 ++++---- .../PositTests/PositTests.cs | 471 +++-- .../PositTests/QuireTests.cs | 153 +- .../UnumTests/UnumEnvironmentTests.cs | 563 +++--- .../UnumTests/UnumHelperTests.cs | 73 +- .../UnumTests/UnumTests.cs | 1003 +++++----- Posit/Posit.cs | 595 +++--- Posit/Posit32.cs | 1689 ++++++++--------- Posit/PositEnvironment.cs | 57 +- Posit/Quire.cs | 307 ++- Unum/Unum.cs | 1263 ++++++------ Unum/UnumConfiguration.cs | 69 +- Unum/UnumEnvironment.cs | 377 ++-- Unum/UnumException.cs | 25 +- Unum/UnumHelper.cs | 171 +- 18 files changed, 4354 insertions(+), 4372 deletions(-) diff --git a/BitMask/BitMask.cs b/BitMask/BitMask.cs index 2d5a44f..2fb95ae 100644 --- a/BitMask/BitMask.cs +++ b/BitMask/BitMask.cs @@ -2,492 +2,491 @@ using System.Collections.Immutable; using System.Runtime.InteropServices; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +[StructLayout(LayoutKind.Auto)] +public struct BitMask : IEquatable { - [StructLayout(LayoutKind.Auto)] - public struct BitMask : IEquatable + private const uint SegmentMaskWithLeadingOne = 0x80000000; // 1000 0000 0000 0000 0000 0000 0000 0000 + private const uint SegmentMaskWithClosingOne = 1; // 0000 0000 0000 0000 0000 0000 0000 0001 + public ushort Size { get; } + public ushort SegmentCount { get; } + public ImmutableArray Segments { get; } + + public uint Lowest32Bits => Segments[0]; + + #region Constructors + + public BitMask(uint segment, ushort size) { - private const uint SegmentMaskWithLeadingOne = 0x80000000; // 1000 0000 0000 0000 0000 0000 0000 0000 - private const uint SegmentMaskWithClosingOne = 1; // 0000 0000 0000 0000 0000 0000 0000 0001 - public ushort Size { get; } - public ushort SegmentCount { get; } - public ImmutableArray Segments { get; } + Size = size; + SegmentCount = (ushort)((size >> 5) + (size % 32 == 0 ? 0 : 1)); + + /* Creating a new, temporary array once that will be used to initialize the ImmutableArray, + * so the "extension" items (i.e. the 0-value items on top of the original segments) aren't added + * using ImmutableArray.Add, which would instantiate a new array for each addition. */ + var extendedSegments = new uint[SegmentCount]; + extendedSegments[0] = segment; + Segments = ImmutableArray.CreateRange(extendedSegments); + } - public uint Lowest32Bits => Segments[0]; + public BitMask(uint[] segments, ushort size = 0) + { + var segmentBits = (ushort)(segments.Length << 5); - #region Constructors + Size = size < segmentBits ? segmentBits : size; + SegmentCount = (ushort)segments.Length; + if (size > segmentBits) SegmentCount = (ushort)((size >> 5) + (size % 32 == 0 ? 0 : 1)); - public BitMask(uint segment, ushort size) + if (SegmentCount > segments.Length) { - Size = size; - SegmentCount = (ushort)((size >> 5) + (size % 32 == 0 ? 0 : 1)); - /* Creating a new, temporary array once that will be used to initialize the ImmutableArray, * so the "extension" items (i.e. the 0-value items on top of the original segments) aren't added * using ImmutableArray.Add, which would instantiate a new array for each addition. */ var extendedSegments = new uint[SegmentCount]; - extendedSegments[0] = segment; + Array.Copy(segments, extendedSegments, segments.Length); Segments = ImmutableArray.CreateRange(extendedSegments); } - - public BitMask(uint[] segments, ushort size = 0) + else { - var segmentBits = (ushort)(segments.Length << 5); + Segments = ImmutableArray.CreateRange(segments); + } + } - Size = size < segmentBits ? segmentBits : size; - SegmentCount = (ushort)segments.Length; - if (size > segmentBits) SegmentCount = (ushort)((size >> 5) + (size % 32 == 0 ? 0 : 1)); + public BitMask(ushort size, bool allOne = false) + { + var partialSegment = size % 32; + SegmentCount = (ushort)((size >> 5) + (partialSegment == 0 ? 0 : 1)); + Size = size; - if (SegmentCount > segments.Length) - { - /* Creating a new, temporary array once that will be used to initialize the ImmutableArray, - * so the "extension" items (i.e. the 0-value items on top of the original segments) aren't added - * using ImmutableArray.Add, which would instantiate a new array for each addition. */ - var extendedSegments = new uint[SegmentCount]; - Array.Copy(segments, extendedSegments, segments.Length); - Segments = ImmutableArray.CreateRange(extendedSegments); - } - else - { - Segments = ImmutableArray.CreateRange(segments); - } - } + // Creating a temporary array, so the items aren't added using ImmutableArray.Add, because that instantiates + // a new array for each execution. + var segments = new uint[SegmentCount]; - public BitMask(ushort size, bool allOne = false) + if (allOne) { - var partialSegment = size % 32; - SegmentCount = (ushort)((size >> 5) + (partialSegment == 0 ? 0 : 1)); - Size = size; + ushort i = 0; + for (; i < SegmentCount - 1; i++) segments[i] = uint.MaxValue; - // Creating a temporary array, so the items aren't added using ImmutableArray.Add, because that instantiates - // a new array for each execution. - var segments = new uint[SegmentCount]; - - if (allOne) - { - ushort i = 0; - for (; i < SegmentCount - 1; i++) segments[i] = uint.MaxValue; + // The last segment is special in a way that it might not be necessary to have all 1 bits. + segments[i] = partialSegment > 0 ? (uint)(1 << partialSegment) - 1 : uint.MaxValue; + } - // The last segment is special in a way that it might not be necessary to have all 1 bits. - segments[i] = partialSegment > 0 ? (uint)(1 << partialSegment) - 1 : uint.MaxValue; - } + Segments = ImmutableArray.CreateRange(segments); + } - Segments = ImmutableArray.CreateRange(segments); - } + public BitMask(BitMask source) + { + Size = source.Size; + SegmentCount = source.SegmentCount; + Segments = source.Segments; + } - public BitMask(BitMask source) - { - Size = source.Size; - SegmentCount = source.SegmentCount; - Segments = source.Segments; - } + #endregion - #endregion + #region Static factories - #region Static factories + public static BitMask FromImmutableArray(ImmutableArray segments, ushort size = 0) + { + var intermediarySegments = new uint[segments.Length]; + segments.CopyTo(intermediarySegments); - public static BitMask FromImmutableArray(ImmutableArray segments, ushort size = 0) - { - var intermediarySegments = new uint[segments.Length]; - segments.CopyTo(intermediarySegments); + return new BitMask(intermediarySegments, size); + } - return new BitMask(intermediarySegments, size); - } + #endregion - #endregion + #region BitMask manipulation functions - #region BitMask manipulation functions + /// + /// Returns a new BitMask, where the given index is set to one. + /// + /// The index of the bit to set. + /// A BitMask where the given bit is set to one. + public BitMask SetOne(ushort index) + { + if (index > SegmentCount * 32) return new BitMask(this); - /// - /// Returns a new BitMask, where the given index is set to one. - /// - /// The index of the bit to set. - /// A BitMask where the given bit is set to one. - public BitMask SetOne(ushort index) - { - if (index > SegmentCount * 32) return new BitMask(this); + var bitPosition = index % 32; + var segmentPosition = index >> 5; - var bitPosition = index % 32; - var segmentPosition = index >> 5; + if ((Segments[segmentPosition] >> bitPosition) % 2 == 0) + return FromImmutableArray(Segments.SetItem(segmentPosition, Segments[segmentPosition] | (uint)(1 << bitPosition)), Size); - if ((Segments[segmentPosition] >> bitPosition) % 2 == 0) - return FromImmutableArray(Segments.SetItem(segmentPosition, Segments[segmentPosition] | (uint)(1 << bitPosition)), Size); + return new BitMask(this); + } - return new BitMask(this); - } + /// + /// Returns a new BitMask, where the given bit is set to zero. + /// + /// The index of the bit to set to zero. + /// A BitMask where the given bit is set to zero. + public BitMask SetZero(ushort index) + { + if (index > SegmentCount * 32) return new BitMask(this); - /// - /// Returns a new BitMask, where the given bit is set to zero. - /// - /// The index of the bit to set to zero. - /// A BitMask where the given bit is set to zero. - public BitMask SetZero(ushort index) - { - if (index > SegmentCount * 32) return new BitMask(this); + var bitPosition = index % 32; + var segmentPosition = index >> 5; - var bitPosition = index % 32; - var segmentPosition = index >> 5; + if ((Segments[segmentPosition] >> bitPosition) % 2 == 1) + return FromImmutableArray(Segments.SetItem(segmentPosition, Segments[segmentPosition] & ~(1U << bitPosition)), Size); - if ((Segments[segmentPosition] >> bitPosition) % 2 == 1) - return FromImmutableArray(Segments.SetItem(segmentPosition, Segments[segmentPosition] & ~(1U << bitPosition)), Size); + return new BitMask(this); + } - return new BitMask(this); - } + /// + /// Shifts the BitMask to the right by the number of trailing zeros. + /// + /// A BitMask where the trailing zeros are shifted out to the right. + public BitMask ShiftOutLeastSignificantZeros() + { + var leastSignificantOnePosition = FindLeastSignificantOnePosition(); + var mask = new BitMask(this); + if (leastSignificantOnePosition == 0) return mask; - /// - /// Shifts the BitMask to the right by the number of trailing zeros. - /// - /// A BitMask where the trailing zeros are shifted out to the right. - public BitMask ShiftOutLeastSignificantZeros() - { - var leastSignificantOnePosition = FindLeastSignificantOnePosition(); - var mask = new BitMask(this); - if (leastSignificantOnePosition == 0) return mask; + return mask >> (leastSignificantOnePosition - 1); + } - return mask >> (leastSignificantOnePosition - 1); - } + /// + /// Sets the segment on the given index to the segment given as an argument. + /// + /// /// The index of the Segment to set. + /// /// The segment that the BitMask's segment on the given index will be set to. + /// A BitMask where the trailing zeros are shifted out to the right. + public BitMask SetSegment(int index, uint segment) + { + if (index >= SegmentCount) return new BitMask(this); - /// - /// Sets the segment on the given index to the segment given as an argument. - /// - /// /// The index of the Segment to set. - /// /// The segment that the BitMask's segment on the given index will be set to. - /// A BitMask where the trailing zeros are shifted out to the right. - public BitMask SetSegment(int index, uint segment) - { - if (index >= SegmentCount) return new BitMask(this); + return FromImmutableArray(Segments.SetItem(index, segment)); + } - return FromImmutableArray(Segments.SetItem(index, segment)); - } + #endregion - #endregion + #region Operators - #region Operators + public static bool operator ==(BitMask left, BitMask right) + { + if (left.SegmentCount != right.SegmentCount) return false; - public static bool operator ==(BitMask left, BitMask right) - { - if (left.SegmentCount != right.SegmentCount) return false; + for (ushort i = 0; i < left.SegmentCount; i++) + if (left.Segments[i] != right.Segments[i]) return false; - for (ushort i = 0; i < left.SegmentCount; i++) - if (left.Segments[i] != right.Segments[i]) return false; + return true; + } - return true; - } + public static bool operator >(BitMask left, BitMask right) + { + for (ushort i = 1; i <= left.SegmentCount; i++) + if (left.Segments[left.SegmentCount - i] > right.Segments[left.SegmentCount - i]) return true; - public static bool operator >(BitMask left, BitMask right) - { - for (ushort i = 1; i <= left.SegmentCount; i++) - if (left.Segments[left.SegmentCount - i] > right.Segments[left.SegmentCount - i]) return true; + return false; + } - return false; - } + public static bool operator <(BitMask left, BitMask right) + { + for (ushort i = 1; i <= left.SegmentCount; i++) + if (left.Segments[left.SegmentCount - i] < right.Segments[left.SegmentCount - i]) return true; - public static bool operator <(BitMask left, BitMask right) - { - for (ushort i = 1; i <= left.SegmentCount; i++) - if (left.Segments[left.SegmentCount - i] < right.Segments[left.SegmentCount - i]) return true; + return false; + } - return false; - } + public static bool operator >=(BitMask left, BitMask right) => !(left < right); - public static bool operator >=(BitMask left, BitMask right) => !(left < right); + public static bool operator <=(BitMask left, BitMask right) => !(left > right); - public static bool operator <=(BitMask left, BitMask right) => !(left > right); + public static bool operator !=(BitMask left, BitMask right) => !(left == right); - public static bool operator !=(BitMask left, BitMask right) => !(left == right); + public static BitMask operator +(BitMask left, uint right) => left + new BitMask(right, left.Size); - public static BitMask operator +(BitMask left, uint right) => left + new BitMask(right, left.Size); + public static BitMask operator -(BitMask left, uint right) => left - new BitMask(right, left.Size); - public static BitMask operator -(BitMask left, uint right) => left - new BitMask(right, left.Size); + /// + /// Bit-by-bit addition of two masks with "ripple-carry". + /// + /// Left operand BitMask. + /// Right operand BitMask. + /// The sum of the masks with respect to the size of the bigger operand. + public static BitMask operator +(BitMask left, BitMask right) + { + if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; + bool carry = false; + byte buffer; + ushort segmentPosition = 0, position = 0; + var segments = new uint[left.SegmentCount]; - /// - /// Bit-by-bit addition of two masks with "ripple-carry". - /// - /// Left operand BitMask. - /// Right operand BitMask. - /// The sum of the masks with respect to the size of the bigger operand. - public static BitMask operator +(BitMask left, BitMask right) + for (ushort i = 0; i < (left.Size > right.Size ? left.Size : right.Size); i++) { - if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; - bool carry = false; - byte buffer; - ushort segmentPosition = 0, position = 0; - var segments = new uint[left.SegmentCount]; + var leftBit = (left.Segments[segmentPosition] >> position) % 2; + var rightBit = i >= right.Size ? 0 : (right.Segments[segmentPosition] >> position) % 2; + var carryBit = carry ? 1 : 0; - for (ushort i = 0; i < (left.Size > right.Size ? left.Size : right.Size); i++) - { - var leftBit = (left.Segments[segmentPosition] >> position) % 2; - var rightBit = i >= right.Size ? 0 : (right.Segments[segmentPosition] >> position) % 2; - var carryBit = carry ? 1 : 0; + buffer = (byte)(leftBit + rightBit + carryBit); - buffer = (byte)(leftBit + rightBit + carryBit); + if (buffer % 2 != 0) segments[segmentPosition] += (uint)(1 << position); + carry = buffer >> 1 == 1; - if (buffer % 2 != 0) segments[segmentPosition] += (uint)(1 << position); - carry = buffer >> 1 == 1; - - position++; - if (position >> 5 == 1) - { - position = 0; - segmentPosition++; - } + position++; + if (position >> 5 == 1) + { + position = 0; + segmentPosition++; } - - return new BitMask(segments); } - /// - /// Bit-by-bit subtraction of two masks with "ripple-carry". - /// - /// Left operand BitMask. - /// Right operand BitMask. - /// The difference between the masks with respect to the size of the bigger operand. - public static BitMask operator -(BitMask left, BitMask right) - { - if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; + return new BitMask(segments); + } - bool carry = false; - byte buffer; - ushort segmentPosition = 0, position = 0; - var segments = new uint[left.SegmentCount]; + /// + /// Bit-by-bit subtraction of two masks with "ripple-carry". + /// + /// Left operand BitMask. + /// Right operand BitMask. + /// The difference between the masks with respect to the size of the bigger operand. + public static BitMask operator -(BitMask left, BitMask right) + { + if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; - for (ushort i = 0; i < (left.Size > right.Size ? left.Size : right.Size); i++) - { - var leftBit = (left.Segments[segmentPosition] >> position) % 2; - var rightBit = i >= right.Size ? 0 : (right.Segments[segmentPosition] >> position) % 2; + bool carry = false; + byte buffer; + ushort segmentPosition = 0, position = 0; + var segments = new uint[left.SegmentCount]; - buffer = (byte)(2 + leftBit - rightBit - (carry ? 1 : 0)); + for (ushort i = 0; i < (left.Size > right.Size ? left.Size : right.Size); i++) + { + var leftBit = (left.Segments[segmentPosition] >> position) % 2; + var rightBit = i >= right.Size ? 0 : (right.Segments[segmentPosition] >> position) % 2; - if (buffer % 2 != 0) segments[segmentPosition] += (uint)(1 << position); - carry = buffer >> 1 == 0; + buffer = (byte)(2 + leftBit - rightBit - (carry ? 1 : 0)); - position++; - if (position >> 5 == 1) - { - position = 0; - segmentPosition++; - } - } + if (buffer % 2 != 0) segments[segmentPosition] += (uint)(1 << position); + carry = buffer >> 1 == 0; - return new BitMask(segments); + position++; + if (position >> 5 == 1) + { + position = 0; + segmentPosition++; + } } - public static BitMask operator ++(BitMask mask) => mask + 1; - - public static BitMask operator --(BitMask mask) => mask - 1; - - public static BitMask operator |(BitMask left, BitMask right) - { - if (left.SegmentCount != right.SegmentCount) return new BitMask(left.Size); + return new BitMask(segments); + } - var segments = new uint[left.SegmentCount]; + public static BitMask operator ++(BitMask mask) => mask + 1; - for (ushort i = 0; i < segments.Length; i++) - segments[i] = left.Segments[i] | right.Segments[i]; + public static BitMask operator --(BitMask mask) => mask - 1; - return new BitMask(segments); - } + public static BitMask operator |(BitMask left, BitMask right) + { + if (left.SegmentCount != right.SegmentCount) return new BitMask(left.Size); - public static BitMask operator &(BitMask left, BitMask right) - { - if (left.SegmentCount != right.SegmentCount) return new BitMask(left.Size); + var segments = new uint[left.SegmentCount]; - var segments = new uint[left.SegmentCount]; + for (ushort i = 0; i < segments.Length; i++) + segments[i] = left.Segments[i] | right.Segments[i]; - for (ushort i = 0; i < segments.Length; i++) - segments[i] = left.Segments[i] & right.Segments[i]; + return new BitMask(segments); + } - return new BitMask(segments); - } + public static BitMask operator &(BitMask left, BitMask right) + { + if (left.SegmentCount != right.SegmentCount) return new BitMask(left.Size); - public static BitMask operator ^(BitMask left, BitMask right) - { - if (left.SegmentCount != right.SegmentCount) return new BitMask(left.Size); + var segments = new uint[left.SegmentCount]; - var segments = new uint[left.SegmentCount]; + for (ushort i = 0; i < segments.Length; i++) + segments[i] = left.Segments[i] & right.Segments[i]; - for (ushort i = 0; i < segments.Length; i++) - segments[i] = left.Segments[i] ^ right.Segments[i]; + return new BitMask(segments); + } - return new BitMask(segments); - } + public static BitMask operator ^(BitMask left, BitMask right) + { + if (left.SegmentCount != right.SegmentCount) return new BitMask(left.Size); - public static BitMask operator ~(BitMask input) - { - var segments = new uint[input.SegmentCount]; + var segments = new uint[left.SegmentCount]; - for (ushort i = 0; i < segments.Length; i++) - segments[i] = ~input.Segments[i]; + for (ushort i = 0; i < segments.Length; i++) + segments[i] = left.Segments[i] ^ right.Segments[i]; - return new BitMask(segments); - } + return new BitMask(segments); + } - /// - /// Bit-shifting of a BitMask to the right by an integer. Shifts left if negative value is given. - /// - /// Left operand BitMask to shift. - /// Right operand int tells how many bits to shift by. - /// BitMask of size of left BitMask, shifted left by number of bits given in the right integer. - public static BitMask operator >>(BitMask left, int right) - { - if (right < 0) return left << -right; + public static BitMask operator ~(BitMask input) + { + var segments = new uint[input.SegmentCount]; - bool carryOld, carryNew; - var segments = new uint[left.SegmentCount]; - left.Segments.CopyTo(segments); - ushort currentIndex; + for (ushort i = 0; i < segments.Length; i++) + segments[i] = ~input.Segments[i]; - for (ushort i = 0; i < right; i++) - { - carryOld = false; + return new BitMask(segments); + } - for (ushort j = 1; j <= segments.Length; j++) - { - currentIndex = (ushort)(segments.Length - j); - carryNew = segments[currentIndex] % 2 == 1; - segments[currentIndex] >>= 1; - if (carryOld) segments[currentIndex] |= SegmentMaskWithLeadingOne; - carryOld = carryNew; - } - } + /// + /// Bit-shifting of a BitMask to the right by an integer. Shifts left if negative value is given. + /// + /// Left operand BitMask to shift. + /// Right operand int tells how many bits to shift by. + /// BitMask of size of left BitMask, shifted left by number of bits given in the right integer. + public static BitMask operator >>(BitMask left, int right) + { + if (right < 0) return left << -right; - return new BitMask(segments); - } + bool carryOld, carryNew; + var segments = new uint[left.SegmentCount]; + left.Segments.CopyTo(segments); + ushort currentIndex; - /// - /// Bit-shifting of a BitMask to the left by an integer. Shifts right if negative value is given. - /// - /// Left operand BitMask. - /// Right operand int tells how many bits to shift by. - /// BitMask of size of left BitMask, shifted right by number of bits given in the right integer. - public static BitMask operator <<(BitMask left, int right) + for (ushort i = 0; i < right; i++) { - if (right < 0) return left >> -right; - - bool carryOld, carryNew; - var segments = new uint[left.SegmentCount]; - left.Segments.CopyTo(segments); + carryOld = false; - for (ushort i = 0; i < right; i++) + for (ushort j = 1; j <= segments.Length; j++) { - carryOld = false; - - for (ushort j = 0; j < segments.Length; j++) - { - carryNew = (segments[j] & SegmentMaskWithLeadingOne) == SegmentMaskWithLeadingOne; - segments[j] <<= 1; - if (carryOld) segments[j] |= SegmentMaskWithClosingOne; - carryOld = carryNew; - } + currentIndex = (ushort)(segments.Length - j); + carryNew = segments[currentIndex] % 2 == 1; + segments[currentIndex] >>= 1; + if (carryOld) segments[currentIndex] |= SegmentMaskWithLeadingOne; + carryOld = carryNew; } - - return new BitMask(segments); } - #endregion + return new BitMask(segments); + } + + /// + /// Bit-shifting of a BitMask to the left by an integer. Shifts right if negative value is given. + /// + /// Left operand BitMask. + /// Right operand int tells how many bits to shift by. + /// BitMask of size of left BitMask, shifted right by number of bits given in the right integer. + public static BitMask operator <<(BitMask left, int right) + { + if (right < 0) return left >> -right; - #region Helper functions + bool carryOld, carryNew; + var segments = new uint[left.SegmentCount]; + left.Segments.CopyTo(segments); - /// - /// Finds the most significant 1-bit. - /// - /// Returns the position (not index!) of the most significant 1-bit - /// or zero if there is none. - public ushort FindMostSignificantOnePosition() + for (ushort i = 0; i < right; i++) { - ushort position = 0; - uint currentSegment; + carryOld = false; - // ushort can't be checked against with ">= 0", because that's always true. - for (ushort i = 1; i <= SegmentCount; i++) + for (ushort j = 0; j < segments.Length; j++) { - currentSegment = Segments[SegmentCount - i]; - while (currentSegment != 0) - { - currentSegment >>= 1; - position++; - if (currentSegment == 0) return (ushort)(((SegmentCount - i) * 32) + position); - } + carryNew = (segments[j] & SegmentMaskWithLeadingOne) == SegmentMaskWithLeadingOne; + segments[j] <<= 1; + if (carryOld) segments[j] |= SegmentMaskWithClosingOne; + carryOld = carryNew; } - - return 0; } - public BitMask GetTwosComplement(ushort size) - { - var mask = new BitMask(this); - return ((~mask + 1) << ((SegmentCount * 32) - size)) >> ((SegmentCount * 32) - size); - } + return new BitMask(segments); + } + + #endregion - public ushort LengthOfRunOfBits(ushort startingPosition) + #region Helper functions + + /// + /// Finds the most significant 1-bit. + /// + /// Returns the position (not index!) of the most significant 1-bit + /// or zero if there is none. + public ushort FindMostSignificantOnePosition() + { + ushort position = 0; + uint currentSegment; + + // ushort can't be checked against with ">= 0", because that's always true. + for (ushort i = 1; i <= SegmentCount; i++) { - ushort length = 1; - var mask = new BitMask(this) << ((SegmentCount * 32) - startingPosition); - var startingBit = mask.Segments[0] >> 31 > 0; - mask <<= 1; - for (var i = 0; i < startingPosition; i++) + currentSegment = Segments[SegmentCount - i]; + while (currentSegment != 0) { - if ((mask.Segments[0] >> 31 > 0) != startingBit) return length; - mask <<= 1; - length++; + currentSegment >>= 1; + position++; + if (currentSegment == 0) return (ushort)(((SegmentCount - i) * 32) + position); } - - return (length > startingPosition) ? startingPosition : length; } - /// - /// Finds the least significant 1-bit. - /// - /// Returns the position (not index!) of the least significant 1-bit - /// or zero if there is none. - public ushort FindLeastSignificantOnePosition() + return 0; + } + + public BitMask GetTwosComplement(ushort size) + { + var mask = new BitMask(this); + return ((~mask + 1) << ((SegmentCount * 32) - size)) >> ((SegmentCount * 32) - size); + } + + public ushort LengthOfRunOfBits(ushort startingPosition) + { + ushort length = 1; + var mask = new BitMask(this) << ((SegmentCount * 32) - startingPosition); + var startingBit = mask.Segments[0] >> 31 > 0; + mask <<= 1; + for (var i = 0; i < startingPosition; i++) { - ushort position = 1; - uint currentSegment; + if ((mask.Segments[0] >> 31 > 0) != startingBit) return length; + mask <<= 1; + length++; + } - for (ushort i = 0; i < SegmentCount; i++) + return (length > startingPosition) ? startingPosition : length; + } + + /// + /// Finds the least significant 1-bit. + /// + /// Returns the position (not index!) of the least significant 1-bit + /// or zero if there is none. + public ushort FindLeastSignificantOnePosition() + { + ushort position = 1; + uint currentSegment; + + for (ushort i = 0; i < SegmentCount; i++) + { + currentSegment = Segments[i]; + if (currentSegment == 0) + { + position += 32; + } + else { - currentSegment = Segments[i]; - if (currentSegment == 0) + while (currentSegment % 2 == 0) { - position += 32; + position++; + currentSegment >>= 1; } - else - { - while (currentSegment % 2 == 0) - { - position++; - currentSegment >>= 1; - } - if (currentSegment % 2 == 1) return position; - } + if (currentSegment % 2 == 1) return position; } - - return 0; } - // Array indexer is not supported by Hastlayer yet. - //// public uint this[int i] => Segments[i]; + return 0; + } - #endregion + // Array indexer is not supported by Hastlayer yet. + //// public uint this[int i] => Segments[i]; - #region Overrides + #endregion - public override bool Equals(object obj) => obj is BitMask other && this == other; + #region Overrides - public bool Equals(BitMask other) => this == other; + public override bool Equals(object obj) => obj is BitMask other && this == other; - public override int GetHashCode() - { - var segmentHashCodes = new int[SegmentCount]; - for (int i = 0; i < SegmentCount; i++) segmentHashCodes[i] = Segments[i].GetHashCode(); + public bool Equals(BitMask other) => this == other; - return segmentHashCodes.GetHashCode(); - } - - public override string ToString() => string.Join(", ", Segments); + public override int GetHashCode() + { + var segmentHashCodes = new int[SegmentCount]; + for (int i = 0; i < SegmentCount; i++) segmentHashCodes[i] = Segments[i].GetHashCode(); - #endregion + return segmentHashCodes.GetHashCode(); } + + public override string ToString() => string.Join(", ", Segments); + + #endregion } diff --git a/Lombiq.Arithmetics.Tests/BitMaskTests.cs b/Lombiq.Arithmetics.Tests/BitMaskTests.cs index c4957db..2c9051b 100644 --- a/Lombiq.Arithmetics.Tests/BitMaskTests.cs +++ b/Lombiq.Arithmetics.Tests/BitMaskTests.cs @@ -4,210 +4,209 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class BitMaskTests { - public class BitMaskTests + [Fact] + public void BitMaskSegmentCountIsCorrectlyCalculatedFromSize() { - [Fact] - public void BitMaskSegmentCountIsCorrectlyCalculatedFromSize() - { - var sizesAndSegmentCounts = new[] - { - Tuple.Create(new BitMask(0), 0U), - Tuple.Create(new BitMask(31), 1U), - Tuple.Create(new BitMask(32), 1U), - Tuple.Create(new BitMask(33), 2U), - Tuple.Create(new BitMask(1023), 32U), - Tuple.Create(new BitMask(1024), 32U), - Tuple.Create(new BitMask(1025), 33U), - }; - - foreach (var item in sizesAndSegmentCounts) item.Item2.ShouldBe(item.Item1.SegmentCount, $"Size: {item.Item1.Size}"); - } - - [Fact] - public void BitMaskSizeIsCorrectlySetWithSegments() - { - var sizesAndSegmentCounts = new[] - { - Tuple.Create(new BitMask(Array.Empty()), 0U), - Tuple.Create(new BitMask(new uint[] { 1 }), 32U), - Tuple.Create(new BitMask(new uint[] { 2, 2 }), 64U), - Tuple.Create(new BitMask(new uint[] { 3, 3, 3 }), 96U), - Tuple.Create(new BitMask(new uint[] { 4, 4, 4, 4 }), 128U), - Tuple.Create(new BitMask(new uint[] { 0 }, 222), 222U), - }; - - foreach (var item in sizesAndSegmentCounts) item.Item2.ShouldBe(item.Item1.Size, $"Mask: {item.Item1}"); - } - - [Fact] - public void BitMaskSetOneIsCorrect() - { - Assert.AreEqual(1, new BitMask(new uint[] { 0 }).SetOne(0).Segments[0]); - Assert.AreEqual(1 << 5, new BitMask(32).SetOne(5).Segments[0]); - Assert.AreEqual(0xFFFF, new BitMask(new uint[] { 0xFFFF }).SetOne(5).Segments[0]); - Assert.AreEqual(0xFFFF + (1 << 30), new BitMask(new uint[] { 0xFFFF }).SetOne(30).Segments[0]); - Assert.AreEqual((uint)(1 << 30) << 1, new BitMask(new uint[] { 0 }).SetOne(31).Segments[0]); - Assert.AreEqual(uint.MaxValue, new BitMask(new[] { 0xFFFFFFFE }).SetOne(0).Segments[0]); - Assert.AreEqual(uint.MaxValue, new BitMask(new uint[] { 0x7FFFFFFF }).SetOne(31).Segments[0]); - Assert.AreEqual(new BitMask(new uint[] { 0, 0, 0xFFFF }), new BitMask(new uint[] { 0, 0, 0xFFFF }).SetOne(79)); - Assert.AreEqual(new BitMask(new uint[] { 0, 0, 0x1FFFF }), new BitMask(new uint[] { 0, 0, 0xFFFF }).SetOne(80)); - } - - [Fact] - public void BitMaskSetZeroIsCorrect() - { - Assert.AreEqual(0, new BitMask(new uint[] { 1 }).SetZero(0).Segments[0]); - Assert.AreEqual(0x7FFF, new BitMask(new uint[] { 0xFFFF }).SetZero(15).Segments[0]); - } + var sizesAndSegmentCounts = new[] + { + Tuple.Create(new BitMask(0), 0U), + Tuple.Create(new BitMask(31), 1U), + Tuple.Create(new BitMask(32), 1U), + Tuple.Create(new BitMask(33), 2U), + Tuple.Create(new BitMask(1023), 32U), + Tuple.Create(new BitMask(1024), 32U), + Tuple.Create(new BitMask(1025), 33U), + }; + + foreach (var item in sizesAndSegmentCounts) item.Item2.ShouldBe(item.Item1.SegmentCount, $"Size: {item.Item1.Size}"); + } - [Fact] - public void BitMaskConstructorCorrectlyCopiesBitMask() + [Fact] + public void BitMaskSizeIsCorrectlySetWithSegments() + { + var sizesAndSegmentCounts = new[] { - var masks = new[] - { - new BitMask(new uint[] { 0x42, 0x42 }), new BitMask(new uint[] { 0x88, 0x88, 0x88 }), - }; + Tuple.Create(new BitMask(Array.Empty()), 0U), + Tuple.Create(new BitMask(new uint[] { 1 }), 32U), + Tuple.Create(new BitMask(new uint[] { 2, 2 }), 64U), + Tuple.Create(new BitMask(new uint[] { 3, 3, 3 }), 96U), + Tuple.Create(new BitMask(new uint[] { 4, 4, 4, 4 }), 128U), + Tuple.Create(new BitMask(new uint[] { 0 }, 222), 222U), + }; - foreach (var mask in masks) mask.ShouldBe(new BitMask(mask)); - } + foreach (var item in sizesAndSegmentCounts) item.Item2.ShouldBe(item.Item1.Size, $"Mask: {item.Item1}"); + } - [Fact] - public void BitMaskIntegerAdditionIsCorrect() - { - Assert.AreEqual(1, (new BitMask(new uint[] { 0 }) + 1).Segments[0]); - Assert.AreEqual(0x1FFFE, (new BitMask(new uint[] { 0xFFFF }) + 0xFFFF).Segments[0]); - Assert.AreEqual(0xFFFFFFFF, (new BitMask(new[] { 0xFFFFFFFE }) + 1).Segments[0]); - Assert.AreEqual(0xFFFFFFFF, (new BitMask(new[] { 0xEFFFFFFF }) + 0x10000000).Segments[0]); - Assert.AreEqual(0, (new BitMask(new[] { 0xFFFFFFFF }) + 1).Segments[0]); - Assert.AreEqual(1, (new BitMask(new[] { 0xFFFFFFFF }) + 2).Segments[0]); - Assert.AreEqual(new BitMask(new uint[] { 0, 0, 1 }), new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 }) + 1); - } - - [Fact] - public void BitMaskIntegerSubtractionIsCorrect() - { - Assert.AreEqual(0, (new BitMask(new uint[] { 1 }) - 1).Segments[0]); - Assert.AreEqual(0, (new BitMask(new[] { 0xFFFFFFFF }) - 0xFFFFFFFF).Segments[0]); - Assert.AreEqual(1, (new BitMask(new[] { 0xFFFFFFFF }) - 0xFFFFFFFE).Segments[0]); - Assert.AreEqual(0xFFFFFFFF, (new BitMask(new uint[] { 0 }) - 1).Segments[0]); - Assert.AreEqual(0xFFFFFFFE, (new BitMask(new uint[] { 0 }) - 2).Segments[0]); - Assert.AreEqual(0xEFFFFFFF, (new BitMask(new[] { 0xFFFFFFFF }) - 0x10000000).Segments[0]); - Assert.AreEqual(0xFFFFFF, (new BitMask(new uint[] { 0x017FFFFF }) - 0x800000).Segments[0]); - Assert.AreEqual(new BitMask(new uint[] { 0xFFFFFFFF, 0 }, 33), new BitMask(new uint[] { 0x7FFFFFFF, 1 }, 33) - 0x80000000); - } - - [Fact] - public void BitMaskAdditionIsCorrect() - { - new BitMask(new[] { 0xFFFFFFFF }).ShouldBe( - new BitMask(new uint[] { 0x55555555 }) + new BitMask(new[] { 0xAAAAAAAA })); - new BitMask(new uint[] { 0xFFFFFFFE, 1 }).ShouldBe( - new BitMask(new uint[] { 0xFFFFFFFF, 0 }) + new BitMask(new uint[] { 0xFFFFFFFF, 0 })); - new BitMask(new uint[] { 0xFFFFFFFE, 0xFFFFFFFF, 1 }).ShouldBe( - new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 }) + new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 })); - } - - [Fact] - public void BitMaskSubtractionIsCorrect() - { - new BitMask(new[] { 0xAAAAAAAA }).ShouldBe( - new BitMask(new[] { 0xFFFFFFFF }) - new BitMask(new uint[] { 0x55555555 })); - new BitMask(new uint[] { 0xFFFFFFFF, 0 }).ShouldBe( - new BitMask(new uint[] { 0xFFFFFFFE, 1 }) - new BitMask(new uint[] { 0xFFFFFFFF, 0 })); - new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 }).ShouldBe( - new BitMask(new uint[] { 0xFFFFFFFE, 0xFFFFFFFF, 1 }) - new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 })); - } - - [Fact] - public void BitMaskBitShiftLeftIsCorrect() - { - new BitMask(new[] { 0x80000000 }).ShouldBe( - new BitMask(new uint[] { 1 }) << 31); - new BitMask(new uint[] { 0x00000003 }).ShouldBe( - new BitMask(new uint[] { 6 }) << -1); - new BitMask(new uint[] { 0x00000000, 0x80000000 }).ShouldBe( - new BitMask(new uint[] { 1, 0 }) << 63); - new BitMask(new uint[] { 0 }).ShouldBe( - new BitMask(new uint[] { 0x00000001 }) << 32); - new BitMask(new uint[] { 0x80000000, 0x00000000 }).ShouldBe( - new BitMask(new uint[] { 0x00800000, 0x00000000 }) << 8); - new BitMask(new uint[] { 1 }).ShouldBe( - new BitMask(new[] { 0x80000000 }) << -31); - (new BitMask(new uint[] { 1, 0 }) << 63).ShouldBe( - new BitMask(new uint[] { 0x00000000, 0x80000000 })); - } - - [Fact] - public void BitMaskBitShiftRightIsCorrect() - { - new BitMask(new uint[] { 0x00800000, 0x00000000 }).ShouldBe( - new BitMask(new uint[] { 0x80000000, 0x00000000 }) >> 8); - new BitMask(new uint[] { 1 }).ShouldBe( - new BitMask(new[] { 0x80000000 }) >> 31); - new BitMask(new uint[] { 1, 0 }).ShouldBe( - new BitMask(new uint[] { 0x00000000, 0x80000000 }) >> 63); - new BitMask(new uint[] { 0x10000010, 0x00000000 }).ShouldBe( - new BitMask(new uint[] { 0x00000100, 0x00000001 }) >> 4); - new BitMask(new uint[] { 0 }).ShouldBe( - new BitMask(new[] { 0x80000000 }) >> 32); - new BitMask(new[] { 0x80000000 }).ShouldBe( - new BitMask(new uint[] { 1 }) >> -31); - } - - [Fact] - public void FindMostSignificantOneIsCorrect() - { - Assert.AreEqual(0, new BitMask(new uint[] { 0x00000000, 0x00000000 }).FindMostSignificantOnePosition()); - Assert.AreEqual(1, new BitMask(new uint[] { 0x00000001, 0x00000000 }).FindMostSignificantOnePosition()); - Assert.AreEqual(2, new BitMask(new uint[] { 0x00000002, 0x00000000 }).FindMostSignificantOnePosition()); - Assert.AreEqual(33, new BitMask(new uint[] { 0x00000002, 0x00000001 }).FindMostSignificantOnePosition()); - } - - [Fact] - public void FindLeastSignificantOneIsCorrect() - { - Assert.AreEqual(0, new BitMask(new uint[] { 0x00000000, 0x00000000 }).FindLeastSignificantOnePosition()); - Assert.AreEqual(1, new BitMask(new uint[] { 0x00000001, 0x00000000 }).FindLeastSignificantOnePosition()); - Assert.AreEqual(2, new BitMask(new uint[] { 0x00000002, 0x00000000 }).FindLeastSignificantOnePosition()); - Assert.AreEqual(2, new BitMask(new uint[] { 0x00000002, 0x00000001 }).FindLeastSignificantOnePosition()); - Assert.AreEqual(33, new BitMask(new uint[] { 0x00000000, 0x00000001 }).FindLeastSignificantOnePosition()); - } - - [Fact] - public void ShiftToRightEndIsCorrect() - { - new BitMask(new uint[] { 0x00000000, 0x00000000 }) - .ShouldBe(new BitMask(new uint[] { 0x00000000, 0x00000000 }).ShiftOutLeastSignificantZeros()); - new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros() - .ShouldBe(new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros()); - new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros() - .ShouldBe(new BitMask(new uint[] { 0x00000002, 0x00000000 }).ShiftOutLeastSignificantZeros()); - new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros() - .ShouldBe(new BitMask(new uint[] { 0x00000000, 0x00000001 }).ShiftOutLeastSignificantZeros()); - new BitMask(new uint[] { 0x00001001, 0x00000000 }).ShiftOutLeastSignificantZeros() - .ShouldBe(new BitMask(new uint[] { 0x10010000, 0x00000000 }).ShiftOutLeastSignificantZeros()); - new BitMask(new uint[] { 0x00001001, 0x00000000 }).ShiftOutLeastSignificantZeros() - .ShouldBe(new BitMask(new uint[] { 0x00000000, 0x10010000 }).ShiftOutLeastSignificantZeros()); - } - - [Fact] - public void GetTwosComplementIsCorrect() - { - new BitMask(new uint[] { 0x00000001 }, 5).GetTwosComplement(5).ShouldBe(new BitMask(new uint[] { 0x1F })); - new BitMask(new uint[] { 0x0000022C }, 12).GetTwosComplement(12).ShouldBe(new BitMask(new uint[] { 0x00000DD4 })); - } + [Fact] + public void BitMaskSetOneIsCorrect() + { + Assert.AreEqual(1, new BitMask(new uint[] { 0 }).SetOne(0).Segments[0]); + Assert.AreEqual(1 << 5, new BitMask(32).SetOne(5).Segments[0]); + Assert.AreEqual(0xFFFF, new BitMask(new uint[] { 0xFFFF }).SetOne(5).Segments[0]); + Assert.AreEqual(0xFFFF + (1 << 30), new BitMask(new uint[] { 0xFFFF }).SetOne(30).Segments[0]); + Assert.AreEqual((uint)(1 << 30) << 1, new BitMask(new uint[] { 0 }).SetOne(31).Segments[0]); + Assert.AreEqual(uint.MaxValue, new BitMask(new[] { 0xFFFFFFFE }).SetOne(0).Segments[0]); + Assert.AreEqual(uint.MaxValue, new BitMask(new uint[] { 0x7FFFFFFF }).SetOne(31).Segments[0]); + Assert.AreEqual(new BitMask(new uint[] { 0, 0, 0xFFFF }), new BitMask(new uint[] { 0, 0, 0xFFFF }).SetOne(79)); + Assert.AreEqual(new BitMask(new uint[] { 0, 0, 0x1FFFF }), new BitMask(new uint[] { 0, 0, 0xFFFF }).SetOne(80)); + } + + [Fact] + public void BitMaskSetZeroIsCorrect() + { + Assert.AreEqual(0, new BitMask(new uint[] { 1 }).SetZero(0).Segments[0]); + Assert.AreEqual(0x7FFF, new BitMask(new uint[] { 0xFFFF }).SetZero(15).Segments[0]); + } - [Fact] - public void LengthOfRunOfBitsIsCorrect() + [Fact] + public void BitMaskConstructorCorrectlyCopiesBitMask() + { + var masks = new[] { - new BitMask(new uint[] { 0x00000001 }).LengthOfRunOfBits(32).ShouldBe((ushort)31); - new BitMask(new uint[] { 0x30000000 }).LengthOfRunOfBits(32).ShouldBe((ushort)2); - new BitMask(new[] { 0x80000000 }).LengthOfRunOfBits(32).ShouldBe((ushort)1); - new BitMask(new uint[] { 0x00000000 }).LengthOfRunOfBits(32).ShouldBe((ushort)32); - new BitMask(new uint[] { 0x00000013 }).LengthOfRunOfBits(5).ShouldBe((ushort)1); - new BitMask(new uint[] { 17 }).LengthOfRunOfBits(5).ShouldBe((ushort)1); - } + new BitMask(new uint[] { 0x42, 0x42 }), new BitMask(new uint[] { 0x88, 0x88, 0x88 }), + }; + + foreach (var mask in masks) mask.ShouldBe(new BitMask(mask)); + } + + [Fact] + public void BitMaskIntegerAdditionIsCorrect() + { + Assert.AreEqual(1, (new BitMask(new uint[] { 0 }) + 1).Segments[0]); + Assert.AreEqual(0x1FFFE, (new BitMask(new uint[] { 0xFFFF }) + 0xFFFF).Segments[0]); + Assert.AreEqual(0xFFFFFFFF, (new BitMask(new[] { 0xFFFFFFFE }) + 1).Segments[0]); + Assert.AreEqual(0xFFFFFFFF, (new BitMask(new[] { 0xEFFFFFFF }) + 0x10000000).Segments[0]); + Assert.AreEqual(0, (new BitMask(new[] { 0xFFFFFFFF }) + 1).Segments[0]); + Assert.AreEqual(1, (new BitMask(new[] { 0xFFFFFFFF }) + 2).Segments[0]); + Assert.AreEqual(new BitMask(new uint[] { 0, 0, 1 }), new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 }) + 1); + } + + [Fact] + public void BitMaskIntegerSubtractionIsCorrect() + { + Assert.AreEqual(0, (new BitMask(new uint[] { 1 }) - 1).Segments[0]); + Assert.AreEqual(0, (new BitMask(new[] { 0xFFFFFFFF }) - 0xFFFFFFFF).Segments[0]); + Assert.AreEqual(1, (new BitMask(new[] { 0xFFFFFFFF }) - 0xFFFFFFFE).Segments[0]); + Assert.AreEqual(0xFFFFFFFF, (new BitMask(new uint[] { 0 }) - 1).Segments[0]); + Assert.AreEqual(0xFFFFFFFE, (new BitMask(new uint[] { 0 }) - 2).Segments[0]); + Assert.AreEqual(0xEFFFFFFF, (new BitMask(new[] { 0xFFFFFFFF }) - 0x10000000).Segments[0]); + Assert.AreEqual(0xFFFFFF, (new BitMask(new uint[] { 0x017FFFFF }) - 0x800000).Segments[0]); + Assert.AreEqual(new BitMask(new uint[] { 0xFFFFFFFF, 0 }, 33), new BitMask(new uint[] { 0x7FFFFFFF, 1 }, 33) - 0x80000000); + } + + [Fact] + public void BitMaskAdditionIsCorrect() + { + new BitMask(new[] { 0xFFFFFFFF }).ShouldBe( + new BitMask(new uint[] { 0x55555555 }) + new BitMask(new[] { 0xAAAAAAAA })); + new BitMask(new uint[] { 0xFFFFFFFE, 1 }).ShouldBe( + new BitMask(new uint[] { 0xFFFFFFFF, 0 }) + new BitMask(new uint[] { 0xFFFFFFFF, 0 })); + new BitMask(new uint[] { 0xFFFFFFFE, 0xFFFFFFFF, 1 }).ShouldBe( + new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 }) + new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 })); + } + + [Fact] + public void BitMaskSubtractionIsCorrect() + { + new BitMask(new[] { 0xAAAAAAAA }).ShouldBe( + new BitMask(new[] { 0xFFFFFFFF }) - new BitMask(new uint[] { 0x55555555 })); + new BitMask(new uint[] { 0xFFFFFFFF, 0 }).ShouldBe( + new BitMask(new uint[] { 0xFFFFFFFE, 1 }) - new BitMask(new uint[] { 0xFFFFFFFF, 0 })); + new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 }).ShouldBe( + new BitMask(new uint[] { 0xFFFFFFFE, 0xFFFFFFFF, 1 }) - new BitMask(new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0 })); + } + + [Fact] + public void BitMaskBitShiftLeftIsCorrect() + { + new BitMask(new[] { 0x80000000 }).ShouldBe( + new BitMask(new uint[] { 1 }) << 31); + new BitMask(new uint[] { 0x00000003 }).ShouldBe( + new BitMask(new uint[] { 6 }) << -1); + new BitMask(new uint[] { 0x00000000, 0x80000000 }).ShouldBe( + new BitMask(new uint[] { 1, 0 }) << 63); + new BitMask(new uint[] { 0 }).ShouldBe( + new BitMask(new uint[] { 0x00000001 }) << 32); + new BitMask(new uint[] { 0x80000000, 0x00000000 }).ShouldBe( + new BitMask(new uint[] { 0x00800000, 0x00000000 }) << 8); + new BitMask(new uint[] { 1 }).ShouldBe( + new BitMask(new[] { 0x80000000 }) << -31); + (new BitMask(new uint[] { 1, 0 }) << 63).ShouldBe( + new BitMask(new uint[] { 0x00000000, 0x80000000 })); + } + + [Fact] + public void BitMaskBitShiftRightIsCorrect() + { + new BitMask(new uint[] { 0x00800000, 0x00000000 }).ShouldBe( + new BitMask(new uint[] { 0x80000000, 0x00000000 }) >> 8); + new BitMask(new uint[] { 1 }).ShouldBe( + new BitMask(new[] { 0x80000000 }) >> 31); + new BitMask(new uint[] { 1, 0 }).ShouldBe( + new BitMask(new uint[] { 0x00000000, 0x80000000 }) >> 63); + new BitMask(new uint[] { 0x10000010, 0x00000000 }).ShouldBe( + new BitMask(new uint[] { 0x00000100, 0x00000001 }) >> 4); + new BitMask(new uint[] { 0 }).ShouldBe( + new BitMask(new[] { 0x80000000 }) >> 32); + new BitMask(new[] { 0x80000000 }).ShouldBe( + new BitMask(new uint[] { 1 }) >> -31); + } + + [Fact] + public void FindMostSignificantOneIsCorrect() + { + Assert.AreEqual(0, new BitMask(new uint[] { 0x00000000, 0x00000000 }).FindMostSignificantOnePosition()); + Assert.AreEqual(1, new BitMask(new uint[] { 0x00000001, 0x00000000 }).FindMostSignificantOnePosition()); + Assert.AreEqual(2, new BitMask(new uint[] { 0x00000002, 0x00000000 }).FindMostSignificantOnePosition()); + Assert.AreEqual(33, new BitMask(new uint[] { 0x00000002, 0x00000001 }).FindMostSignificantOnePosition()); + } + + [Fact] + public void FindLeastSignificantOneIsCorrect() + { + Assert.AreEqual(0, new BitMask(new uint[] { 0x00000000, 0x00000000 }).FindLeastSignificantOnePosition()); + Assert.AreEqual(1, new BitMask(new uint[] { 0x00000001, 0x00000000 }).FindLeastSignificantOnePosition()); + Assert.AreEqual(2, new BitMask(new uint[] { 0x00000002, 0x00000000 }).FindLeastSignificantOnePosition()); + Assert.AreEqual(2, new BitMask(new uint[] { 0x00000002, 0x00000001 }).FindLeastSignificantOnePosition()); + Assert.AreEqual(33, new BitMask(new uint[] { 0x00000000, 0x00000001 }).FindLeastSignificantOnePosition()); + } + + [Fact] + public void ShiftToRightEndIsCorrect() + { + new BitMask(new uint[] { 0x00000000, 0x00000000 }) + .ShouldBe(new BitMask(new uint[] { 0x00000000, 0x00000000 }).ShiftOutLeastSignificantZeros()); + new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros() + .ShouldBe(new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros()); + new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros() + .ShouldBe(new BitMask(new uint[] { 0x00000002, 0x00000000 }).ShiftOutLeastSignificantZeros()); + new BitMask(new uint[] { 0x00000001, 0x00000000 }).ShiftOutLeastSignificantZeros() + .ShouldBe(new BitMask(new uint[] { 0x00000000, 0x00000001 }).ShiftOutLeastSignificantZeros()); + new BitMask(new uint[] { 0x00001001, 0x00000000 }).ShiftOutLeastSignificantZeros() + .ShouldBe(new BitMask(new uint[] { 0x10010000, 0x00000000 }).ShiftOutLeastSignificantZeros()); + new BitMask(new uint[] { 0x00001001, 0x00000000 }).ShiftOutLeastSignificantZeros() + .ShouldBe(new BitMask(new uint[] { 0x00000000, 0x10010000 }).ShiftOutLeastSignificantZeros()); + } + + [Fact] + public void GetTwosComplementIsCorrect() + { + new BitMask(new uint[] { 0x00000001 }, 5).GetTwosComplement(5).ShouldBe(new BitMask(new uint[] { 0x1F })); + new BitMask(new uint[] { 0x0000022C }, 12).GetTwosComplement(12).ShouldBe(new BitMask(new uint[] { 0x00000DD4 })); + } + + [Fact] + public void LengthOfRunOfBitsIsCorrect() + { + new BitMask(new uint[] { 0x00000001 }).LengthOfRunOfBits(32).ShouldBe((ushort)31); + new BitMask(new uint[] { 0x30000000 }).LengthOfRunOfBits(32).ShouldBe((ushort)2); + new BitMask(new[] { 0x80000000 }).LengthOfRunOfBits(32).ShouldBe((ushort)1); + new BitMask(new uint[] { 0x00000000 }).LengthOfRunOfBits(32).ShouldBe((ushort)32); + new BitMask(new uint[] { 0x00000013 }).LengthOfRunOfBits(5).ShouldBe((ushort)1); + new BitMask(new uint[] { 17 }).LengthOfRunOfBits(5).ShouldBe((ushort)1); } } diff --git a/Lombiq.Arithmetics.Tests/CompatibilityAssert.cs b/Lombiq.Arithmetics.Tests/CompatibilityAssert.cs index 61e1c98..d862b55 100644 --- a/Lombiq.Arithmetics.Tests/CompatibilityAssert.cs +++ b/Lombiq.Arithmetics.Tests/CompatibilityAssert.cs @@ -1,25 +1,24 @@ using Xunit.Sdk; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public static class CompatibilityAssert { - public static class CompatibilityAssert - { - public static void AreEqual(T actual, T expected) => Xunit.Assert.Equal(expected, actual); + public static void AreEqual(T actual, T expected) => Xunit.Assert.Equal(expected, actual); - public static void AreEqual(uint actual, int expected) => Xunit.Assert.Equal((uint)expected, actual); + public static void AreEqual(uint actual, int expected) => Xunit.Assert.Equal((uint)expected, actual); - public static void AreEqual(int actual, uint expected) => Xunit.Assert.Equal(expected, (uint)actual); + public static void AreEqual(int actual, uint expected) => Xunit.Assert.Equal(expected, (uint)actual); - public static void AreEqual(T actual, T expected, string userMessage) + public static void AreEqual(T actual, T expected, string userMessage) + { + try + { + Xunit.Assert.Equal(expected, actual); + } + catch (EqualException) { - try - { - Xunit.Assert.Equal(expected, actual); - } - catch (EqualException) - { - Xunit.Assert.True(false, userMessage); - } + Xunit.Assert.True(false, userMessage); } } } diff --git a/Lombiq.Arithmetics.Tests/PositTests/Posit32Tests.cs b/Lombiq.Arithmetics.Tests/PositTests/Posit32Tests.cs index c03a34b..fa16170 100644 --- a/Lombiq.Arithmetics.Tests/PositTests/Posit32Tests.cs +++ b/Lombiq.Arithmetics.Tests/PositTests/Posit32Tests.cs @@ -5,494 +5,493 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class Posit32Tests { - public class Posit32Tests + [Fact] + public void EncodeRegimeBitsIsCorrect() { - [Fact] - public void EncodeRegimeBitsIsCorrect() - { - Assert.AreEqual(Posit32.EncodeRegimeBits(0), 0x_4000_0000); - Assert.AreEqual(Posit32.EncodeRegimeBits(1), 0x_6000_0000); - Assert.AreEqual(Posit32.EncodeRegimeBits(2), 0x_7000_0000); - Assert.AreEqual(Posit32.EncodeRegimeBits(-3), 0x_0800_0000); - Assert.AreEqual(Posit32.EncodeRegimeBits(-30), 0x_0000_0001); - Assert.AreEqual(Posit32.EncodeRegimeBits(30), 0x_7FFF_FFFF); - } - - [Fact] - public void Posit32IsCorrectlyConstructedFromInt() - { - Assert.AreEqual(new Posit32(0).PositBits, 0x_0000_0000); + Assert.AreEqual(Posit32.EncodeRegimeBits(0), 0x_4000_0000); + Assert.AreEqual(Posit32.EncodeRegimeBits(1), 0x_6000_0000); + Assert.AreEqual(Posit32.EncodeRegimeBits(2), 0x_7000_0000); + Assert.AreEqual(Posit32.EncodeRegimeBits(-3), 0x_0800_0000); + Assert.AreEqual(Posit32.EncodeRegimeBits(-30), 0x_0000_0001); + Assert.AreEqual(Posit32.EncodeRegimeBits(30), 0x_7FFF_FFFF); + } - Assert.AreEqual(new Posit32(1).PositBits, 0x_4000_0000); + [Fact] + public void Posit32IsCorrectlyConstructedFromInt() + { + Assert.AreEqual(new Posit32(0).PositBits, 0x_0000_0000); - Assert.AreEqual(new Posit32(-1).PositBits, 0x_C000_0000); + Assert.AreEqual(new Posit32(1).PositBits, 0x_4000_0000); - Assert.AreEqual(new Posit32(2).PositBits, 0x_4800_0000); + Assert.AreEqual(new Posit32(-1).PositBits, 0x_C000_0000); - Assert.AreEqual(new Posit32(13).PositBits, 0x_5D00_0000); + Assert.AreEqual(new Posit32(2).PositBits, 0x_4800_0000); - Assert.AreEqual(new Posit32(17).PositBits, 0x_6040_0000); + Assert.AreEqual(new Posit32(13).PositBits, 0x_5D00_0000); - Assert.AreEqual(new Posit32(500).PositBits, 0x_71E8_0000); + Assert.AreEqual(new Posit32(17).PositBits, 0x_6040_0000); - Assert.AreEqual(new Posit32(100).PositBits, 0b_01101010_01000000_00000000_00000000); + Assert.AreEqual(new Posit32(500).PositBits, 0x_71E8_0000); - Assert.AreEqual(new Posit32(-500).PositBits, 0x_8E18_0000); + Assert.AreEqual(new Posit32(100).PositBits, 0b_01101010_01000000_00000000_00000000); - Assert.AreEqual(new Posit32(-499).PositBits, 0x_8E1A_0000); + Assert.AreEqual(new Posit32(-500).PositBits, 0x_8E18_0000); - Assert.AreEqual(new Posit32(int.MaxValue).PositBits, 0b_01111111_10110000_00000000_00000000); + Assert.AreEqual(new Posit32(-499).PositBits, 0x_8E1A_0000); - Assert.AreEqual(new Posit32(int.MinValue).PositBits, 0b_10000000_01010000_00000000_00000000); + Assert.AreEqual(new Posit32(int.MaxValue).PositBits, 0b_01111111_10110000_00000000_00000000); - Assert.AreEqual(new Posit32(int.MaxValue - 1).PositBits, 0b_01111111_10110000_00000000_00000000); - } + Assert.AreEqual(new Posit32(int.MinValue).PositBits, 0b_10000000_01010000_00000000_00000000); - [Fact] - public void Posit32AdditionIsCorrect() - { - var posit16 = new Posit32(16); - var posit17 = posit16 + 1; - posit17.PositBits.ShouldBe(new Posit32(17).PositBits); + Assert.AreEqual(new Posit32(int.MaxValue - 1).PositBits, 0b_01111111_10110000_00000000_00000000); + } - var posit1 = new Posit32(1); - var posit0 = posit1 - 1; - posit0.PositBits.ShouldBe(new Posit32(0).PositBits); - var positNegative1 = posit0 - 1; - positNegative1.PositBits.ShouldBe(0x_C000_0000); + [Fact] + public void Posit32AdditionIsCorrect() + { + var posit16 = new Posit32(16); + var posit17 = posit16 + 1; + posit17.PositBits.ShouldBe(new Posit32(17).PositBits); - var positNegative500 = new Posit32(-500); - var positNegative499 = positNegative500 + 1; - positNegative499.PositBits.ShouldBe(new Posit32(-499).PositBits); + var posit1 = new Posit32(1); + var posit0 = posit1 - 1; + posit0.PositBits.ShouldBe(new Posit32(0).PositBits); + var positNegative1 = posit0 - 1; + positNegative1.PositBits.ShouldBe(0x_C000_0000); - var positNegative2 = positNegative1 - 1; - positNegative2.PositBits.ShouldBe(new Posit32(-2).PositBits); + var positNegative500 = new Posit32(-500); + var positNegative499 = positNegative500 + 1; + positNegative499.PositBits.ShouldBe(new Posit32(-499).PositBits); - var posit3 = new Posit32(100.0125F); - var posit4 = posit3 - 100; + var positNegative2 = positNegative1 - 1; + positNegative2.PositBits.ShouldBe(new Posit32(-2).PositBits); - posit4.PositBits.ShouldBe(new Posit32(0b_00010110_01100110_00000000_00000000, fromBitMask: true).PositBits); + var posit3 = new Posit32(100.0125F); + var posit4 = posit3 - 100; - (new Posit32(500) + new Posit32(-500)).PositBits.ShouldBe(new Posit32(0).PositBits); - (new Posit32(99_988) + new Posit32(-88_999)).PositBits.ShouldBe(new Posit32(10_989).PositBits); - (new Posit32(0.75F) + new Posit32(0.75F)).PositBits.ShouldBe(new Posit32(1.5F).PositBits); - (new Posit32(4F) + new Posit32(-3.75F)).PositBits.ShouldBe(new Posit32(0.25F).PositBits); - } + posit4.PositBits.ShouldBe(new Posit32(0b_00010110_01100110_00000000_00000000, fromBitMask: true).PositBits); - [Fact] - public void Posit32AdditionIsCorrectForPositives() - { - var posit1 = new Posit32(1); - - for (var i = 1; i < 50_000; i++) - { - posit1 += 1; - } + (new Posit32(500) + new Posit32(-500)).PositBits.ShouldBe(new Posit32(0).PositBits); + (new Posit32(99_988) + new Posit32(-88_999)).PositBits.ShouldBe(new Posit32(10_989).PositBits); + (new Posit32(0.75F) + new Posit32(0.75F)).PositBits.ShouldBe(new Posit32(1.5F).PositBits); + (new Posit32(4F) + new Posit32(-3.75F)).PositBits.ShouldBe(new Posit32(0.25F).PositBits); + } - posit1.PositBits.ShouldBe(new Posit32(50_000).PositBits); - } + [Fact] + public void Posit32AdditionIsCorrectForPositives() + { + var posit1 = new Posit32(1); - [Fact] - public void Posit32LengthOfRunOfBitsIsCorrect() + for (var i = 1; i < 50_000; i++) { - Assert.AreEqual(Posit32.LengthOfRunOfBits(1, 31), 30); - Assert.AreEqual(Posit32.LengthOfRunOfBits(0x_6000_0000, 31), 2); - Assert.AreEqual(Posit32.LengthOfRunOfBits(0b_00010000_10001111_01010011_11000101, 31), 2); + posit1 += 1; } - [Fact] - public void Posit32AdditionIsCorrectForNegatives() - { - var posit1 = new Posit32(-500); + posit1.PositBits.ShouldBe(new Posit32(50_000).PositBits); + } - for (var i = 1; i <= 500; i++) - { - posit1 += 1; - } + [Fact] + public void Posit32LengthOfRunOfBitsIsCorrect() + { + Assert.AreEqual(Posit32.LengthOfRunOfBits(1, 31), 30); + Assert.AreEqual(Posit32.LengthOfRunOfBits(0x_6000_0000, 31), 2); + Assert.AreEqual(Posit32.LengthOfRunOfBits(0b_00010000_10001111_01010011_11000101, 31), 2); + } - for (var j = 1; j <= 500; j++) - { - posit1 -= 1; - } + [Fact] + public void Posit32AdditionIsCorrectForNegatives() + { + var posit1 = new Posit32(-500); - posit1.PositBits.ShouldBe(new Posit32(-500).PositBits); + for (var i = 1; i <= 500; i++) + { + posit1 += 1; } - [Fact] - public void Posit32MultiplicationIsCorrect() + for (var j = 1; j <= 500; j++) { - var posit1 = new Posit32(1); - posit1 *= 5; - posit1.PositBits.ShouldBe(new Posit32(5).PositBits); + posit1 -= 1; + } - var posit2 = new Posit32(2); - posit2 *= new Posit32(0.25F); - posit2.PositBits.ShouldBe(new Posit32(0.5F).PositBits); + posit1.PositBits.ShouldBe(new Posit32(-500).PositBits); + } - var posit3 = new Posit32(0.1F); - posit3 *= new Posit32(0.01F); - posit3.PositBits.ShouldBe(new Posit32(0b_00001100_00001100_01001001_10111010, fromBitMask: true).PositBits); + [Fact] + public void Posit32MultiplicationIsCorrect() + { + var posit1 = new Posit32(1); + posit1 *= 5; + posit1.PositBits.ShouldBe(new Posit32(5).PositBits); - var posit55 = new Posit32(int.MaxValue - 1); - posit55 *= new Posit32(0.25F); - posit55.PositBits.ShouldBe(new Posit32((int.MaxValue - 1) / 4).PositBits); + var posit2 = new Posit32(2); + posit2 *= new Posit32(0.25F); + posit2.PositBits.ShouldBe(new Posit32(0.5F).PositBits); - posit55 *= new Posit32(0); - posit55.PositBits.ShouldBe(new Posit32(0).PositBits); + var posit3 = new Posit32(0.1F); + posit3 *= new Posit32(0.01F); + posit3.PositBits.ShouldBe(new Posit32(0b_00001100_00001100_01001001_10111010, fromBitMask: true).PositBits); - var positReal1 = new Posit32(0b_01000000_00000000_00110100_01101110, fromBitMask: true); - var positReal2 = new Posit32(0b_01000000_00000000_00110100_01101110, fromBitMask: true); - var pr3 = positReal1 * positReal2; + var posit55 = new Posit32(int.MaxValue - 1); + posit55 *= new Posit32(0.25F); + posit55.PositBits.ShouldBe(new Posit32((int.MaxValue - 1) / 4).PositBits); - Assert.AreEqual(pr3.PositBits, 0b_01000000_00000000_01101000_11011101); - } + posit55 *= new Posit32(0); + posit55.PositBits.ShouldBe(new Posit32(0).PositBits); - [Fact] - public void Posit32DivisionIsCorrect() - { - var posit6 = new Posit32(6); - posit6 /= 4; - posit6.PositBits.ShouldBe(new Posit32(1.5F).PositBits); + var positReal1 = new Posit32(0b_01000000_00000000_00110100_01101110, fromBitMask: true); + var positReal2 = new Posit32(0b_01000000_00000000_00110100_01101110, fromBitMask: true); + var pr3 = positReal1 * positReal2; - var posit2 = new Posit32(2); - posit2 /= 4; - posit2.PositBits.ShouldBe(new Posit32(0.5F).PositBits); + Assert.AreEqual(pr3.PositBits, 0b_01000000_00000000_01101000_11011101); + } - var posit55 = new Posit32(int.MaxValue - 1); - posit55 /= new Posit32(4); - posit55.PositBits.ShouldBe(new Posit32((int.MaxValue - 1) / 4).PositBits); + [Fact] + public void Posit32DivisionIsCorrect() + { + var posit6 = new Posit32(6); + posit6 /= 4; + posit6.PositBits.ShouldBe(new Posit32(1.5F).PositBits); - posit55 /= new Posit32(0); - posit55.PositBits.ShouldBe(new Posit32(Posit32.NaNBitMask, fromBitMask: true).PositBits); + var posit2 = new Posit32(2); + posit2 /= 4; + posit2.PositBits.ShouldBe(new Posit32(0.5F).PositBits); - var posit12345 = new Posit32(12_345); - posit12345 /= 100; - posit12345.PositBits.ShouldBe(new Posit32(0b_01101011_10110111_00110011_00110011, fromBitMask: true).PositBits); + var posit55 = new Posit32(int.MaxValue - 1); + posit55 /= new Posit32(4); + posit55.PositBits.ShouldBe(new Posit32((int.MaxValue - 1) / 4).PositBits); - var positBig = new Posit32(5_000_000); - positBig /= 1_000_000; - positBig.PositBits.ShouldBe(new Posit32(5).PositBits); + posit55 /= new Posit32(0); + posit55.PositBits.ShouldBe(new Posit32(Posit32.NaNBitMask, fromBitMask: true).PositBits); - var positBig2 = new Posit32(50_000_000); - positBig2 /= 50_000_000; - positBig2.PositBits.ShouldBe(new Posit32(1).PositBits); + var posit12345 = new Posit32(12_345); + posit12345 /= 100; + posit12345.PositBits.ShouldBe(new Posit32(0b_01101011_10110111_00110011_00110011, fromBitMask: true).PositBits); - var positSmall = new Posit32(0.02F); - positSmall /= new Posit32(0.05F); - positSmall.PositBits.ShouldBe(new Posit32(0b_00110100_11001100_11001100_11000101, fromBitMask: true).PositBits); + var positBig = new Posit32(5_000_000); + positBig /= 1_000_000; + positBig.PositBits.ShouldBe(new Posit32(5).PositBits); - var positSmall2 = new Posit32(0.1F); + var positBig2 = new Posit32(50_000_000); + positBig2 /= 50_000_000; + positBig2.PositBits.ShouldBe(new Posit32(1).PositBits); - positSmall2 /= 100; - positSmall2.PositBits.ShouldBe(new Posit32(0b_00001100_00001100_01001001_10111011, fromBitMask: true).PositBits); - } + var positSmall = new Posit32(0.02F); + positSmall /= new Posit32(0.05F); + positSmall.PositBits.ShouldBe(new Posit32(0b_00110100_11001100_11001100_11000101, fromBitMask: true).PositBits); - [Fact] - public void Posit32ToIntIsCorrect() - { - var posit0 = new Posit32(0); - Assert.AreEqual((int)posit0, 0); + var positSmall2 = new Posit32(0.1F); + + positSmall2 /= 100; + positSmall2.PositBits.ShouldBe(new Posit32(0b_00001100_00001100_01001001_10111011, fromBitMask: true).PositBits); + } - var posit1 = new Posit32(1); - Assert.AreEqual((int)posit1, 1); + [Fact] + public void Posit32ToIntIsCorrect() + { + var posit0 = new Posit32(0); + Assert.AreEqual((int)posit0, 0); - var posit8 = new Posit32(8); - Assert.AreEqual((int)posit8, 8); + var posit1 = new Posit32(1); + Assert.AreEqual((int)posit1, 1); - var posit16384 = new Posit32(16_384); - Assert.AreEqual((int)posit16384, 16_384); + var posit8 = new Posit32(8); + Assert.AreEqual((int)posit8, 8); - var positNegative13 = new Posit32(-13); - Assert.AreEqual((int)positNegative13, -13); + var posit16384 = new Posit32(16_384); + Assert.AreEqual((int)posit16384, 16_384); - var positIntMaxValue = new Posit32(int.MaxValue); - Assert.AreEqual((int)positIntMaxValue, int.MaxValue); - var positCloseToIntMaxValue = new Posit32(2_147_481_600); - Assert.AreEqual((int)positCloseToIntMaxValue, 2_147_481_600); - } + var positNegative13 = new Posit32(-13); + Assert.AreEqual((int)positNegative13, -13); - [Fact] - public void Posit32IsCorrectlyConstructedFromFloat() - { - Assert.AreEqual(new Posit32(0F).PositBits, 0x_0000_0000); - Assert.AreEqual(new Posit32(-0F).PositBits, 0x_0000_0000); - Assert.AreEqual(new Posit32(0.75F).PositBits, 0b_00111100_00000000_00000000_00000000); + var positIntMaxValue = new Posit32(int.MaxValue); + Assert.AreEqual((int)positIntMaxValue, int.MaxValue); + var positCloseToIntMaxValue = new Posit32(2_147_481_600); + Assert.AreEqual((int)positCloseToIntMaxValue, 2_147_481_600); + } + + [Fact] + public void Posit32IsCorrectlyConstructedFromFloat() + { + Assert.AreEqual(new Posit32(0F).PositBits, 0x_0000_0000); + Assert.AreEqual(new Posit32(-0F).PositBits, 0x_0000_0000); + Assert.AreEqual(new Posit32(0.75F).PositBits, 0b_00111100_00000000_00000000_00000000); - Assert.AreEqual(new Posit32(0.0500000007450580596923828125F).PositBits, 0b_00011110_01100110_01100110_01101000); - Assert.AreEqual(new Posit32(-0.00179999996908009052276611328125F).PositBits, 0b_11110010_01010000_01001000_00011000); + Assert.AreEqual(new Posit32(0.0500000007450580596923828125F).PositBits, 0b_00011110_01100110_01100110_01101000); + Assert.AreEqual(new Posit32(-0.00179999996908009052276611328125F).PositBits, 0b_11110010_01010000_01001000_00011000); - Assert.AreEqual(new Posit32(-134.75F).PositBits, 0x_93CA_0000); - Assert.AreEqual(new Posit32(100000.5F).PositBits, 0b_01111100_01000011_01010000_01000000); - Assert.AreEqual(new Posit32(-2_000_000.5F).PositBits, 0b_10000001_11000101_11101101_11111110); + Assert.AreEqual(new Posit32(-134.75F).PositBits, 0x_93CA_0000); + Assert.AreEqual(new Posit32(100000.5F).PositBits, 0b_01111100_01000011_01010000_01000000); + Assert.AreEqual(new Posit32(-2_000_000.5F).PositBits, 0b_10000001_11000101_11101101_11111110); - Assert.AreEqual( - new Posit32( + Assert.AreEqual( + new Posit32( 1.065291755432698054096667486857660145523165660824704316367306233814815641380846500396728515625E-38F).PositBits, - 0b_00000000_00000000_00000000_00000001); - Assert.AreEqual(new Posit32(2.7647944E+38F).PositBits, 0b_01111111_11111111_11111111_11111111); - } + 0b_00000000_00000000_00000000_00000001); + Assert.AreEqual(new Posit32(2.7647944E+38F).PositBits, 0b_01111111_11111111_11111111_11111111); + } - [Fact] - public void Posit32IsCorrectlyConstructedFromDouble() - { - Assert.AreEqual(new Posit32(0D).PositBits, 0x_0000_0000); - Assert.AreEqual(new Posit32(-0D).PositBits, 0x_0000_0000); - Assert.AreEqual(new Posit32(0.75).PositBits, 0b_00111100_00000000_00000000_00000000); - - Assert.AreEqual(new Posit32(0.0500000007450580596923828125).PositBits, 0b_00011110_01100110_01100110_01101000); - Assert.AreEqual(new Posit32(-0.00179999996908009052276611328125).PositBits, 0b_11110010_01010000_01001000_00011000); - - Assert.AreEqual(new Posit32(-134.75).PositBits, 0b_10010011_11001010_00000000_00000000); - Assert.AreEqual(new Posit32(100000.5).PositBits, 0b_01111100_01000011_01010000_01000000); - Assert.AreEqual(new Posit32(-2_000_000.5).PositBits, 0b_10000001_11000101_11101101_11111110); - - Assert.AreEqual( - new Posit32( - 1.065291755432698054096667486857660145523165660824704316367306233814815641380846500396728515625E-38).PositBits, - 0b_00000000_00000000_00000000_00000001); - Assert.AreEqual(new Posit32(2.7647944E+38).PositBits, 0b_01111111_11111111_11111111_11111111); - } + [Fact] + public void Posit32IsCorrectlyConstructedFromDouble() + { + Assert.AreEqual(new Posit32(0D).PositBits, 0x_0000_0000); + Assert.AreEqual(new Posit32(-0D).PositBits, 0x_0000_0000); + Assert.AreEqual(new Posit32(0.75).PositBits, 0b_00111100_00000000_00000000_00000000); + + Assert.AreEqual(new Posit32(0.0500000007450580596923828125).PositBits, 0b_00011110_01100110_01100110_01101000); + Assert.AreEqual(new Posit32(-0.00179999996908009052276611328125).PositBits, 0b_11110010_01010000_01001000_00011000); + + Assert.AreEqual(new Posit32(-134.75).PositBits, 0b_10010011_11001010_00000000_00000000); + Assert.AreEqual(new Posit32(100000.5).PositBits, 0b_01111100_01000011_01010000_01000000); + Assert.AreEqual(new Posit32(-2_000_000.5).PositBits, 0b_10000001_11000101_11101101_11111110); + + Assert.AreEqual( + new Posit32( + 1.065291755432698054096667486857660145523165660824704316367306233814815641380846500396728515625E-38).PositBits, + 0b_00000000_00000000_00000000_00000001); + Assert.AreEqual(new Posit32(2.7647944E+38).PositBits, 0b_01111111_11111111_11111111_11111111); + } - [Fact] - public void Posit32ToFloatIsCorrect() - { - var posit1 = new Posit32(1); - Assert.AreEqual((float)posit1, 1); + [Fact] + public void Posit32ToFloatIsCorrect() + { + var posit1 = new Posit32(1); + Assert.AreEqual((float)posit1, 1); - var positNegative1234 = new Posit32(-1_234); - Assert.AreEqual((float)positNegative1234, -1_234); + var positNegative1234 = new Posit32(-1_234); + Assert.AreEqual((float)positNegative1234, -1_234); - var posit3 = new Posit32(0.75F); - Assert.AreEqual((float)posit3, 0.75); + var posit3 = new Posit32(0.75F); + Assert.AreEqual((float)posit3, 0.75); - var posit4 = new Posit32(-134.75F); - Assert.AreEqual((float)posit4, -134.75); + var posit4 = new Posit32(-134.75F); + Assert.AreEqual((float)posit4, -134.75); - var posit5 = new Posit32(100000.5F); - Assert.AreEqual((float)posit5, 100000.5); + var posit5 = new Posit32(100000.5F); + Assert.AreEqual((float)posit5, 100000.5); - var posit6 = new Posit32(-2_000_000.5F); - Assert.AreEqual((float)posit6, -2_000_000.5); + var posit6 = new Posit32(-2_000_000.5F); + Assert.AreEqual((float)posit6, -2_000_000.5); - var posit7 = new Posit32(-0.00179999996908009052276611328125F); - Assert.AreEqual((float)posit7, -0.00179999996908009052276611328125); + var posit7 = new Posit32(-0.00179999996908009052276611328125F); + Assert.AreEqual((float)posit7, -0.00179999996908009052276611328125); - var posit8 = new Posit32(0.0500000007450580596923828125F); - Assert.AreEqual((float)posit8, 0.0500000007450580596923828125); + var posit8 = new Posit32(0.0500000007450580596923828125F); + Assert.AreEqual((float)posit8, 0.0500000007450580596923828125); - var posit11 = new Posit32(0.002F); - Assert.AreEqual((float)posit11, 0.002F); + var posit11 = new Posit32(0.002F); + Assert.AreEqual((float)posit11, 0.002F); - var posit9 = new Posit32(0.005F); - Assert.AreEqual((float)posit9, 0.005F); + var posit9 = new Posit32(0.005F); + Assert.AreEqual((float)posit9, 0.005F); - var posit10 = new Posit32(0.1F); - Assert.AreEqual((float)posit10, 0.1F); + var posit10 = new Posit32(0.1F); + Assert.AreEqual((float)posit10, 0.1F); - var posit12 = new Posit32(0.707106781F); - Assert.AreEqual((float)posit12, 0.707106781F); - } + var posit12 = new Posit32(0.707106781F); + Assert.AreEqual((float)posit12, 0.707106781F); + } - [Fact] - public void Posit32ToDoubleIsCorrect() - { - var posit1 = new Posit32(1); - Assert.AreEqual((double)posit1, 1); + [Fact] + public void Posit32ToDoubleIsCorrect() + { + var posit1 = new Posit32(1); + Assert.AreEqual((double)posit1, 1); - var positNegative1234 = new Posit32(-1_234); - Assert.AreEqual((double)positNegative1234, -1_234); + var positNegative1234 = new Posit32(-1_234); + Assert.AreEqual((double)positNegative1234, -1_234); - var posit3 = new Posit32(0.75); - Assert.AreEqual((double)posit3, 0.75); + var posit3 = new Posit32(0.75); + Assert.AreEqual((double)posit3, 0.75); - var posit4 = new Posit32(-134.75); - Assert.AreEqual((double)posit4, -134.75); + var posit4 = new Posit32(-134.75); + Assert.AreEqual((double)posit4, -134.75); - var posit5 = new Posit32(100000.5); - Assert.AreEqual((double)posit5, 100000.5); + var posit5 = new Posit32(100000.5); + Assert.AreEqual((double)posit5, 100000.5); - var posit6 = new Posit32(-2_000_000.5); - Assert.AreEqual((float)posit6, -2_000_000.5); + var posit6 = new Posit32(-2_000_000.5); + Assert.AreEqual((float)posit6, -2_000_000.5); - var posit7 = new Posit32(-0.00179999996908009052276611328125); - Assert.AreEqual((double)posit7, -0.00179999996908009052276611328125); + var posit7 = new Posit32(-0.00179999996908009052276611328125); + Assert.AreEqual((double)posit7, -0.00179999996908009052276611328125); - var posit8 = new Posit32(0.0500000007450580596923828125); - Assert.AreEqual((double)posit8, 0.0500000007450580596923828125); + var posit8 = new Posit32(0.0500000007450580596923828125); + Assert.AreEqual((double)posit8, 0.0500000007450580596923828125); - var posit11 = new Posit32(0.002); - Assert.AreEqual((double)posit11, 0.001999999978579581); + var posit11 = new Posit32(0.002); + Assert.AreEqual((double)posit11, 0.001999999978579581); - var posit9 = new Posit32(0.005); - Assert.AreEqual((double)posit9, 0.005000000004656613); + var posit9 = new Posit32(0.005); + Assert.AreEqual((double)posit9, 0.005000000004656613); - var posit10 = new Posit32(0.1); - Assert.AreEqual((double)posit10, 0.10000000009313226); + var posit10 = new Posit32(0.1); + Assert.AreEqual((double)posit10, 0.10000000009313226); - var posit12 = new Posit32(0.707106781); - Assert.AreEqual((double)posit12, 0.7071067802608013); - } + var posit12 = new Posit32(0.707106781); + Assert.AreEqual((double)posit12, 0.7071067802608013); + } - [Fact] - public void Posit32ToQuireIsCorrect() - { - var posit1 = new Posit32(1); - Assert.AreEqual(((Quire)posit1).Segments, (new Quire(new ulong[] { 1 }, 512) << 240).Segments); - - var positNegative1 = new Posit32(-1); - Assert.AreEqual( - ((Quire)positNegative1).Segments, - new Quire( - new ulong[] { 0, 0, 0, 0x_FFFF_0000_0000_0000, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }, 512) - .Segments); - - var positNegative3 = new Posit32(-3); - Assert.AreEqual( - ((Quire)positNegative3).Segments, - new Quire( - new ulong[] { 0, 0, 0, 0x_FFFD_0000_0000_0000, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }, 512) - .Segments); - - var positMax = new Posit32(0x_7FFF_FFFF, fromBitMask: true); - Assert.AreEqual(((Quire)positMax).Segments, (new Quire(new ulong[] { 1 }, 512) << 360).Segments); - - var positNaN = new Posit32(Posit32.NaNBitMask, fromBitMask: true); - var quireNaN = (Quire)positNaN; - var quireNaNFromMask = new Quire(new ulong[] { 1 }, 512) << 511; - - Assert.AreEqual(quireNaN.Segments, quireNaNFromMask.Segments); - } + [Fact] + public void Posit32ToQuireIsCorrect() + { + var posit1 = new Posit32(1); + Assert.AreEqual(((Quire)posit1).Segments, (new Quire(new ulong[] { 1 }, 512) << 240).Segments); + + var positNegative1 = new Posit32(-1); + Assert.AreEqual( + ((Quire)positNegative1).Segments, + new Quire( + new ulong[] { 0, 0, 0, 0x_FFFF_0000_0000_0000, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }, 512) + .Segments); + + var positNegative3 = new Posit32(-3); + Assert.AreEqual( + ((Quire)positNegative3).Segments, + new Quire( + new ulong[] { 0, 0, 0, 0x_FFFD_0000_0000_0000, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }, 512) + .Segments); + + var positMax = new Posit32(0x_7FFF_FFFF, fromBitMask: true); + Assert.AreEqual(((Quire)positMax).Segments, (new Quire(new ulong[] { 1 }, 512) << 360).Segments); + + var positNaN = new Posit32(Posit32.NaNBitMask, fromBitMask: true); + var quireNaN = (Quire)positNaN; + var quireNaNFromMask = new Quire(new ulong[] { 1 }, 512) << 511; + + Assert.AreEqual(quireNaN.Segments, quireNaNFromMask.Segments); + } - [Fact] - public void Posit32FusedSumIsCorrect() - { - var positArray = new Posit32[3]; - positArray[0] = new Posit32(1); - positArray[1] = new Posit32(16_777_216); - positArray[2] = new Posit32(4); - Assert.AreEqual(Posit32.FusedSum(positArray).PositBits, new Posit32(16_777_224).PositBits); - - positArray[2] = new Posit32(Posit32.NaNBitMask, fromBitMask: true); - Assert.AreEqual(Posit32.FusedSum(positArray).PositBits, positArray[2].PositBits); - } + [Fact] + public void Posit32FusedSumIsCorrect() + { + var positArray = new Posit32[3]; + positArray[0] = new Posit32(1); + positArray[1] = new Posit32(16_777_216); + positArray[2] = new Posit32(4); + Assert.AreEqual(Posit32.FusedSum(positArray).PositBits, new Posit32(16_777_224).PositBits); + + positArray[2] = new Posit32(Posit32.NaNBitMask, fromBitMask: true); + Assert.AreEqual(Posit32.FusedSum(positArray).PositBits, positArray[2].PositBits); + } - [Fact] - public void Posit32MultiplyIntoQuireIsCorrect() - { - var posit1 = new Posit32(3); - var posit2 = new Posit32(4); - var posit3 = new Posit32(-1); + [Fact] + public void Posit32MultiplyIntoQuireIsCorrect() + { + var posit1 = new Posit32(3); + var posit2 = new Posit32(4); + var posit3 = new Posit32(-1); - Assert.AreEqual(new Posit32(Posit32.MultiplyIntoQuire(posit1, posit2)).PositBits, new Posit32(12).PositBits); + Assert.AreEqual(new Posit32(Posit32.MultiplyIntoQuire(posit1, posit2)).PositBits, new Posit32(12).PositBits); - Assert.AreEqual(new Posit32(Posit32.MultiplyIntoQuire(posit1, posit3)).PositBits, new Posit32(-3).PositBits); - } + Assert.AreEqual(new Posit32(Posit32.MultiplyIntoQuire(posit1, posit3)).PositBits, new Posit32(-3).PositBits); + } - [Fact] - public void Posit32FusedDotProductIsCorrect() - { - var positArray1 = new Posit32[3]; - var positArray2 = new Posit32[3]; - positArray1[0] = new Posit32(1); - positArray1[1] = new Posit32(2); - positArray1[2] = new Posit32(3); - - positArray2[0] = new Posit32(1); - positArray2[1] = new Posit32(2); - positArray2[2] = new Posit32(4); - Assert.AreEqual(Posit32.FusedDotProduct(positArray1, positArray2).PositBits, new Posit32(17).PositBits); - - var positArray3 = new Posit32[3]; - positArray3[0] = new Posit32(-1); - positArray3[1] = new Posit32(2); - positArray3[2] = new Posit32(-100); - Assert.AreEqual(Posit32.FusedDotProduct(positArray1, positArray3).PositBits, new Posit32(-297).PositBits); - } + [Fact] + public void Posit32FusedDotProductIsCorrect() + { + var positArray1 = new Posit32[3]; + var positArray2 = new Posit32[3]; + positArray1[0] = new Posit32(1); + positArray1[1] = new Posit32(2); + positArray1[2] = new Posit32(3); + + positArray2[0] = new Posit32(1); + positArray2[1] = new Posit32(2); + positArray2[2] = new Posit32(4); + Assert.AreEqual(Posit32.FusedDotProduct(positArray1, positArray2).PositBits, new Posit32(17).PositBits); + + var positArray3 = new Posit32[3]; + positArray3[0] = new Posit32(-1); + positArray3[1] = new Posit32(2); + positArray3[2] = new Posit32(-100); + Assert.AreEqual(Posit32.FusedDotProduct(positArray1, positArray3).PositBits, new Posit32(-297).PositBits); + } - [Fact] - public void Posit32FusedMultiplyAddIsCorrect() - { - var posit1 = new Posit32(300); - var posit2 = new Posit32(0.5F); - var posit3 = new Posit32(-1); + [Fact] + public void Posit32FusedMultiplyAddIsCorrect() + { + var posit1 = new Posit32(300); + var posit2 = new Posit32(0.5F); + var posit3 = new Posit32(-1); - Assert.AreEqual(Posit32.FusedMultiplyAdd(posit1, posit2, posit3).PositBits, new Posit32(149).PositBits); - Assert.AreEqual(Posit32.FusedMultiplyAdd(posit1, posit3, posit2).PositBits, new Posit32(-299.5F).PositBits); - } + Assert.AreEqual(Posit32.FusedMultiplyAdd(posit1, posit2, posit3).PositBits, new Posit32(149).PositBits); + Assert.AreEqual(Posit32.FusedMultiplyAdd(posit1, posit3, posit2).PositBits, new Posit32(-299.5F).PositBits); + } - [Fact] - public void Posit32FusedAddMultiplyIsCorrect() - { - var posit1 = new Posit32(0.75F); - var posit2 = new Posit32(0.5F); - var posit3 = new Posit32(-2); + [Fact] + public void Posit32FusedAddMultiplyIsCorrect() + { + var posit1 = new Posit32(0.75F); + var posit2 = new Posit32(0.5F); + var posit3 = new Posit32(-2); - Assert.AreEqual(Posit32.FusedAddMultiply(posit1, posit2, posit3).PositBits, new Posit32(-2.5F).PositBits); - Assert.AreEqual(Posit32.FusedAddMultiply(posit2, posit3, posit1).PositBits, new Posit32(-1.125F).PositBits); - } + Assert.AreEqual(Posit32.FusedAddMultiply(posit1, posit2, posit3).PositBits, new Posit32(-2.5F).PositBits); + Assert.AreEqual(Posit32.FusedAddMultiply(posit2, posit3, posit1).PositBits, new Posit32(-1.125F).PositBits); + } - [Fact] - public void Posit32FusedMultiplyMultiplySubtractIsCorrect() - { - var posit1 = new Posit32(0.75F); - var posit2 = new Posit32(0.5F); - var posit3 = new Posit32(-2); - var posit4 = new Posit32(125.125F); - - Assert.AreEqual( - Posit32.FusedMultiplyMultiplySubtract(posit1, posit2, posit3, posit4).PositBits, - new Posit32(250.625F).PositBits); - Assert.AreEqual( - Posit32.FusedMultiplyMultiplySubtract(posit2, posit3, posit1, posit4).PositBits, - new Posit32(-94.84375F).PositBits); - } + [Fact] + public void Posit32FusedMultiplyMultiplySubtractIsCorrect() + { + var posit1 = new Posit32(0.75F); + var posit2 = new Posit32(0.5F); + var posit3 = new Posit32(-2); + var posit4 = new Posit32(125.125F); + + Assert.AreEqual( + Posit32.FusedMultiplyMultiplySubtract(posit1, posit2, posit3, posit4).PositBits, + new Posit32(250.625F).PositBits); + Assert.AreEqual( + Posit32.FusedMultiplyMultiplySubtract(posit2, posit3, posit1, posit4).PositBits, + new Posit32(-94.84375F).PositBits); + } - [Fact] - public void Posit32SquareRootIsCorrect() - { - var positNaN = new Posit32(Posit32.NaNBitMask, fromBitMask: true); - Posit32.Sqrt(positNaN).PositBits.ShouldBe(new Posit32(Posit32.NaNBitMask, fromBitMask: true).PositBits); + [Fact] + public void Posit32SquareRootIsCorrect() + { + var positNaN = new Posit32(Posit32.NaNBitMask, fromBitMask: true); + Posit32.Sqrt(positNaN).PositBits.ShouldBe(new Posit32(Posit32.NaNBitMask, fromBitMask: true).PositBits); - var positZero = new Posit32(0); - Posit32.Sqrt(positZero).PositBits.ShouldBe(new Posit32(0).PositBits); + var positZero = new Posit32(0); + Posit32.Sqrt(positZero).PositBits.ShouldBe(new Posit32(0).PositBits); - var positOne = new Posit32(1); - Posit32.Sqrt(positOne).PositBits.ShouldBe(new Posit32(1).PositBits); + var positOne = new Posit32(1); + Posit32.Sqrt(positOne).PositBits.ShouldBe(new Posit32(1).PositBits); - var positNegative = new Posit32(-1); - Posit32.Sqrt(positNegative).PositBits.ShouldBe(new Posit32(Posit32.NaNBitMask, fromBitMask: true).PositBits); + var positNegative = new Posit32(-1); + Posit32.Sqrt(positNegative).PositBits.ShouldBe(new Posit32(Posit32.NaNBitMask, fromBitMask: true).PositBits); - var posit4 = new Posit32(4); - Posit32.Sqrt(posit4).PositBits.ShouldBe(new Posit32(2).PositBits); + var posit4 = new Posit32(4); + Posit32.Sqrt(posit4).PositBits.ShouldBe(new Posit32(2).PositBits); - var posit9 = new Posit32(9); - Posit32.Sqrt(posit9).PositBits.ShouldBe(new Posit32(3).PositBits); + var posit9 = new Posit32(9); + Posit32.Sqrt(posit9).PositBits.ShouldBe(new Posit32(3).PositBits); - var posit625 = new Posit32(625); - Posit32.Sqrt(posit625).PositBits.ShouldBe(new Posit32(25).PositBits); + var posit625 = new Posit32(625); + Posit32.Sqrt(posit625).PositBits.ShouldBe(new Posit32(25).PositBits); - var positSmallerThanOne1 = new Posit32(0.5F); - Debug.WriteLine(((float)Posit32.Sqrt(positSmallerThanOne1)).ToString("0.0000000000", CultureInfo.InvariantCulture)); - Posit32.Sqrt(positSmallerThanOne1).PositBits.ShouldBe(new Posit32(0b_00111011_01010000_01001111_00110011, fromBitMask: true).PositBits); + var positSmallerThanOne1 = new Posit32(0.5F); + Debug.WriteLine(((float)Posit32.Sqrt(positSmallerThanOne1)).ToString("0.0000000000", CultureInfo.InvariantCulture)); + Posit32.Sqrt(positSmallerThanOne1).PositBits.ShouldBe(new Posit32(0b_00111011_01010000_01001111_00110011, fromBitMask: true).PositBits); - var positBig = new Posit32(1_004_004); - Posit32.Sqrt(positBig).PositBits.ShouldBe(new Posit32(1_002).PositBits); - } + var positBig = new Posit32(1_004_004); + Posit32.Sqrt(positBig).PositBits.ShouldBe(new Posit32(1_002).PositBits); + } - [Fact] - public void Posit32ToStringIsCorrect() - { - var posit1 = new Posit32(0.75F); - var posit2 = new Posit32(-200_000); - var posit3 = new Posit32(125.12545F); - var posit4 = new Posit32(0.999); - - posit1.ToString(CultureInfo.InvariantCulture).ShouldBe("0.75"); - posit2.ToString(CultureInfo.InvariantCulture).ShouldBe("-200000"); - posit3.ToString("0.############", CultureInfo.InvariantCulture).ShouldBe("125.125450134277"); - posit4.ToString("0.###############", CultureInfo.InvariantCulture).ShouldBe("0.998999997973442"); - } + [Fact] + public void Posit32ToStringIsCorrect() + { + var posit1 = new Posit32(0.75F); + var posit2 = new Posit32(-200_000); + var posit3 = new Posit32(125.12545F); + var posit4 = new Posit32(0.999); + + posit1.ToString(CultureInfo.InvariantCulture).ShouldBe("0.75"); + posit2.ToString(CultureInfo.InvariantCulture).ShouldBe("-200000"); + posit3.ToString("0.############", CultureInfo.InvariantCulture).ShouldBe("125.125450134277"); + posit4.ToString("0.###############", CultureInfo.InvariantCulture).ShouldBe("0.998999997973442"); } } diff --git a/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs b/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs index 00fe61a..31773ca 100644 --- a/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs +++ b/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs @@ -4,333 +4,332 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class PositTests { - public class PositTests + private readonly PositEnvironment _environment_6_1; + private readonly PositEnvironment _environment_6_2; + private readonly PositEnvironment _environment_6_3; + private readonly PositEnvironment _environment_8_2; + private readonly PositEnvironment _environment_12_2; + private readonly PositEnvironment _environment_16_3; + private readonly PositEnvironment _environment_32_3; + private readonly PositEnvironment _environment_32_2; + + public PositTests() { - private readonly PositEnvironment _environment_6_1; - private readonly PositEnvironment _environment_6_2; - private readonly PositEnvironment _environment_6_3; - private readonly PositEnvironment _environment_8_2; - private readonly PositEnvironment _environment_12_2; - private readonly PositEnvironment _environment_16_3; - private readonly PositEnvironment _environment_32_3; - private readonly PositEnvironment _environment_32_2; - - public PositTests() - { - _environment_6_1 = new PositEnvironment(6, 1); - _environment_6_2 = new PositEnvironment(6, 2); - _environment_6_3 = new PositEnvironment(6, 3); - _environment_8_2 = new PositEnvironment(8, 2); - _environment_12_2 = new PositEnvironment(12, 2); - _environment_16_3 = new PositEnvironment(16, 3); - _environment_32_3 = new PositEnvironment(32, 3); - _environment_32_2 = new PositEnvironment(32, 2); - } - - [Fact] - public void EncodeRegimeBitsIsCorrect() - { - new Posit(_environment_8_2).EncodeRegimeBits(0).ShouldBe(new BitMask(0x40, _environment_8_2.Size)); + _environment_6_1 = new PositEnvironment(6, 1); + _environment_6_2 = new PositEnvironment(6, 2); + _environment_6_3 = new PositEnvironment(6, 3); + _environment_8_2 = new PositEnvironment(8, 2); + _environment_12_2 = new PositEnvironment(12, 2); + _environment_16_3 = new PositEnvironment(16, 3); + _environment_32_3 = new PositEnvironment(32, 3); + _environment_32_2 = new PositEnvironment(32, 2); + } - new Posit(_environment_6_3).EncodeRegimeBits(-3).ShouldBe(new BitMask(0x2, _environment_6_3.Size)); + [Fact] + public void EncodeRegimeBitsIsCorrect() + { + new Posit(_environment_8_2).EncodeRegimeBits(0).ShouldBe(new BitMask(0x40, _environment_8_2.Size)); - new Posit(_environment_6_3).EncodeRegimeBits(3).ShouldBe(new BitMask(0x1E, _environment_6_3.Size)); + new Posit(_environment_6_3).EncodeRegimeBits(-3).ShouldBe(new BitMask(0x2, _environment_6_3.Size)); - new Posit(_environment_6_3).EncodeRegimeBits(2).ShouldBe(new BitMask(0x1C, _environment_6_3.Size)); + new Posit(_environment_6_3).EncodeRegimeBits(3).ShouldBe(new BitMask(0x1E, _environment_6_3.Size)); - new Posit(_environment_8_2).EncodeRegimeBits(1).ShouldBe(new BitMask(0x60, _environment_6_3.Size)); + new Posit(_environment_6_3).EncodeRegimeBits(2).ShouldBe(new BitMask(0x1C, _environment_6_3.Size)); - new Posit(_environment_8_2).EncodeRegimeBits(3).ShouldBe(new BitMask(0x78, _environment_8_2.Size)); + new Posit(_environment_8_2).EncodeRegimeBits(1).ShouldBe(new BitMask(0x60, _environment_6_3.Size)); - new Posit(_environment_8_2).EncodeRegimeBits(6).ShouldBe(new BitMask(0x7F, _environment_8_2.Size)); - } + new Posit(_environment_8_2).EncodeRegimeBits(3).ShouldBe(new BitMask(0x78, _environment_8_2.Size)); - [Fact] - public void PositIsCorrectlyConstructedFromUint() - { - new Posit(_environment_6_3, 0U).PositBits.ShouldBe(new BitMask(0x0, _environment_6_3.Size)); + new Posit(_environment_8_2).EncodeRegimeBits(6).ShouldBe(new BitMask(0x7F, _environment_8_2.Size)); + } - new Posit(_environment_6_3, 2).PositBits.ShouldBe(new BitMask(17, _environment_6_3.Size)); + [Fact] + public void PositIsCorrectlyConstructedFromUint() + { + new Posit(_environment_6_3, 0U).PositBits.ShouldBe(new BitMask(0x0, _environment_6_3.Size)); - new Posit(_environment_6_3, 8U).PositBits.ShouldBe(new BitMask(0x13, _environment_6_3.Size)); + new Posit(_environment_6_3, 2).PositBits.ShouldBe(new BitMask(17, _environment_6_3.Size)); - new Posit(_environment_6_3, 16384U).PositBits.ShouldBe(new BitMask(0x1B, _environment_6_3.Size)); + new Posit(_environment_6_3, 8U).PositBits.ShouldBe(new BitMask(0x13, _environment_6_3.Size)); - new Posit(_environment_6_3, 1_048_576U).PositBits.ShouldBe(new BitMask(0x1D, _environment_6_3.Size)); + new Posit(_environment_6_3, 16384U).PositBits.ShouldBe(new BitMask(0x1B, _environment_6_3.Size)); - new Posit(_environment_8_2, 13U).PositBits.ShouldBe(new BitMask(0x5D, _environment_8_2.Size)); + new Posit(_environment_6_3, 1_048_576U).PositBits.ShouldBe(new BitMask(0x1D, _environment_6_3.Size)); - new Posit(_environment_32_2, 17U).PositBits.ShouldBe(new BitMask(0x60400000, _environment_32_2.Size)); + new Posit(_environment_8_2, 13U).PositBits.ShouldBe(new BitMask(0x5D, _environment_8_2.Size)); - new Posit(_environment_12_2, 172U).PositBits.ShouldBe(new BitMask(0x6D6, _environment_12_2.Size)); + new Posit(_environment_32_2, 17U).PositBits.ShouldBe(new BitMask(0x60400000, _environment_32_2.Size)); - new Posit(_environment_12_2, 173U).PositBits.ShouldBe(new BitMask(0x6D6, _environment_12_2.Size)); + new Posit(_environment_12_2, 172U).PositBits.ShouldBe(new BitMask(0x6D6, _environment_12_2.Size)); - new Posit(_environment_16_3, 48U).PositBits.ShouldBe(new BitMask(22016, _environment_16_3.Size)); + new Posit(_environment_12_2, 173U).PositBits.ShouldBe(new BitMask(0x6D6, _environment_12_2.Size)); - new Posit(_environment_16_3, 13200U).PositBits.ShouldBe(new BitMask(27449, _environment_16_3.Size)); + new Posit(_environment_16_3, 48U).PositBits.ShouldBe(new BitMask(22016, _environment_16_3.Size)); - new Posit(_environment_16_3, 500U).PositBits.ShouldBe(new BitMask(25064, _environment_16_3.Size)); + new Posit(_environment_16_3, 13200U).PositBits.ShouldBe(new BitMask(27449, _environment_16_3.Size)); - new Posit(_environment_32_3, 1U).PositBits.ShouldBe(new BitMask(0x40000000, _environment_32_3.Size)); + new Posit(_environment_16_3, 500U).PositBits.ShouldBe(new BitMask(25064, _environment_16_3.Size)); - // examples of Posit rounding - new Posit(_environment_8_2, 90U).PositBits.ShouldBe(new BitMask(0x6A, _environment_12_2.Size)); - new Posit(_environment_8_2, 82U).PositBits.ShouldBe(new BitMask(0x69, _environment_12_2.Size)); + new Posit(_environment_32_3, 1U).PositBits.ShouldBe(new BitMask(0x40000000, _environment_32_3.Size)); - // Numbers out of range don't get rounded up infinity. They get rounded to the biggest representable - // finite value (MaxValue). - new Posit(_environment_6_1, 500U).PositBits.ShouldBe(_environment_6_1.MaxValueBitMask); - } + // examples of Posit rounding + new Posit(_environment_8_2, 90U).PositBits.ShouldBe(new BitMask(0x6A, _environment_12_2.Size)); + new Posit(_environment_8_2, 82U).PositBits.ShouldBe(new BitMask(0x69, _environment_12_2.Size)); - [Fact] - public void PositIsCorrectlyConstructedFromInt() - { - new Posit(_environment_6_3, 8).PositBits.ShouldBe(new BitMask(0x13, _environment_6_3.Size)); + // Numbers out of range don't get rounded up infinity. They get rounded to the biggest representable + // finite value (MaxValue). + new Posit(_environment_6_1, 500U).PositBits.ShouldBe(_environment_6_1.MaxValueBitMask); + } - new Posit(_environment_6_3, 16384).PositBits.ShouldBe(new BitMask(0x1B, _environment_6_3.Size)); + [Fact] + public void PositIsCorrectlyConstructedFromInt() + { + new Posit(_environment_6_3, 8).PositBits.ShouldBe(new BitMask(0x13, _environment_6_3.Size)); - new Posit(_environment_8_2, 13).PositBits.ShouldBe(new BitMask(0x5D, _environment_8_2.Size)); + new Posit(_environment_6_3, 16384).PositBits.ShouldBe(new BitMask(0x1B, _environment_6_3.Size)); - new Posit(_environment_6_3, -8).PositBits.ShouldBe(new BitMask(0x2D, _environment_6_3.Size)); + new Posit(_environment_8_2, 13).PositBits.ShouldBe(new BitMask(0x5D, _environment_8_2.Size)); - new Posit(_environment_8_2, -13).PositBits.ShouldBe(new BitMask(0xA3, _environment_8_2.Size)); + new Posit(_environment_6_3, -8).PositBits.ShouldBe(new BitMask(0x2D, _environment_6_3.Size)); - new Posit(_environment_32_3, -1).PositBits.ShouldBe(new BitMask(0xC0000000, _environment_32_3.Size)); + new Posit(_environment_8_2, -13).PositBits.ShouldBe(new BitMask(0xA3, _environment_8_2.Size)); - new Posit(_environment_6_3, -16384).PositBits.ShouldBe(new BitMask(0x25, _environment_6_3.Size)); + new Posit(_environment_32_3, -1).PositBits.ShouldBe(new BitMask(0xC0000000, _environment_32_3.Size)); - new Posit(_environment_16_3, -500).PositBits.ShouldBe(new BitMask(40472, _environment_16_3.Size)); - } + new Posit(_environment_6_3, -16384).PositBits.ShouldBe(new BitMask(0x25, _environment_6_3.Size)); - [Fact] - public void PositToIntIsCorrect() - { - var posit8 = new Posit(_environment_6_3, 8); - Assert.AreEqual((int)posit8, 8); + new Posit(_environment_16_3, -500).PositBits.ShouldBe(new BitMask(40472, _environment_16_3.Size)); + } - var posit16384 = new Posit(_environment_6_3, 16384); - Assert.AreEqual((int)posit16384, 16384); + [Fact] + public void PositToIntIsCorrect() + { + var posit8 = new Posit(_environment_6_3, 8); + Assert.AreEqual((int)posit8, 8); - var posit1_32_3 = new Posit(_environment_32_3, 1); - Assert.AreEqual((int)posit1_32_3, 1); - } + var posit16384 = new Posit(_environment_6_3, 16384); + Assert.AreEqual((int)posit16384, 16384); - [Fact] - public void ExponentSizeIsCorrect() - { - var posit16384 = new Posit(_environment_6_3, 16384); - Assert.AreEqual(posit16384.ExponentSize(), 2); + var posit1_32_3 = new Posit(_environment_32_3, 1); + Assert.AreEqual((int)posit1_32_3, 1); + } - var posit2 = new Posit(_environment_6_3, 2); - Assert.AreEqual(posit2.ExponentSize(), 3); + [Fact] + public void ExponentSizeIsCorrect() + { + var posit16384 = new Posit(_environment_6_3, 16384); + Assert.AreEqual(posit16384.ExponentSize(), 2); - var posit3 = new Posit(_environment_6_1, 3); - Assert.AreEqual(posit3.ExponentSize(), 1); + var posit2 = new Posit(_environment_6_3, 2); + Assert.AreEqual(posit2.ExponentSize(), 3); - var posit3_6_2 = new Posit(_environment_6_2, 3); - Assert.AreEqual(posit3_6_2.ExponentSize(), 2); + var posit3 = new Posit(_environment_6_1, 3); + Assert.AreEqual(posit3.ExponentSize(), 1); - var posit_negative13 = new Posit(_environment_8_2, -13); - Assert.AreEqual(posit_negative13.ExponentSize(), 2); - } + var posit3_6_2 = new Posit(_environment_6_2, 3); + Assert.AreEqual(posit3_6_2.ExponentSize(), 2); - [Fact] - public void GetExponentValueIsCorrect() - { - var posit16384 = new Posit(_environment_6_3, 16384); - Assert.AreEqual(posit16384.GetExponentValue(), 6); + var posit_negative13 = new Posit(_environment_8_2, -13); + Assert.AreEqual(posit_negative13.ExponentSize(), 2); + } - var posit2 = new Posit(_environment_6_3, 2); - Assert.AreEqual(posit2.GetExponentValue(), 1); + [Fact] + public void GetExponentValueIsCorrect() + { + var posit16384 = new Posit(_environment_6_3, 16384); + Assert.AreEqual(posit16384.GetExponentValue(), 6); - var posit3 = new Posit(_environment_6_1, 3); - Assert.AreEqual(posit3.GetExponentValue(), 1); + var posit2 = new Posit(_environment_6_3, 2); + Assert.AreEqual(posit2.GetExponentValue(), 1); - var posit3_6_2 = new Posit(_environment_6_2, 3); - Assert.AreEqual(posit3_6_2.GetExponentValue(), 1); + var posit3 = new Posit(_environment_6_1, 3); + Assert.AreEqual(posit3.GetExponentValue(), 1); - var posit_negative13 = new Posit(_environment_8_2, -13); - Assert.AreEqual(posit_negative13.GetExponentValue(), 3); + var posit3_6_2 = new Posit(_environment_6_2, 3); + Assert.AreEqual(posit3_6_2.GetExponentValue(), 1); - var posit13248 = new Posit(_environment_16_3, 13248); - Assert.AreEqual(posit13248.GetExponentValue(), 5); - } + var posit_negative13 = new Posit(_environment_8_2, -13); + Assert.AreEqual(posit_negative13.GetExponentValue(), 3); - [Fact] - public void FractionSizeIsCorrect() - { - var posit16384 = new Posit(_environment_6_3, 16384); - Assert.AreEqual(posit16384.FractionSize(), 0); + var posit13248 = new Posit(_environment_16_3, 13248); + Assert.AreEqual(posit13248.GetExponentValue(), 5); + } - var posit0 = new Posit(_environment_6_3, 0); - Assert.AreEqual(posit0.FractionSize(), 0); + [Fact] + public void FractionSizeIsCorrect() + { + var posit16384 = new Posit(_environment_6_3, 16384); + Assert.AreEqual(posit16384.FractionSize(), 0); - var posit2 = new Posit(_environment_6_3, 2); - Assert.AreEqual(posit2.FractionSize(), 0); + var posit0 = new Posit(_environment_6_3, 0); + Assert.AreEqual(posit0.FractionSize(), 0); - var posit3 = new Posit(_environment_6_1, 3); - Assert.AreEqual(posit3.FractionSize(), 2); + var posit2 = new Posit(_environment_6_3, 2); + Assert.AreEqual(posit2.FractionSize(), 0); - var posit_negative13 = new Posit(_environment_8_2, -13); - Assert.AreEqual(posit_negative13.FractionSize(), 3); + var posit3 = new Posit(_environment_6_1, 3); + Assert.AreEqual(posit3.FractionSize(), 2); - var posit13248 = new Posit(_environment_16_3, 13248); - Assert.AreEqual(posit13248.FractionSize(), 9); - } + var posit_negative13 = new Posit(_environment_8_2, -13); + Assert.AreEqual(posit_negative13.FractionSize(), 3); - [Fact] - public void FractionWithHiddenBitIsCorrect() - { - var posit16384 = new Posit(_environment_6_3, 16384); - posit16384.FractionWithHiddenBit().ShouldBe(new BitMask(1, _environment_6_3.Size)); + var posit13248 = new Posit(_environment_16_3, 13248); + Assert.AreEqual(posit13248.FractionSize(), 9); + } - var posit0 = new Posit(_environment_6_1, 0); - posit0.FractionWithHiddenBit().ShouldBe(new BitMask(1, _environment_6_1.Size)); + [Fact] + public void FractionWithHiddenBitIsCorrect() + { + var posit16384 = new Posit(_environment_6_3, 16384); + posit16384.FractionWithHiddenBit().ShouldBe(new BitMask(1, _environment_6_3.Size)); - var posit3 = new Posit(_environment_6_1, 3); - posit3.FractionWithHiddenBit().ShouldBe(new BitMask(6, _environment_6_1.Size)); + var posit0 = new Posit(_environment_6_1, 0); + posit0.FractionWithHiddenBit().ShouldBe(new BitMask(1, _environment_6_1.Size)); - var posit_negative13 = new Posit(_environment_8_2, -13); - posit_negative13.FractionWithHiddenBit().ShouldBe(new BitMask(0xD, _environment_6_1.Size)); - } + var posit3 = new Posit(_environment_6_1, 3); + posit3.FractionWithHiddenBit().ShouldBe(new BitMask(6, _environment_6_1.Size)); - [Fact] - public void GetRegimeKValueIsCorrect() - { - new Posit(_environment_6_3, 8).GetRegimeKValue().ShouldBe(0); + var posit_negative13 = new Posit(_environment_8_2, -13); + posit_negative13.FractionWithHiddenBit().ShouldBe(new BitMask(0xD, _environment_6_1.Size)); + } - new Posit(_environment_6_3, 16384).GetRegimeKValue().ShouldBe(1); + [Fact] + public void GetRegimeKValueIsCorrect() + { + new Posit(_environment_6_3, 8).GetRegimeKValue().ShouldBe(0); - new Posit(_environment_6_3, 0).GetRegimeKValue().ShouldBe(-5); + new Posit(_environment_6_3, 16384).GetRegimeKValue().ShouldBe(1); - new Posit(_environment_8_2, 13).GetRegimeKValue().ShouldBe(0); + new Posit(_environment_6_3, 0).GetRegimeKValue().ShouldBe(-5); - new Posit(_environment_6_3, -8).GetRegimeKValue().ShouldBe(0); + new Posit(_environment_8_2, 13).GetRegimeKValue().ShouldBe(0); - new Posit(_environment_8_2, -13).GetRegimeKValue().ShouldBe(0); + new Posit(_environment_6_3, -8).GetRegimeKValue().ShouldBe(0); - new Posit(_environment_6_3, -16384).GetRegimeKValue().ShouldBe(1); - } + new Posit(_environment_8_2, -13).GetRegimeKValue().ShouldBe(0); - [Fact] - public void CalculateScaleFactorIsCorrect() - { - new Posit(_environment_16_3, 13200).CalculateScaleFactor().ShouldBe(13); - new Posit(_environment_16_3, 48).CalculateScaleFactor().ShouldBe(5); - new Posit(_environment_16_3, 13248).CalculateScaleFactor().ShouldBe(13); - new Posit(_environment_16_3, 1).CalculateScaleFactor().ShouldBe(0); - new Posit(_environment_16_3, 2).CalculateScaleFactor().ShouldBe(1); - } + new Posit(_environment_6_3, -16384).GetRegimeKValue().ShouldBe(1); + } - [Fact] - public void AdditionIsCorrect() - { - var posit0 = new Posit(_environment_6_3, 0); - var posit = posit0 + 1; - posit.PositBits.ShouldBe(new Posit(_environment_6_3, 1).PositBits); + [Fact] + public void CalculateScaleFactorIsCorrect() + { + new Posit(_environment_16_3, 13200).CalculateScaleFactor().ShouldBe(13); + new Posit(_environment_16_3, 48).CalculateScaleFactor().ShouldBe(5); + new Posit(_environment_16_3, 13248).CalculateScaleFactor().ShouldBe(13); + new Posit(_environment_16_3, 1).CalculateScaleFactor().ShouldBe(0); + new Posit(_environment_16_3, 2).CalculateScaleFactor().ShouldBe(1); + } - var posit_negative_1 = new Posit(_environment_6_3, -1); - var posit_negative_2 = posit_negative_1 + posit_negative_1; + [Fact] + public void AdditionIsCorrect() + { + var posit0 = new Posit(_environment_6_3, 0); + var posit = posit0 + 1; + posit.PositBits.ShouldBe(new Posit(_environment_6_3, 1).PositBits); - posit_negative_2.PositBits.ShouldBe(new Posit(_environment_6_3, -2).PositBits); + var posit_negative_1 = new Posit(_environment_6_3, -1); + var posit_negative_2 = posit_negative_1 + posit_negative_1; - posit_negative_1 -= 1; - posit_negative_1.PositBits.ShouldBe(new Posit(_environment_6_3, -2).PositBits); + posit_negative_2.PositBits.ShouldBe(new Posit(_environment_6_3, -2).PositBits); - posit_negative_2 += 1; - posit_negative_2.PositBits.ShouldBe(new Posit(_environment_6_3, -1).PositBits); + posit_negative_1 -= 1; + posit_negative_1.PositBits.ShouldBe(new Posit(_environment_6_3, -2).PositBits); - var posit1 = new Posit(_environment_6_3, 1); - var posit2 = posit1 + 1; - posit2.PositBits.ShouldBe(new Posit(_environment_6_3, 2).PositBits); + posit_negative_2 += 1; + posit_negative_2.PositBits.ShouldBe(new Posit(_environment_6_3, -1).PositBits); - var isPosit0 = posit1 - 1; - isPosit0.PositBits.ShouldBe(posit0.PositBits); + var posit1 = new Posit(_environment_6_3, 1); + var posit2 = posit1 + 1; + posit2.PositBits.ShouldBe(new Posit(_environment_6_3, 2).PositBits); - var posit3 = new Posit(_environment_6_2, 3); - var posit6 = posit3 + posit3; - posit6.PositBits.ShouldBe(new Posit(_environment_6_2, 6).PositBits); + var isPosit0 = posit1 - 1; + isPosit0.PositBits.ShouldBe(posit0.PositBits); - var posit1_16_3 = new Posit(_environment_16_3, 1); - var posit2_16_3 = new Posit(_environment_16_3, 2); - var posit3_16_3 = posit2_16_3 + posit1_16_3; - posit3_16_3.PositBits.ShouldBe(new Posit(_environment_16_3, 3).PositBits); + var posit3 = new Posit(_environment_6_2, 3); + var posit6 = posit3 + posit3; + posit6.PositBits.ShouldBe(new Posit(_environment_6_2, 6).PositBits); - var posit4_16_3 = new Posit(_environment_16_3, 3) + posit1_16_3; - posit4_16_3.PositBits.ShouldBe(new Posit(_environment_16_3, 4).PositBits); + var posit1_16_3 = new Posit(_environment_16_3, 1); + var posit2_16_3 = new Posit(_environment_16_3, 2); + var posit3_16_3 = posit2_16_3 + posit1_16_3; + posit3_16_3.PositBits.ShouldBe(new Posit(_environment_16_3, 3).PositBits); - // This will be OK, once the quire will be used. - //// var posit66K_32_3 = new Posit.Posit(_environment_32_3, 66000); - //// var posit66K1_32_3 = posit66K_32_3 + 1; - //// posit66K1_32_3.PositBits.ShouldBe(new Posit.Posit(_environment_32_3, 66001).PositBits); + var posit4_16_3 = new Posit(_environment_16_3, 3) + posit1_16_3; + posit4_16_3.PositBits.ShouldBe(new Posit(_environment_16_3, 4).PositBits); - var posit48 = new Posit(_environment_16_3, 48); - var posit13200 = new Posit(_environment_16_3, 13200); - var posit13248 = posit48 + posit13200; - posit13248.PositBits.ShouldBe(new Posit(_environment_16_3, 13248).PositBits); + // This will be OK, once the quire will be used. + //// var posit66K_32_3 = new Posit.Posit(_environment_32_3, 66000); + //// var posit66K1_32_3 = posit66K_32_3 + 1; + //// posit66K1_32_3.PositBits.ShouldBe(new Posit.Posit(_environment_32_3, 66001).PositBits); - var posit1_32_2 = new Posit(_environment_32_2, 1); - var posit2_32_2 = posit1_32_2 + posit1_32_2; - posit2_32_2.PositBits.ShouldBe(new Posit(_environment_32_2, 2).PositBits); + var posit48 = new Posit(_environment_16_3, 48); + var posit13200 = new Posit(_environment_16_3, 13200); + var posit13248 = posit48 + posit13200; + posit13248.PositBits.ShouldBe(new Posit(_environment_16_3, 13248).PositBits); - var otherPosit13248 = posit13200 + posit48; - otherPosit13248.PositBits.ShouldBe(new Posit(_environment_16_3, 13248).PositBits); - } + var posit1_32_2 = new Posit(_environment_32_2, 1); + var posit2_32_2 = posit1_32_2 + posit1_32_2; + posit2_32_2.PositBits.ShouldBe(new Posit(_environment_32_2, 2).PositBits); - [Fact] - public void AdditionIsCorrectForPositives() - { - var posit1 = new Posit(_environment_32_3, 1); + var otherPosit13248 = posit13200 + posit48; + otherPosit13248.PositBits.ShouldBe(new Posit(_environment_16_3, 13248).PositBits); + } - for (var i = 1; i < 10000; i++) - { - posit1 += 1; - } + [Fact] + public void AdditionIsCorrectForPositives() + { + var posit1 = new Posit(_environment_32_3, 1); - posit1.PositBits.ShouldBe(new Posit(_environment_32_3, 10000).PositBits); + for (var i = 1; i < 10000; i++) + { + posit1 += 1; + } - var posit1_32_2 = new Posit(_environment_32_2, 1); + posit1.PositBits.ShouldBe(new Posit(_environment_32_3, 10000).PositBits); - for (var i = 1; i < 10000; i++) - { - posit1_32_2 += 1; - } + var posit1_32_2 = new Posit(_environment_32_2, 1); - posit1_32_2.PositBits.ShouldBe(new Posit(_environment_32_2, 10000).PositBits); + for (var i = 1; i < 10000; i++) + { + posit1_32_2 += 1; } - [Fact] - public void AdditionIsCorrectForNegatives() - { - var posit1 = new Posit(_environment_16_3, -500); + posit1_32_2.PositBits.ShouldBe(new Posit(_environment_32_2, 10000).PositBits); + } - for (var i = 1; i <= 1000; i++) - { - posit1 += 1; - } + [Fact] + public void AdditionIsCorrectForNegatives() + { + var posit1 = new Posit(_environment_16_3, -500); - for (var j = 1; j <= 500; j++) - { - posit1 -= 1; - } + for (var i = 1; i <= 1000; i++) + { + posit1 += 1; + } - posit1.PositBits.ShouldBe(new Posit(_environment_16_3, 0).PositBits); + for (var j = 1; j <= 500; j++) + { + posit1 -= 1; + } - var positA = new Posit(_environment_32_3, 1); - Console.WriteLine((int)positA); - var positB = positA; - Console.WriteLine((int)positB); + posit1.PositBits.ShouldBe(new Posit(_environment_16_3, 0).PositBits); - for (var i = 1; i < 100000; i++) - { - positA += positB; - } + var positA = new Posit(_environment_32_3, 1); + Console.WriteLine((int)positA); + var positB = positA; + Console.WriteLine((int)positB); - var result = (int)positA; - Assert.AreEqual(result, 100000); + for (var i = 1; i < 100000; i++) + { + positA += positB; } + + var result = (int)positA; + Assert.AreEqual(result, 100000); } } diff --git a/Lombiq.Arithmetics.Tests/PositTests/QuireTests.cs b/Lombiq.Arithmetics.Tests/PositTests/QuireTests.cs index 34fef8b..7c6893a 100644 --- a/Lombiq.Arithmetics.Tests/PositTests/QuireTests.cs +++ b/Lombiq.Arithmetics.Tests/PositTests/QuireTests.cs @@ -2,88 +2,87 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class QuireTests { - public class QuireTests + [Fact] + public void QuireBitShiftLeftIsCorrect() { - [Fact] - public void QuireBitShiftLeftIsCorrect() - { - Assert.AreEqual( - new Quire(new ulong[] { 0x80000000 }).Segments, - (new Quire(new ulong[] { 1 }) << 31).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 0 }).Segments, - (new Quire(new ulong[] { 6 }) << -1).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 0, 0x_8000_0000_0000_0000 }).Segments, - (new Quire(new ulong[] { 1, 0 }) << 127).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 1 }).Segments, - (new Quire(new ulong[] { 0x00000001 }) << 64).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 0x80000000, 0x00000000 }).Segments, - (new Quire(new ulong[] { 0x00800000, 0x00000000 }) << 8).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 0x200000000 }).Segments, - (new Quire(new ulong[] { 0x00000001 }) << -31).Segments); - } + Assert.AreEqual( + new Quire(new ulong[] { 0x80000000 }).Segments, + (new Quire(new ulong[] { 1 }) << 31).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 0 }).Segments, + (new Quire(new ulong[] { 6 }) << -1).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 0, 0x_8000_0000_0000_0000 }).Segments, + (new Quire(new ulong[] { 1, 0 }) << 127).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 1 }).Segments, + (new Quire(new ulong[] { 0x00000001 }) << 64).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 0x80000000, 0x00000000 }).Segments, + (new Quire(new ulong[] { 0x00800000, 0x00000000 }) << 8).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 0x200000000 }).Segments, + (new Quire(new ulong[] { 0x00000001 }) << -31).Segments); + } - [Fact] - public void QuireBitShiftRightIsCorrect() - { - Assert.AreEqual( - new Quire(new ulong[] { 0x00800000, 0x00000000 }).Segments, - (new Quire(new ulong[] { 0x80000000, 0x00000000 }) >> 8).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 1 }).Segments, - (new Quire(new ulong[] { 0x80000000 }) >> 31).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 1, 0 }).Segments, - (new Quire(new ulong[] { 0, 0x_8000_0000_0000_0000 }) >> 127).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 1_152_921_504_606_846_992, 0 }).Segments, - (new Quire(new ulong[] { 0x_0000_0000_0000_0100, 0x_0000_0000_0000_0001 }) >> 4).Segments); - Assert.AreEqual( - new Quire(new[] { 0x_8000_0000_0000_0000 }).Segments, - (new Quire(new[] { 0x_8000_0000_0000_0000 }) >> 64).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 0x_4000_0000_0000_0000 }).Segments, - (new Quire(new[] { 0x_8000_0000_0000_0000 }) >> -63).Segments); - } + [Fact] + public void QuireBitShiftRightIsCorrect() + { + Assert.AreEqual( + new Quire(new ulong[] { 0x00800000, 0x00000000 }).Segments, + (new Quire(new ulong[] { 0x80000000, 0x00000000 }) >> 8).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 1 }).Segments, + (new Quire(new ulong[] { 0x80000000 }) >> 31).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 1, 0 }).Segments, + (new Quire(new ulong[] { 0, 0x_8000_0000_0000_0000 }) >> 127).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 1_152_921_504_606_846_992, 0 }).Segments, + (new Quire(new ulong[] { 0x_0000_0000_0000_0100, 0x_0000_0000_0000_0001 }) >> 4).Segments); + Assert.AreEqual( + new Quire(new[] { 0x_8000_0000_0000_0000 }).Segments, + (new Quire(new[] { 0x_8000_0000_0000_0000 }) >> 64).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 0x_4000_0000_0000_0000 }).Segments, + (new Quire(new[] { 0x_8000_0000_0000_0000 }) >> -63).Segments); + } - [Fact] - public void QuireAdditionIsCorrect() - { - Assert.AreEqual( - new Quire(new ulong[] { 5 }).Segments, - (new Quire(new ulong[] { 4 }) + new Quire(new ulong[] { 1 })).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 0, 2 }).Segments, - (new Quire(new ulong[] { ulong.MaxValue, 1 }) + new Quire(new ulong[] { 1, 0 })).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 2, 0, 0, 1, 2 }).Segments, - (new Quire(new ulong[] { 1, 0, 0, 0, 1 }) + new Quire(new ulong[] { 1, 0, 0, 1, 1 })).Segments); - } + [Fact] + public void QuireAdditionIsCorrect() + { + Assert.AreEqual( + new Quire(new ulong[] { 5 }).Segments, + (new Quire(new ulong[] { 4 }) + new Quire(new ulong[] { 1 })).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 0, 2 }).Segments, + (new Quire(new ulong[] { ulong.MaxValue, 1 }) + new Quire(new ulong[] { 1, 0 })).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 2, 0, 0, 1, 2 }).Segments, + (new Quire(new ulong[] { 1, 0, 0, 0, 1 }) + new Quire(new ulong[] { 1, 0, 0, 1, 1 })).Segments); + } - [Fact] - public void QuireToIntegerAdditionIsCorrect() => - Assert.AreEqual( - new Quire(new ulong[] { 5 }).Segments, - (new Quire(new ulong[] { 4 }) + 1).Segments); + [Fact] + public void QuireToIntegerAdditionIsCorrect() => + Assert.AreEqual( + new Quire(new ulong[] { 5 }).Segments, + (new Quire(new ulong[] { 4 }) + 1).Segments); - [Fact] - public void QuireSubtractionIsCorrect() - { - Assert.AreEqual( - new Quire(new ulong[] { 4 }).Segments, - (new Quire(new ulong[] { 5 }) - new Quire(new ulong[] { 1 })).Segments); - Assert.AreEqual( - new Quire(new ulong[] { 1, 0, 0, 0, 1 }).Segments, - (new Quire(new ulong[] { 2, 0, 0, 1, 2 }) - new Quire(new ulong[] { 1, 0, 0, 1, 1 })).Segments); - Assert.AreEqual( - new Quire(new ulong[] { ulong.MaxValue, 1 }).Segments, - (new Quire(new ulong[] { 0, 2 }) - new Quire(new ulong[] { 1, 0 })).Segments); - } + [Fact] + public void QuireSubtractionIsCorrect() + { + Assert.AreEqual( + new Quire(new ulong[] { 4 }).Segments, + (new Quire(new ulong[] { 5 }) - new Quire(new ulong[] { 1 })).Segments); + Assert.AreEqual( + new Quire(new ulong[] { 1, 0, 0, 0, 1 }).Segments, + (new Quire(new ulong[] { 2, 0, 0, 1, 2 }) - new Quire(new ulong[] { 1, 0, 0, 1, 1 })).Segments); + Assert.AreEqual( + new Quire(new ulong[] { ulong.MaxValue, 1 }).Segments, + (new Quire(new ulong[] { 0, 2 }) - new Quire(new ulong[] { 1, 0 })).Segments); } } diff --git a/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs b/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs index ad4108e..08c6fe1 100644 --- a/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs +++ b/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs @@ -2,289 +2,288 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class UnumEnvironmentTests { - public class UnumEnvironmentTests + private readonly UnumEnvironment _warlpiriEnvironment; + private readonly UnumEnvironment _environment_3_2; + private readonly UnumEnvironment _environment_3_4; + private readonly Unum _unum_3_2; + private readonly Unum _unum_3_4; + + public UnumEnvironmentTests() + { + _warlpiriEnvironment = UnumEnvironment.FromStandardEnvironment(StandardEnvironment.Warlpiri); + _environment_3_2 = new UnumEnvironment(3, 2); + _environment_3_4 = new UnumEnvironment(3, 4); + _unum_3_2 = new Unum(_environment_3_2); + _unum_3_4 = new Unum(_environment_3_4); + } + + [Fact] + public void WarlpiriUnumEnvironmentIsCorrect() + { + Assert.AreEqual(new BitMask(4), _warlpiriEnvironment.EmptyBitMask); + Assert.AreEqual(_warlpiriEnvironment.EmptyBitMask, _warlpiriEnvironment.ExponentSizeMask); + Assert.AreEqual(1, _warlpiriEnvironment.ExponentSizeMax); + Assert.AreEqual(0, _warlpiriEnvironment.ExponentSizeSize); + Assert.AreEqual(_warlpiriEnvironment.EmptyBitMask, _warlpiriEnvironment.FractionSizeMask); + Assert.AreEqual(1, _warlpiriEnvironment.FractionSizeMax); + Assert.AreEqual(0, _warlpiriEnvironment.FractionSizeSize); + Assert.AreEqual(_warlpiriEnvironment.EmptyBitMask, _warlpiriEnvironment.ExponentAndFractionSizeMask); + Assert.AreEqual(4, _warlpiriEnvironment.Size); + + Assert.AreEqual(12, _warlpiriEnvironment.LargestNegative.Lowest32Bits); // 1100 + Assert.AreEqual(4, _warlpiriEnvironment.LargestPositive.Lowest32Bits); // 0100 + Assert.AreEqual(14, _warlpiriEnvironment.NegativeInfinity.Lowest32Bits); // 1110 + Assert.AreEqual(6, _warlpiriEnvironment.PositiveInfinity.Lowest32Bits); // 0110 + Assert.AreEqual(7, _warlpiriEnvironment.QuietNotANumber.Lowest32Bits); // 0111 + Assert.AreEqual(15, _warlpiriEnvironment.SignalingNotANumber.Lowest32Bits); // 1111 + Assert.AreEqual(8, _warlpiriEnvironment.SignBitMask.Lowest32Bits); // 1000 + Assert.AreEqual(2, _warlpiriEnvironment.SmallestPositive.Lowest32Bits); // 0010 + Assert.AreEqual(2, _warlpiriEnvironment.ULP.Lowest32Bits); // 0010 + Assert.AreEqual(1, _warlpiriEnvironment.UncertaintyBitMask.Lowest32Bits); // 0001 + Assert.AreEqual(1, _warlpiriEnvironment.UnumTagMask.Lowest32Bits); // 0001 + Assert.AreEqual(1, _warlpiriEnvironment.UnumTagSize); + } + + [Fact] + public void UnumExponentSizeSizeIsCorrect() + { + Assert.AreEqual(3, _unum_3_2.ExponentSizeSize); + Assert.AreEqual(3, _unum_3_4.ExponentSizeSize); + } + + [Fact] + public void UnumFractionSizeSizeIsCorrect() + { + Assert.AreEqual(2, _unum_3_2.FractionSizeSize); + Assert.AreEqual(4, _unum_3_4.FractionSizeSize); + } + + [Fact] + public void UnumTagSizeIsCorrect() + { + Assert.AreEqual(6, _unum_3_2.UnumTagSize); + Assert.AreEqual(8, _unum_3_4.UnumTagSize); + } + + [Fact] + public void UnumSizeIsCorrect() + { + Assert.AreEqual(19, _unum_3_2.Size); + Assert.AreEqual(33, _unum_3_4.Size); + } + + [Fact] + public void UnumUncertaintyBitMaskIsCorrect() + { + // 0 0000 0000 0000 1 000 00 + Assert.AreEqual( + new BitMask(new uint[] { 0x20 }, _unum_3_2.Size), + _unum_3_2.UncertaintyBitMask, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.UncertaintyBitMask))); + + // 0 0000 0000 0000 0000 0000 0000 1 000 0000 + Assert.AreEqual( + new BitMask(new uint[] { 0x80, 0 }, _unum_3_4.Size), + _unum_3_4.UncertaintyBitMask, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.UncertaintyBitMask))); + } + + [Fact] + public void UnumExponentSizeMaskIsCorrect() + { + // 0 0000 0000 0000 0 111 00 + Assert.AreEqual( + new BitMask(new uint[] { 0x1C }, _unum_3_2.Size), + _unum_3_2.ExponentSizeMask, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.ExponentSizeMask))); + + // 0 0000 0000 0000 0000 0000 0000 0 111 0000 + Assert.AreEqual( + new BitMask(new uint[] { 0x70, 0 }, _unum_3_4.Size), + _unum_3_4.ExponentSizeMask, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.ExponentSizeMask))); + } + + [Fact] + public void UnumFractionSizeMaskIsCorrect() + { + // 0 0000 0000 0000 0 000 11 + Assert.AreEqual( + new BitMask(new uint[] { 3 }, _unum_3_2.Size), + _unum_3_2.FractionSizeMask, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.FractionSizeMask))); + + // 0 0000 0000 0000 0000 0000 0000 0 000 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xF, 0 }, _unum_3_4.Size), + _unum_3_4.FractionSizeMask, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.FractionSizeMask))); + } + + [Fact] + public void UnumExponentAndFractionSizeMaskIsCorrect() { - private readonly UnumEnvironment _warlpiriEnvironment; - private readonly UnumEnvironment _environment_3_2; - private readonly UnumEnvironment _environment_3_4; - private readonly Unum _unum_3_2; - private readonly Unum _unum_3_4; - - public UnumEnvironmentTests() - { - _warlpiriEnvironment = UnumEnvironment.FromStandardEnvironment(StandardEnvironment.Warlpiri); - _environment_3_2 = new UnumEnvironment(3, 2); - _environment_3_4 = new UnumEnvironment(3, 4); - _unum_3_2 = new Unum(_environment_3_2); - _unum_3_4 = new Unum(_environment_3_4); - } - - [Fact] - public void WarlpiriUnumEnvironmentIsCorrect() - { - Assert.AreEqual(new BitMask(4), _warlpiriEnvironment.EmptyBitMask); - Assert.AreEqual(_warlpiriEnvironment.EmptyBitMask, _warlpiriEnvironment.ExponentSizeMask); - Assert.AreEqual(1, _warlpiriEnvironment.ExponentSizeMax); - Assert.AreEqual(0, _warlpiriEnvironment.ExponentSizeSize); - Assert.AreEqual(_warlpiriEnvironment.EmptyBitMask, _warlpiriEnvironment.FractionSizeMask); - Assert.AreEqual(1, _warlpiriEnvironment.FractionSizeMax); - Assert.AreEqual(0, _warlpiriEnvironment.FractionSizeSize); - Assert.AreEqual(_warlpiriEnvironment.EmptyBitMask, _warlpiriEnvironment.ExponentAndFractionSizeMask); - Assert.AreEqual(4, _warlpiriEnvironment.Size); - - Assert.AreEqual(12, _warlpiriEnvironment.LargestNegative.Lowest32Bits); // 1100 - Assert.AreEqual(4, _warlpiriEnvironment.LargestPositive.Lowest32Bits); // 0100 - Assert.AreEqual(14, _warlpiriEnvironment.NegativeInfinity.Lowest32Bits); // 1110 - Assert.AreEqual(6, _warlpiriEnvironment.PositiveInfinity.Lowest32Bits); // 0110 - Assert.AreEqual(7, _warlpiriEnvironment.QuietNotANumber.Lowest32Bits); // 0111 - Assert.AreEqual(15, _warlpiriEnvironment.SignalingNotANumber.Lowest32Bits); // 1111 - Assert.AreEqual(8, _warlpiriEnvironment.SignBitMask.Lowest32Bits); // 1000 - Assert.AreEqual(2, _warlpiriEnvironment.SmallestPositive.Lowest32Bits); // 0010 - Assert.AreEqual(2, _warlpiriEnvironment.ULP.Lowest32Bits); // 0010 - Assert.AreEqual(1, _warlpiriEnvironment.UncertaintyBitMask.Lowest32Bits); // 0001 - Assert.AreEqual(1, _warlpiriEnvironment.UnumTagMask.Lowest32Bits); // 0001 - Assert.AreEqual(1, _warlpiriEnvironment.UnumTagSize); - } - - [Fact] - public void UnumExponentSizeSizeIsCorrect() - { - Assert.AreEqual(3, _unum_3_2.ExponentSizeSize); - Assert.AreEqual(3, _unum_3_4.ExponentSizeSize); - } - - [Fact] - public void UnumFractionSizeSizeIsCorrect() - { - Assert.AreEqual(2, _unum_3_2.FractionSizeSize); - Assert.AreEqual(4, _unum_3_4.FractionSizeSize); - } - - [Fact] - public void UnumTagSizeIsCorrect() - { - Assert.AreEqual(6, _unum_3_2.UnumTagSize); - Assert.AreEqual(8, _unum_3_4.UnumTagSize); - } - - [Fact] - public void UnumSizeIsCorrect() - { - Assert.AreEqual(19, _unum_3_2.Size); - Assert.AreEqual(33, _unum_3_4.Size); - } - - [Fact] - public void UnumUncertaintyBitMaskIsCorrect() - { - // 0 0000 0000 0000 1 000 00 - Assert.AreEqual( - new BitMask(new uint[] { 0x20 }, _unum_3_2.Size), - _unum_3_2.UncertaintyBitMask, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.UncertaintyBitMask))); - - // 0 0000 0000 0000 0000 0000 0000 1 000 0000 - Assert.AreEqual( - new BitMask(new uint[] { 0x80, 0 }, _unum_3_4.Size), - _unum_3_4.UncertaintyBitMask, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.UncertaintyBitMask))); - } - - [Fact] - public void UnumExponentSizeMaskIsCorrect() - { - // 0 0000 0000 0000 0 111 00 - Assert.AreEqual( - new BitMask(new uint[] { 0x1C }, _unum_3_2.Size), - _unum_3_2.ExponentSizeMask, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.ExponentSizeMask))); - - // 0 0000 0000 0000 0000 0000 0000 0 111 0000 - Assert.AreEqual( - new BitMask(new uint[] { 0x70, 0 }, _unum_3_4.Size), - _unum_3_4.ExponentSizeMask, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.ExponentSizeMask))); - } - - [Fact] - public void UnumFractionSizeMaskIsCorrect() - { - // 0 0000 0000 0000 0 000 11 - Assert.AreEqual( - new BitMask(new uint[] { 3 }, _unum_3_2.Size), - _unum_3_2.FractionSizeMask, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.FractionSizeMask))); - - // 0 0000 0000 0000 0000 0000 0000 0 000 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xF, 0 }, _unum_3_4.Size), - _unum_3_4.FractionSizeMask, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.FractionSizeMask))); - } - - [Fact] - public void UnumExponentAndFractionSizeMaskIsCorrect() - { - // 0 0000 0000 0000 0 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x1F }, _unum_3_2.Size), - _unum_3_2.ExponentAndFractionSizeMask, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.ExponentAndFractionSizeMask))); - - // 0 0000 0000 0000 0000 0000 0000 0 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0x7F, 0 }, _unum_3_4.Size), - _unum_3_4.ExponentAndFractionSizeMask, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.ExponentAndFractionSizeMask))); - } - - [Fact] - public void UnumTagMaskIsCorrect() - { - // 0 0000 0000 0000 1 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x3F }, _unum_3_2.Size), - _unum_3_2.UnumTagMask, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.UnumTagMask))); - - // 0 0000 0000 0000 0000 0000 0000 1 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFF, 0 }, _unum_3_4.Size), - _unum_3_4.UnumTagMask, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.UnumTagMask))); - } - - [Fact] - public void UnumSignBitMaskIsCorrect() - { - // 1 0000 0000 0000 0 000 00 - Assert.AreEqual( - new BitMask(new uint[] { 0x40000 }, _unum_3_2.Size), - _unum_3_2.SignBitMask, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SignBitMask))); - - // 1 0000 0000 0000 0000 0000 0000 0 000 0000 - Assert.AreEqual( - new BitMask(new uint[] { 0, 1 }, _unum_3_4.Size), - _unum_3_4.SignBitMask, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.SignBitMask))); - } - - [Fact] - public void UnumPositiveInfinityIsCorrect() - { - // 0 1111 1111 1111 0 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x3FFDF }, _unum_3_2.Size), - _unum_3_2.PositiveInfinity, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.PositiveInfinity))); - - // 0 1111 1111 1111 1111 1111 1111 0 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFFFFFF7F, 0 }, _unum_3_4.Size), - _unum_3_4.PositiveInfinity, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.PositiveInfinity))); - } - - [Fact] - public void UnumNegativeInfinityIsCorrect() - { - // 1 1111 1111 1111 0 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x7FFDF }, _unum_3_2.Size), - _unum_3_2.NegativeInfinity, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.NegativeInfinity))); - - // 1 1111 1111 1111 1111 1111 1111 0 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFFFFFF7F, 1 }, _unum_3_4.Size), - _unum_3_4.NegativeInfinity, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.NegativeInfinity))); - } - - [Fact] - public void UnumQuietNotANumberIsCorrect() - { - // 0 1111 1111 1111 1 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x3FFFF }, _unum_3_2.Size), - _unum_3_2.QuietNotANumber, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.QuietNotANumber))); - - // 0 1111 1111 1111 1111 1111 1111 1 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFFFFFFFF, 0 }, _unum_3_4.Size), - _unum_3_4.QuietNotANumber, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.QuietNotANumber))); - } - - [Fact] - public void UnumSignalingNotANumberIsCorrect() - { - // 1 1111 1111 1111 1 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x7FFFF }, _unum_3_2.Size), - _unum_3_2.SignalingNotANumber, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SignalingNotANumber))); - - // 1 1111 1111 1111 1111 1111 1111 1 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFFFFFFFF, 1 }, _unum_3_4.Size), - _unum_3_4.SignalingNotANumber, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.SignalingNotANumber))); - } - - [Fact] - public void UnumLargestPositiveIsCorrect() - { - // 0 1111 1111 1110 0 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x3FF9F }, _unum_3_2.Size), - _unum_3_2.LargestPositive, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.LargestPositive))); - - // 0 1111 1111 1111 1111 1111 1110 0 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFFFFFE7F, 0 }, _unum_3_4.Size), - _unum_3_4.LargestPositive, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.LargestPositive))); - } - - [Fact] - public void UnumSmallestPositiveIsCorrect() - { - // 0 0000 0000 0001 0 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x5F }, _unum_3_2.Size), - _unum_3_2.SmallestPositive, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SmallestPositive))); - - // 0 0000 0000 0000 0000 0000 0001 0 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0x17F, 0 }, _unum_3_4.Size), - _unum_3_4.SmallestPositive, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.SmallestPositive))); - } - - [Fact] - public void UnumLargestNegativeIsCorrect() - { - // 1 1111 1111 1110 0 111 11 - Assert.AreEqual( - new BitMask(new uint[] { 0x7FF9F }, _unum_3_2.Size), - _unum_3_2.LargestNegative, - TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.LargestNegative))); - - // 1 1111 1111 1111 1111 1111 1110 0 111 1111 - Assert.AreEqual( - new BitMask(new uint[] { 0xFFFFFE7F, 1 }, _unum_3_4.Size), - _unum_3_4.LargestNegative, - TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.LargestNegative))); - } - - private static string TestFailureMessageBuilder(Unum unum, string propertyName) => - $"Testing the \"{propertyName}\" property of the Unum ({unum.ExponentSizeSize}, {unum.FractionSizeSize}) environment failed."; + // 0 0000 0000 0000 0 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x1F }, _unum_3_2.Size), + _unum_3_2.ExponentAndFractionSizeMask, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.ExponentAndFractionSizeMask))); + + // 0 0000 0000 0000 0000 0000 0000 0 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0x7F, 0 }, _unum_3_4.Size), + _unum_3_4.ExponentAndFractionSizeMask, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.ExponentAndFractionSizeMask))); } + + [Fact] + public void UnumTagMaskIsCorrect() + { + // 0 0000 0000 0000 1 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x3F }, _unum_3_2.Size), + _unum_3_2.UnumTagMask, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.UnumTagMask))); + + // 0 0000 0000 0000 0000 0000 0000 1 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFF, 0 }, _unum_3_4.Size), + _unum_3_4.UnumTagMask, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.UnumTagMask))); + } + + [Fact] + public void UnumSignBitMaskIsCorrect() + { + // 1 0000 0000 0000 0 000 00 + Assert.AreEqual( + new BitMask(new uint[] { 0x40000 }, _unum_3_2.Size), + _unum_3_2.SignBitMask, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SignBitMask))); + + // 1 0000 0000 0000 0000 0000 0000 0 000 0000 + Assert.AreEqual( + new BitMask(new uint[] { 0, 1 }, _unum_3_4.Size), + _unum_3_4.SignBitMask, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.SignBitMask))); + } + + [Fact] + public void UnumPositiveInfinityIsCorrect() + { + // 0 1111 1111 1111 0 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x3FFDF }, _unum_3_2.Size), + _unum_3_2.PositiveInfinity, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.PositiveInfinity))); + + // 0 1111 1111 1111 1111 1111 1111 0 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFFFFFF7F, 0 }, _unum_3_4.Size), + _unum_3_4.PositiveInfinity, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.PositiveInfinity))); + } + + [Fact] + public void UnumNegativeInfinityIsCorrect() + { + // 1 1111 1111 1111 0 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x7FFDF }, _unum_3_2.Size), + _unum_3_2.NegativeInfinity, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.NegativeInfinity))); + + // 1 1111 1111 1111 1111 1111 1111 0 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFFFFFF7F, 1 }, _unum_3_4.Size), + _unum_3_4.NegativeInfinity, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.NegativeInfinity))); + } + + [Fact] + public void UnumQuietNotANumberIsCorrect() + { + // 0 1111 1111 1111 1 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x3FFFF }, _unum_3_2.Size), + _unum_3_2.QuietNotANumber, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.QuietNotANumber))); + + // 0 1111 1111 1111 1111 1111 1111 1 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFFFFFFFF, 0 }, _unum_3_4.Size), + _unum_3_4.QuietNotANumber, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.QuietNotANumber))); + } + + [Fact] + public void UnumSignalingNotANumberIsCorrect() + { + // 1 1111 1111 1111 1 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x7FFFF }, _unum_3_2.Size), + _unum_3_2.SignalingNotANumber, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SignalingNotANumber))); + + // 1 1111 1111 1111 1111 1111 1111 1 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFFFFFFFF, 1 }, _unum_3_4.Size), + _unum_3_4.SignalingNotANumber, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.SignalingNotANumber))); + } + + [Fact] + public void UnumLargestPositiveIsCorrect() + { + // 0 1111 1111 1110 0 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x3FF9F }, _unum_3_2.Size), + _unum_3_2.LargestPositive, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.LargestPositive))); + + // 0 1111 1111 1111 1111 1111 1110 0 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFFFFFE7F, 0 }, _unum_3_4.Size), + _unum_3_4.LargestPositive, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.LargestPositive))); + } + + [Fact] + public void UnumSmallestPositiveIsCorrect() + { + // 0 0000 0000 0001 0 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x5F }, _unum_3_2.Size), + _unum_3_2.SmallestPositive, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SmallestPositive))); + + // 0 0000 0000 0000 0000 0000 0001 0 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0x17F, 0 }, _unum_3_4.Size), + _unum_3_4.SmallestPositive, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.SmallestPositive))); + } + + [Fact] + public void UnumLargestNegativeIsCorrect() + { + // 1 1111 1111 1110 0 111 11 + Assert.AreEqual( + new BitMask(new uint[] { 0x7FF9F }, _unum_3_2.Size), + _unum_3_2.LargestNegative, + TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.LargestNegative))); + + // 1 1111 1111 1111 1111 1111 1110 0 111 1111 + Assert.AreEqual( + new BitMask(new uint[] { 0xFFFFFE7F, 1 }, _unum_3_4.Size), + _unum_3_4.LargestNegative, + TestFailureMessageBuilder(_unum_3_4, nameof(_unum_3_4.LargestNegative))); + } + + private static string TestFailureMessageBuilder(Unum unum, string propertyName) => + $"Testing the \"{propertyName}\" property of the Unum ({unum.ExponentSizeSize}, {unum.FractionSizeSize}) environment failed."; } diff --git a/Lombiq.Arithmetics.Tests/UnumTests/UnumHelperTests.cs b/Lombiq.Arithmetics.Tests/UnumTests/UnumHelperTests.cs index ebe4c2c..8e86029 100644 --- a/Lombiq.Arithmetics.Tests/UnumTests/UnumHelperTests.cs +++ b/Lombiq.Arithmetics.Tests/UnumTests/UnumHelperTests.cs @@ -2,46 +2,45 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class UnumHelperTests { - public class UnumHelperTests - { - private readonly UnumEnvironment _warlpiriEnvironment; - private readonly UnumEnvironment _environment_2_2; - private readonly UnumEnvironment _environment_2_3; - private readonly UnumEnvironment _environment_2_4; - private readonly UnumEnvironment _environment_3_2; - private readonly UnumEnvironment _environment_4_8; + private readonly UnumEnvironment _warlpiriEnvironment; + private readonly UnumEnvironment _environment_2_2; + private readonly UnumEnvironment _environment_2_3; + private readonly UnumEnvironment _environment_2_4; + private readonly UnumEnvironment _environment_3_2; + private readonly UnumEnvironment _environment_4_8; - public UnumHelperTests() - { - _warlpiriEnvironment = UnumEnvironment.FromStandardEnvironment(StandardEnvironment.Warlpiri); - _environment_2_2 = new UnumEnvironment(2, 2); - _environment_2_3 = new UnumEnvironment(2, 3); - _environment_2_4 = new UnumEnvironment(2, 4); - _environment_3_2 = new UnumEnvironment(3, 2); - _environment_4_8 = new UnumEnvironment(4, 8); - } + public UnumHelperTests() + { + _warlpiriEnvironment = UnumEnvironment.FromStandardEnvironment(StandardEnvironment.Warlpiri); + _environment_2_2 = new UnumEnvironment(2, 2); + _environment_2_3 = new UnumEnvironment(2, 3); + _environment_2_4 = new UnumEnvironment(2, 4); + _environment_3_2 = new UnumEnvironment(3, 2); + _environment_4_8 = new UnumEnvironment(4, 8); + } - [Fact] - public void BitsRequiredByLargestExpressablePositiveIntegerIsCorrect() - { - Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_warlpiriEnvironment), 2); - Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_2_2), 9); - Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_2_3), 9); - Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_2_4), 9); - Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_3_2), 129); - } + [Fact] + public void BitsRequiredByLargestExpressablePositiveIntegerIsCorrect() + { + Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_warlpiriEnvironment), 2); + Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_2_2), 9); + Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_2_3), 9); + Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_2_4), 9); + Assert.AreEqual(UnumHelper.BitsRequiredByLargestExpressablePositiveInteger(_environment_3_2), 129); + } - [Fact] - public void LargestExpressablePositiveIntegerIsCorrect() - { - Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_4_8), _environment_4_8.EmptyBitMask); - Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_3_2), _environment_3_2.EmptyBitMask); - Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_warlpiriEnvironment), new BitMask(2, _warlpiriEnvironment.Size)); - Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_2_2), new BitMask(480, _environment_2_2.Size)); - Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_2_3), new BitMask(510, _environment_2_3.Size)); - Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_2_4), new BitMask(511, _environment_2_4.Size)); - } + [Fact] + public void LargestExpressablePositiveIntegerIsCorrect() + { + Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_4_8), _environment_4_8.EmptyBitMask); + Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_3_2), _environment_3_2.EmptyBitMask); + Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_warlpiriEnvironment), new BitMask(2, _warlpiriEnvironment.Size)); + Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_2_2), new BitMask(480, _environment_2_2.Size)); + Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_2_3), new BitMask(510, _environment_2_3.Size)); + Assert.AreEqual(UnumHelper.LargestExpressablePositiveInteger(_environment_2_4), new BitMask(511, _environment_2_4.Size)); } } diff --git a/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs b/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs index 539c86b..ccd1baa 100644 --- a/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs +++ b/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs @@ -2,602 +2,601 @@ using Assert = Lombiq.Arithmetics.Tests.CompatibilityAssert; -namespace Lombiq.Arithmetics.Tests +namespace Lombiq.Arithmetics.Tests; + +public class UnumTests { - public class UnumTests + private readonly UnumEnvironment _warlpiriEnvironment; + private readonly UnumEnvironment _environment_2_2; + private readonly UnumEnvironment _environment_2_3; + private readonly UnumEnvironment _environment_2_4; + private readonly UnumEnvironment _environment_3_2; + private readonly UnumEnvironment _environment_3_4; + private readonly UnumEnvironment _environment_3_5; + private readonly UnumEnvironment _environment_4_3; + private readonly UnumEnvironment _environment_4_8; + + public UnumTests() { - private readonly UnumEnvironment _warlpiriEnvironment; - private readonly UnumEnvironment _environment_2_2; - private readonly UnumEnvironment _environment_2_3; - private readonly UnumEnvironment _environment_2_4; - private readonly UnumEnvironment _environment_3_2; - private readonly UnumEnvironment _environment_3_4; - private readonly UnumEnvironment _environment_3_5; - private readonly UnumEnvironment _environment_4_3; - private readonly UnumEnvironment _environment_4_8; - - public UnumTests() - { - _warlpiriEnvironment = UnumEnvironment.FromStandardEnvironment(StandardEnvironment.Warlpiri); - _environment_2_2 = new UnumEnvironment(2, 2); - _environment_2_3 = new UnumEnvironment(2, 3); - _environment_2_4 = new UnumEnvironment(2, 4); - _environment_3_2 = new UnumEnvironment(3, 2); - _environment_3_4 = new UnumEnvironment(3, 4); - _environment_3_5 = new UnumEnvironment(3, 5); - _environment_4_3 = new UnumEnvironment(4, 3); - _environment_4_8 = new UnumEnvironment(4, 8); - } + _warlpiriEnvironment = UnumEnvironment.FromStandardEnvironment(StandardEnvironment.Warlpiri); + _environment_2_2 = new UnumEnvironment(2, 2); + _environment_2_3 = new UnumEnvironment(2, 3); + _environment_2_4 = new UnumEnvironment(2, 4); + _environment_3_2 = new UnumEnvironment(3, 2); + _environment_3_4 = new UnumEnvironment(3, 4); + _environment_3_5 = new UnumEnvironment(3, 5); + _environment_4_3 = new UnumEnvironment(4, 3); + _environment_4_8 = new UnumEnvironment(4, 8); + } - [Fact] - public void WarlpiriUnumValuesAndCalculationsAreCorrect() - { - var unumNegative2 = new Unum(_warlpiriEnvironment, -2); - Assert.AreEqual(-2, (int)unumNegative2); + [Fact] + public void WarlpiriUnumValuesAndCalculationsAreCorrect() + { + var unumNegative2 = new Unum(_warlpiriEnvironment, -2); + Assert.AreEqual(-2, (int)unumNegative2); - var unumNegative1 = new Unum(_warlpiriEnvironment, -1); - Assert.AreEqual(-1, (int)unumNegative1); + var unumNegative1 = new Unum(_warlpiriEnvironment, -1); + Assert.AreEqual(-1, (int)unumNegative1); - var unumNegative0 = new Unum(_warlpiriEnvironment, new BitMask(new uint[] { 8 }, _warlpiriEnvironment.Size)); - Assert.AreEqual(0, (int)unumNegative0); + var unumNegative0 = new Unum(_warlpiriEnvironment, new BitMask(new uint[] { 8 }, _warlpiriEnvironment.Size)); + Assert.AreEqual(0, (int)unumNegative0); - var unum0 = new Unum(_warlpiriEnvironment, 0); - Assert.AreEqual(0, (int)unum0); + var unum0 = new Unum(_warlpiriEnvironment, 0); + Assert.AreEqual(0, (int)unum0); - var unum1 = new Unum(_warlpiriEnvironment, 1); - Assert.AreEqual(1, (int)unum1); + var unum1 = new Unum(_warlpiriEnvironment, 1); + Assert.AreEqual(1, (int)unum1); - var unum2 = new Unum(_warlpiriEnvironment, 2); - Assert.AreEqual(2, (int)unum2); + var unum2 = new Unum(_warlpiriEnvironment, 2); + Assert.AreEqual(2, (int)unum2); - Assert.AreEqual(unumNegative0, unumNegative2 + unum2); + Assert.AreEqual(unumNegative0, unumNegative2 + unum2); - Assert.AreEqual(unumNegative0, unumNegative1 + unum1); + Assert.AreEqual(unumNegative0, unumNegative1 + unum1); - Assert.AreEqual(unum0, unum2 - unum2); + Assert.AreEqual(unum0, unum2 - unum2); - Assert.AreEqual(unum0, unum1 - unum1); + Assert.AreEqual(unum0, unum1 - unum1); - Assert.AreEqual(unum2, unum1 + unum1); + Assert.AreEqual(unum2, unum1 + unum1); - Assert.AreEqual(unumNegative2, unumNegative1 + unumNegative1); + Assert.AreEqual(unumNegative2, unumNegative1 + unumNegative1); - Assert.AreEqual(unumNegative1, unumNegative2 + unum1); + Assert.AreEqual(unumNegative1, unumNegative2 + unum1); - Assert.AreEqual(unum1, unum2 + unumNegative1); + Assert.AreEqual(unum1, unum2 + unumNegative1); - Assert.AreEqual(unumNegative0, unumNegative1 - unumNegative1); + Assert.AreEqual(unumNegative0, unumNegative1 - unumNegative1); - Assert.AreEqual(unumNegative0, unumNegative2 - unumNegative2); + Assert.AreEqual(unumNegative0, unumNegative2 - unumNegative2); - Assert.AreEqual(unum1, unumNegative1 - unumNegative2); + Assert.AreEqual(unum1, unumNegative1 - unumNegative2); - Assert.AreEqual(unum1, unum0 - unumNegative1); + Assert.AreEqual(unum1, unum0 - unumNegative1); - Assert.AreEqual(unum1, unumNegative0 - unumNegative1); + Assert.AreEqual(unum1, unumNegative0 - unumNegative1); - Assert.AreEqual(unum2, unum0 - unumNegative2); + Assert.AreEqual(unum2, unum0 - unumNegative2); - Assert.AreEqual(unum2, unumNegative0 - unumNegative2); - } + Assert.AreEqual(unum2, unumNegative0 - unumNegative2); + } - [Fact] - public void UnumIsCorrectlyConstructedFromUintArray() - { - var unum0 = new Unum(_environment_4_8, new uint[] { 0 }); - Assert.AreEqual(unum0.IsZero(), expected: true); - - var unumMinus1 = new Unum(_environment_4_8, new uint[] { 1 }, negative: true); - var bitMaskMinus1 = new BitMask(new uint[] { 0x2000, 0, 0, 0, 0, 0, 0, 0, 0x20000000 }, _environment_4_8.Size); - Assert.AreEqual(unumMinus1.UnumBits, bitMaskMinus1); - - var unum10 = new Unum(_environment_2_2, new uint[] { 10 }); - var bitMask10 = new BitMask(new uint[] { 0x329 }, _environment_2_2.Size); - Assert.AreEqual(unum10.UnumBits, bitMask10); - - var unum500000 = new Unum(_environment_4_8, new uint[] { 500000 }); // 0xC7A1250C9 - var bitMask500000 = new BitMask(new[] { 0xC7A1250C }, _environment_4_8.Size); - Assert.AreEqual(unum500000.UnumBits, bitMask500000); - - var unumBig = new Unum(_environment_4_8, new uint[] { 594_967_295 }); - var bitMaskBig = new BitMask(new uint[] { 0xCF5FE51C, 0xF06E }, _environment_4_8.Size); - Assert.AreEqual(unumBig.UnumBits, bitMaskBig); - - var minValue = new uint[8]; - for (var i = 0; i < 8; i++) minValue[i] = uint.MaxValue; - minValue[7] >>= 1; - var unumMin = new Unum(_environment_4_8, minValue, negative: true); // This is negative. - var bitMaskMinValue = new BitMask( - new uint[] - { - 0xFFFFE8FD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0x200FEFFF, - }, - _environment_4_8.Size); - Assert.AreEqual(unumMin.UnumBits, bitMaskMinValue); - - var maxValue = new uint[8]; - for (int i = 0; i < 8; i++) maxValue[i] = uint.MaxValue; - maxValue[7] >>= 1; - - var bitMaskMaxValue = new BitMask( - new uint[] - { - 0xFFFFE8FD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFFF, - }, - _environment_4_8.Size); - var unumMax = new Unum(_environment_4_8, maxValue); - - Assert.AreEqual(unumMax.IsPositive(), expected: true); - Assert.AreEqual(unumMax.Size, _environment_4_8.Size); - Assert.AreEqual(unumMax.FractionSizeWithHiddenBit(), 255); - Assert.AreEqual(unumMax.ExponentValueWithBias(), 254); - Assert.AreEqual(unumMax.FractionWithHiddenBit(), new BitMask(maxValue, _environment_4_8.Size)); - Assert.AreEqual(unumMax.UnumBits, bitMaskMaxValue); - - var tooBigUnum_warlpiri = new Unum(_warlpiriEnvironment, 3); - var tooBigBitMask_warlpiri = _warlpiriEnvironment.LargestPositive | _warlpiriEnvironment.UncertaintyBitMask; - Assert.AreEqual(tooBigUnum_warlpiri.UnumBits, tooBigBitMask_warlpiri); - - var tooBigNegativeUnum_warlpiri = new Unum(_warlpiriEnvironment, -3); - var tooBigNegativeBitMask_warlpiri = _warlpiriEnvironment.LargestNegative | _warlpiriEnvironment.UncertaintyBitMask; - Assert.AreEqual(tooBigNegativeUnum_warlpiri.UnumBits, tooBigNegativeBitMask_warlpiri); - - var maxValue_2_2 = new Unum(_environment_2_2, 480); - var maxBitMask_2_2 = new BitMask(new uint[] { 0xFEE }, _environment_2_2.Size); - Assert.AreEqual(maxValue_2_2.UnumBits, maxBitMask_2_2); - - var minValue_2_2 = new Unum(_environment_2_2, -480); - var bitMaskMinValue_2_2 = new BitMask(new uint[] { 0x2FEE }, _environment_2_2.Size); - Assert.AreEqual(minValue_2_2.UnumBits, bitMaskMinValue_2_2); - - var tooBigUnum_2_2 = new Unum(_environment_2_2, 481); - var tooBigBitMask_2_2 = _environment_2_2.LargestPositive | _environment_2_2.UncertaintyBitMask; - Assert.AreEqual(tooBigUnum_2_2.UnumBits, tooBigBitMask_2_2); - - var tooBigNegativeUnum_2_2 = new Unum(_environment_2_2, -481); - var tooBigNegativeBitMask_2_2 = _environment_2_2.LargestNegative | _environment_2_2.UncertaintyBitMask; - Assert.AreEqual(tooBigNegativeUnum_2_2.UnumBits, tooBigNegativeBitMask_2_2); - - var maxValue_2_3 = new Unum(_environment_2_3, 510); - var maxBitMask_2_3 = new BitMask(new uint[] { 0x1FFDE }, _environment_2_3.Size); - Assert.AreEqual(maxValue_2_3.UnumBits, maxBitMask_2_3); - - var minValue_2_3 = new Unum(_environment_2_3, -510); - var bitMaskMinValue_2_3 = new BitMask(new uint[] { 0x5FFDE }, _environment_2_3.Size); - Assert.AreEqual(minValue_2_3.UnumBits, bitMaskMinValue_2_3); - - var tooBigUnum_2_3 = new Unum(_environment_2_3, 511); - var tooBigBitMask_2_3 = _environment_2_3.LargestPositive | _environment_2_3.UncertaintyBitMask; - Assert.AreEqual(tooBigUnum_2_3.UnumBits, tooBigBitMask_2_3); - - var tooBigNegativeUnum_2_3 = new Unum(_environment_2_3, -511); - var tooBigNegativeBitMask_2_3 = _environment_2_3.LargestNegative | _environment_2_3.UncertaintyBitMask; - Assert.AreEqual(tooBigNegativeUnum_2_3.UnumBits, tooBigNegativeBitMask_2_3); - - // Testing in an environment where the biggest representable value isn't an integer. - var maxValue_2_4 = new Unum(_environment_2_4, 511); - var maxBitMask_2_4 = new BitMask(new uint[] { 0x7FFB7 }, _environment_2_4.Size); - Assert.AreEqual(maxValue_2_4.UnumBits, maxBitMask_2_4); - - var minValue_2_4 = new Unum(_environment_2_4, -511); - var bitMaskMinValue_2_4 = new BitMask(new uint[] { 0x807FFB7 }, _environment_2_4.Size); - Assert.AreEqual(minValue_2_4.UnumBits, bitMaskMinValue_2_4); - - var tooBigUnum_2_4 = new Unum(_environment_2_4, 512); - var tooBigBitMask_2_4 = _environment_2_4.LargestPositive | _environment_2_4.UncertaintyBitMask; - Assert.AreEqual(tooBigUnum_2_4.UnumBits, tooBigBitMask_2_4); - - var tooBigNegativeUnum_2_4 = new Unum(_environment_2_4, -512); - var tooBigNegativeBitMask_2_4 = _environment_2_4.LargestNegative | _environment_2_4.UncertaintyBitMask; - Assert.AreEqual(tooBigNegativeUnum_2_4.UnumBits, tooBigNegativeBitMask_2_4); - } + [Fact] + public void UnumIsCorrectlyConstructedFromUintArray() + { + var unum0 = new Unum(_environment_4_8, new uint[] { 0 }); + Assert.AreEqual(unum0.IsZero(), expected: true); + + var unumMinus1 = new Unum(_environment_4_8, new uint[] { 1 }, negative: true); + var bitMaskMinus1 = new BitMask(new uint[] { 0x2000, 0, 0, 0, 0, 0, 0, 0, 0x20000000 }, _environment_4_8.Size); + Assert.AreEqual(unumMinus1.UnumBits, bitMaskMinus1); + + var unum10 = new Unum(_environment_2_2, new uint[] { 10 }); + var bitMask10 = new BitMask(new uint[] { 0x329 }, _environment_2_2.Size); + Assert.AreEqual(unum10.UnumBits, bitMask10); + + var unum500000 = new Unum(_environment_4_8, new uint[] { 500000 }); // 0xC7A1250C9 + var bitMask500000 = new BitMask(new[] { 0xC7A1250C }, _environment_4_8.Size); + Assert.AreEqual(unum500000.UnumBits, bitMask500000); + + var unumBig = new Unum(_environment_4_8, new uint[] { 594_967_295 }); + var bitMaskBig = new BitMask(new uint[] { 0xCF5FE51C, 0xF06E }, _environment_4_8.Size); + Assert.AreEqual(unumBig.UnumBits, bitMaskBig); + + var minValue = new uint[8]; + for (var i = 0; i < 8; i++) minValue[i] = uint.MaxValue; + minValue[7] >>= 1; + var unumMin = new Unum(_environment_4_8, minValue, negative: true); // This is negative. + var bitMaskMinValue = new BitMask( + new uint[] + { + 0xFFFFE8FD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x200FEFFF, + }, + _environment_4_8.Size); + Assert.AreEqual(unumMin.UnumBits, bitMaskMinValue); + + var maxValue = new uint[8]; + for (int i = 0; i < 8; i++) maxValue[i] = uint.MaxValue; + maxValue[7] >>= 1; + + var bitMaskMaxValue = new BitMask( + new uint[] + { + 0xFFFFE8FD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFEFFF, + }, + _environment_4_8.Size); + var unumMax = new Unum(_environment_4_8, maxValue); + + Assert.AreEqual(unumMax.IsPositive(), expected: true); + Assert.AreEqual(unumMax.Size, _environment_4_8.Size); + Assert.AreEqual(unumMax.FractionSizeWithHiddenBit(), 255); + Assert.AreEqual(unumMax.ExponentValueWithBias(), 254); + Assert.AreEqual(unumMax.FractionWithHiddenBit(), new BitMask(maxValue, _environment_4_8.Size)); + Assert.AreEqual(unumMax.UnumBits, bitMaskMaxValue); + + var tooBigUnum_warlpiri = new Unum(_warlpiriEnvironment, 3); + var tooBigBitMask_warlpiri = _warlpiriEnvironment.LargestPositive | _warlpiriEnvironment.UncertaintyBitMask; + Assert.AreEqual(tooBigUnum_warlpiri.UnumBits, tooBigBitMask_warlpiri); + + var tooBigNegativeUnum_warlpiri = new Unum(_warlpiriEnvironment, -3); + var tooBigNegativeBitMask_warlpiri = _warlpiriEnvironment.LargestNegative | _warlpiriEnvironment.UncertaintyBitMask; + Assert.AreEqual(tooBigNegativeUnum_warlpiri.UnumBits, tooBigNegativeBitMask_warlpiri); + + var maxValue_2_2 = new Unum(_environment_2_2, 480); + var maxBitMask_2_2 = new BitMask(new uint[] { 0xFEE }, _environment_2_2.Size); + Assert.AreEqual(maxValue_2_2.UnumBits, maxBitMask_2_2); + + var minValue_2_2 = new Unum(_environment_2_2, -480); + var bitMaskMinValue_2_2 = new BitMask(new uint[] { 0x2FEE }, _environment_2_2.Size); + Assert.AreEqual(minValue_2_2.UnumBits, bitMaskMinValue_2_2); + + var tooBigUnum_2_2 = new Unum(_environment_2_2, 481); + var tooBigBitMask_2_2 = _environment_2_2.LargestPositive | _environment_2_2.UncertaintyBitMask; + Assert.AreEqual(tooBigUnum_2_2.UnumBits, tooBigBitMask_2_2); + + var tooBigNegativeUnum_2_2 = new Unum(_environment_2_2, -481); + var tooBigNegativeBitMask_2_2 = _environment_2_2.LargestNegative | _environment_2_2.UncertaintyBitMask; + Assert.AreEqual(tooBigNegativeUnum_2_2.UnumBits, tooBigNegativeBitMask_2_2); + + var maxValue_2_3 = new Unum(_environment_2_3, 510); + var maxBitMask_2_3 = new BitMask(new uint[] { 0x1FFDE }, _environment_2_3.Size); + Assert.AreEqual(maxValue_2_3.UnumBits, maxBitMask_2_3); + + var minValue_2_3 = new Unum(_environment_2_3, -510); + var bitMaskMinValue_2_3 = new BitMask(new uint[] { 0x5FFDE }, _environment_2_3.Size); + Assert.AreEqual(minValue_2_3.UnumBits, bitMaskMinValue_2_3); + + var tooBigUnum_2_3 = new Unum(_environment_2_3, 511); + var tooBigBitMask_2_3 = _environment_2_3.LargestPositive | _environment_2_3.UncertaintyBitMask; + Assert.AreEqual(tooBigUnum_2_3.UnumBits, tooBigBitMask_2_3); + + var tooBigNegativeUnum_2_3 = new Unum(_environment_2_3, -511); + var tooBigNegativeBitMask_2_3 = _environment_2_3.LargestNegative | _environment_2_3.UncertaintyBitMask; + Assert.AreEqual(tooBigNegativeUnum_2_3.UnumBits, tooBigNegativeBitMask_2_3); + + // Testing in an environment where the biggest representable value isn't an integer. + var maxValue_2_4 = new Unum(_environment_2_4, 511); + var maxBitMask_2_4 = new BitMask(new uint[] { 0x7FFB7 }, _environment_2_4.Size); + Assert.AreEqual(maxValue_2_4.UnumBits, maxBitMask_2_4); + + var minValue_2_4 = new Unum(_environment_2_4, -511); + var bitMaskMinValue_2_4 = new BitMask(new uint[] { 0x807FFB7 }, _environment_2_4.Size); + Assert.AreEqual(minValue_2_4.UnumBits, bitMaskMinValue_2_4); + + var tooBigUnum_2_4 = new Unum(_environment_2_4, 512); + var tooBigBitMask_2_4 = _environment_2_4.LargestPositive | _environment_2_4.UncertaintyBitMask; + Assert.AreEqual(tooBigUnum_2_4.UnumBits, tooBigBitMask_2_4); + + var tooBigNegativeUnum_2_4 = new Unum(_environment_2_4, -512); + var tooBigNegativeBitMask_2_4 = _environment_2_4.LargestNegative | _environment_2_4.UncertaintyBitMask; + Assert.AreEqual(tooBigNegativeUnum_2_4.UnumBits, tooBigNegativeBitMask_2_4); + } - [Fact] - public void FractionToUintArrayIsCorrect() - { - var unumZero = new Unum(_environment_4_8, new uint[] { 0 }); - Assert.AreEqual(unumZero.FractionToUintArray(), new uint[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }); + [Fact] + public void FractionToUintArrayIsCorrect() + { + var unumZero = new Unum(_environment_4_8, new uint[] { 0 }); + Assert.AreEqual(unumZero.FractionToUintArray(), new uint[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }); - var unum1 = new Unum(_environment_4_8, new uint[] { 1 }); - Assert.AreEqual(unum1.FractionToUintArray(), new uint[] { 1, 0, 0, 0, 0, 0, 0, 0, 0 }); + var unum1 = new Unum(_environment_4_8, new uint[] { 1 }); + Assert.AreEqual(unum1.FractionToUintArray(), new uint[] { 1, 0, 0, 0, 0, 0, 0, 0, 0 }); - var unum500000 = new Unum(_environment_4_8, new uint[] { 500000 }); - Assert.AreEqual(unum500000.FractionToUintArray(), new uint[] { 500000, 0, 0, 0, 0, 0, 0, 0, 0 }); + var unum500000 = new Unum(_environment_4_8, new uint[] { 500000 }); + Assert.AreEqual(unum500000.FractionToUintArray(), new uint[] { 500000, 0, 0, 0, 0, 0, 0, 0, 0 }); - var unumBig = new Unum(_environment_4_8, new uint[] { 594_967_295 }); - Assert.AreEqual(unumBig.FractionToUintArray(), new uint[] { 594_967_295, 0, 0, 0, 0, 0, 0, 0, 0 }); + var unumBig = new Unum(_environment_4_8, new uint[] { 594_967_295 }); + Assert.AreEqual(unumBig.FractionToUintArray(), new uint[] { 594_967_295, 0, 0, 0, 0, 0, 0, 0, 0 }); - var maxValue = new uint[8]; - for (var i = 0; i < 8; i++) - { - maxValue[i] = uint.MaxValue; - } - - maxValue[7] >>= 1; - var unumMax = new Unum(_environment_4_8, maxValue); - Assert.AreEqual( - unumMax.FractionToUintArray(), - new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0 }); + var maxValue = new uint[8]; + for (var i = 0; i < 8; i++) + { + maxValue[i] = uint.MaxValue; } - [Fact] - public void UnumIsCorrectlyConstructedFromInt() - { - var unum0 = new Unum(_environment_3_4, 0); - var bitMask0 = new BitMask(new uint[] { 0 }, _environment_3_4.Size); - Assert.AreEqual(unum0.UnumBits, bitMask0); + maxValue[7] >>= 1; + var unumMax = new Unum(_environment_4_8, maxValue); + Assert.AreEqual( + unumMax.FractionToUintArray(), + new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF, 0 }); + } - var unum1 = new Unum(_environment_3_4, 1); - var bitMask1 = new BitMask(new uint[] { 0x100 }, _environment_3_4.Size); - Assert.AreEqual(unum1.UnumBits, bitMask1); + [Fact] + public void UnumIsCorrectlyConstructedFromInt() + { + var unum0 = new Unum(_environment_3_4, 0); + var bitMask0 = new BitMask(new uint[] { 0 }, _environment_3_4.Size); + Assert.AreEqual(unum0.UnumBits, bitMask0); - var unum30 = new Unum(_environment_3_4, 30); - var bitMask30 = new BitMask(new uint[] { 0x3F22 }, _environment_3_4.Size); - Assert.AreEqual(unum30.UnumBits, bitMask30); + var unum1 = new Unum(_environment_3_4, 1); + var bitMask1 = new BitMask(new uint[] { 0x100 }, _environment_3_4.Size); + Assert.AreEqual(unum1.UnumBits, bitMask1); - var unum1000 = new Unum(_environment_3_4, 1000); - var bitMask1000 = new BitMask(new uint[] { 0x63D45 }, _environment_3_4.Size); - Assert.AreEqual(unum1000.UnumBits, bitMask1000); + var unum30 = new Unum(_environment_3_4, 30); + var bitMask30 = new BitMask(new uint[] { 0x3F22 }, _environment_3_4.Size); + Assert.AreEqual(unum30.UnumBits, bitMask30); - var unum5000 = new Unum(_environment_3_4, 5000); - var bitMask5000 = new BitMask(new uint[] { 0x367148 }, _environment_3_4.Size); - Assert.AreEqual(unum5000.UnumBits, bitMask5000); + var unum1000 = new Unum(_environment_3_4, 1000); + var bitMask1000 = new BitMask(new uint[] { 0x63D45 }, _environment_3_4.Size); + Assert.AreEqual(unum1000.UnumBits, bitMask1000); - var unum6000 = new Unum(_environment_3_4, 6000); - var bitMask6000 = new BitMask(new uint[] { 0x1B7747 }, _environment_3_4.Size); - Assert.AreEqual(unum6000.UnumBits, bitMask6000); + var unum5000 = new Unum(_environment_3_4, 5000); + var bitMask5000 = new BitMask(new uint[] { 0x367148 }, _environment_3_4.Size); + Assert.AreEqual(unum5000.UnumBits, bitMask5000); - var unumNegative30 = new Unum(_environment_3_4, -30); - var bitMaskMinus30 = new BitMask(new uint[] { 0x3F22, 1 }, _environment_3_4.Size); - Assert.AreEqual(unumNegative30.UnumBits, bitMaskMinus30); + var unum6000 = new Unum(_environment_3_4, 6000); + var bitMask6000 = new BitMask(new uint[] { 0x1B7747 }, _environment_3_4.Size); + Assert.AreEqual(unum6000.UnumBits, bitMask6000); - var unumNegative1000 = new Unum(_environment_3_4, -1000); - var bitMaskMinus1000 = new BitMask(new uint[] { 0x63D45, 1 }, _environment_3_4.Size); - Assert.AreEqual(unumNegative1000.UnumBits, bitMaskMinus1000); - } + var unumNegative30 = new Unum(_environment_3_4, -30); + var bitMaskMinus30 = new BitMask(new uint[] { 0x3F22, 1 }, _environment_3_4.Size); + Assert.AreEqual(unumNegative30.UnumBits, bitMaskMinus30); - [Fact] - public void UnumIsCorrectlyConstructedFromUInt() - { - var unum0 = new Unum(_environment_3_4, 0U); - var bitMask0 = new BitMask(new uint[] { 0 }, _environment_3_4.Size); - Assert.AreEqual(bitMask0, unum0.UnumBits); + var unumNegative1000 = new Unum(_environment_3_4, -1000); + var bitMaskMinus1000 = new BitMask(new uint[] { 0x63D45, 1 }, _environment_3_4.Size); + Assert.AreEqual(unumNegative1000.UnumBits, bitMaskMinus1000); + } - var unum1 = new Unum(_environment_3_4, 1U); - var bitMask1 = new BitMask(new uint[] { 0x100 }, _environment_3_4.Size); - Assert.AreEqual(bitMask1, unum1.UnumBits); + [Fact] + public void UnumIsCorrectlyConstructedFromUInt() + { + var unum0 = new Unum(_environment_3_4, 0U); + var bitMask0 = new BitMask(new uint[] { 0 }, _environment_3_4.Size); + Assert.AreEqual(bitMask0, unum0.UnumBits); - var unum2 = new Unum(_environment_3_4, 2U); - var bitMask2 = new BitMask(new uint[] { 0x200 }, _environment_3_4.Size); - Assert.AreEqual(bitMask2, unum2.UnumBits); + var unum1 = new Unum(_environment_3_4, 1U); + var bitMask1 = new BitMask(new uint[] { 0x100 }, _environment_3_4.Size); + Assert.AreEqual(bitMask1, unum1.UnumBits); - var unum4 = new Unum(_environment_3_4, 4U); - var bitMask4 = new BitMask(new uint[] { 0x610 }, _environment_3_4.Size); - Assert.AreEqual(bitMask4, unum4.UnumBits); + var unum2 = new Unum(_environment_3_4, 2U); + var bitMask2 = new BitMask(new uint[] { 0x200 }, _environment_3_4.Size); + Assert.AreEqual(bitMask2, unum2.UnumBits); - var unum8 = new Unum(_environment_3_4, 8U); - var bitMask8 = new BitMask(new uint[] { 0xC20 }, _environment_3_4.Size); - Assert.AreEqual(bitMask8, unum8.UnumBits); + var unum4 = new Unum(_environment_3_4, 4U); + var bitMask4 = new BitMask(new uint[] { 0x610 }, _environment_3_4.Size); + Assert.AreEqual(bitMask4, unum4.UnumBits); - var unum10 = new Unum(_environment_2_2, 10U); - var bitMask10 = new BitMask(new uint[] { 0x329 }, _environment_2_2.Size); - Assert.AreEqual(bitMask10, unum10.UnumBits); + var unum8 = new Unum(_environment_3_4, 8U); + var bitMask8 = new BitMask(new uint[] { 0xC20 }, _environment_3_4.Size); + Assert.AreEqual(bitMask8, unum8.UnumBits); - var unum13 = new Unum(_environment_3_4, 13U); - var bitMask13 = new BitMask(new uint[] { 0x3522 }, _environment_3_4.Size); - Assert.AreEqual(bitMask13, unum13.UnumBits); + var unum10 = new Unum(_environment_2_2, 10U); + var bitMask10 = new BitMask(new uint[] { 0x329 }, _environment_2_2.Size); + Assert.AreEqual(bitMask10, unum10.UnumBits); - var unum30 = new Unum(_environment_3_4, 30U); - var bitMask30 = new BitMask(new uint[] { 0x3F22 }, _environment_3_4.Size); - Assert.AreEqual(bitMask30, unum30.UnumBits); + var unum13 = new Unum(_environment_3_4, 13U); + var bitMask13 = new BitMask(new uint[] { 0x3522 }, _environment_3_4.Size); + Assert.AreEqual(bitMask13, unum13.UnumBits); - var unum1000 = new Unum(_environment_3_4, 1000U); - var bitMask1000 = new BitMask(new uint[] { 0x63D45 }, _environment_3_4.Size); - Assert.AreEqual(bitMask1000, unum1000.UnumBits); + var unum30 = new Unum(_environment_3_4, 30U); + var bitMask30 = new BitMask(new uint[] { 0x3F22 }, _environment_3_4.Size); + Assert.AreEqual(bitMask30, unum30.UnumBits); - var unum5000 = new Unum(_environment_3_4, 5000U); - var bitMask5000 = new BitMask(new uint[] { 0x367148 }, _environment_3_4.Size); - Assert.AreEqual(bitMask5000, unum5000.UnumBits); + var unum1000 = new Unum(_environment_3_4, 1000U); + var bitMask1000 = new BitMask(new uint[] { 0x63D45 }, _environment_3_4.Size); + Assert.AreEqual(bitMask1000, unum1000.UnumBits); - var unum6000 = new Unum(_environment_3_4, 6000U); - var bitMask6000 = new BitMask(new uint[] { 0x1B7747 }, _environment_3_4.Size); - Assert.AreEqual(bitMask6000, unum6000.UnumBits); - } + var unum5000 = new Unum(_environment_3_4, 5000U); + var bitMask5000 = new BitMask(new uint[] { 0x367148 }, _environment_3_4.Size); + Assert.AreEqual(bitMask5000, unum5000.UnumBits); - [Fact] - public void IsExactIsCorrect() - { - // 0 0000 0000 0000 1 000 00 - var bitMask_3_2_uncertain = new BitMask(new uint[] { 0x20 }, 19); - var unum_3_2_uncertain = new Unum(_environment_3_2, bitMask_3_2_uncertain); - Assert.AreEqual(actual: false, unum_3_2_uncertain.IsExact()); - - var bitMask_3_2_certain = new BitMask(19, allOne: false); - var unum_3_2_certain = new Unum(_environment_3_2, bitMask_3_2_certain); - Assert.AreEqual(actual: true, unum_3_2_certain.IsExact()); - - var bitMask_3_4_uncertain = new BitMask(new uint[] { 0x80, 0 }, 33); - var unum_3_4_uncertain = new Unum(_environment_3_4, bitMask_3_4_uncertain); - Assert.AreEqual(actual: false, unum_3_4_uncertain.IsExact()); - - var bitMask_3_4_certain = new BitMask(33, allOne: false); - var unum_3_4_certain = new Unum(_environment_3_4, bitMask_3_4_certain); - Assert.AreEqual(actual: true, unum_3_4_certain.IsExact()); - } + var unum6000 = new Unum(_environment_3_4, 6000U); + var bitMask6000 = new BitMask(new uint[] { 0x1B7747 }, _environment_3_4.Size); + Assert.AreEqual(bitMask6000, unum6000.UnumBits); + } - [Fact] - public void FractionSizeIsCorrect() - { - var bitMask_3_2_allOne = new BitMask(19, allOne: true); - var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); - Assert.AreEqual(4, unum_3_2_allOne.FractionSize()); + [Fact] + public void IsExactIsCorrect() + { + // 0 0000 0000 0000 1 000 00 + var bitMask_3_2_uncertain = new BitMask(new uint[] { 0x20 }, 19); + var unum_3_2_uncertain = new Unum(_environment_3_2, bitMask_3_2_uncertain); + Assert.AreEqual(actual: false, unum_3_2_uncertain.IsExact()); + + var bitMask_3_2_certain = new BitMask(19, allOne: false); + var unum_3_2_certain = new Unum(_environment_3_2, bitMask_3_2_certain); + Assert.AreEqual(actual: true, unum_3_2_certain.IsExact()); + + var bitMask_3_4_uncertain = new BitMask(new uint[] { 0x80, 0 }, 33); + var unum_3_4_uncertain = new Unum(_environment_3_4, bitMask_3_4_uncertain); + Assert.AreEqual(actual: false, unum_3_4_uncertain.IsExact()); + + var bitMask_3_4_certain = new BitMask(33, allOne: false); + var unum_3_4_certain = new Unum(_environment_3_4, bitMask_3_4_certain); + Assert.AreEqual(actual: true, unum_3_4_certain.IsExact()); + } - var bitMask_3_4_allOne = new BitMask(33, allOne: true); - var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); - Assert.AreEqual(16, unum_3_4_allOne.FractionSize()); - } + [Fact] + public void FractionSizeIsCorrect() + { + var bitMask_3_2_allOne = new BitMask(19, allOne: true); + var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); + Assert.AreEqual(4, unum_3_2_allOne.FractionSize()); - [Fact] - public void ExponentSizeIsCorrect() - { - var bitMask_3_2_allOne = new BitMask(19, allOne: true); - var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); - Assert.AreEqual(8, unum_3_2_allOne.ExponentSize()); + var bitMask_3_4_allOne = new BitMask(33, allOne: true); + var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); + Assert.AreEqual(16, unum_3_4_allOne.FractionSize()); + } - var bitMask_3_4_allOne = new BitMask(33, allOne: true); - var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); - Assert.AreEqual(8, unum_3_4_allOne.ExponentSize()); + [Fact] + public void ExponentSizeIsCorrect() + { + var bitMask_3_2_allOne = new BitMask(19, allOne: true); + var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); + Assert.AreEqual(8, unum_3_2_allOne.ExponentSize()); - var bitMask_4_3_allOne = new BitMask(33, allOne: true); - var unum_4_3_allOne = new Unum(_environment_4_3, bitMask_4_3_allOne); - Assert.AreEqual(16, unum_4_3_allOne.ExponentSize()); - } + var bitMask_3_4_allOne = new BitMask(33, allOne: true); + var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); + Assert.AreEqual(8, unum_3_4_allOne.ExponentSize()); - [Fact] - public void FractionMaskIsCorrect() - { - // 0 0000 0000 1111 0000 00 - var bitMask_3_2_allOne = new BitMask(19, allOne: true); - var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); - var bitMask_3_2_FractionMask = new BitMask(new uint[] { 0x3C0 }, 19); - Assert.AreEqual(bitMask_3_2_FractionMask, unum_3_2_allOne.FractionMask()); - - // 0 0000 0000 1111 1111 1111 1111 0000 0000 - var bitMask_3_4_allOne = new BitMask(33, allOne: true); - var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); - var bitMask_3_4_FractionMask = new BitMask(new uint[] { 0xFFFF00 }, 33); - Assert.AreEqual(bitMask_3_4_FractionMask, unum_3_4_allOne.FractionMask()); - } + var bitMask_4_3_allOne = new BitMask(33, allOne: true); + var unum_4_3_allOne = new Unum(_environment_4_3, bitMask_4_3_allOne); + Assert.AreEqual(16, unum_4_3_allOne.ExponentSize()); + } - [Fact] - public void ExponentMaskIsCorrect() - { - // 0 1111 1111 0000 0 000 00 - var bitMask_3_2_allOne = new BitMask(19, allOne: true); - var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); - var bitMask_3_2_ExponentMask = new BitMask(new uint[] { 0x3FC00 }, 19); - Assert.AreEqual(bitMask_3_2_ExponentMask, unum_3_2_allOne.ExponentMask()); - - // 0 1111 1111 0000 0000 0000 0000 0 000 0000 - var bitMask_3_4_allOne = new BitMask(33, allOne: true); - var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); - var bitMask_3_4_ExponentMask = new BitMask(new[] { 0xFF000000 }, 33); - Assert.AreEqual(bitMask_3_4_ExponentMask, unum_3_4_allOne.ExponentMask()); - } + [Fact] + public void FractionMaskIsCorrect() + { + // 0 0000 0000 1111 0000 00 + var bitMask_3_2_allOne = new BitMask(19, allOne: true); + var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); + var bitMask_3_2_FractionMask = new BitMask(new uint[] { 0x3C0 }, 19); + Assert.AreEqual(bitMask_3_2_FractionMask, unum_3_2_allOne.FractionMask()); + + // 0 0000 0000 1111 1111 1111 1111 0000 0000 + var bitMask_3_4_allOne = new BitMask(33, allOne: true); + var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); + var bitMask_3_4_FractionMask = new BitMask(new uint[] { 0xFFFF00 }, 33); + Assert.AreEqual(bitMask_3_4_FractionMask, unum_3_4_allOne.FractionMask()); + } - [Fact] - public void ExponentValueWithBiasIsCorrect() - { - var bitMask1 = new BitMask(new uint[] { 0xE40 }, 33); - var unum1 = new Unum(_environment_3_4, bitMask1); - Assert.AreEqual(unum1.ExponentValueWithBias(), -8); + [Fact] + public void ExponentMaskIsCorrect() + { + // 0 1111 1111 0000 0 000 00 + var bitMask_3_2_allOne = new BitMask(19, allOne: true); + var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); + var bitMask_3_2_ExponentMask = new BitMask(new uint[] { 0x3FC00 }, 19); + Assert.AreEqual(bitMask_3_2_ExponentMask, unum_3_2_allOne.ExponentMask()); + + // 0 1111 1111 0000 0000 0000 0000 0 000 0000 + var bitMask_3_4_allOne = new BitMask(33, allOne: true); + var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); + var bitMask_3_4_ExponentMask = new BitMask(new[] { 0xFF000000 }, 33); + Assert.AreEqual(bitMask_3_4_ExponentMask, unum_3_4_allOne.ExponentMask()); + } - var unumZero = new Unum(_environment_3_4, 0); - Assert.AreEqual(unumZero.ExponentValueWithBias(), 1); - } + [Fact] + public void ExponentValueWithBiasIsCorrect() + { + var bitMask1 = new BitMask(new uint[] { 0xE40 }, 33); + var unum1 = new Unum(_environment_3_4, bitMask1); + Assert.AreEqual(unum1.ExponentValueWithBias(), -8); - [Fact] - public void FractionWithHiddenBitIsCorrect() - { - var bitMask1 = new BitMask(new uint[] { 0xE40 }, 33); - var unum1 = new Unum(_environment_3_4, bitMask1); - Assert.AreEqual(new BitMask(new uint[] { 2 }, 33), unum1.FractionWithHiddenBit()); + var unumZero = new Unum(_environment_3_4, 0); + Assert.AreEqual(unumZero.ExponentValueWithBias(), 1); + } - var bitMask2 = new BitMask(new uint[] { 0x3F22 }, 33); - var unum2 = new Unum(_environment_3_4, bitMask2); - Assert.AreEqual(new BitMask(new uint[] { 0xF }, 33), unum2.FractionWithHiddenBit()); + [Fact] + public void FractionWithHiddenBitIsCorrect() + { + var bitMask1 = new BitMask(new uint[] { 0xE40 }, 33); + var unum1 = new Unum(_environment_3_4, bitMask1); + Assert.AreEqual(new BitMask(new uint[] { 2 }, 33), unum1.FractionWithHiddenBit()); - var bitMask3 = new BitMask(new uint[] { 0x7E012B }, 33); - var unum3 = new Unum(_environment_3_4, bitMask3); - Assert.AreEqual(new BitMask(new uint[] { 0x1E01 }, 33), unum3.FractionWithHiddenBit()); - } + var bitMask2 = new BitMask(new uint[] { 0x3F22 }, 33); + var unum2 = new Unum(_environment_3_4, bitMask2); + Assert.AreEqual(new BitMask(new uint[] { 0xF }, 33), unum2.FractionWithHiddenBit()); - [Fact] - public void AddExactUnumsIsCorrect() - { - // First example from The End of Error p. 117. - var bitMask1 = new BitMask(new uint[] { 0xE40 }, 33); - var bitMask2 = new BitMask(new uint[] { 0x3F22 }, 33); - var unumFirst = new Unum(_environment_3_4, bitMask1); - var unumSecond = new Unum(_environment_3_4, bitMask2); - var bitMaskSum = new BitMask(new uint[] { 0x7E012B }, 33); - var unumSum1 = Unum.AddExactUnums(unumFirst, unumSecond); - Assert.AreEqual(unumSum1.UnumBits, bitMaskSum); - - // Addition should be commutative. - var unumSum2 = Unum.AddExactUnums(unumSecond, unumFirst); - Assert.AreEqual(unumSum1.UnumBits, unumSum2.UnumBits); - - var unum0 = new Unum(_environment_3_4, 0); - var unum1 = new Unum(_environment_3_4, 1); - var unum0Plus1 = unum0 + unum1; - var unum31 = new Unum(_environment_3_4, 30) + unum1; - var unum0PlusUnum1 = Unum.AddExactUnums(unum0, unum1); - Assert.AreEqual(unum31.UnumBits, new Unum(_environment_3_4, 31).UnumBits); - Assert.AreEqual(unum1.UnumBits, unum0Plus1.UnumBits); - Assert.AreEqual(unum1.UnumBits, unum0PlusUnum1.UnumBits); - - // Case of inexact result, second example from The End or Error, p. 117. - var bitMask4 = new BitMask(new uint[] { 0x18F400CF }, 33); // 1000.0078125 - var unum1000 = new Unum(_environment_3_4, 1000); - var unum6 = Unum.AddExactUnums(unum1000, unumFirst); // 1/256 - Assert.AreEqual(unum6.UnumBits, bitMask4); - - var unum5000 = new Unum(_environment_3_4, 5000); - var unum6000 = new Unum(_environment_3_4, 6000); - Assert.AreEqual(Unum.AddExactUnums(unum5000, unum1000).UnumBits, unum6000.UnumBits); - - var unumNegativeThirty = new Unum(_environment_3_4, -30); - var unum30 = new Unum(_environment_3_4, 30); - Assert.AreEqual(Unum.AddExactUnums(unum30, unumNegativeThirty).UnumBits, unum0.UnumBits); - } + var bitMask3 = new BitMask(new uint[] { 0x7E012B }, 33); + var unum3 = new Unum(_environment_3_4, bitMask3); + Assert.AreEqual(new BitMask(new uint[] { 0x1E01 }, 33), unum3.FractionWithHiddenBit()); + } - [Fact] - public void AdditionIsCorrectForIntegers() - { - var result = new Unum(_environment_3_5, 0); - var count = 100; + [Fact] + public void AddExactUnumsIsCorrect() + { + // First example from The End of Error p. 117. + var bitMask1 = new BitMask(new uint[] { 0xE40 }, 33); + var bitMask2 = new BitMask(new uint[] { 0x3F22 }, 33); + var unumFirst = new Unum(_environment_3_4, bitMask1); + var unumSecond = new Unum(_environment_3_4, bitMask2); + var bitMaskSum = new BitMask(new uint[] { 0x7E012B }, 33); + var unumSum1 = Unum.AddExactUnums(unumFirst, unumSecond); + Assert.AreEqual(unumSum1.UnumBits, bitMaskSum); + + // Addition should be commutative. + var unumSum2 = Unum.AddExactUnums(unumSecond, unumFirst); + Assert.AreEqual(unumSum1.UnumBits, unumSum2.UnumBits); + + var unum0 = new Unum(_environment_3_4, 0); + var unum1 = new Unum(_environment_3_4, 1); + var unum0Plus1 = unum0 + unum1; + var unum31 = new Unum(_environment_3_4, 30) + unum1; + var unum0PlusUnum1 = Unum.AddExactUnums(unum0, unum1); + Assert.AreEqual(unum31.UnumBits, new Unum(_environment_3_4, 31).UnumBits); + Assert.AreEqual(unum1.UnumBits, unum0Plus1.UnumBits); + Assert.AreEqual(unum1.UnumBits, unum0PlusUnum1.UnumBits); + + // Case of inexact result, second example from The End or Error, p. 117. + var bitMask4 = new BitMask(new uint[] { 0x18F400CF }, 33); // 1000.0078125 + var unum1000 = new Unum(_environment_3_4, 1000); + var unum6 = Unum.AddExactUnums(unum1000, unumFirst); // 1/256 + Assert.AreEqual(unum6.UnumBits, bitMask4); + + var unum5000 = new Unum(_environment_3_4, 5000); + var unum6000 = new Unum(_environment_3_4, 6000); + Assert.AreEqual(Unum.AddExactUnums(unum5000, unum1000).UnumBits, unum6000.UnumBits); + + var unumNegativeThirty = new Unum(_environment_3_4, -30); + var unum30 = new Unum(_environment_3_4, 30); + Assert.AreEqual(Unum.AddExactUnums(unum30, unumNegativeThirty).UnumBits, unum0.UnumBits); + } - for (int i = 1; i <= count; i++) result += new Unum(_environment_3_5, i * 1000); - for (int i = 1; i <= count; i++) result -= new Unum(_environment_3_5, i * 1000); + [Fact] + public void AdditionIsCorrectForIntegers() + { + var result = new Unum(_environment_3_5, 0); + var count = 100; - Assert.AreEqual(result.UnumBits, new Unum(_environment_3_5, 0).UnumBits); - } + for (int i = 1; i <= count; i++) result += new Unum(_environment_3_5, i * 1000); + for (int i = 1; i <= count; i++) result -= new Unum(_environment_3_5, i * 1000); - [Fact] - public void SubtractExactUnumsIsCorrect() - { - var bitMask1 = new BitMask(new uint[] { 0x7E012B }, 33); // 30.00390625 - var bitMask2 = new BitMask(new uint[] { 0xE40 }, 33); // 0.00390625 - var bitMask3 = new BitMask(new uint[] { 0x3F22 }, 33); // 30 + Assert.AreEqual(result.UnumBits, new Unum(_environment_3_5, 0).UnumBits); + } - var unum1 = new Unum(_environment_3_4, bitMask1); - var unum2 = new Unum(_environment_3_4, bitMask2); - var unum3 = Unum.SubtractExactUnums(unum1, unum2); - Assert.AreEqual(unum3.UnumBits, bitMask3); + [Fact] + public void SubtractExactUnumsIsCorrect() + { + var bitMask1 = new BitMask(new uint[] { 0x7E012B }, 33); // 30.00390625 + var bitMask2 = new BitMask(new uint[] { 0xE40 }, 33); // 0.00390625 + var bitMask3 = new BitMask(new uint[] { 0x3F22 }, 33); // 30 - var unum5000 = new Unum(_environment_3_4, 5000); - var unum6000 = new Unum(_environment_3_4, 6000); - var unum1000 = new Unum(_environment_3_4, 1000); + var unum1 = new Unum(_environment_3_4, bitMask1); + var unum2 = new Unum(_environment_3_4, bitMask2); + var unum3 = Unum.SubtractExactUnums(unum1, unum2); + Assert.AreEqual(unum3.UnumBits, bitMask3); - var unumRes = Unum.SubtractExactUnums(unum6000, unum5000); - Assert.AreEqual(unumRes.UnumBits, unum1000.UnumBits); + var unum5000 = new Unum(_environment_3_4, 5000); + var unum6000 = new Unum(_environment_3_4, 6000); + var unum1000 = new Unum(_environment_3_4, 1000); - var unum30 = new Unum(_environment_3_4, 30); - var unumZero = new Unum(_environment_3_4, 0); - Assert.AreEqual(Unum.SubtractExactUnums(unum30, unum30).UnumBits, unumZero.UnumBits); - } + var unumRes = Unum.SubtractExactUnums(unum6000, unum5000); + Assert.AreEqual(unumRes.UnumBits, unum1000.UnumBits); - [Fact] - public void IntToUnumIsCorrect() - { - var unum0 = new Unum(_environment_3_4, 0); - var bitMask0 = new BitMask(new uint[] { 0 }, 33); - Assert.AreEqual(unum0.UnumBits, bitMask0); + var unum30 = new Unum(_environment_3_4, 30); + var unumZero = new Unum(_environment_3_4, 0); + Assert.AreEqual(Unum.SubtractExactUnums(unum30, unum30).UnumBits, unumZero.UnumBits); + } - var unum1 = new Unum(_environment_3_4, 1); - Assert.AreEqual(unum1.UnumBits, new BitMask(new uint[] { 0x100 }, 33)); + [Fact] + public void IntToUnumIsCorrect() + { + var unum0 = new Unum(_environment_3_4, 0); + var bitMask0 = new BitMask(new uint[] { 0 }, 33); + Assert.AreEqual(unum0.UnumBits, bitMask0); - var unum2 = new Unum(_environment_3_4, 2); - Assert.AreEqual(unum2.UnumBits, new BitMask(new uint[] { 0x200 }, 33)); + var unum1 = new Unum(_environment_3_4, 1); + Assert.AreEqual(unum1.UnumBits, new BitMask(new uint[] { 0x100 }, 33)); - var unum30 = new Unum(_environment_3_4, 30); - var bitMask30 = new BitMask(new uint[] { 0x3F22 }, 33); - Assert.AreEqual(unum30.UnumBits, bitMask30); + var unum2 = new Unum(_environment_3_4, 2); + Assert.AreEqual(unum2.UnumBits, new BitMask(new uint[] { 0x200 }, 33)); - var unum1000 = new Unum(_environment_3_4, 1000); - var bitMask1000 = new BitMask(new uint[] { 0x63D45 }, 33); - Assert.AreEqual(unum1000.UnumBits, bitMask1000); + var unum30 = new Unum(_environment_3_4, 30); + var bitMask30 = new BitMask(new uint[] { 0x3F22 }, 33); + Assert.AreEqual(unum30.UnumBits, bitMask30); - var unum5000 = new Unum(_environment_3_4, 5000); - var bitMask5000 = new BitMask(new uint[] { 0x367148 }, 33); - Assert.AreEqual(unum5000.UnumBits, bitMask5000); + var unum1000 = new Unum(_environment_3_4, 1000); + var bitMask1000 = new BitMask(new uint[] { 0x63D45 }, 33); + Assert.AreEqual(unum1000.UnumBits, bitMask1000); - var bitMask6000 = new BitMask(new uint[] { 0x1B7747 }, 33); - var unum6000 = new Unum(_environment_3_4, 6000); - Assert.AreEqual(unum6000.UnumBits, bitMask6000); + var unum5000 = new Unum(_environment_3_4, 5000); + var bitMask5000 = new BitMask(new uint[] { 0x367148 }, 33); + Assert.AreEqual(unum5000.UnumBits, bitMask5000); - var unumNegative30 = new Unum(_environment_3_4, -30); - var bitMaskNegative30 = new BitMask(new uint[] { 0x3F22, 1 }, 33); - Assert.AreEqual(unumNegative30.UnumBits, bitMaskNegative30); + var bitMask6000 = new BitMask(new uint[] { 0x1B7747 }, 33); + var unum6000 = new Unum(_environment_3_4, 6000); + Assert.AreEqual(unum6000.UnumBits, bitMask6000); - var unumNegative1000 = new Unum(_environment_3_4, -1000); - var bitMaskNegative1000 = new BitMask(new uint[] { 0x63D45, 1 }, 33); - Assert.AreEqual(unumNegative1000.UnumBits, bitMaskNegative1000); - } + var unumNegative30 = new Unum(_environment_3_4, -30); + var bitMaskNegative30 = new BitMask(new uint[] { 0x3F22, 1 }, 33); + Assert.AreEqual(unumNegative30.UnumBits, bitMaskNegative30); - [Fact] - public void UnumToUintIsCorrect() - { - var unum1 = new Unum(_environment_3_4, 1); - var number1 = (uint)unum1; - Assert.AreEqual(number1, 1); + var unumNegative1000 = new Unum(_environment_3_4, -1000); + var bitMaskNegative1000 = new BitMask(new uint[] { 0x63D45, 1 }, 33); + Assert.AreEqual(unumNegative1000.UnumBits, bitMaskNegative1000); + } + + [Fact] + public void UnumToUintIsCorrect() + { + var unum1 = new Unum(_environment_3_4, 1); + var number1 = (uint)unum1; + Assert.AreEqual(number1, 1); - var unum2 = new Unum(_environment_3_4, 2); - var number2 = (uint)unum2; - Assert.AreEqual(number2, 2); + var unum2 = new Unum(_environment_3_4, 2); + var number2 = (uint)unum2; + Assert.AreEqual(number2, 2); - var unum30 = new Unum(_environment_3_4, 30); - var number30 = (uint)unum30; - Assert.AreEqual(number30, 30); + var unum30 = new Unum(_environment_3_4, 30); + var number30 = (uint)unum30; + Assert.AreEqual(number30, 30); - var unum1000 = new Unum(_environment_3_4, 1000); - var number1000 = (uint)unum1000; - Assert.AreEqual(number1000, 1000); + var unum1000 = new Unum(_environment_3_4, 1000); + var number1000 = (uint)unum1000; + Assert.AreEqual(number1000, 1000); - var unum5000 = new Unum(_environment_3_4, 5000); - var number5000 = (uint)unum5000; - Assert.AreEqual(number5000, 5000); + var unum5000 = new Unum(_environment_3_4, 5000); + var number5000 = (uint)unum5000; + Assert.AreEqual(number5000, 5000); - var unum6000 = new Unum(_environment_3_4, 6000); - var number6000 = (uint)unum6000; - Assert.AreEqual(number6000, 6000); - } + var unum6000 = new Unum(_environment_3_4, 6000); + var number6000 = (uint)unum6000; + Assert.AreEqual(number6000, 6000); + } - [Fact] - public void UnumToIntIsCorrect() - { - var unum1 = new Unum(_environment_3_4, 1); - var one = (int)unum1; - Assert.AreEqual(one, 1); + [Fact] + public void UnumToIntIsCorrect() + { + var unum1 = new Unum(_environment_3_4, 1); + var one = (int)unum1; + Assert.AreEqual(one, 1); - var unum30 = new Unum(_environment_3_4, 30); - var number30 = (int)unum30; - Assert.AreEqual(number30, 30); + var unum30 = new Unum(_environment_3_4, 30); + var number30 = (int)unum30; + Assert.AreEqual(number30, 30); - var unum1000 = new Unum(_environment_3_4, 1000); - var number1000 = (int)unum1000; - Assert.AreEqual(number1000, 1000); + var unum1000 = new Unum(_environment_3_4, 1000); + var number1000 = (int)unum1000; + Assert.AreEqual(number1000, 1000); - var unumNegative30 = new Unum(_environment_3_4, -30); - var numberNegative30 = (int)unumNegative30; - Assert.AreEqual(numberNegative30, -30); + var unumNegative30 = new Unum(_environment_3_4, -30); + var numberNegative30 = (int)unumNegative30; + Assert.AreEqual(numberNegative30, -30); - var unumNegative1000 = new Unum(_environment_3_4, -1000); - var numberNegative1000 = (int)unumNegative1000; - Assert.AreEqual(numberNegative1000, -1000); - } + var unumNegative1000 = new Unum(_environment_3_4, -1000); + var numberNegative1000 = (int)unumNegative1000; + Assert.AreEqual(numberNegative1000, -1000); + } - [Fact] - public void UnumToFloatIsCorrect() - { - var unum30 = new Unum(_environment_3_4, 30); - var numbe30 = (float)unum30; - Assert.AreEqual(numbe30, 30F); + [Fact] + public void UnumToFloatIsCorrect() + { + var unum30 = new Unum(_environment_3_4, 30); + var numbe30 = (float)unum30; + Assert.AreEqual(numbe30, 30F); - var unum1000 = new Unum(_environment_3_4, 1000); - var number1000 = (float)unum1000; - Assert.AreEqual(number1000, 1000); + var unum1000 = new Unum(_environment_3_4, 1000); + var number1000 = (float)unum1000; + Assert.AreEqual(number1000, 1000); - var unumNegative30 = new Unum(_environment_3_4, -30); - var numberNegative30 = (float)unumNegative30; - Assert.AreEqual(numberNegative30, -30); + var unumNegative30 = new Unum(_environment_3_4, -30); + var numberNegative30 = (float)unumNegative30; + Assert.AreEqual(numberNegative30, -30); - var unumNegative1000 = new Unum(_environment_3_4, -1000); - var numberNegative1000 = (float)unumNegative1000; - Assert.AreEqual(numberNegative1000, -1000); - } + var unumNegative1000 = new Unum(_environment_3_4, -1000); + var numberNegative1000 = (float)unumNegative1000; + Assert.AreEqual(numberNegative1000, -1000); } } diff --git a/Posit/Posit.cs b/Posit/Posit.cs index f9e62e4..861992d 100644 --- a/Posit/Posit.cs +++ b/Posit/Posit.cs @@ -1,406 +1,405 @@ using System.Diagnostics.CodeAnalysis; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +// signbit regime exponent(?) fraction(?) +public readonly struct Posit : System.IEquatable { - // signbit regime exponent(?) fraction(?) - public readonly struct Posit : System.IEquatable - { - private readonly PositEnvironment _environment; - public BitMask PositBits { get; } + private readonly PositEnvironment _environment; + public BitMask PositBits { get; } - #region Posit structure - public byte MaximumExponentSize => _environment.MaximumExponentSize; - public ushort Size => _environment.Size; - public uint Useed => _environment.Useed; - public ushort FirstRegimeBitIndex => _environment.FirstRegimeBitIndex; + #region Posit structure + public byte MaximumExponentSize => _environment.MaximumExponentSize; + public ushort Size => _environment.Size; + public uint Useed => _environment.Useed; + public ushort FirstRegimeBitIndex => _environment.FirstRegimeBitIndex; - #endregion + #endregion - #region Posit Masks + #region Posit Masks - public BitMask SignBitMask => _environment.SignBitMask; + public BitMask SignBitMask => _environment.SignBitMask; - public BitMask FirstRegimeBitBitMask => _environment.FirstRegimeBitBitMask; + public BitMask FirstRegimeBitBitMask => _environment.FirstRegimeBitBitMask; - public BitMask EmptyBitMask => _environment.EmptyBitMask; + public BitMask EmptyBitMask => _environment.EmptyBitMask; - public BitMask MaxValueBitMask => _environment.MaxValueBitMask; + public BitMask MaxValueBitMask => _environment.MaxValueBitMask; - public BitMask MinValueBitMask => _environment.MinValueBitMask; + public BitMask MinValueBitMask => _environment.MinValueBitMask; - public BitMask NaNBitMask => _environment.NaNBitMask; + public BitMask NaNBitMask => _environment.NaNBitMask; - #endregion + #endregion - #region Posit constructors + #region Posit constructors - public Posit(PositEnvironment environment) - { - _environment = environment; + public Posit(PositEnvironment environment) + { + _environment = environment; - PositBits = new BitMask(_environment.Size); - } + PositBits = new BitMask(_environment.Size); + } - public Posit(PositEnvironment environment, BitMask bits) - { - _environment = environment; + public Posit(PositEnvironment environment, BitMask bits) + { + _environment = environment; - PositBits = BitMask.FromImmutableArray(bits.Segments, _environment.Size); + PositBits = BitMask.FromImmutableArray(bits.Segments, _environment.Size); + } + + public Posit(PositEnvironment environment, uint value) + { + _environment = environment; + + PositBits = new BitMask(value, _environment.Size); + if (value == 0) return; + + var exponentValue = (uint)PositBits.FindMostSignificantOnePosition() - 1; + + ushort kValue = 0; + while (exponentValue >= 1 << environment.MaximumExponentSize && kValue < _environment.Size - 1) + { + exponentValue -= 1U << environment.MaximumExponentSize; + kValue++; } - public Posit(PositEnvironment environment, uint value) + PositBits = AssemblePositBitsWithRounding(signBit: false, kValue, new BitMask(exponentValue, 32), PositBits); + } + + public Posit(PositEnvironment environment, int value) + { + _environment = environment; + PositBits = value >= 0 ? new Posit(environment, (uint)value).PositBits : + new Posit(environment, (uint)-value).PositBits.GetTwosComplement(_environment.Size); + } + + #endregion + + #region Posit numeric states + + public bool IsPositive() => (PositBits & SignBitMask) == EmptyBitMask; + + public bool IsNaN() => PositBits == NaNBitMask; + + public bool IsZero() => PositBits == EmptyBitMask; + + #endregion + + #region Methods to handle parts of the Posit + + public BitMask EncodeRegimeBits(int regimeKValue) + { + BitMask regimeBits; + if (regimeKValue > 0) { - _environment = environment; + regimeBits = (new BitMask(1, _environment.Size) << (regimeKValue + 1)) - 1; + regimeBits <<= _environment.Size - regimeBits.FindMostSignificantOnePosition() - 1; + } + else + { + regimeBits = _environment.FirstRegimeBitBitMask << regimeKValue; + } - PositBits = new BitMask(value, _environment.Size); - if (value == 0) return; + return regimeBits; + } - var exponentValue = (uint)PositBits.FindMostSignificantOnePosition() - 1; + private BitMask AssemblePositBitsWithRounding(bool signBit, int regimeKValue, BitMask exponentBits, BitMask fractionBits) + { + // Calculating the regime. + var wholePosit = EncodeRegimeBits(regimeKValue); - ushort kValue = 0; - while (exponentValue >= 1 << environment.MaximumExponentSize && kValue < _environment.Size - 1) - { - exponentValue -= 1U << environment.MaximumExponentSize; - kValue++; - } + // Attaching the exponent. + var regimeLength = wholePosit.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)); + + var exponentShiftedLeftBy = Size - (regimeLength + 2) - MaximumExponentSize; + wholePosit += exponentBits << exponentShiftedLeftBy; - PositBits = AssemblePositBitsWithRounding(signBit: false, kValue, new BitMask(exponentValue, 32), PositBits); + // Calculating rounding. + if (exponentShiftedLeftBy < 0) + { + CaclulateRounding(exponentShiftedLeftBy, ref exponentBits, ref wholePosit); + return !signBit ? wholePosit : wholePosit.GetTwosComplement(_environment.Size); } - public Posit(PositEnvironment environment, int value) + var fractionMostSignificantOneIndex = fractionBits.FindMostSignificantOnePosition() - 1; + + // Hiding the hidden bit. (It is always one.) + fractionBits = fractionBits.SetZero((ushort)fractionMostSignificantOneIndex); + + var fractionShiftedLeftBy = _environment.Size - 2 - fractionMostSignificantOneIndex - regimeLength - + _environment.MaximumExponentSize; + // Attaching the fraction. + wholePosit += fractionBits << fractionShiftedLeftBy; + // Calculating rounding. + if (fractionShiftedLeftBy < 0) { - _environment = environment; - PositBits = value >= 0 ? new Posit(environment, (uint)value).PositBits : - new Posit(environment, (uint)-value).PositBits.GetTwosComplement(_environment.Size); + CaclulateRounding(fractionShiftedLeftBy, ref fractionBits, ref wholePosit); } - #endregion + return !signBit ? wholePosit : wholePosit.GetTwosComplement(_environment.Size); + } - #region Posit numeric states + public int GetRegimeKValue() + { + var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); + return (bits & FirstRegimeBitBitMask) == EmptyBitMask + ? -bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + : bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) - 1; + } - public bool IsPositive() => (PositBits & SignBitMask) == EmptyBitMask; + public int CalculateScaleFactor() + { + if (GetRegimeKValue() == -(Size - 1)) return 0; + return (int)((GetRegimeKValue() * (1 << MaximumExponentSize)) + GetExponentValue()); + } - public bool IsNaN() => PositBits == NaNBitMask; + public uint ExponentSize() + { + var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); + return Size - (bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + 2) > MaximumExponentSize + ? MaximumExponentSize : (uint)(Size - (bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + 2)); + } - public bool IsZero() => PositBits == EmptyBitMask; + public uint GetExponentValue() + { + var exponentMask = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); + exponentMask = (exponentMask >> (int)FractionSize()) + << (int)((PositBits.SegmentCount * 32) - ExponentSize()) + >> ((PositBits.SegmentCount * 32) - MaximumExponentSize); + return exponentMask.Lowest32Bits; + } + + public uint FractionSize() + { + var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); + var fractionSize = Size - (bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + 2 + MaximumExponentSize); + return fractionSize > 0 ? (uint)fractionSize : 0; + } - #endregion + #endregion + + #region Helper methods for operations and conversions + + public BitMask FractionWithHiddenBit() + { + var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); + var result = bits << (int)((PositBits.SegmentCount * 32) - FractionSize()) + >> (int)((PositBits.SegmentCount * 32) - FractionSize()); + return result.SetOne((ushort)FractionSize()); + } - #region Methods to handle parts of the Posit + public static int CalculateScaleFactor(int regimeKValue, uint exponentValue, byte maximumExponentSize) => + (int)((regimeKValue * (1 << maximumExponentSize)) + exponentValue); - public BitMask EncodeRegimeBits(int regimeKValue) + private static void CaclulateRounding(int shiftedLeftBy, ref BitMask bits, ref BitMask wholePosit) + { + bits <<= bits.Size + shiftedLeftBy; + if (bits >= new BitMask(bits.Size).SetOne((ushort)(bits.Size - 1))) { - BitMask regimeBits; - if (regimeKValue > 0) + if (bits == new BitMask(bits.Size).SetOne((ushort)(bits.Size - 1))) { - regimeBits = (new BitMask(1, _environment.Size) << (regimeKValue + 1)) - 1; - regimeBits <<= _environment.Size - regimeBits.FindMostSignificantOnePosition() - 1; + wholePosit += wholePosit.Lowest32Bits & 1; } else { - regimeBits = _environment.FirstRegimeBitBitMask << regimeKValue; + wholePosit += 1; } - - return regimeBits; } + } - private BitMask AssemblePositBitsWithRounding(bool signBit, int regimeKValue, BitMask exponentBits, BitMask fractionBits) - { - // Calculating the regime. - var wholePosit = EncodeRegimeBits(regimeKValue); - - // Attaching the exponent. - var regimeLength = wholePosit.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)); - - var exponentShiftedLeftBy = Size - (regimeLength + 2) - MaximumExponentSize; - wholePosit += exponentBits << exponentShiftedLeftBy; + #endregion - // Calculating rounding. - if (exponentShiftedLeftBy < 0) - { - CaclulateRounding(exponentShiftedLeftBy, ref exponentBits, ref wholePosit); - return !signBit ? wholePosit : wholePosit.GetTwosComplement(_environment.Size); - } + #region operators - var fractionMostSignificantOneIndex = fractionBits.FindMostSignificantOnePosition() - 1; + [SuppressMessage( + "Critical Code Smell", + "S3776:Cognitive Complexity of methods should not be too high", + Justification = "It's really not that bad.")] + public static Posit operator +(Posit left, Posit right) + { + var leftIsPositive = left.IsPositive(); + var rightIsPositive = right.IsPositive(); + var resultSignBit = (left.PositBits + right.PositBits).FindMostSignificantOnePosition() < left.PositBits.Size + ? !leftIsPositive + : !rightIsPositive; - // Hiding the hidden bit. (It is always one.) - fractionBits = fractionBits.SetZero((ushort)fractionMostSignificantOneIndex); + var signBitsMatch = leftIsPositive == rightIsPositive; - var fractionShiftedLeftBy = _environment.Size - 2 - fractionMostSignificantOneIndex - regimeLength - - _environment.MaximumExponentSize; - // Attaching the fraction. - wholePosit += fractionBits << fractionShiftedLeftBy; - // Calculating rounding. - if (fractionShiftedLeftBy < 0) - { - CaclulateRounding(fractionShiftedLeftBy, ref fractionBits, ref wholePosit); - } + int leftRegimeKValue; + uint leftExponentValue; + int rightRegimeKValue; + uint rightExponentValue; - return !signBit ? wholePosit : wholePosit.GetTwosComplement(_environment.Size); + if (!leftIsPositive) + { + var negatedLeft = -left; + leftRegimeKValue = negatedLeft.GetRegimeKValue(); + leftExponentValue = negatedLeft.GetExponentValue(); } - - public int GetRegimeKValue() + else { - var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); - return (bits & FirstRegimeBitBitMask) == EmptyBitMask - ? -bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) - : bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) - 1; + leftRegimeKValue = left.GetRegimeKValue(); + leftExponentValue = left.GetExponentValue(); } - public int CalculateScaleFactor() + if (!rightIsPositive) { - if (GetRegimeKValue() == -(Size - 1)) return 0; - return (int)((GetRegimeKValue() * (1 << MaximumExponentSize)) + GetExponentValue()); + var negatedRight = -right; + rightRegimeKValue = negatedRight.GetRegimeKValue(); + rightExponentValue = negatedRight.GetExponentValue(); } - - public uint ExponentSize() + else { - var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); - return Size - (bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + 2) > MaximumExponentSize - ? MaximumExponentSize : (uint)(Size - (bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + 2)); + rightRegimeKValue = right.GetRegimeKValue(); + rightExponentValue = right.GetExponentValue(); } - public uint GetExponentValue() + // Handling special cases first. + if (leftRegimeKValue == -(left.Size - 1)) { - var exponentMask = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); - exponentMask = (exponentMask >> (int)FractionSize()) - << (int)((PositBits.SegmentCount * 32) - ExponentSize()) - >> ((PositBits.SegmentCount * 32) - MaximumExponentSize); - return exponentMask.Lowest32Bits; + return leftIsPositive ? right : left; } - public uint FractionSize() + if (rightRegimeKValue == -(right.Size - 1)) { - var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); - var fractionSize = Size - (bits.LengthOfRunOfBits((ushort)(FirstRegimeBitIndex + 1)) + 2 + MaximumExponentSize); - return fractionSize > 0 ? (uint)fractionSize : 0; + return rightIsPositive ? left : right; } - #endregion + var resultFractionBits = new BitMask(left._environment.Size); // Later on the quire will be used here. - #region Helper methods for operations and conversions + var scaleFactorDifference = CalculateScaleFactor(leftRegimeKValue, leftExponentValue, left.MaximumExponentSize) + - CalculateScaleFactor(rightRegimeKValue, rightExponentValue, right.MaximumExponentSize); - public BitMask FractionWithHiddenBit() - { - var bits = IsPositive() ? PositBits : PositBits.GetTwosComplement(Size); - var result = bits << (int)((PositBits.SegmentCount * 32) - FractionSize()) - >> (int)((PositBits.SegmentCount * 32) - FractionSize()); - return result.SetOne((ushort)FractionSize()); - } + var scaleFactor = + scaleFactorDifference >= 0 + ? CalculateScaleFactor(leftRegimeKValue, leftExponentValue, left.MaximumExponentSize) + : CalculateScaleFactor(rightRegimeKValue, rightExponentValue, right.MaximumExponentSize); - public static int CalculateScaleFactor(int regimeKValue, uint exponentValue, byte maximumExponentSize) => - (int)((regimeKValue * (1 << maximumExponentSize)) + exponentValue); - - private static void CaclulateRounding(int shiftedLeftBy, ref BitMask bits, ref BitMask wholePosit) + if (scaleFactorDifference == 0) { - bits <<= bits.Size + shiftedLeftBy; - if (bits >= new BitMask(bits.Size).SetOne((ushort)(bits.Size - 1))) + if (signBitsMatch) { - if (bits == new BitMask(bits.Size).SetOne((ushort)(bits.Size - 1))) - { - wholePosit += wholePosit.Lowest32Bits & 1; - } - else - { - wholePosit += 1; - } + resultFractionBits += left.FractionWithHiddenBit() + right.FractionWithHiddenBit(); } - } - - #endregion - - #region operators - - [SuppressMessage( - "Critical Code Smell", - "S3776:Cognitive Complexity of methods should not be too high", - Justification = "It's really not that bad.")] - public static Posit operator +(Posit left, Posit right) - { - var leftIsPositive = left.IsPositive(); - var rightIsPositive = right.IsPositive(); - var resultSignBit = (left.PositBits + right.PositBits).FindMostSignificantOnePosition() < left.PositBits.Size - ? !leftIsPositive - : !rightIsPositive; - - var signBitsMatch = leftIsPositive == rightIsPositive; - - int leftRegimeKValue; - uint leftExponentValue; - int rightRegimeKValue; - uint rightExponentValue; - - if (!leftIsPositive) + else if (left.FractionWithHiddenBit() >= right.FractionWithHiddenBit()) { - var negatedLeft = -left; - leftRegimeKValue = negatedLeft.GetRegimeKValue(); - leftExponentValue = negatedLeft.GetExponentValue(); + resultFractionBits += left.FractionWithHiddenBit() - right.FractionWithHiddenBit(); } else { - leftRegimeKValue = left.GetRegimeKValue(); - leftExponentValue = left.GetExponentValue(); + resultFractionBits += right.FractionWithHiddenBit() - left.FractionWithHiddenBit(); } - if (!rightIsPositive) + scaleFactor += resultFractionBits.FindMostSignificantOnePosition() - + left.FractionWithHiddenBit().FindMostSignificantOnePosition(); + } + else if (scaleFactorDifference > 0) + { + // The scale factor of the left Posit is bigger. + var fractionSizeDifference = (int)(left.FractionSize() - right.FractionSize()); + resultFractionBits += left.FractionWithHiddenBit(); + var biggerPositMovedToLeft = left.Size - 1 - left.FractionWithHiddenBit().FindMostSignificantOnePosition(); + resultFractionBits <<= biggerPositMovedToLeft; + + var difference = right.FractionWithHiddenBit() << + (biggerPositMovedToLeft - scaleFactorDifference + fractionSizeDifference); + resultFractionBits = signBitsMatch + ? resultFractionBits + difference + : resultFractionBits - difference; + + scaleFactor += resultFractionBits.FindMostSignificantOnePosition() - (left.Size - 1); + } + else + { + // The scale factor of the right Posit is bigger. + var fractionSizeDifference = (int)(right.FractionSize() - left.FractionSize()); + resultFractionBits += right.FractionWithHiddenBit(); + var biggerPositMovedToLeft = right.Size - 1 - right.FractionWithHiddenBit().FindMostSignificantOnePosition(); + resultFractionBits <<= biggerPositMovedToLeft; + + if (signBitsMatch) { - var negatedRight = -right; - rightRegimeKValue = negatedRight.GetRegimeKValue(); - rightExponentValue = negatedRight.GetExponentValue(); + resultFractionBits += left.FractionWithHiddenBit() << + (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); } else { - rightRegimeKValue = right.GetRegimeKValue(); - rightExponentValue = right.GetExponentValue(); + resultFractionBits -= left.FractionWithHiddenBit() << + (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); } - // Handling special cases first. - if (leftRegimeKValue == -(left.Size - 1)) - { - return leftIsPositive ? right : left; - } + scaleFactor += resultFractionBits.FindMostSignificantOnePosition() - (right.Size - 1); + } - if (rightRegimeKValue == -(right.Size - 1)) - { - return rightIsPositive ? left : right; - } + if (resultFractionBits.FindMostSignificantOnePosition() == 0) return new Posit(left._environment, left.EmptyBitMask); - var resultFractionBits = new BitMask(left._environment.Size); // Later on the quire will be used here. + var resultRegimeKValue = scaleFactor / (1 << left.MaximumExponentSize); + var resultExponentBits = new BitMask((uint)(scaleFactor % (1 << left.MaximumExponentSize)), left._environment.Size); - var scaleFactorDifference = CalculateScaleFactor(leftRegimeKValue, leftExponentValue, left.MaximumExponentSize) - - CalculateScaleFactor(rightRegimeKValue, rightExponentValue, right.MaximumExponentSize); + return new Posit( + left._environment, + left.AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, resultExponentBits, resultFractionBits)); + } - var scaleFactor = - scaleFactorDifference >= 0 - ? CalculateScaleFactor(leftRegimeKValue, leftExponentValue, left.MaximumExponentSize) - : CalculateScaleFactor(rightRegimeKValue, rightExponentValue, right.MaximumExponentSize); + public static Posit operator +(Posit left, int right) => left + new Posit(left._environment, right); - if (scaleFactorDifference == 0) - { - if (signBitsMatch) - { - resultFractionBits += left.FractionWithHiddenBit() + right.FractionWithHiddenBit(); - } - else if (left.FractionWithHiddenBit() >= right.FractionWithHiddenBit()) - { - resultFractionBits += left.FractionWithHiddenBit() - right.FractionWithHiddenBit(); - } - else - { - resultFractionBits += right.FractionWithHiddenBit() - left.FractionWithHiddenBit(); - } - - scaleFactor += resultFractionBits.FindMostSignificantOnePosition() - - left.FractionWithHiddenBit().FindMostSignificantOnePosition(); - } - else if (scaleFactorDifference > 0) - { - // The scale factor of the left Posit is bigger. - var fractionSizeDifference = (int)(left.FractionSize() - right.FractionSize()); - resultFractionBits += left.FractionWithHiddenBit(); - var biggerPositMovedToLeft = left.Size - 1 - left.FractionWithHiddenBit().FindMostSignificantOnePosition(); - resultFractionBits <<= biggerPositMovedToLeft; - - var difference = right.FractionWithHiddenBit() << - (biggerPositMovedToLeft - scaleFactorDifference + fractionSizeDifference); - resultFractionBits = signBitsMatch - ? resultFractionBits + difference - : resultFractionBits - difference; - - scaleFactor += resultFractionBits.FindMostSignificantOnePosition() - (left.Size - 1); - } - else - { - // The scale factor of the right Posit is bigger. - var fractionSizeDifference = (int)(right.FractionSize() - left.FractionSize()); - resultFractionBits += right.FractionWithHiddenBit(); - var biggerPositMovedToLeft = right.Size - 1 - right.FractionWithHiddenBit().FindMostSignificantOnePosition(); - resultFractionBits <<= biggerPositMovedToLeft; - - if (signBitsMatch) - { - resultFractionBits += left.FractionWithHiddenBit() << - (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); - } - else - { - resultFractionBits -= left.FractionWithHiddenBit() << - (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); - } - - scaleFactor += resultFractionBits.FindMostSignificantOnePosition() - (right.Size - 1); - } - - if (resultFractionBits.FindMostSignificantOnePosition() == 0) return new Posit(left._environment, left.EmptyBitMask); + public static Posit operator -(Posit left, Posit right) => left + (-right); - var resultRegimeKValue = scaleFactor / (1 << left.MaximumExponentSize); - var resultExponentBits = new BitMask((uint)(scaleFactor % (1 << left.MaximumExponentSize)), left._environment.Size); + public static Posit operator -(Posit left, int right) => left - new Posit(left._environment, right); - return new Posit( - left._environment, - left.AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, resultExponentBits, resultFractionBits)); - } + public static Posit operator -(Posit x) + { + if (x.IsNaN() || x.IsZero()) return new Posit(x._environment, x.PositBits); + return new Posit(x._environment, x.PositBits.GetTwosComplement(x.Size)); + } - public static Posit operator +(Posit left, int right) => left + new Posit(left._environment, right); + public static bool operator ==(Posit left, Posit right) => left.PositBits == right.PositBits; - public static Posit operator -(Posit left, Posit right) => left + (-right); + public static bool operator >(Posit left, Posit right) + { + if (!left.IsPositive()) left = -left; + if (!right.IsPositive()) right = -right; + return (left.PositBits + right.PositBits).FindMostSignificantOnePosition() > left.PositBits.Size; + } - public static Posit operator -(Posit left, int right) => left - new Posit(left._environment, right); + public static bool operator <(Posit left, Posit right) => !(left.PositBits > right.PositBits); - public static Posit operator -(Posit x) - { - if (x.IsNaN() || x.IsZero()) return new Posit(x._environment, x.PositBits); - return new Posit(x._environment, x.PositBits.GetTwosComplement(x.Size)); - } + public static bool operator !=(Posit left, Posit right) => !(left == right); - public static bool operator ==(Posit left, Posit right) => left.PositBits == right.PositBits; + public static explicit operator int(Posit x) + { + uint result; - public static bool operator >(Posit left, Posit right) + // The posit fits into the range + if ((x.GetRegimeKValue() * (1 << x.MaximumExponentSize)) + x.GetExponentValue() + 1 < 31) { - if (!left.IsPositive()) left = -left; - if (!right.IsPositive()) right = -right; - return (left.PositBits + right.PositBits).FindMostSignificantOnePosition() > left.PositBits.Size; + result = (x.FractionWithHiddenBit() << ( + (int)((x.GetRegimeKValue() * (1 << x.MaximumExponentSize)) + x.GetExponentValue()) - + x.FractionWithHiddenBit().FindMostSignificantOnePosition() + + 1)) + .Lowest32Bits; } - - public static bool operator <(Posit left, Posit right) => !(left.PositBits > right.PositBits); - - public static bool operator !=(Posit left, Posit right) => !(left == right); - - public static explicit operator int(Posit x) + else { - uint result; - - // The posit fits into the range - if ((x.GetRegimeKValue() * (1 << x.MaximumExponentSize)) + x.GetExponentValue() + 1 < 31) - { - result = (x.FractionWithHiddenBit() << ( - (int)((x.GetRegimeKValue() * (1 << x.MaximumExponentSize)) + x.GetExponentValue()) - - x.FractionWithHiddenBit().FindMostSignificantOnePosition() + - 1)) - .Lowest32Bits; - } - else - { - return x.IsPositive() ? int.MaxValue : int.MinValue; - } - - return x.IsPositive() ? (int)result : (int)-result; + return x.IsPositive() ? int.MaxValue : int.MinValue; } - public override bool Equals(object obj) => obj is Posit other && this == other; + return x.IsPositive() ? (int)result : (int)-result; + } + + public override bool Equals(object obj) => obj is Posit other && this == other; - public bool Equals(Posit other) => this == other; + public bool Equals(Posit other) => this == other; - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - return ((_environment != null ? _environment.GetHashCode() : 0) * 397) ^ PositBits.GetHashCode(); - } + return ((_environment != null ? _environment.GetHashCode() : 0) * 397) ^ PositBits.GetHashCode(); } + } - #endregion + #endregion - } } diff --git a/Posit/Posit32.cs b/Posit/Posit32.cs index dd3facf..e0a69cf 100644 --- a/Posit/Posit32.cs +++ b/Posit/Posit32.cs @@ -3,1118 +3,1117 @@ using System.Globalization; using System.Runtime.CompilerServices; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +[SuppressMessage( + "Major Bug", + "S1244:Floating point numbers should not be tested for equality", + Justification = "Only test zero, should be exactly zero.")] +public readonly struct Posit32 : IComparable, IConvertible, IFormattable, IEquatable, IComparable { - [SuppressMessage( - "Major Bug", - "S1244:Floating point numbers should not be tested for equality", - Justification = "Only test zero, should be exactly zero.")] - public readonly struct Posit32 : IComparable, IConvertible, IFormattable, IEquatable, IComparable - { - public uint PositBits { get; } + public uint PositBits { get; } - #region Posit structure + #region Posit structure - public const byte MaximumExponentSize = 2; + public const byte MaximumExponentSize = 2; - public const byte Size = 32; + public const byte Size = 32; - public const byte Useed = 1 << (1 << MaximumExponentSize); + public const byte Useed = 1 << (1 << MaximumExponentSize); - public const byte FirstRegimeBitIndex = Size - 2; + public const byte FirstRegimeBitIndex = Size - 2; - public const byte FirstRegimeBitPosition = Size - 1; + public const byte FirstRegimeBitPosition = Size - 1; - public const byte SizeMinusFixedBits = Size - 4; + public const byte SizeMinusFixedBits = Size - 4; - public const short QuireSize = 512; + public const short QuireSize = 512; - #endregion + #endregion - #region Posit Masks + #region Posit Masks - public const uint SignBitMask = 1U << (Size - 1); + public const uint SignBitMask = 1U << (Size - 1); - public const uint FirstRegimeBitBitMask = 1U << (Size - 2); + public const uint FirstRegimeBitBitMask = 1U << (Size - 2); - public const uint EmptyBitMask = 0; + public const uint EmptyBitMask = 0; - public const uint MaxValueBitMask = uint.MaxValue; + public const uint MaxValueBitMask = uint.MaxValue; - public const uint MinValueBitMask = uint.MinValue; + public const uint MinValueBitMask = uint.MinValue; - public const uint NaNBitMask = SignBitMask; + public const uint NaNBitMask = SignBitMask; - public const uint Float32ExponentMask = 0x_7f80_0000; + public const uint Float32ExponentMask = 0x_7f80_0000; - public const uint Float32FractionMask = 0x_007f_ffff; + public const uint Float32FractionMask = 0x_007f_ffff; - public const uint Float32HiddenBitMask = 0x_0080_0000; + public const uint Float32HiddenBitMask = 0x_0080_0000; - public const ulong Double64FractionMask = 0x_000F_FFFF_FFFF_FFFF; + public const ulong Double64FractionMask = 0x_000F_FFFF_FFFF_FFFF; - public const ulong Double64ExponentMask = 0x_7FF0_0000_0000_0000; + public const ulong Double64ExponentMask = 0x_7FF0_0000_0000_0000; - public const ulong Double64HiddenBitMask = 0x_0010_0000_0000_0000; + public const ulong Double64HiddenBitMask = 0x_0010_0000_0000_0000; - #endregion + #endregion - #region Posit constructors + #region Posit constructors - public Posit32(uint bits, bool fromBitMask) => - PositBits = fromBitMask ? bits : new Posit32(bits).PositBits; + public Posit32(uint bits, bool fromBitMask) => + PositBits = fromBitMask ? bits : new Posit32(bits).PositBits; - public Posit32(Quire q) + public Posit32(Quire q) + { + PositBits = NaNBitMask; + var sign = false; + var positionOfMostSigniFicantOne = 511; + var firstSegment = (ulong)(q >> (QuireSize - 64)); + if (firstSegment >= 0x_8000_0000_0000_0000) { - PositBits = NaNBitMask; - var sign = false; - var positionOfMostSigniFicantOne = 511; - var firstSegment = (ulong)(q >> (QuireSize - 64)); - if (firstSegment >= 0x_8000_0000_0000_0000) - { - q = ~q; - q += 1; - sign = true; - } + q = ~q; + q += 1; + sign = true; + } + firstSegment = (ulong)(q >> (QuireSize - 64)); + while (firstSegment < 0x_8000_0000_0000_0000) + { + q <<= 1; + positionOfMostSigniFicantOne -= 1; firstSegment = (ulong)(q >> (QuireSize - 64)); - while (firstSegment < 0x_8000_0000_0000_0000) - { - q <<= 1; - positionOfMostSigniFicantOne -= 1; - firstSegment = (ulong)(q >> (QuireSize - 64)); - } - - var scaleFactor = positionOfMostSigniFicantOne - 240; - if (positionOfMostSigniFicantOne == 0) - { - PositBits = 0; - return; - } - - var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); - var resultExponentBits = (uint)(scaleFactor % (1 << MaximumExponentSize)); - if (resultExponentBits < 0) - { - resultRegimeKValue -= 1; - resultExponentBits += 1 << MaximumExponentSize; - } - - PositBits = AssemblePositBitsWithRounding(sign, resultRegimeKValue, resultExponentBits, (uint)(q >> (QuireSize - 32))); } - public Posit32(uint value) + var scaleFactor = positionOfMostSigniFicantOne - 240; + if (positionOfMostSigniFicantOne == 0) { - PositBits = value; - if (value == 0) return; + PositBits = 0; + return; + } - var exponentValue = (byte)(GetMostSignificantOnePosition(PositBits) - 1); + var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); + var resultExponentBits = (uint)(scaleFactor % (1 << MaximumExponentSize)); + if (resultExponentBits < 0) + { + resultRegimeKValue -= 1; + resultExponentBits += 1 << MaximumExponentSize; + } - byte kValue = 0; - while (exponentValue >= 1 << MaximumExponentSize && kValue < Size - 1) - { - exponentValue -= 1 << MaximumExponentSize; - kValue++; - } + PositBits = AssemblePositBitsWithRounding(sign, resultRegimeKValue, resultExponentBits, (uint)(q >> (QuireSize - 32))); + } - PositBits = AssemblePositBitsWithRounding(signBit: false, kValue, exponentValue, PositBits); - } + public Posit32(uint value) + { + PositBits = value; + if (value == 0) return; - public Posit32(int value) => - PositBits = value >= 0 - ? new Posit32((uint)value).PositBits - : GetTwosComplement(new Posit32((uint)-value).PositBits); + var exponentValue = (byte)(GetMostSignificantOnePosition(PositBits) - 1); - public Posit32(float floatBits) + byte kValue = 0; + while (exponentValue >= 1 << MaximumExponentSize && kValue < Size - 1) { - PositBits = NaNBitMask; - if (float.IsInfinity(floatBits) || float.IsNaN(floatBits)) - { - return; - } + exponentValue -= 1 << MaximumExponentSize; + kValue++; + } - if (floatBits == 0) - { - PositBits = 0; - return; - } + PositBits = AssemblePositBitsWithRounding(signBit: false, kValue, exponentValue, PositBits); + } - uint uintRepresentation; - unsafe - { - uint* floatPointer = (uint*)&floatBits; - uintRepresentation = *floatPointer; - } + public Posit32(int value) => + PositBits = value >= 0 + ? new Posit32((uint)value).PositBits + : GetTwosComplement(new Posit32((uint)-value).PositBits); - var signBit = (uintRepresentation & SignBitMask) != 0; - int scaleFactor = (int)((uintRepresentation << 1) >> 24) - 127; - var fractionBits = uintRepresentation & Float32FractionMask; + public Posit32(float floatBits) + { + PositBits = NaNBitMask; + if (float.IsInfinity(floatBits) || float.IsNaN(floatBits)) + { + return; + } - // Adding the hidden bit if it is one. - if (scaleFactor != -127) fractionBits += Float32HiddenBitMask; - else scaleFactor += 1; + if (floatBits == 0) + { + PositBits = 0; + return; + } - var regimeKValue = scaleFactor / (1 << MaximumExponentSize); - if (scaleFactor < 0) regimeKValue--; + uint uintRepresentation; + unsafe + { + uint* floatPointer = (uint*)&floatBits; + uintRepresentation = *floatPointer; + } - var exponentValue = (uint)(scaleFactor - (regimeKValue * (1 << MaximumExponentSize))); - if (exponentValue == 1 << MaximumExponentSize) - { - regimeKValue += 1; - exponentValue = 0; - } + var signBit = (uintRepresentation & SignBitMask) != 0; + int scaleFactor = (int)((uintRepresentation << 1) >> 24) - 127; + var fractionBits = uintRepresentation & Float32FractionMask; - if (regimeKValue < -(Size - 2)) - { - regimeKValue = -(Size - 2); - exponentValue = 0; - } + // Adding the hidden bit if it is one. + if (scaleFactor != -127) fractionBits += Float32HiddenBitMask; + else scaleFactor += 1; - if (regimeKValue > (Size - 2)) - { - regimeKValue = Size - 2; - exponentValue = 0; - } + var regimeKValue = scaleFactor / (1 << MaximumExponentSize); + if (scaleFactor < 0) regimeKValue--; - PositBits = AssemblePositBitsWithRounding(signBit, regimeKValue, exponentValue, fractionBits); + var exponentValue = (uint)(scaleFactor - (regimeKValue * (1 << MaximumExponentSize))); + if (exponentValue == 1 << MaximumExponentSize) + { + regimeKValue += 1; + exponentValue = 0; } - public Posit32(double doubleBits) + if (regimeKValue < -(Size - 2)) { - PositBits = NaNBitMask; - if (double.IsInfinity(doubleBits) || double.IsNaN(doubleBits)) - { - return; - } + regimeKValue = -(Size - 2); + exponentValue = 0; + } - if (doubleBits == 0) - { - PositBits = 0; - return; - } + if (regimeKValue > (Size - 2)) + { + regimeKValue = Size - 2; + exponentValue = 0; + } - ulong ulongRepresentation; - unsafe - { - ulong* doublePointer = (ulong*)&doubleBits; - ulongRepresentation = *doublePointer; - } + PositBits = AssemblePositBitsWithRounding(signBit, regimeKValue, exponentValue, fractionBits); + } - var signBit = (ulongRepresentation & ((ulong)SignBitMask << 32)) != 0; - int scaleFactor = (int)((ulongRepresentation << 1) >> 53) - 1_023; - uint fractionBits = (uint)((ulongRepresentation & Double64FractionMask) >> 21); + public Posit32(double doubleBits) + { + PositBits = NaNBitMask; + if (double.IsInfinity(doubleBits) || double.IsNaN(doubleBits)) + { + return; + } - // Adding the hidden bit if it is one. - if (scaleFactor != -1_023) fractionBits += (uint)(Double64HiddenBitMask >> 21); - else scaleFactor += 1; + if (doubleBits == 0) + { + PositBits = 0; + return; + } - var regimeKValue = scaleFactor / (1 << MaximumExponentSize); - if (scaleFactor < 0) regimeKValue--; + ulong ulongRepresentation; + unsafe + { + ulong* doublePointer = (ulong*)&doubleBits; + ulongRepresentation = *doublePointer; + } - var exponentValue = (uint)(scaleFactor - (regimeKValue * (1 << MaximumExponentSize))); - if (exponentValue == 1 << MaximumExponentSize) - { - regimeKValue += 1; - exponentValue = 0; - } + var signBit = (ulongRepresentation & ((ulong)SignBitMask << 32)) != 0; + int scaleFactor = (int)((ulongRepresentation << 1) >> 53) - 1_023; + uint fractionBits = (uint)((ulongRepresentation & Double64FractionMask) >> 21); - if (regimeKValue < -(Size - 2)) - { - regimeKValue = -(Size - 2); - exponentValue = 0; - } + // Adding the hidden bit if it is one. + if (scaleFactor != -1_023) fractionBits += (uint)(Double64HiddenBitMask >> 21); + else scaleFactor += 1; - if (regimeKValue > (Size - 2)) - { - regimeKValue = Size - 2; - exponentValue = 0; - } + var regimeKValue = scaleFactor / (1 << MaximumExponentSize); + if (scaleFactor < 0) regimeKValue--; - PositBits = AssemblePositBitsWithRounding(signBit, regimeKValue, exponentValue, fractionBits); + var exponentValue = (uint)(scaleFactor - (regimeKValue * (1 << MaximumExponentSize))); + if (exponentValue == 1 << MaximumExponentSize) + { + regimeKValue += 1; + exponentValue = 0; } - #endregion - - #region Posit numeric states - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsPositive() => (PositBits & SignBitMask) == EmptyBitMask; + if (regimeKValue < -(Size - 2)) + { + regimeKValue = -(Size - 2); + exponentValue = 0; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsNaN() => PositBits == NaNBitMask; + if (regimeKValue > (Size - 2)) + { + regimeKValue = Size - 2; + exponentValue = 0; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsZero() => PositBits == EmptyBitMask; + PositBits = AssemblePositBitsWithRounding(signBit, regimeKValue, exponentValue, fractionBits); + } - #endregion + #endregion - #region Methods to handle parts of the Posit + #region Posit numeric states - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint EncodeRegimeBits(int regimeKValue) - { - uint regimeBits; - if (regimeKValue > 0) - { - regimeBits = (uint)(1 << (regimeKValue + 1)) - 1; - regimeBits <<= Size - GetMostSignificantOnePosition(regimeBits) - 1; - } - else - { - regimeBits = FirstRegimeBitBitMask >> -regimeKValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsPositive() => (PositBits & SignBitMask) == EmptyBitMask; - return regimeBits; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsNaN() => PositBits == NaNBitMask; - [SuppressMessage( - "Critical Code Smell", - "S3776:Cognitive Complexity of methods should not be too high", - Justification = "It's not so complicated.")] - public static uint AssemblePositBitsWithRounding(bool signBit, int regimeKValue, uint exponentBits, uint fractionBits) - { - // Calculating the regime. - var wholePosit = EncodeRegimeBits(regimeKValue); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsZero() => PositBits == EmptyBitMask; - // Attaching the exponent. - var regimeLength = LengthOfRunOfBits(wholePosit, FirstRegimeBitPosition); + #endregion - var exponentShiftedLeftBy = (sbyte)SizeMinusFixedBits - regimeLength; - wholePosit += exponentShiftedLeftBy >= 0 ? exponentBits << exponentShiftedLeftBy : exponentBits >> -exponentShiftedLeftBy; + #region Methods to handle parts of the Posit - // Calculating rounding. - if (exponentShiftedLeftBy < 0) - { - if (exponentShiftedLeftBy <= SizeMinusFixedBits) exponentBits <<= Size + exponentShiftedLeftBy; - else exponentBits >>= Size + exponentShiftedLeftBy; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint EncodeRegimeBits(int regimeKValue) + { + uint regimeBits; + if (regimeKValue > 0) + { + regimeBits = (uint)(1 << (regimeKValue + 1)) - 1; + regimeBits <<= Size - GetMostSignificantOnePosition(regimeBits) - 1; + } + else + { + regimeBits = FirstRegimeBitBitMask >> -regimeKValue; + } - if (exponentBits < SignBitMask) return signBit ? GetTwosComplement(wholePosit) : wholePosit; + return regimeBits; + } - if (exponentBits == SignBitMask) wholePosit += wholePosit & 1; - else wholePosit += 1; + [SuppressMessage( + "Critical Code Smell", + "S3776:Cognitive Complexity of methods should not be too high", + Justification = "It's not so complicated.")] + public static uint AssemblePositBitsWithRounding(bool signBit, int regimeKValue, uint exponentBits, uint fractionBits) + { + // Calculating the regime. + var wholePosit = EncodeRegimeBits(regimeKValue); - return signBit ? GetTwosComplement(wholePosit) : wholePosit; - } + // Attaching the exponent. + var regimeLength = LengthOfRunOfBits(wholePosit, FirstRegimeBitPosition); - var fractionMostSignificantOneIndex = GetMostSignificantOnePosition(fractionBits) - 1; + var exponentShiftedLeftBy = (sbyte)SizeMinusFixedBits - regimeLength; + wholePosit += exponentShiftedLeftBy >= 0 ? exponentBits << exponentShiftedLeftBy : exponentBits >> -exponentShiftedLeftBy; - // Hiding the hidden bit. (It is always one.) - fractionBits = SetZero(fractionBits, (ushort)fractionMostSignificantOneIndex); + // Calculating rounding. + if (exponentShiftedLeftBy < 0) + { + if (exponentShiftedLeftBy <= SizeMinusFixedBits) exponentBits <<= Size + exponentShiftedLeftBy; + else exponentBits >>= Size + exponentShiftedLeftBy; - var fractionShiftedLeftBy = SizeMinusFixedBits - fractionMostSignificantOneIndex - regimeLength; - // Attaching the fraction. - wholePosit += fractionShiftedLeftBy >= 0 ? fractionBits << fractionShiftedLeftBy : fractionBits >> -fractionShiftedLeftBy; - // Calculating rounding. - if (fractionShiftedLeftBy < 0) - { - if (Size + fractionShiftedLeftBy >= 0) fractionBits <<= Size + fractionShiftedLeftBy; - else fractionBits >>= -(Size - fractionShiftedLeftBy); + if (exponentBits < SignBitMask) return signBit ? GetTwosComplement(wholePosit) : wholePosit; - if (fractionBits >= SignBitMask) - { - wholePosit += fractionBits == SignBitMask ? wholePosit & 1 : 1; - } - } + if (exponentBits == SignBitMask) wholePosit += wholePosit & 1; + else wholePosit += 1; return signBit ? GetTwosComplement(wholePosit) : wholePosit; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public sbyte GetRegimeKValue() + var fractionMostSignificantOneIndex = GetMostSignificantOnePosition(fractionBits) - 1; + + // Hiding the hidden bit. (It is always one.) + fractionBits = SetZero(fractionBits, (ushort)fractionMostSignificantOneIndex); + + var fractionShiftedLeftBy = SizeMinusFixedBits - fractionMostSignificantOneIndex - regimeLength; + // Attaching the fraction. + wholePosit += fractionShiftedLeftBy >= 0 ? fractionBits << fractionShiftedLeftBy : fractionBits >> -fractionShiftedLeftBy; + // Calculating rounding. + if (fractionShiftedLeftBy < 0) { - var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); - var lengthOfRunOfBits = LengthOfRunOfBits(bits, FirstRegimeBitPosition); + if (Size + fractionShiftedLeftBy >= 0) fractionBits <<= Size + fractionShiftedLeftBy; + else fractionBits >>= -(Size - fractionShiftedLeftBy); - return (bits & FirstRegimeBitBitMask) == EmptyBitMask - ? (sbyte)-lengthOfRunOfBits - : (sbyte)(lengthOfRunOfBits - 1); + if (fractionBits >= SignBitMask) + { + wholePosit += fractionBits == SignBitMask ? wholePosit & 1 : 1; + } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public sbyte GetRegimeKValueWithoutSignCheck(byte lengthOfRunOfBits) => - (PositBits & FirstRegimeBitBitMask) == EmptyBitMask - ? (sbyte)-lengthOfRunOfBits - : (sbyte)(lengthOfRunOfBits - 1); + return signBit ? GetTwosComplement(wholePosit) : wholePosit; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public short CalculateScaleFactor() - { - var regimeKvalue = GetRegimeKValue(); - return (regimeKvalue == -FirstRegimeBitPosition) ? (short)0 : (short)((regimeKvalue * (1 << MaximumExponentSize)) + GetExponentValue()); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte GetRegimeKValue() + { + var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); + var lengthOfRunOfBits = LengthOfRunOfBits(bits, FirstRegimeBitPosition); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte ExponentSize() - { - var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); - var lengthOfRunOfBits = LengthOfRunOfBits(bits, FirstRegimeBitPosition); - var result = (byte)(Size - lengthOfRunOfBits - 1); + return (bits & FirstRegimeBitBitMask) == EmptyBitMask + ? (sbyte)-lengthOfRunOfBits + : (sbyte)(lengthOfRunOfBits - 1); + } - if (lengthOfRunOfBits + 2 <= Size) - { - result = Size - (lengthOfRunOfBits + 2) > MaximumExponentSize - ? MaximumExponentSize - : (byte)(Size - (lengthOfRunOfBits + 2)); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public sbyte GetRegimeKValueWithoutSignCheck(byte lengthOfRunOfBits) => + (PositBits & FirstRegimeBitBitMask) == EmptyBitMask + ? (sbyte)-lengthOfRunOfBits + : (sbyte)(lengthOfRunOfBits - 1); - return result; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public short CalculateScaleFactor() + { + var regimeKvalue = GetRegimeKValue(); + return (regimeKvalue == -FirstRegimeBitPosition) ? (short)0 : (short)((regimeKvalue * (1 << MaximumExponentSize)) + GetExponentValue()); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte ExponentSizeWithoutSignCheck() - { - var lengthOfRunOfBits = LengthOfRunOfBits(PositBits, FirstRegimeBitPosition); - return Size - (lengthOfRunOfBits + 2) > MaximumExponentSize - ? MaximumExponentSize : (byte)(Size - (lengthOfRunOfBits + 2)); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte ExponentSize() + { + var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); + var lengthOfRunOfBits = LengthOfRunOfBits(bits, FirstRegimeBitPosition); + var result = (byte)(Size - lengthOfRunOfBits - 1); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint GetExponentValue() + if (lengthOfRunOfBits + 2 <= Size) { - var exponentMask = IsPositive() ? PositBits : GetTwosComplement(PositBits); - var exponentSize = ExponentSize(); - exponentMask = (exponentMask >> (int)FractionSize()) - << (Size - exponentSize) - >> (Size - MaximumExponentSize); - return exponentSize == 0 ? 0 : exponentMask; + result = Size - (lengthOfRunOfBits + 2) > MaximumExponentSize + ? MaximumExponentSize + : (byte)(Size - (lengthOfRunOfBits + 2)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint GetExponentValueWithoutSignCheck() => - (PositBits >> (int)FractionSizeWithoutSignCheck()) << (Size - ExponentSize()) >> (Size - MaximumExponentSize); + return result; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint GetExponentValueWithoutSignCheck(uint fractionSize) => - (PositBits >> (int)fractionSize) << (Size - ExponentSize()) >> (Size - MaximumExponentSize); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte ExponentSizeWithoutSignCheck() + { + var lengthOfRunOfBits = LengthOfRunOfBits(PositBits, FirstRegimeBitPosition); + return Size - (lengthOfRunOfBits + 2) > MaximumExponentSize + ? MaximumExponentSize : (byte)(Size - (lengthOfRunOfBits + 2)); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FractionSize() - { - var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); - var fractionSize = Size - (LengthOfRunOfBits(bits, FirstRegimeBitPosition) + 2 + MaximumExponentSize); - return fractionSize > 0 ? (uint)fractionSize : 0; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetExponentValue() + { + var exponentMask = IsPositive() ? PositBits : GetTwosComplement(PositBits); + var exponentSize = ExponentSize(); + exponentMask = (exponentMask >> (int)FractionSize()) + << (Size - exponentSize) + >> (Size - MaximumExponentSize); + return exponentSize == 0 ? 0 : exponentMask; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FractionSizeWithoutSignCheck() - { - var fractionSize = Size - (LengthOfRunOfBits(PositBits, FirstRegimeBitPosition) + 2 + MaximumExponentSize); - return fractionSize > 0 ? (uint)fractionSize : 0; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetExponentValueWithoutSignCheck() => + (PositBits >> (int)FractionSizeWithoutSignCheck()) << (Size - ExponentSize()) >> (Size - MaximumExponentSize); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint FractionSizeWithoutSignCheck(byte lengthOfRunOfBits) - { - var fractionSize = Size - (lengthOfRunOfBits + 2 + MaximumExponentSize); - return fractionSize > 0 ? (uint)fractionSize : 0; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetExponentValueWithoutSignCheck(uint fractionSize) => + (PositBits >> (int)fractionSize) << (Size - ExponentSize()) >> (Size - MaximumExponentSize); - #endregion + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint FractionSize() + { + var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); + var fractionSize = Size - (LengthOfRunOfBits(bits, FirstRegimeBitPosition) + 2 + MaximumExponentSize); + return fractionSize > 0 ? (uint)fractionSize : 0; + } - #region Helper methods for operations and conversions + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint FractionSizeWithoutSignCheck() + { + var fractionSize = Size - (LengthOfRunOfBits(PositBits, FirstRegimeBitPosition) + 2 + MaximumExponentSize); + return fractionSize > 0 ? (uint)fractionSize : 0; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint Fraction() - { - var fractionSize = FractionSize(); - var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); - return bits << (int)(Size - fractionSize) - >> (int)(Size - fractionSize); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint FractionSizeWithoutSignCheck(byte lengthOfRunOfBits) + { + var fractionSize = Size - (lengthOfRunOfBits + 2 + MaximumExponentSize); + return fractionSize > 0 ? (uint)fractionSize : 0; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FractionWithHiddenBit() - { - var fractionSize = FractionSize(); - var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); - var result = bits << (int)(Size - fractionSize) - >> (int)(Size - fractionSize); - return fractionSize == 0 ? 1 : SetOne(result, (ushort)fractionSize); - } + #endregion - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FractionWithHiddenBit(uint fractionSize) - { - var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); - var result = bits << (int)(Size - fractionSize) - >> (int)(Size - fractionSize); - return SetOne(result, (ushort)fractionSize); - } + #region Helper methods for operations and conversions - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FractionWithHiddenBitWithoutSignCheck() - { - var fractionSizeWithoutSignCheck = FractionSizeWithoutSignCheck(); - var result = PositBits << (int)(Size - fractionSizeWithoutSignCheck) - >> (int)(Size - fractionSizeWithoutSignCheck); - return SetOne(result, (ushort)fractionSizeWithoutSignCheck); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint Fraction() + { + var fractionSize = FractionSize(); + var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); + return bits << (int)(Size - fractionSize) + >> (int)(Size - fractionSize); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint FractionWithHiddenBitWithoutSignCheck(uint fractionSize) - { - var numberOfNonFractionBits = (int)(Size - fractionSize); - var result = PositBits << numberOfNonFractionBits - >> numberOfNonFractionBits; - return SetOne(result, (ushort)fractionSize); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint FractionWithHiddenBit() + { + var fractionSize = FractionSize(); + var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); + var result = bits << (int)(Size - fractionSize) + >> (int)(Size - fractionSize); + return fractionSize == 0 ? 1 : SetOne(result, (ushort)fractionSize); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static short CalculateScaleFactor(sbyte regimeKValue, uint exponentValue, byte maximumExponentSize) => - (short)((regimeKValue * (1 << maximumExponentSize)) + exponentValue); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint FractionWithHiddenBit(uint fractionSize) + { + var bits = IsPositive() ? PositBits : GetTwosComplement(PositBits); + var result = bits << (int)(Size - fractionSize) + >> (int)(Size - fractionSize); + return SetOne(result, (ushort)fractionSize); + } - public static Quire MultiplyIntoQuire(Posit32 left, Posit32 right) - { - if (left.IsZero() || right.IsZero()) return new Quire((ushort)QuireSize); - if (left.IsNaN() || right.IsNaN()) return new Quire(1, (ushort)QuireSize) << (QuireSize - 1); - var leftIsPositive = left.IsPositive(); - var rightIsPositive = right.IsPositive(); - var resultSignBit = leftIsPositive != rightIsPositive; - - left = Abs(left); - right = Abs(right); - var leftFractionSize = left.FractionSizeWithoutSignCheck(); - var rightFractionSize = right.FractionSizeWithoutSignCheck(); - - var longResultFractionBits = left.FractionWithHiddenBitWithoutSignCheck() * - (ulong)right.FractionWithHiddenBitWithoutSignCheck(); - var fractionSizeChange = GetMostSignificantOnePosition(longResultFractionBits) - (leftFractionSize + rightFractionSize + 1); - var scaleFactor = - CalculateScaleFactor(left.GetRegimeKValue(), left.GetExponentValue(), MaximumExponentSize) + - CalculateScaleFactor(right.GetRegimeKValue(), right.GetExponentValue(), MaximumExponentSize); - - scaleFactor += (int)fractionSizeChange; - - var quireArray = new ulong[QuireSize / 64]; - quireArray[0] = longResultFractionBits; - var resultQuire = new Quire(quireArray); - resultQuire <<= 240 - GetMostSignificantOnePosition(longResultFractionBits) + 1 + scaleFactor; - - return !resultSignBit ? resultQuire : (~resultQuire) + 1; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint FractionWithHiddenBitWithoutSignCheck() + { + var fractionSizeWithoutSignCheck = FractionSizeWithoutSignCheck(); + var result = PositBits << (int)(Size - fractionSizeWithoutSignCheck) + >> (int)(Size - fractionSizeWithoutSignCheck); + return SetOne(result, (ushort)fractionSizeWithoutSignCheck); + } - #endregion + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint FractionWithHiddenBitWithoutSignCheck(uint fractionSize) + { + var numberOfNonFractionBits = (int)(Size - fractionSize); + var result = PositBits << numberOfNonFractionBits + >> numberOfNonFractionBits; + return SetOne(result, (ushort)fractionSize); + } - #region Bit level Helper Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static short CalculateScaleFactor(sbyte regimeKValue, uint exponentValue, byte maximumExponentSize) => + (short)((regimeKValue * (1 << maximumExponentSize)) + exponentValue); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte GetMostSignificantOnePosition(uint bits) - { - byte position = 0; - while (bits != 0) - { - bits >>= 1; - position++; - } + public static Quire MultiplyIntoQuire(Posit32 left, Posit32 right) + { + if (left.IsZero() || right.IsZero()) return new Quire((ushort)QuireSize); + if (left.IsNaN() || right.IsNaN()) return new Quire(1, (ushort)QuireSize) << (QuireSize - 1); + var leftIsPositive = left.IsPositive(); + var rightIsPositive = right.IsPositive(); + var resultSignBit = leftIsPositive != rightIsPositive; + + left = Abs(left); + right = Abs(right); + var leftFractionSize = left.FractionSizeWithoutSignCheck(); + var rightFractionSize = right.FractionSizeWithoutSignCheck(); + + var longResultFractionBits = left.FractionWithHiddenBitWithoutSignCheck() * + (ulong)right.FractionWithHiddenBitWithoutSignCheck(); + var fractionSizeChange = GetMostSignificantOnePosition(longResultFractionBits) - (leftFractionSize + rightFractionSize + 1); + var scaleFactor = + CalculateScaleFactor(left.GetRegimeKValue(), left.GetExponentValue(), MaximumExponentSize) + + CalculateScaleFactor(right.GetRegimeKValue(), right.GetExponentValue(), MaximumExponentSize); + + scaleFactor += (int)fractionSizeChange; + + var quireArray = new ulong[QuireSize / 64]; + quireArray[0] = longResultFractionBits; + var resultQuire = new Quire(quireArray); + resultQuire <<= 240 - GetMostSignificantOnePosition(longResultFractionBits) + 1 + scaleFactor; + + return !resultSignBit ? resultQuire : (~resultQuire) + 1; + } - return position; - } + #endregion - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte GetMostSignificantOnePosition(ulong bits) - { - byte position = 0; - while (bits != 0) - { - bits >>= 1; - position++; - } + #region Bit level Helper Methods - return position; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte GetMostSignificantOnePosition(uint bits) + { + byte position = 0; + while (bits != 0) + { + bits >>= 1; + position++; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Posit32 Abs(Posit32 input) + return position; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte GetMostSignificantOnePosition(ulong bits) + { + byte position = 0; + while (bits != 0) { - var signBit = input.PositBits >> (Size - 1); - var maskOfSignBits = 0 - signBit; - return new Posit32((input.PositBits ^ maskOfSignBits) + signBit, fromBitMask: true); + bits >>= 1; + position++; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SetOne(uint bits, ushort index) => bits | (uint)(1 << index); + return position; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Posit32 Abs(Posit32 input) + { + var signBit = input.PositBits >> (Size - 1); + var maskOfSignBits = 0 - signBit; + return new Posit32((input.PositBits ^ maskOfSignBits) + signBit, fromBitMask: true); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SetOne(uint bits, ushort index) => bits | (uint)(1 << index); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint SetZero(uint bits, ushort index) => bits & (uint)~(1 << index); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SetZero(uint bits, ushort index) => bits & (uint)~(1 << index); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte LengthOfRunOfBits(uint bits, byte startingPosition) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte LengthOfRunOfBits(uint bits, byte startingPosition) + { + byte length = 1; + bits <<= Size - startingPosition; + var startingBit = (bits >> 31) & 1; + bits <<= 1; + for (var i = 0; i < startingPosition && bits >> 31 == startingBit; i++) { - byte length = 1; - bits <<= Size - startingPosition; - var startingBit = (bits >> 31) & 1; bits <<= 1; - for (var i = 0; i < startingPosition && bits >> 31 == startingBit; i++) - { - bits <<= 1; - length++; - } - - return length; + length++; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint GetTwosComplement(uint bits) => ~bits + 1; + return length; + } - #endregion + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint GetTwosComplement(uint bits) => ~bits + 1; - #region Algebraic functions + #endregion - public static Posit32 Sqrt(Posit32 number) - { - if (number.IsNaN() || number.IsZero()) return number; - if (!number.IsPositive()) return new Posit32(NaNBitMask, fromBitMask: true); + #region Algebraic functions - var inputScaleFactor = number.CalculateScaleFactor(); - var inputFractionWithHiddenBit = number.FractionWithHiddenBitWithoutSignCheck(); + public static Posit32 Sqrt(Posit32 number) + { + if (number.IsNaN() || number.IsZero()) return number; + if (!number.IsPositive()) return new Posit32(NaNBitMask, fromBitMask: true); - if ((inputScaleFactor & 1) != 0) - { - // if the scaleFactor is odd, shift the number to make it even - inputScaleFactor -= 1; - inputFractionWithHiddenBit += inputFractionWithHiddenBit; - } + var inputScaleFactor = number.CalculateScaleFactor(); + var inputFractionWithHiddenBit = number.FractionWithHiddenBitWithoutSignCheck(); - inputScaleFactor >>= 1; + if ((inputScaleFactor & 1) != 0) + { + // if the scaleFactor is odd, shift the number to make it even + inputScaleFactor -= 1; + inputFractionWithHiddenBit += inputFractionWithHiddenBit; + } - uint resultFractionBits = 0; - uint startingEstimate = 0; - uint temporaryEstimate; - uint estimateMaskingBit = 1U << (int)number.FractionSizeWithoutSignCheck(); + inputScaleFactor >>= 1; - while (estimateMaskingBit != 0) - { - temporaryEstimate = startingEstimate + estimateMaskingBit; - if (temporaryEstimate <= inputFractionWithHiddenBit) - { - startingEstimate = temporaryEstimate + estimateMaskingBit; - inputFractionWithHiddenBit -= temporaryEstimate; - resultFractionBits += estimateMaskingBit; - } - - inputFractionWithHiddenBit += inputFractionWithHiddenBit; - estimateMaskingBit >>= 1; - } + uint resultFractionBits = 0; + uint startingEstimate = 0; + uint temporaryEstimate; + uint estimateMaskingBit = 1U << (int)number.FractionSizeWithoutSignCheck(); - var resultRegimeKValue = inputScaleFactor / (1 << MaximumExponentSize); - var resultExponentBits = inputScaleFactor % (1 << MaximumExponentSize); - if (resultExponentBits < 0) + while (estimateMaskingBit != 0) + { + temporaryEstimate = startingEstimate + estimateMaskingBit; + if (temporaryEstimate <= inputFractionWithHiddenBit) { - resultRegimeKValue -= 1; - resultExponentBits += 1 << MaximumExponentSize; + startingEstimate = temporaryEstimate + estimateMaskingBit; + inputFractionWithHiddenBit -= temporaryEstimate; + resultFractionBits += estimateMaskingBit; } - return new Posit32( - AssemblePositBitsWithRounding(signBit: false, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), - fromBitMask: true); + inputFractionWithHiddenBit += inputFractionWithHiddenBit; + estimateMaskingBit >>= 1; } - #endregion + var resultRegimeKValue = inputScaleFactor / (1 << MaximumExponentSize); + var resultExponentBits = inputScaleFactor % (1 << MaximumExponentSize); + if (resultExponentBits < 0) + { + resultRegimeKValue -= 1; + resultExponentBits += 1 << MaximumExponentSize; + } - #region Fused operations + return new Posit32( + AssemblePositBitsWithRounding(signBit: false, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), + fromBitMask: true); + } - public static Posit32 FusedSum(Posit32[] posits) - { - var resultQuire = new Quire((ushort)QuireSize); + #endregion - for (var i = 0; i < posits.Length; i++) - { - if (posits[i].IsNaN()) return posits[i]; - resultQuire += (Quire)posits[i]; - } + #region Fused operations - return new Posit32(resultQuire); - } + public static Posit32 FusedSum(Posit32[] posits) + { + var resultQuire = new Quire((ushort)QuireSize); - public static Quire FusedSum(Posit32[] posits, Quire startingValue) + for (var i = 0; i < posits.Length; i++) { - var quireNaNMask = new Quire(1, (ushort)QuireSize) << (QuireSize - 1); + if (posits[i].IsNaN()) return posits[i]; + resultQuire += (Quire)posits[i]; + } - if (startingValue == quireNaNMask) return quireNaNMask; - for (var i = 0; i < posits.Length; i++) - { - if (posits[i].IsNaN()) return quireNaNMask; - startingValue += (Quire)posits[i]; - } + return new Posit32(resultQuire); + } - return startingValue; - } + public static Quire FusedSum(Posit32[] posits, Quire startingValue) + { + var quireNaNMask = new Quire(1, (ushort)QuireSize) << (QuireSize - 1); - public static Posit32 FusedDotProduct(Posit32[] positArray1, Posit32[] positArray2) + if (startingValue == quireNaNMask) return quireNaNMask; + for (var i = 0; i < posits.Length; i++) { - if (positArray1.Length != positArray2.Length) return new Posit32(NaNBitMask, fromBitMask: true); + if (posits[i].IsNaN()) return quireNaNMask; + startingValue += (Quire)posits[i]; + } - var resultQuire = new Quire((ushort)QuireSize); + return startingValue; + } - for (var i = 0; i < positArray1.Length; i++) - { - if (positArray1[i].IsNaN()) return positArray1[i]; - if (positArray2[i].IsNaN()) return positArray2[i]; - resultQuire += MultiplyIntoQuire(positArray1[i], positArray2[i]); - } + public static Posit32 FusedDotProduct(Posit32[] positArray1, Posit32[] positArray2) + { + if (positArray1.Length != positArray2.Length) return new Posit32(NaNBitMask, fromBitMask: true); - return new Posit32(resultQuire); - } + var resultQuire = new Quire((ushort)QuireSize); - public static Posit32 FusedMultiplyAdd(Posit32 a, Posit32 b, Posit32 c) + for (var i = 0; i < positArray1.Length; i++) { - var positArray1 = new Posit32[2]; - var positArray2 = new Posit32[2]; + if (positArray1[i].IsNaN()) return positArray1[i]; + if (positArray2[i].IsNaN()) return positArray2[i]; + resultQuire += MultiplyIntoQuire(positArray1[i], positArray2[i]); + } - positArray1[0] = a; - positArray1[1] = new Posit32(1); - positArray2[0] = b; - positArray2[1] = c; + return new Posit32(resultQuire); + } - return FusedDotProduct(positArray1, positArray2); - } + public static Posit32 FusedMultiplyAdd(Posit32 a, Posit32 b, Posit32 c) + { + var positArray1 = new Posit32[2]; + var positArray2 = new Posit32[2]; - public static Posit32 FusedAddMultiply(Posit32 a, Posit32 b, Posit32 c) - { - var positArray1 = new Posit32[2]; - var positArray2 = new Posit32[2]; + positArray1[0] = a; + positArray1[1] = new Posit32(1); + positArray2[0] = b; + positArray2[1] = c; - positArray1[0] = a; - positArray1[1] = b; - positArray2[0] = c; - positArray2[1] = c; + return FusedDotProduct(positArray1, positArray2); + } - return FusedDotProduct(positArray1, positArray2); - } + public static Posit32 FusedAddMultiply(Posit32 a, Posit32 b, Posit32 c) + { + var positArray1 = new Posit32[2]; + var positArray2 = new Posit32[2]; - public static Posit32 FusedMultiplyMultiplySubtract(Posit32 a, Posit32 b, Posit32 c, Posit32 d) - { - var positArray1 = new Posit32[2]; - var positArray2 = new Posit32[2]; + positArray1[0] = a; + positArray1[1] = b; + positArray2[0] = c; + positArray2[1] = c; - positArray1[0] = a; - positArray1[1] = -c; - positArray2[0] = b; - positArray2[1] = d; + return FusedDotProduct(positArray1, positArray2); + } - return FusedDotProduct(positArray1, positArray2); - } - #endregion + public static Posit32 FusedMultiplyMultiplySubtract(Posit32 a, Posit32 b, Posit32 c, Posit32 d) + { + var positArray1 = new Posit32[2]; + var positArray2 = new Posit32[2]; - #region Operators + positArray1[0] = a; + positArray1[1] = -c; + positArray2[0] = b; + positArray2[1] = d; - [SuppressMessage( - "Critical Code Smell", - "S3776:Cognitive Complexity of methods should not be too high", - Justification = "Breaking this method up wouldn't be too helpful.")] - public static Posit32 operator +(Posit32 left, Posit32 right) - { - // Handling special cases first. - if (left.IsNaN()) return left; - if (right.IsNaN()) return right; - if (left.IsZero()) return right; - if (right.IsZero()) return left; + return FusedDotProduct(positArray1, positArray2); + } + #endregion + + #region Operators + + [SuppressMessage( + "Critical Code Smell", + "S3776:Cognitive Complexity of methods should not be too high", + Justification = "Breaking this method up wouldn't be too helpful.")] + public static Posit32 operator +(Posit32 left, Posit32 right) + { + // Handling special cases first. + if (left.IsNaN()) return left; + if (right.IsNaN()) return right; + if (left.IsZero()) return right; + if (right.IsZero()) return left; - var leftSignBit = left.PositBits >> (Size - 1); - var leftMaskOfSignBits = 0 - leftSignBit; - var leftAbsoluteValue = new Posit32((left.PositBits ^ leftMaskOfSignBits) + leftSignBit, fromBitMask: true); + var leftSignBit = left.PositBits >> (Size - 1); + var leftMaskOfSignBits = 0 - leftSignBit; + var leftAbsoluteValue = new Posit32((left.PositBits ^ leftMaskOfSignBits) + leftSignBit, fromBitMask: true); - var rightSignBit = right.PositBits >> (Size - 1); - var rightMaskOfSignBits = 0 - rightSignBit; - var rightAbsoluteValue = new Posit32((right.PositBits ^ rightMaskOfSignBits) + rightSignBit, fromBitMask: true); + var rightSignBit = right.PositBits >> (Size - 1); + var rightMaskOfSignBits = 0 - rightSignBit; + var rightAbsoluteValue = new Posit32((right.PositBits ^ rightMaskOfSignBits) + rightSignBit, fromBitMask: true); - var leftLengthOfRunOfBits = LengthOfRunOfBits(leftAbsoluteValue.PositBits, FirstRegimeBitPosition); - var rightLengthOfRunOfBits = LengthOfRunOfBits(rightAbsoluteValue.PositBits, FirstRegimeBitPosition); + var leftLengthOfRunOfBits = LengthOfRunOfBits(leftAbsoluteValue.PositBits, FirstRegimeBitPosition); + var rightLengthOfRunOfBits = LengthOfRunOfBits(rightAbsoluteValue.PositBits, FirstRegimeBitPosition); - var leftFractionSize = FractionSizeWithoutSignCheck(leftLengthOfRunOfBits); - var rightFractionSize = FractionSizeWithoutSignCheck(rightLengthOfRunOfBits); + var leftFractionSize = FractionSizeWithoutSignCheck(leftLengthOfRunOfBits); + var rightFractionSize = FractionSizeWithoutSignCheck(rightLengthOfRunOfBits); - var signBitsMatch = leftSignBit == rightSignBit; - sbyte leftRegimeKValue = leftAbsoluteValue.GetRegimeKValueWithoutSignCheck(leftLengthOfRunOfBits); - uint leftExponentValue = leftAbsoluteValue.GetExponentValueWithoutSignCheck(leftFractionSize); - sbyte rightRegimeKValue = rightAbsoluteValue.GetRegimeKValueWithoutSignCheck(rightLengthOfRunOfBits); - uint rightExponentValue = rightAbsoluteValue.GetExponentValueWithoutSignCheck(rightFractionSize); + var signBitsMatch = leftSignBit == rightSignBit; + sbyte leftRegimeKValue = leftAbsoluteValue.GetRegimeKValueWithoutSignCheck(leftLengthOfRunOfBits); + uint leftExponentValue = leftAbsoluteValue.GetExponentValueWithoutSignCheck(leftFractionSize); + sbyte rightRegimeKValue = rightAbsoluteValue.GetRegimeKValueWithoutSignCheck(rightLengthOfRunOfBits); + uint rightExponentValue = rightAbsoluteValue.GetExponentValueWithoutSignCheck(rightFractionSize); - var resultSignBit = leftAbsoluteValue > rightAbsoluteValue ? leftSignBit == 1 : rightSignBit == 1; - uint resultFractionBits = 0; + var resultSignBit = leftAbsoluteValue > rightAbsoluteValue ? leftSignBit == 1 : rightSignBit == 1; + uint resultFractionBits = 0; - var leftScaleFactor = CalculateScaleFactor(leftRegimeKValue, leftExponentValue, MaximumExponentSize); - var rightScaleFactor = CalculateScaleFactor(rightRegimeKValue, rightExponentValue, MaximumExponentSize); + var leftScaleFactor = CalculateScaleFactor(leftRegimeKValue, leftExponentValue, MaximumExponentSize); + var rightScaleFactor = CalculateScaleFactor(rightRegimeKValue, rightExponentValue, MaximumExponentSize); - var scaleFactorDifference = leftScaleFactor - rightScaleFactor; + var scaleFactorDifference = leftScaleFactor - rightScaleFactor; - var scaleFactor = - scaleFactorDifference >= 0 - ? leftScaleFactor - : rightScaleFactor; + var scaleFactor = + scaleFactorDifference >= 0 + ? leftScaleFactor + : rightScaleFactor; - var leftFraction = leftAbsoluteValue.FractionWithHiddenBitWithoutSignCheck(leftFractionSize); - var rightFraction = rightAbsoluteValue.FractionWithHiddenBitWithoutSignCheck(rightFractionSize); + var leftFraction = leftAbsoluteValue.FractionWithHiddenBitWithoutSignCheck(leftFractionSize); + var rightFraction = rightAbsoluteValue.FractionWithHiddenBitWithoutSignCheck(rightFractionSize); - if (scaleFactorDifference == 0) - { - // False positive, will cause nested ternary. + if (scaleFactorDifference == 0) + { + // False positive, will cause nested ternary. #pragma warning disable S3240 // The simplest possible condition syntax should be used - if (signBitsMatch) - { - resultFractionBits += leftFraction + rightFraction; - } - else - { - resultFractionBits += leftFraction >= rightFraction - ? leftFraction - rightFraction - : rightFraction - leftFraction; - } + if (signBitsMatch) + { + resultFractionBits += leftFraction + rightFraction; + } + else + { + resultFractionBits += leftFraction >= rightFraction + ? leftFraction - rightFraction + : rightFraction - leftFraction; + } #pragma warning restore S3240 // The simplest possible condition syntax should be used - scaleFactor += (short)(GetMostSignificantOnePosition(resultFractionBits) - - leftFractionSize - 1); - } - else if (scaleFactorDifference > 0) + scaleFactor += (short)(GetMostSignificantOnePosition(resultFractionBits) - + leftFractionSize - 1); + } + else if (scaleFactorDifference > 0) + { + // The scale factor of the left Posit is bigger. + var fractionSizeDifference = (int)(leftFractionSize - rightFractionSize); + resultFractionBits += leftFraction; + var biggerPositMovedToLeft = (int)(FirstRegimeBitPosition - leftFractionSize - 1); + resultFractionBits <<= biggerPositMovedToLeft; + var smallerPositMovedToLeft = biggerPositMovedToLeft - scaleFactorDifference + fractionSizeDifference; + + if (signBitsMatch) { - // The scale factor of the left Posit is bigger. - var fractionSizeDifference = (int)(leftFractionSize - rightFractionSize); - resultFractionBits += leftFraction; - var biggerPositMovedToLeft = (int)(FirstRegimeBitPosition - leftFractionSize - 1); - resultFractionBits <<= biggerPositMovedToLeft; - var smallerPositMovedToLeft = biggerPositMovedToLeft - scaleFactorDifference + fractionSizeDifference; - - if (signBitsMatch) - { - resultFractionBits += smallerPositMovedToLeft >= 0 - ? rightFraction << smallerPositMovedToLeft - : rightFraction >> -smallerPositMovedToLeft; - } - else - { - resultFractionBits -= smallerPositMovedToLeft >= 0 - ? rightFraction << smallerPositMovedToLeft - : rightFraction >> -smallerPositMovedToLeft; - } - - scaleFactor += (short)(GetMostSignificantOnePosition(resultFractionBits) - FirstRegimeBitPosition); + resultFractionBits += smallerPositMovedToLeft >= 0 + ? rightFraction << smallerPositMovedToLeft + : rightFraction >> -smallerPositMovedToLeft; } else { - // The scale factor of the right Posit is bigger. - var fractionSizeDifference = (int)(rightFractionSize - leftFractionSize); - resultFractionBits += rightFraction; - var biggerPositMovedToLeft = (int)(FirstRegimeBitPosition - rightFractionSize - 1); - resultFractionBits <<= biggerPositMovedToLeft; - - if (signBitsMatch) - { - resultFractionBits += biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference >= 0 - ? leftFraction << (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference) - : leftFraction >> -(biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); - } - else if (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference >= 0) - { - resultFractionBits -= leftFraction << (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); - } - else - { - resultFractionBits -= leftFraction >> -(biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); - } - - scaleFactor += (short)(GetMostSignificantOnePosition(resultFractionBits) - FirstRegimeBitPosition); + resultFractionBits -= smallerPositMovedToLeft >= 0 + ? rightFraction << smallerPositMovedToLeft + : rightFraction >> -smallerPositMovedToLeft; } - if (resultFractionBits == 0) return new Posit32(0, fromBitMask: true); + scaleFactor += (short)(GetMostSignificantOnePosition(resultFractionBits) - FirstRegimeBitPosition); + } + else + { + // The scale factor of the right Posit is bigger. + var fractionSizeDifference = (int)(rightFractionSize - leftFractionSize); + resultFractionBits += rightFraction; + var biggerPositMovedToLeft = (int)(FirstRegimeBitPosition - rightFractionSize - 1); + resultFractionBits <<= biggerPositMovedToLeft; - var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); - var resultExponentBits = scaleFactor % (1 << MaximumExponentSize); - if (resultExponentBits < 0) + if (signBitsMatch) { - resultRegimeKValue -= 1; - resultExponentBits += 1 << MaximumExponentSize; + resultFractionBits += biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference >= 0 + ? leftFraction << (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference) + : leftFraction >> -(biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); + } + else if (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference >= 0) + { + resultFractionBits -= leftFraction << (biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); + } + else + { + resultFractionBits -= leftFraction >> -(biggerPositMovedToLeft + scaleFactorDifference + fractionSizeDifference); } - return new Posit32( - AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), - fromBitMask: true); + scaleFactor += (short)(GetMostSignificantOnePosition(resultFractionBits) - FirstRegimeBitPosition); } - public static Posit32 operator +(Posit32 left, int right) => left + new Posit32(right); - - public static Posit32 operator -(Posit32 left, Posit32 right) => left + -right; + if (resultFractionBits == 0) return new Posit32(0, fromBitMask: true); - public static Posit32 operator -(Posit32 left, int right) => left - new Posit32(right); - - public static Posit32 operator -(Posit32 x) + var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); + var resultExponentBits = scaleFactor % (1 << MaximumExponentSize); + if (resultExponentBits < 0) { - if (x.IsNaN() || x.IsZero()) return new Posit32(x.PositBits, fromBitMask: true); - return new Posit32(GetTwosComplement(x.PositBits), fromBitMask: true); + resultRegimeKValue -= 1; + resultExponentBits += 1 << MaximumExponentSize; } - public static bool operator ==(Posit32 left, Posit32 right) => left.PositBits == right.PositBits; + return new Posit32( + AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), + fromBitMask: true); + } - public static bool operator >(Posit32 left, Posit32 right) - { - if (left.IsPositive() != right.IsPositive()) return left.IsPositive(); - return left.IsPositive() ? left.PositBits > right.PositBits : !(left.PositBits > right.PositBits); - } + public static Posit32 operator +(Posit32 left, int right) => left + new Posit32(right); - public static bool operator <(Posit32 left, Posit32 right) => !(left.PositBits > right.PositBits); + public static Posit32 operator -(Posit32 left, Posit32 right) => left + -right; - public static bool operator !=(Posit32 left, Posit32 right) => !(left == right); + public static Posit32 operator -(Posit32 left, int right) => left - new Posit32(right); - public static bool operator <=(Posit32 left, Posit32 right) => left.CompareTo(right) <= 0; + public static Posit32 operator -(Posit32 x) + { + if (x.IsNaN() || x.IsZero()) return new Posit32(x.PositBits, fromBitMask: true); + return new Posit32(GetTwosComplement(x.PositBits), fromBitMask: true); + } - public static bool operator >=(Posit32 left, Posit32 right) => left.CompareTo(right) >= 0; + public static bool operator ==(Posit32 left, Posit32 right) => left.PositBits == right.PositBits; - public static Posit32 operator *(Posit32 left, int right) => left * new Posit32(right); + public static bool operator >(Posit32 left, Posit32 right) + { + if (left.IsPositive() != right.IsPositive()) return left.IsPositive(); + return left.IsPositive() ? left.PositBits > right.PositBits : !(left.PositBits > right.PositBits); + } - public static Posit32 operator *(Posit32 left, Posit32 right) - { - if (left.IsZero() || right.IsZero()) return new Posit32(0); - var leftIsPositive = left.IsPositive(); - var rightIsPositive = right.IsPositive(); - var resultSignBit = leftIsPositive != rightIsPositive; - - left = Abs(left); - right = Abs(right); - var leftFractionSize = left.FractionSizeWithoutSignCheck(); - var rightFractionSize = right.FractionSizeWithoutSignCheck(); - - var longResultFractionBits = left.FractionWithHiddenBitWithoutSignCheck() * - (ulong)right.FractionWithHiddenBitWithoutSignCheck(); - var fractionSizeChange = GetMostSignificantOnePosition(longResultFractionBits) - (leftFractionSize + rightFractionSize + 1); - var resultFractionBits = (uint)(longResultFractionBits >> (int)(leftFractionSize + 1 + rightFractionSize + 1 - 32)); - var scaleFactor = - CalculateScaleFactor(left.GetRegimeKValue(), left.GetExponentValue(), MaximumExponentSize) + - CalculateScaleFactor(right.GetRegimeKValue(), right.GetExponentValue(), MaximumExponentSize); - - scaleFactor += (int)fractionSizeChange; - - var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); - var resultExponentBits = scaleFactor % (1 << MaximumExponentSize); - if (resultExponentBits < 0) - { - resultRegimeKValue -= 1; - resultExponentBits += 1 << MaximumExponentSize; - } + public static bool operator <(Posit32 left, Posit32 right) => !(left.PositBits > right.PositBits); - return new Posit32( - AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), - fromBitMask: true); - } + public static bool operator !=(Posit32 left, Posit32 right) => !(left == right); - public static Posit32 operator /(Posit32 left, int right) => left / new Posit32(right); + public static bool operator <=(Posit32 left, Posit32 right) => left.CompareTo(right) <= 0; - public static Posit32 operator /(Posit32 left, Posit32 right) - { - if (left.IsZero()) return new Posit32(0); - if (right.IsZero()) return new Posit32(NaNBitMask, fromBitMask: true); - var leftIsPositive = left.IsPositive(); - var rightIsPositive = right.IsPositive(); - var resultSignBit = leftIsPositive != rightIsPositive; - - left = Abs(left); - right = Abs(right); - var leftFractionSize = left.FractionSizeWithoutSignCheck(); - var rightFractionSize = right.FractionSizeWithoutSignCheck(); - - var longResultFractionBits = ((ulong)left.FractionWithHiddenBitWithoutSignCheck() << (int)(63 - leftFractionSize)) / - (right.FractionWithHiddenBitWithoutSignCheck() << (int)(31 - rightFractionSize)); - var fractionSizeChange = GetMostSignificantOnePosition(longResultFractionBits) - 33; - - var scaleFactor = - CalculateScaleFactor(left.GetRegimeKValue(), left.GetExponentValue(), MaximumExponentSize) - - CalculateScaleFactor(right.GetRegimeKValue(), right.GetExponentValue(), MaximumExponentSize); - scaleFactor += fractionSizeChange; - - var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); - var resultExponentBits = scaleFactor % (1 << MaximumExponentSize); - if (resultExponentBits < 0) - { - resultRegimeKValue -= 1; - resultExponentBits += 1 << MaximumExponentSize; - } + public static bool operator >=(Posit32 left, Posit32 right) => left.CompareTo(right) >= 0; - var resultFractionBits = (uint)(longResultFractionBits >> (resultRegimeKValue > 0 ? resultRegimeKValue + 1 : -resultRegimeKValue + 1)); + public static Posit32 operator *(Posit32 left, int right) => left * new Posit32(right); - return new Posit32( - AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), - fromBitMask: true); + public static Posit32 operator *(Posit32 left, Posit32 right) + { + if (left.IsZero() || right.IsZero()) return new Posit32(0); + var leftIsPositive = left.IsPositive(); + var rightIsPositive = right.IsPositive(); + var resultSignBit = leftIsPositive != rightIsPositive; + + left = Abs(left); + right = Abs(right); + var leftFractionSize = left.FractionSizeWithoutSignCheck(); + var rightFractionSize = right.FractionSizeWithoutSignCheck(); + + var longResultFractionBits = left.FractionWithHiddenBitWithoutSignCheck() * + (ulong)right.FractionWithHiddenBitWithoutSignCheck(); + var fractionSizeChange = GetMostSignificantOnePosition(longResultFractionBits) - (leftFractionSize + rightFractionSize + 1); + var resultFractionBits = (uint)(longResultFractionBits >> (int)(leftFractionSize + 1 + rightFractionSize + 1 - 32)); + var scaleFactor = + CalculateScaleFactor(left.GetRegimeKValue(), left.GetExponentValue(), MaximumExponentSize) + + CalculateScaleFactor(right.GetRegimeKValue(), right.GetExponentValue(), MaximumExponentSize); + + scaleFactor += (int)fractionSizeChange; + + var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); + var resultExponentBits = scaleFactor % (1 << MaximumExponentSize); + if (resultExponentBits < 0) + { + resultRegimeKValue -= 1; + resultExponentBits += 1 << MaximumExponentSize; } - public static explicit operator int(Posit32 x) + return new Posit32( + AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), + fromBitMask: true); + } + + public static Posit32 operator /(Posit32 left, int right) => left / new Posit32(right); + + public static Posit32 operator /(Posit32 left, Posit32 right) + { + if (left.IsZero()) return new Posit32(0); + if (right.IsZero()) return new Posit32(NaNBitMask, fromBitMask: true); + var leftIsPositive = left.IsPositive(); + var rightIsPositive = right.IsPositive(); + var resultSignBit = leftIsPositive != rightIsPositive; + + left = Abs(left); + right = Abs(right); + var leftFractionSize = left.FractionSizeWithoutSignCheck(); + var rightFractionSize = right.FractionSizeWithoutSignCheck(); + + var longResultFractionBits = ((ulong)left.FractionWithHiddenBitWithoutSignCheck() << (int)(63 - leftFractionSize)) / + (right.FractionWithHiddenBitWithoutSignCheck() << (int)(31 - rightFractionSize)); + var fractionSizeChange = GetMostSignificantOnePosition(longResultFractionBits) - 33; + + var scaleFactor = + CalculateScaleFactor(left.GetRegimeKValue(), left.GetExponentValue(), MaximumExponentSize) - + CalculateScaleFactor(right.GetRegimeKValue(), right.GetExponentValue(), MaximumExponentSize); + scaleFactor += fractionSizeChange; + + var resultRegimeKValue = scaleFactor / (1 << MaximumExponentSize); + var resultExponentBits = scaleFactor % (1 << MaximumExponentSize); + if (resultExponentBits < 0) { - uint result; - if (x.PositBits == 0) return 0; + resultRegimeKValue -= 1; + resultExponentBits += 1 << MaximumExponentSize; + } - var scaleFactor = (x.GetRegimeKValue() * (1 << MaximumExponentSize)) + x.GetExponentValue(); + var resultFractionBits = (uint)(longResultFractionBits >> (resultRegimeKValue > 0 ? resultRegimeKValue + 1 : -resultRegimeKValue + 1)); - if (scaleFactor + 1 <= 31) - { - // The posit fits into the range - var mostSignificantOnePosition = GetMostSignificantOnePosition(x.FractionWithHiddenBit()); + return new Posit32( + AssemblePositBitsWithRounding(resultSignBit, resultRegimeKValue, (uint)resultExponentBits, resultFractionBits), + fromBitMask: true); + } - result = scaleFactor - mostSignificantOnePosition + 1 >= 0 - ? x.FractionWithHiddenBit() << (int)(scaleFactor - mostSignificantOnePosition + 1) - : x.FractionWithHiddenBit() >> -(int)(scaleFactor - mostSignificantOnePosition + 1); - } - else - { - return x.IsPositive() ? int.MaxValue : int.MinValue; - } + public static explicit operator int(Posit32 x) + { + uint result; + if (x.PositBits == 0) return 0; - return x.IsPositive() ? (int)result : (int)-result; - } + var scaleFactor = (x.GetRegimeKValue() * (1 << MaximumExponentSize)) + x.GetExponentValue(); - public static explicit operator float(Posit32 x) + if (scaleFactor + 1 <= 31) { - if (x.IsNaN()) return float.NaN; - if (x.IsZero()) return 0F; + // The posit fits into the range + var mostSignificantOnePosition = GetMostSignificantOnePosition(x.FractionWithHiddenBit()); - var floatBits = x.IsPositive() ? EmptyBitMask : SignBitMask; - float floatRepresentation; - var scaleFactor = (x.GetRegimeKValue() * (1 << MaximumExponentSize)) + x.GetExponentValue(); + result = scaleFactor - mostSignificantOnePosition + 1 >= 0 + ? x.FractionWithHiddenBit() << (int)(scaleFactor - mostSignificantOnePosition + 1) + : x.FractionWithHiddenBit() >> -(int)(scaleFactor - mostSignificantOnePosition + 1); + } + else + { + return x.IsPositive() ? int.MaxValue : int.MinValue; + } - if (scaleFactor > 127) return x.IsPositive() ? float.MaxValue : float.MinValue; - if (scaleFactor < -127) return x.IsPositive() ? float.Epsilon : -float.Epsilon; + return x.IsPositive() ? (int)result : (int)-result; + } - var fraction = x.Fraction(); + public static explicit operator float(Posit32 x) + { + if (x.IsNaN()) return float.NaN; + if (x.IsZero()) return 0F; - if (scaleFactor == -127) - { - fraction >>= 1; - fraction += Float32HiddenBitMask >> 1; - } + var floatBits = x.IsPositive() ? EmptyBitMask : SignBitMask; + float floatRepresentation; + var scaleFactor = (x.GetRegimeKValue() * (1 << MaximumExponentSize)) + x.GetExponentValue(); - floatBits += (uint)((scaleFactor + 127) << 23); + if (scaleFactor > 127) return x.IsPositive() ? float.MaxValue : float.MinValue; + if (scaleFactor < -127) return x.IsPositive() ? float.Epsilon : -float.Epsilon; - if (x.FractionSize() <= 23) - { - fraction <<= (int)(23 - x.FractionSize()); - } - else - { - fraction >>= (int)-(23 - x.FractionSize()); - } + var fraction = x.Fraction(); - floatBits += (fraction << (32 - GetMostSignificantOnePosition(fraction) - 1)) >> (32 - GetMostSignificantOnePosition(fraction) - 1); + if (scaleFactor == -127) + { + fraction >>= 1; + fraction += Float32HiddenBitMask >> 1; + } - unsafe - { - float* floatPointer = (float*)&floatBits; - floatRepresentation = *floatPointer; - } + floatBits += (uint)((scaleFactor + 127) << 23); - return floatRepresentation; + if (x.FractionSize() <= 23) + { + fraction <<= (int)(23 - x.FractionSize()); } + else + { + fraction >>= (int)-(23 - x.FractionSize()); + } + + floatBits += (fraction << (32 - GetMostSignificantOnePosition(fraction) - 1)) >> (32 - GetMostSignificantOnePosition(fraction) - 1); - public static explicit operator double(Posit32 x) + unsafe { - if (x.IsNaN()) return double.NaN; - if (x.IsZero()) return 0D; + float* floatPointer = (float*)&floatBits; + floatRepresentation = *floatPointer; + } - ulong doubleBits = x.IsPositive() ? EmptyBitMask : ((ulong)SignBitMask) << 32; - double doubleRepresentation; - var scaleFactor = (x.GetRegimeKValue() * (1 << MaximumExponentSize)) + x.GetExponentValue(); + return floatRepresentation; + } - var fraction = (ulong)x.Fraction(); + public static explicit operator double(Posit32 x) + { + if (x.IsNaN()) return double.NaN; + if (x.IsZero()) return 0D; - doubleBits += (ulong)((scaleFactor + 1_023) << 52); + ulong doubleBits = x.IsPositive() ? EmptyBitMask : ((ulong)SignBitMask) << 32; + double doubleRepresentation; + var scaleFactor = (x.GetRegimeKValue() * (1 << MaximumExponentSize)) + x.GetExponentValue(); - fraction <<= (int)(52 - x.FractionSize()); - doubleBits += (fraction << (64 - GetMostSignificantOnePosition(fraction) - 1)) >> (64 - GetMostSignificantOnePosition(fraction) - 1); + var fraction = (ulong)x.Fraction(); - unsafe - { - double* doublePointer = (double*)&doubleBits; - doubleRepresentation = *doublePointer; - } + doubleBits += (ulong)((scaleFactor + 1_023) << 52); - return doubleRepresentation; - } + fraction <<= (int)(52 - x.FractionSize()); + doubleBits += (fraction << (64 - GetMostSignificantOnePosition(fraction) - 1)) >> (64 - GetMostSignificantOnePosition(fraction) - 1); - public static explicit operator Quire(Posit32 x) + unsafe { - if (x.IsNaN()) return new Quire(1, 512) << 511; - var quireArray = new ulong[QuireSize / 64]; - quireArray[0] = x.FractionWithHiddenBit(); - var resultQuire = new Quire(quireArray); - resultQuire <<= (int)(240 - x.FractionSize() + x.CalculateScaleFactor()); - // This is not a conditional expression return because Hastlayer would throw a "You can't at the moment - // assign to a variable that you previously assigned to using a reference type-holding variable." - if (x.IsPositive()) return resultQuire; - return (~resultQuire) + 1; + double* doublePointer = (double*)&doubleBits; + doubleRepresentation = *doublePointer; } - #endregion + return doubleRepresentation; + } - #region Support methods + public static explicit operator Quire(Posit32 x) + { + if (x.IsNaN()) return new Quire(1, 512) << 511; + var quireArray = new ulong[QuireSize / 64]; + quireArray[0] = x.FractionWithHiddenBit(); + var resultQuire = new Quire(quireArray); + resultQuire <<= (int)(240 - x.FractionSize() + x.CalculateScaleFactor()); + // This is not a conditional expression return because Hastlayer would throw a "You can't at the moment + // assign to a variable that you previously assigned to using a reference type-holding variable." + if (x.IsPositive()) return resultQuire; + return (~resultQuire) + 1; + } - public int CompareTo(object obj) - { - if (obj == null) return 1; - if (obj is Posit32 positValue) return CompareTo(positValue); + #endregion - throw new ArgumentException("Argument must be an other posit"); - } + #region Support methods - public int CompareTo(Posit32 obj) - { - var otherIsNaN = obj.IsNaN(); + public int CompareTo(object obj) + { + if (obj == null) return 1; + if (obj is Posit32 positValue) return CompareTo(positValue); - if (IsNaN()) return otherIsNaN ? 0 : -1; - if (otherIsNaN) return 1; + throw new ArgumentException("Argument must be an other posit"); + } - if (this < obj) return -1; - if (this > obj) return 1; - return 0; - } + public int CompareTo(Posit32 obj) + { + var otherIsNaN = obj.IsNaN(); - public override string ToString() => ((double)this).ToString(CultureInfo.InvariantCulture); + if (IsNaN()) return otherIsNaN ? 0 : -1; + if (otherIsNaN) return 1; - public string ToString(string format, IFormatProvider formatProvider) => ((double)this).ToString(format, formatProvider); + if (this < obj) return -1; + if (this > obj) return 1; + return 0; + } - public string ToString(IFormatProvider provider) => ((double)this).ToString(provider); + public override string ToString() => ((double)this).ToString(CultureInfo.InvariantCulture); - public static Posit32 Parse(string number) => new(double.Parse(number, CultureInfo.InvariantCulture)); + public string ToString(string format, IFormatProvider formatProvider) => ((double)this).ToString(format, formatProvider); - public static bool TryParse(string number, out Posit32 positResult) - { - var returnValue = double.TryParse(number, out double result); - positResult = new Posit32(result); - return returnValue; - } + public string ToString(IFormatProvider provider) => ((double)this).ToString(provider); - public override bool Equals(object obj) => obj is Posit32 other && this == other; + public static Posit32 Parse(string number) => new(double.Parse(number, CultureInfo.InvariantCulture)); - public bool Equals(Posit32 other) => this == other; + public static bool TryParse(string number, out Posit32 positResult) + { + var returnValue = double.TryParse(number, out double result); + positResult = new Posit32(result); + return returnValue; + } - public TypeCode GetTypeCode() => throw new NotSupportedException(); + public override bool Equals(object obj) => obj is Posit32 other && this == other; - public bool ToBoolean(IFormatProvider provider) => !IsZero(); + public bool Equals(Posit32 other) => this == other; - public char ToChar(IFormatProvider provider) => throw new InvalidCastException(); + public TypeCode GetTypeCode() => throw new NotSupportedException(); - public sbyte ToSByte(IFormatProvider provider) => (sbyte)(int)this; + public bool ToBoolean(IFormatProvider provider) => !IsZero(); - public byte ToByte(IFormatProvider provider) => (byte)(uint)this; + public char ToChar(IFormatProvider provider) => throw new InvalidCastException(); - public short ToInt16(IFormatProvider provider) => (short)(int)this; + public sbyte ToSByte(IFormatProvider provider) => (sbyte)(int)this; - public ushort ToUInt16(IFormatProvider provider) => (ushort)(uint)this; + public byte ToByte(IFormatProvider provider) => (byte)(uint)this; - public int ToInt32(IFormatProvider provider) => (int)this; + public short ToInt16(IFormatProvider provider) => (short)(int)this; - public uint ToUInt32(IFormatProvider provider) => (uint)this; + public ushort ToUInt16(IFormatProvider provider) => (ushort)(uint)this; - public long ToInt64(IFormatProvider provider) => (long)this; + public int ToInt32(IFormatProvider provider) => (int)this; - public ulong ToUInt64(IFormatProvider provider) => (ulong)this; + public uint ToUInt32(IFormatProvider provider) => (uint)this; - public float ToSingle(IFormatProvider provider) => (float)this; + public long ToInt64(IFormatProvider provider) => (long)this; - public double ToDouble(IFormatProvider provider) => (double)this; + public ulong ToUInt64(IFormatProvider provider) => (ulong)this; - public decimal ToDecimal(IFormatProvider provider) => throw new NotSupportedException(); + public float ToSingle(IFormatProvider provider) => (float)this; - public DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException(); + public double ToDouble(IFormatProvider provider) => (double)this; - public object ToType(Type conversionType, IFormatProvider provider) => throw new NotSupportedException(); + public decimal ToDecimal(IFormatProvider provider) => throw new NotSupportedException(); - public override int GetHashCode() => (int)PositBits; + public DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException(); - #endregion - } + public object ToType(Type conversionType, IFormatProvider provider) => throw new NotSupportedException(); + + public override int GetHashCode() => (int)PositBits; + + #endregion } diff --git a/Posit/PositEnvironment.cs b/Posit/PositEnvironment.cs index ea22bad..9d5a30b 100644 --- a/Posit/PositEnvironment.cs +++ b/Posit/PositEnvironment.cs @@ -1,43 +1,42 @@ -namespace Lombiq.Arithmetics -{ - public class PositEnvironment - { - public byte MaximumExponentSize { get; } +namespace Lombiq.Arithmetics; - public ushort Size { get; } +public class PositEnvironment +{ + public byte MaximumExponentSize { get; } - public uint Useed { get; } + public ushort Size { get; } - public ushort FirstRegimeBitIndex { get; } + public uint Useed { get; } - public BitMask SignBitMask { get; } + public ushort FirstRegimeBitIndex { get; } - public BitMask FirstRegimeBitBitMask { get; } + public BitMask SignBitMask { get; } - public BitMask EmptyBitMask { get; } + public BitMask FirstRegimeBitBitMask { get; } - public BitMask MaxValueBitMask { get; } + public BitMask EmptyBitMask { get; } - public BitMask MinValueBitMask { get; } + public BitMask MaxValueBitMask { get; } - public BitMask NaNBitMask { get; } + public BitMask MinValueBitMask { get; } - public uint QuireSize { get; } + public BitMask NaNBitMask { get; } - public PositEnvironment(byte size, byte maximumExponentSize) - { - Size = size; - MaximumExponentSize = maximumExponentSize; + public uint QuireSize { get; } - Useed = 1U << (1 << MaximumExponentSize); - SignBitMask = new BitMask(Size).SetOne((ushort)(Size - 1)); - FirstRegimeBitIndex = (ushort)(Size - 2); - FirstRegimeBitBitMask = new BitMask(Size).SetOne(FirstRegimeBitIndex); - EmptyBitMask = new BitMask(Size); - MaxValueBitMask = new BitMask(Size, allOne: true) >> 1; - MinValueBitMask = SignBitMask + 1; - NaNBitMask = SignBitMask; - QuireSize = new BitMask((uint)(((Size - 2) * (1 << MaximumExponentSize)) + 5), size).FindMostSignificantOnePosition(); - } + public PositEnvironment(byte size, byte maximumExponentSize) + { + Size = size; + MaximumExponentSize = maximumExponentSize; + + Useed = 1U << (1 << MaximumExponentSize); + SignBitMask = new BitMask(Size).SetOne((ushort)(Size - 1)); + FirstRegimeBitIndex = (ushort)(Size - 2); + FirstRegimeBitBitMask = new BitMask(Size).SetOne(FirstRegimeBitIndex); + EmptyBitMask = new BitMask(Size); + MaxValueBitMask = new BitMask(Size, allOne: true) >> 1; + MinValueBitMask = SignBitMask + 1; + NaNBitMask = SignBitMask; + QuireSize = new BitMask((uint)(((Size - 2) * (1 << MaximumExponentSize)) + 5), size).FindMostSignificantOnePosition(); } } diff --git a/Posit/Quire.cs b/Posit/Quire.cs index 4b01879..3c6cfc4 100644 --- a/Posit/Quire.cs +++ b/Posit/Quire.cs @@ -2,211 +2,210 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +[SuppressMessage( + "Major Code Smell", + "S4035:Classes implementing \"IEquatable\" should be sealed", + Justification = "False positive, it actually implements IEqualityComparer.")] + +public class Quire : IEqualityComparer { - [SuppressMessage( - "Major Code Smell", - "S4035:Classes implementing \"IEquatable\" should be sealed", - Justification = "False positive, it actually implements IEqualityComparer.")] + private const ulong SegmentMaskWithLeadingOne = 0x_8000_0000_0000_0000; + private const ulong SegmentMaskWithClosingOne = 1; - public class Quire : IEqualityComparer - { - private const ulong SegmentMaskWithLeadingOne = 0x_8000_0000_0000_0000; - private const ulong SegmentMaskWithClosingOne = 1; + public ushort Size { get; } + public ushort SegmentCount { get; } - public ushort Size { get; } - public ushort SegmentCount { get; } + [SuppressMessage( + "Performance", + "CA1819:Properties should not return arrays", + Justification = "Not currently posisble due to IArraySizeHolder limitations.")] + // See: https://github.com/Lombiq/Hastlayer-SDK/issues/63 + public ulong[] Segments { get; } - [SuppressMessage( - "Performance", - "CA1819:Properties should not return arrays", - Justification = "Not currently posisble due to IArraySizeHolder limitations.")] - // See: https://github.com/Lombiq/Hastlayer-SDK/issues/63 - public ulong[] Segments { get; } + public Quire(ushort size) + { + var partialSegment = size % 64; + SegmentCount = (ushort)((size >> 6) + (partialSegment == 0 ? 0 : 1)); + Size = size; + Segments = new ulong[SegmentCount]; + for (int i = 0; i < SegmentCount; i++) + Segments[i] = 0; + } - public Quire(ushort size) + public Quire(ulong[] segments, ushort size = 0) + { + SegmentCount = (ushort)segments.Length; + Size = size; + if (size > SegmentCount << 6) { - var partialSegment = size % 64; - SegmentCount = (ushort)((size >> 6) + (partialSegment == 0 ? 0 : 1)); - Size = size; - Segments = new ulong[SegmentCount]; - for (int i = 0; i < SegmentCount; i++) - Segments[i] = 0; + SegmentCount = (ushort)((size >> 6) + (size % 32 == 0 ? 0 : 1)); } - public Quire(ulong[] segments, ushort size = 0) - { - SegmentCount = (ushort)segments.Length; - Size = size; - if (size > SegmentCount << 6) - { - SegmentCount = (ushort)((size >> 6) + (size % 32 == 0 ? 0 : 1)); - } + Segments = new ulong[SegmentCount]; - Segments = new ulong[SegmentCount]; + Array.Copy(segments, Segments, segments.Length); + for (int i = segments.Length; i < SegmentCount; i++) + Segments[i] = 0; + } - Array.Copy(segments, Segments, segments.Length); - for (int i = segments.Length; i < SegmentCount; i++) - Segments[i] = 0; - } + public Quire(uint firstSegment, ushort size) + { + Size = size; + SegmentCount = (ushort)((size >> 6) + (size % 32 == 0 ? 0 : 1)); + Segments = new ulong[SegmentCount]; + Segments[0] = firstSegment; + for (int i = 1; i < SegmentCount; i++) + Segments[i] = 0; + } - public Quire(uint firstSegment, ushort size) - { - Size = size; - SegmentCount = (ushort)((size >> 6) + (size % 32 == 0 ? 0 : 1)); - Segments = new ulong[SegmentCount]; - Segments[0] = firstSegment; - for (int i = 1; i < SegmentCount; i++) - Segments[i] = 0; - } + public static Quire operator +(Quire left, Quire right) + { + if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; + var result = new ulong[left.SegmentCount]; + bool carry = false; + ushort segmentPosition = 0, position = 0; - public static Quire operator +(Quire left, Quire right) + for (ushort i = 0; i < left.SegmentCount << 6; i++) { - if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; - var result = new ulong[left.SegmentCount]; - bool carry = false; - ushort segmentPosition = 0, position = 0; + bool leftBit = ((left.Segments[segmentPosition] >> position) & 1) == 1; + bool rightBit = ((right.Segments[segmentPosition] >> position) & 1) == 1; + byte buffer = (byte)((leftBit ? 1 : 0) + (rightBit ? 1 : 0) + (carry ? 1 : 0)); - for (ushort i = 0; i < left.SegmentCount << 6; i++) + if ((buffer & 1) == 1) result[segmentPosition] += 1UL << position; + carry = buffer >> 1 == 1; + + position++; + if (position >> 6 == 1) { - bool leftBit = ((left.Segments[segmentPosition] >> position) & 1) == 1; - bool rightBit = ((right.Segments[segmentPosition] >> position) & 1) == 1; - byte buffer = (byte)((leftBit ? 1 : 0) + (rightBit ? 1 : 0) + (carry ? 1 : 0)); - - if ((buffer & 1) == 1) result[segmentPosition] += 1UL << position; - carry = buffer >> 1 == 1; - - position++; - if (position >> 6 == 1) - { - position = 0; - segmentPosition++; - } + position = 0; + segmentPosition++; } - - return new Quire(result); } - public static Quire operator +(Quire left, uint right) => left + new Quire(right, (ushort)(left.SegmentCount << 6)); - public static Quire operator -(Quire left, Quire right) - { - if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; - - var result = new ulong[left.SegmentCount]; - bool carry = false; - ushort segmentPosition = 0, position = 0; + return new Quire(result); + } - for (ushort i = 0; i < left.SegmentCount << 6; i++) - { - bool leftBit = ((left.Segments[segmentPosition] >> position) & 1) == 1; - bool rightBit = ((right.Segments[segmentPosition] >> position) & 1) == 1; + public static Quire operator +(Quire left, uint right) => left + new Quire(right, (ushort)(left.SegmentCount << 6)); + public static Quire operator -(Quire left, Quire right) + { + if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; - byte buffer = (byte)(2 + (leftBit ? 1 : 0) - (rightBit ? 1 : 0) - (carry ? 1 : 0)); + var result = new ulong[left.SegmentCount]; + bool carry = false; + ushort segmentPosition = 0, position = 0; - if ((buffer & 1) == 1) result[segmentPosition] += 1UL << position; - carry = buffer >> 1 == 0; + for (ushort i = 0; i < left.SegmentCount << 6; i++) + { + bool leftBit = ((left.Segments[segmentPosition] >> position) & 1) == 1; + bool rightBit = ((right.Segments[segmentPosition] >> position) & 1) == 1; - position++; - if (position >> 6 == 1) - { - position = 0; - segmentPosition++; - } - } + byte buffer = (byte)(2 + (leftBit ? 1 : 0) - (rightBit ? 1 : 0) - (carry ? 1 : 0)); - return new Quire(result); - } + if ((buffer & 1) == 1) result[segmentPosition] += 1UL << position; + carry = buffer >> 1 == 0; - public static Quire operator ~(Quire q) - { - for (ushort i = 0; i < q.SegmentCount; i++) + position++; + if (position >> 6 == 1) { - q.Segments[i] = ~q.Segments[i]; + position = 0; + segmentPosition++; } - - return q; } - public static bool operator ==(Quire left, Quire right) + return new Quire(result); + } + + public static Quire operator ~(Quire q) + { + for (ushort i = 0; i < q.SegmentCount; i++) { - if (left.SegmentCount != right.SegmentCount) return false; + q.Segments[i] = ~q.Segments[i]; + } - for (ushort i = 0; i < left.SegmentCount; i++) - { - if (left.Segments[i] != right.Segments[i]) return false; - } + return q; + } - return true; + public static bool operator ==(Quire left, Quire right) + { + if (left.SegmentCount != right.SegmentCount) return false; + + for (ushort i = 0; i < left.SegmentCount; i++) + { + if (left.Segments[i] != right.Segments[i]) return false; } - public static bool operator !=(Quire left, Quire right) => !(left == right); + return true; + } - public static Quire operator >>(Quire left, int right) - { - right &= (1 << (left.SegmentCount * 6)) - 1; + public static bool operator !=(Quire left, Quire right) => !(left == right); + + public static Quire operator >>(Quire left, int right) + { + right &= (1 << (left.SegmentCount * 6)) - 1; - var segments = new ulong[left.SegmentCount]; - Array.Copy(left.Segments, segments, left.Segments.Length); + var segments = new ulong[left.SegmentCount]; + Array.Copy(left.Segments, segments, left.Segments.Length); - for (ushort i = 0; i < right; i++) + for (ushort i = 0; i < right; i++) + { + bool carryOld = false; + + for (ushort j = 1; j <= segments.Length; j++) { - bool carryOld = false; - - for (ushort j = 1; j <= segments.Length; j++) - { - ushort currentIndex = (ushort)(segments.Length - j); - bool carryNew = (segments[currentIndex] & 1) == 1; - segments[currentIndex] >>= 1; - if (carryOld) segments[currentIndex] |= SegmentMaskWithLeadingOne; - carryOld = carryNew; - } + ushort currentIndex = (ushort)(segments.Length - j); + bool carryNew = (segments[currentIndex] & 1) == 1; + segments[currentIndex] >>= 1; + if (carryOld) segments[currentIndex] |= SegmentMaskWithLeadingOne; + carryOld = carryNew; } - - return new Quire(segments); } - public static Quire operator <<(Quire left, int right) - { - right &= (1 << (left.SegmentCount * 6)) - 1; + return new Quire(segments); + } + + public static Quire operator <<(Quire left, int right) + { + right &= (1 << (left.SegmentCount * 6)) - 1; - var segments = new ulong[left.SegmentCount]; - Array.Copy(left.Segments, segments, left.Segments.Length); + var segments = new ulong[left.SegmentCount]; + Array.Copy(left.Segments, segments, left.Segments.Length); - for (ushort i = 0; i < right; i++) + for (ushort i = 0; i < right; i++) + { + bool carryOld = false; + + for (ushort j = 0; j < segments.Length; j++) { - bool carryOld = false; - - for (ushort j = 0; j < segments.Length; j++) - { - bool carryNew = (segments[j] & SegmentMaskWithLeadingOne) == SegmentMaskWithLeadingOne; - segments[j] <<= 1; - if (carryOld) segments[j] |= SegmentMaskWithClosingOne; - carryOld = carryNew; - } + bool carryNew = (segments[j] & SegmentMaskWithLeadingOne) == SegmentMaskWithLeadingOne; + segments[j] <<= 1; + if (carryOld) segments[j] |= SegmentMaskWithClosingOne; + carryOld = carryNew; } - - return new Quire(segments); } - public static explicit operator ulong(Quire x) => x.Segments[0]; + return new Quire(segments); + } + + public static explicit operator ulong(Quire x) => x.Segments[0]; - public static explicit operator uint(Quire x) => (uint)x.Segments[0]; + public static explicit operator uint(Quire x) => (uint)x.Segments[0]; - protected bool Equals(Quire other) => this == other; - public bool Equals(Quire x, Quire y) => x == y; - public override bool Equals(object obj) => obj is Quire other && this == other; + protected bool Equals(Quire other) => this == other; + public bool Equals(Quire x, Quire y) => x == y; + public override bool Equals(object obj) => obj is Quire other && this == other; - public int GetHashCode(Quire obj) => obj.GetHashCode(); + public int GetHashCode(Quire obj) => obj.GetHashCode(); - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - var hashCode = Segments != null ? Segments.GetHashCode() : 0; - hashCode = (hashCode * 397) ^ Size.GetHashCode(); - hashCode = (hashCode * 397) ^ SegmentCount.GetHashCode(); - return hashCode; - } + var hashCode = Segments != null ? Segments.GetHashCode() : 0; + hashCode = (hashCode * 397) ^ Size.GetHashCode(); + hashCode = (hashCode * 397) ^ SegmentCount.GetHashCode(); + return hashCode; } } } diff --git a/Unum/Unum.cs b/Unum/Unum.cs index 1d79ee7..bb98228 100644 --- a/Unum/Unum.cs +++ b/Unum/Unum.cs @@ -1,769 +1,768 @@ using System; using System.Diagnostics.CodeAnalysis; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +public readonly struct Unum : IEquatable { - public readonly struct Unum : IEquatable + private readonly UnumEnvironment _environment; + + // Signbit Exponent Fraction Ubit ExponentSize FractionSize + public BitMask UnumBits { get; } + + #region Unum structure + + /// + /// Gets the number of bits allocated to store the maximum number of bits in the exponent field of a unum. + /// + public byte ExponentSizeSize => _environment.ExponentSizeSize; // "esizesize" + + /// + /// Gets the number of bits allocated to store the maximum number of bits in the fraction field of a unum. + /// + public byte FractionSizeSize => _environment.FractionSizeSize; // "fsizesize" + + /// + /// Gets the maximum number of bits usable to store the exponent. + /// + public byte ExponentSizeMax => _environment.ExponentSizeMax; // "esizemax" + + /// + /// Gets the maximum number of bits usable to store the fraction. + /// + public ushort FractionSizeMax => _environment.FractionSizeMax; // "fsizemax" + + /// + /// Gets the number of bits that are used storing the utag. + /// + public byte UnumTagSize => _environment.UnumTagSize; // "utagsize" + + /// + /// Gets the maximum number of bits used by the environment. + /// + public ushort Size => _environment.Size; // "maxubits" + + #endregion + + #region Unum masks + + /// + /// Gets a BitMask for picking out the UncertainityBit. + /// + public BitMask UncertaintyBitMask => _environment.UncertaintyBitMask; // "ubitmask" + + /// + /// Gets a BitMask for picking out the ExponentSize. + /// + public BitMask ExponentSizeMask => _environment.ExponentSizeMask; // "esizemask" + + /// + /// Gets a BitMask for picking out the FractionSize. + /// + public BitMask FractionSizeMask => _environment.FractionSizeMask; // "fsizemask" + + /// + /// Gets a BitMask for picking out the ExponentSize and FractionSize. + /// + public BitMask ExponentAndFractionSizeMask => _environment.ExponentAndFractionSizeMask; // "efsizemask" + + /// + /// Gets a BitMask for picking out the utag. + /// + public BitMask UnumTagMask => _environment.UnumTagMask; // "utagmask" + + /// + /// Gets a BitMask for picking out the SignBit. + /// + public BitMask SignBitMask => _environment.SignBitMask; // "signbigu" + + #endregion + + #region Unum environment + + /// + /// Gets a BitMask for the Unit in the Last Place or Unit of Least Precision. + /// + [SuppressMessage("Minor Code Smell", "S100:Methods and properties should be named in PascalCase", Justification = "It's an acronym.")] + public BitMask ULP => _environment.ULP; + + /// + /// Gets a BitMask for the unum notation of positive infinity. + /// + public BitMask PositiveInfinity => _environment.PositiveInfinity; // "posinfu" + + /// + /// Gets a BitMask for the unum notation of negative infinity. + /// + public BitMask NegativeInfinity => _environment.NegativeInfinity; // "neginfu" + + /// + /// Gets a BitMask for the unum notation of a quiet NaN value. + /// + public BitMask QuietNotANumber => _environment.QuietNotANumber; // "qNaNu" + + /// + /// Gets a BitMask for the unum notation of a signaling NaN value. + /// + public BitMask SignalingNotANumber => _environment.SignalingNotANumber; // "sNaNu" + + /// + /// Gets a BitMask for the largest expressable finite positive unum in the environment. + /// + public BitMask LargestPositive => _environment.LargestPositive; // "maxrealu" + + /// + /// Gets a BitMask for the smallest expressable positive real unum in the environment. + /// + public BitMask SmallestPositive => _environment.SmallestPositive; // "smallsubnormalu" + + /// + /// Gets a BitMask for the largest expressable finite negative unum in the environment. + /// + public BitMask LargestNegative => _environment.LargestNegative; // "negbigu" + + /// + /// Gets a BitMask for the largest magnitude negative unum in the environment. + /// + public BitMask MinRealU => _environment.MinRealU; // "minrealu" + + #endregion + + #region Unum constructors + + public Unum(UnumEnvironment environment) { - private readonly UnumEnvironment _environment; - - // Signbit Exponent Fraction Ubit ExponentSize FractionSize - public BitMask UnumBits { get; } - - #region Unum structure - - /// - /// Gets the number of bits allocated to store the maximum number of bits in the exponent field of a unum. - /// - public byte ExponentSizeSize => _environment.ExponentSizeSize; // "esizesize" - - /// - /// Gets the number of bits allocated to store the maximum number of bits in the fraction field of a unum. - /// - public byte FractionSizeSize => _environment.FractionSizeSize; // "fsizesize" - - /// - /// Gets the maximum number of bits usable to store the exponent. - /// - public byte ExponentSizeMax => _environment.ExponentSizeMax; // "esizemax" - - /// - /// Gets the maximum number of bits usable to store the fraction. - /// - public ushort FractionSizeMax => _environment.FractionSizeMax; // "fsizemax" - - /// - /// Gets the number of bits that are used storing the utag. - /// - public byte UnumTagSize => _environment.UnumTagSize; // "utagsize" - - /// - /// Gets the maximum number of bits used by the environment. - /// - public ushort Size => _environment.Size; // "maxubits" - - #endregion - - #region Unum masks - - /// - /// Gets a BitMask for picking out the UncertainityBit. - /// - public BitMask UncertaintyBitMask => _environment.UncertaintyBitMask; // "ubitmask" - - /// - /// Gets a BitMask for picking out the ExponentSize. - /// - public BitMask ExponentSizeMask => _environment.ExponentSizeMask; // "esizemask" - - /// - /// Gets a BitMask for picking out the FractionSize. - /// - public BitMask FractionSizeMask => _environment.FractionSizeMask; // "fsizemask" - - /// - /// Gets a BitMask for picking out the ExponentSize and FractionSize. - /// - public BitMask ExponentAndFractionSizeMask => _environment.ExponentAndFractionSizeMask; // "efsizemask" - - /// - /// Gets a BitMask for picking out the utag. - /// - public BitMask UnumTagMask => _environment.UnumTagMask; // "utagmask" - - /// - /// Gets a BitMask for picking out the SignBit. - /// - public BitMask SignBitMask => _environment.SignBitMask; // "signbigu" - - #endregion - - #region Unum environment - - /// - /// Gets a BitMask for the Unit in the Last Place or Unit of Least Precision. - /// - [SuppressMessage("Minor Code Smell", "S100:Methods and properties should be named in PascalCase", Justification = "It's an acronym.")] - public BitMask ULP => _environment.ULP; - - /// - /// Gets a BitMask for the unum notation of positive infinity. - /// - public BitMask PositiveInfinity => _environment.PositiveInfinity; // "posinfu" - - /// - /// Gets a BitMask for the unum notation of negative infinity. - /// - public BitMask NegativeInfinity => _environment.NegativeInfinity; // "neginfu" - - /// - /// Gets a BitMask for the unum notation of a quiet NaN value. - /// - public BitMask QuietNotANumber => _environment.QuietNotANumber; // "qNaNu" - - /// - /// Gets a BitMask for the unum notation of a signaling NaN value. - /// - public BitMask SignalingNotANumber => _environment.SignalingNotANumber; // "sNaNu" - - /// - /// Gets a BitMask for the largest expressable finite positive unum in the environment. - /// - public BitMask LargestPositive => _environment.LargestPositive; // "maxrealu" - - /// - /// Gets a BitMask for the smallest expressable positive real unum in the environment. - /// - public BitMask SmallestPositive => _environment.SmallestPositive; // "smallsubnormalu" - - /// - /// Gets a BitMask for the largest expressable finite negative unum in the environment. - /// - public BitMask LargestNegative => _environment.LargestNegative; // "negbigu" - - /// - /// Gets a BitMask for the largest magnitude negative unum in the environment. - /// - public BitMask MinRealU => _environment.MinRealU; // "minrealu" - - #endregion - - #region Unum constructors - - public Unum(UnumEnvironment environment) - { - _environment = environment; - - UnumBits = new BitMask(_environment.Size); - } - - public Unum(UnumEnvironment environment, BitMask bits) - { - _environment = environment; + _environment = environment; - // To be sure that UnumBits has the same size as the environment. Excess bits will be truncated. - UnumBits = BitMask.FromImmutableArray(bits.Segments, _environment.Size); - } + UnumBits = new BitMask(_environment.Size); + } - /// - /// Initializes a new instance of the struct. - /// Creates a Unum of the given environment initialized with the value of the uint. - /// - /// The Unum environment. - /// The uint value to initialize the new Unum with. - 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; + public Unum(UnumEnvironment environment, BitMask bits) + { + _environment = environment; - UnumBits = new Unum(environment, valueArray).UnumBits; - } + // To be sure that UnumBits has the same size as the environment. Excess bits will be truncated. + UnumBits = BitMask.FromImmutableArray(bits.Segments, _environment.Size); + } - /// - /// Initializes a new instance of the struct. - /// Creates a Unum initialized with a value that is defined by the bits in a uint array. - /// - /// The Unum environment. - /// - /// 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. - /// - /// Defines whether the number is positive or not. - public Unum(UnumEnvironment environment, uint[] value, bool negative = false) - { - _environment = environment; + /// + /// Initializes a new instance of the struct. + /// Creates a Unum of the given environment initialized with the value of the uint. + /// + /// The Unum environment. + /// The uint value to initialize the new Unum with. + 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 BitMask(value, environment.Size); - if (UnumBits == _environment.EmptyBitMask) return; + UnumBits = new Unum(environment, valueArray).UnumBits; + } - // Handling the case when the number wouldn't fit in the range of the environment. - if (UnumHelper.LargestExpressablePositiveInteger(environment) != environment.EmptyBitMask && - UnumBits > UnumHelper.LargestExpressablePositiveInteger(environment)) - { - UnumBits = negative ? environment.LargestNegative | environment.UncertaintyBitMask - : environment.LargestPositive | environment.UncertaintyBitMask; - return; - } + /// + /// Initializes a new instance of the struct. + /// Creates a Unum initialized with a value that is defined by the bits in a uint array. + /// + /// The Unum environment. + /// + /// 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. + /// + /// Defines whether the number is positive or not. + public Unum(UnumEnvironment environment, uint[] value, bool negative = false) + { + _environment = environment; - var uncertainityBit = false; + UnumBits = new BitMask(value, environment.Size); + if (UnumBits == _environment.EmptyBitMask) return; - // Putting the actual value in a BitMask. - var exponent = new BitMask(value, Size); + // Handling the case when the number wouldn't fit in the range of the environment. + if (UnumHelper.LargestExpressablePositiveInteger(environment) != environment.EmptyBitMask && + UnumBits > UnumHelper.LargestExpressablePositiveInteger(environment)) + { + UnumBits = negative ? environment.LargestNegative | environment.UncertaintyBitMask + : environment.LargestPositive | environment.UncertaintyBitMask; + return; + } - // The value of the exponent is one less than the number of binary digits in the integer. - var exponentValue = new BitMask((uint)(exponent.FindMostSignificantOnePosition() - 1), Size); + var uncertainityBit = false; - // Calculating the number of bits needed to represent the value of the exponent. - var exponentSize = exponentValue.FindMostSignificantOnePosition(); + // Putting the actual value in a BitMask. + var exponent = new BitMask(value, Size); - // 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.Lowest32Bits & (exponentValue.Lowest32Bits - 1)) > 0) exponentSize++; + // The value of the exponent is one less than the number of binary digits in the integer. + var exponentValue = new BitMask((uint)(exponent.FindMostSignificantOnePosition() - 1), Size); - // 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 number of bits needed to represent the value of the exponent. + var exponentSize = exponentValue.FindMostSignificantOnePosition(); - // Calculating the bias from the number of bits representing the exponent. - var bias = exponentSize == 0 ? 0 : (1 << (exponentSize - 1)) - 1; + // 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.Lowest32Bits & (exponentValue.Lowest32Bits - 1)) > 0) exponentSize++; - // Applying the bias to the exponent. - exponent = exponentValue + (uint)bias; + // 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; + } - // Putting the actual value in a BitMask. - var fraction = new BitMask(value, Size); + // Calculating the bias from the number of bits representing the exponent. + var bias = exponentSize == 0 ? 0 : (1 << (exponentSize - 1)) - 1; - // Shifting out the zeros after the least significant 1-bit. - fraction = fraction.ShiftOutLeastSignificantZeros(); + // Applying the bias to the exponent. + exponent = exponentValue + (uint)bias; - // Calculating the number of bits needed to represent the fraction. - var fractionSize = fraction.FindMostSignificantOnePosition(); + // Putting the actual value in a BitMask. + var fraction = new BitMask(value, Size); - /* 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.Lowest32Bits > 0) - { - fractionSize--; - fraction = fraction.SetZero(fractionSize); - } + // Shifting out the zeros after the least significant 1-bit. + fraction = fraction.ShiftOutLeastSignificantZeros(); - // Handling input numbers that fit in the range, but are too big to represent exactly. - if (fractionSize > FractionSizeMax) - { - fraction >>= FractionSizeMax - fractionSize; - uncertainityBit = true; - } + // Calculating the number of bits needed to represent the fraction. + var fractionSize = fraction.FindMostSignificantOnePosition(); - UnumBits = AssembleUnumBits( - negative, - exponent, - fraction, - uncertainityBit, - (byte)(exponentSize > 0 ? exponentSize - 1 : 0), - (ushort)(fractionSize > 0 ? fractionSize - 1 : 0)); - } - - public Unum(UnumEnvironment environment, int value) + /* 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.Lowest32Bits > 0) { - _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]; - - if (value >= 0) - { - valueArray[0] = (uint)value; - UnumBits = new Unum(environment, valueArray).UnumBits; - } - else - { - valueArray[0] = (uint)-value; - UnumBits = new Unum(environment, valueArray, negative: true).UnumBits; - } + fractionSize--; + fraction = fraction.SetZero(fractionSize); } - #endregion - - #region Methods to set the values of individual Unum structure elements - - /// - /// Assembles the Unum from its pre-computed parts. - /// - /// The SignBit of the Unum. - /// The biased notation of the exponent of the Unum. - /// The fraction of the Unum without the hidden bit. - /// The value of the uncertainity bit (Ubit). - /// The Unum's exponent size, in a notation that is one less than the actual value. - /// The Unum's fraction size, in a notation that is one less than the actual value. - /// The BitMask representing the whole Unum with all the parts set. - private BitMask AssembleUnumBits( - bool signBit, - BitMask exponent, - BitMask fraction, - bool uncertainityBit, - byte exponentSize, - ushort fractionSize) + // Handling input numbers that fit in the range, but are too big to represent exactly. + if (fractionSize > FractionSizeMax) { - var wholeUnum = new BitMask(exponentSize, Size) << FractionSizeSize; - wholeUnum += fractionSize; - - if (uncertainityBit) wholeUnum += UncertaintyBitMask; + fraction >>= FractionSizeMax - fractionSize; + uncertainityBit = true; + } - wholeUnum += fraction << UnumTagSize; - wholeUnum += exponent << (UnumTagSize + fractionSize + 1); + UnumBits = AssembleUnumBits( + negative, + exponent, + fraction, + uncertainityBit, + (byte)(exponentSize > 0 ? exponentSize - 1 : 0), + (ushort)(fractionSize > 0 ? fractionSize - 1 : 0)); + } - if (signBit) wholeUnum += SignBitMask; + public Unum(UnumEnvironment environment, int value) + { + _environment = environment; - return wholeUnum; - } + // 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]; - /// - /// Sets the SignBit to the given value and leaves everything else as is. - /// - /// The desired SignBit. - /// The BitMask representing the Unum with its SignBit set to the given value. - public Unum SetSignBit(bool signBit) + if (value >= 0) { - var newUnumBits = signBit ? UnumBits | SignBitMask : UnumBits & (new BitMask(Size, allOne: true) ^ SignBitMask); - return new Unum(_environment, newUnumBits); + valueArray[0] = (uint)value; + UnumBits = new Unum(environment, valueArray).UnumBits; } - - /// - /// Sets the Ubit to the given value and leaves everything else as is. - /// - /// The desired UBit. - /// The BitMask representing the Unum with its UBit set to the given value. - public Unum SetUncertainityBit(bool uncertainityBit) + else { - var newUnumBits = uncertainityBit ? UnumBits | UncertaintyBitMask : UnumBits & (~UncertaintyBitMask); - return new Unum(_environment, newUnumBits); + valueArray[0] = (uint)-value; + UnumBits = new Unum(environment, valueArray, negative: true).UnumBits; } + } - /// - /// Changes the exponent to the bitstring given in the input BitMask and leaves everything else as is. - /// - /// The desired exponent in biased notation. - /// The BitMask representing the Unum with its exponent set to the given value. - public Unum SetExponentBits(BitMask exponent) - { - var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ ExponentMask())) | - (exponent << (FractionSizeSize + ExponentSizeSize + 1 + FractionSize())); - return new Unum(_environment, newUnumBits); - } + #endregion + + #region Methods to set the values of individual Unum structure elements + + /// + /// Assembles the Unum from its pre-computed parts. + /// + /// The SignBit of the Unum. + /// The biased notation of the exponent of the Unum. + /// The fraction of the Unum without the hidden bit. + /// The value of the uncertainity bit (Ubit). + /// The Unum's exponent size, in a notation that is one less than the actual value. + /// The Unum's fraction size, in a notation that is one less than the actual value. + /// The BitMask representing the whole Unum with all the parts set. + private BitMask AssembleUnumBits( + bool signBit, + BitMask exponent, + BitMask fraction, + bool uncertainityBit, + byte exponentSize, + ushort fractionSize) + { + var wholeUnum = new BitMask(exponentSize, Size) << FractionSizeSize; + wholeUnum += fractionSize; - /// - /// Sets the fraction to the given value and leaves everything else as is. - /// - /// The desired fraction without the hidden bit. - /// The BitMask representing the Unum with its fraction set to the given value. - public Unum SetFractionBits(BitMask fraction) - { - var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ FractionMask())) | - (fraction << (FractionSizeSize + ExponentSizeSize + 1)); - return new Unum(_environment, newUnumBits); - } + if (uncertainityBit) wholeUnum += UncertaintyBitMask; - /// - /// Sets the fractionSize to the given value and leaves everything else as is. - /// - /// - /// The desired fractionSize in a notation that is one less than the actual value. - /// - /// The BitMask representing the Unum with its fractionSize set to the given value. - public Unum SetFractionSizeBits(byte fractionSize) - { - var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ FractionSizeMask)) | - new BitMask(fractionSize, Size); - return new Unum(_environment, newUnumBits); - } + wholeUnum += fraction << UnumTagSize; + wholeUnum += exponent << (UnumTagSize + fractionSize + 1); - /// - /// Sets the exponentSize to the given value and leaves everything else as is. - /// - /// The BitMask representing the Unum with its exponentSize set to the given value. - public Unum SetExponentSizeBits(byte exponentSize) - { - var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ ExponentSizeMask)) | - (new BitMask(exponentSize, Size) << FractionSizeSize); - return new Unum(_environment, newUnumBits); - } + if (signBit) wholeUnum += SignBitMask; - #endregion + return wholeUnum; + } - #region Binary data extraction + /// + /// Sets the SignBit to the given value and leaves everything else as is. + /// + /// The desired SignBit. + /// The BitMask representing the Unum with its SignBit set to the given value. + public Unum SetSignBit(bool signBit) + { + var newUnumBits = signBit ? UnumBits | SignBitMask : UnumBits & (new BitMask(Size, allOne: true) ^ SignBitMask); + return new Unum(_environment, newUnumBits); + } - /// - /// Copies the actual integer value represented by the Unum into an array of unsigned integers with the - /// most significant bit of the last element functioning as the signbit. - /// - /// - /// An array of unsigned integers that together represent the integer value of the Unum with the most - /// significant bit of the last uint functioning as a signbit. - /// - public uint[] FractionToUintArray() - { - var resultMask = FractionWithHiddenBit() << (ExponentValueWithBias() - FractionSize()); - var result = new uint[resultMask.SegmentCount]; + /// + /// Sets the Ubit to the given value and leaves everything else as is. + /// + /// The desired UBit. + /// The BitMask representing the Unum with its UBit set to the given value. + public Unum SetUncertainityBit(bool uncertainityBit) + { + var newUnumBits = uncertainityBit ? UnumBits | UncertaintyBitMask : UnumBits & (~UncertaintyBitMask); + return new Unum(_environment, newUnumBits); + } - for (var i = 0; i < resultMask.SegmentCount; i++) result[i] = resultMask.Segments[i]; - if (!IsPositive()) - { - result[resultMask.SegmentCount - 1] |= 0x80000000; - } - else - { - result[resultMask.SegmentCount - 1] <<= 1; - result[resultMask.SegmentCount - 1] >>= 1; - } + /// + /// Changes the exponent to the bitstring given in the input BitMask and leaves everything else as is. + /// + /// The desired exponent in biased notation. + /// The BitMask representing the Unum with its exponent set to the given value. + public Unum SetExponentBits(BitMask exponent) + { + var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ ExponentMask())) | + (exponent << (FractionSizeSize + ExponentSizeSize + 1 + FractionSize())); + return new Unum(_environment, newUnumBits); + } - return result; - } + /// + /// Sets the fraction to the given value and leaves everything else as is. + /// + /// The desired fraction without the hidden bit. + /// The BitMask representing the Unum with its fraction set to the given value. + public Unum SetFractionBits(BitMask fraction) + { + var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ FractionMask())) | + (fraction << (FractionSizeSize + ExponentSizeSize + 1)); + return new Unum(_environment, newUnumBits); + } - #endregion + /// + /// Sets the fractionSize to the given value and leaves everything else as is. + /// + /// + /// The desired fractionSize in a notation that is one less than the actual value. + /// + /// The BitMask representing the Unum with its fractionSize set to the given value. + public Unum SetFractionSizeBits(byte fractionSize) + { + var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ FractionSizeMask)) | + new BitMask(fractionSize, Size); + return new Unum(_environment, newUnumBits); + } - #region Binary data manipulation + /// + /// Sets the exponentSize to the given value and leaves everything else as is. + /// + /// The BitMask representing the Unum with its exponentSize set to the given value. + public Unum SetExponentSizeBits(byte exponentSize) + { + var newUnumBits = (UnumBits & (new BitMask(Size, allOne: true) ^ ExponentSizeMask)) | + (new BitMask(exponentSize, Size) << FractionSizeSize); + return new Unum(_environment, newUnumBits); + } + + #endregion + + #region Binary data extraction + + /// + /// Copies the actual integer value represented by the Unum into an array of unsigned integers with the + /// most significant bit of the last element functioning as the signbit. + /// + /// + /// An array of unsigned integers that together represent the integer value of the Unum with the most + /// significant bit of the last uint functioning as a signbit. + /// + public uint[] FractionToUintArray() + { + var resultMask = FractionWithHiddenBit() << (ExponentValueWithBias() - FractionSize()); + var result = new uint[resultMask.SegmentCount]; - public Unum Negate() + for (var i = 0; i < resultMask.SegmentCount; i++) result[i] = resultMask.Segments[i]; + if (!IsPositive()) { - var newUnumBits = UnumBits ^ SignBitMask; - return new Unum(_environment, newUnumBits); + result[resultMask.SegmentCount - 1] |= 0x80000000; + } + else + { + result[resultMask.SegmentCount - 1] <<= 1; + result[resultMask.SegmentCount - 1] >>= 1; } - #endregion + return result; + } - #region Unum numeric states + #endregion - public bool IsExact() => (UnumBits & UncertaintyBitMask) == _environment.EmptyBitMask; + #region Binary data manipulation - public bool IsPositive() => (UnumBits & SignBitMask) == _environment.EmptyBitMask; + public Unum Negate() + { + var newUnumBits = UnumBits ^ SignBitMask; + return new Unum(_environment, newUnumBits); + } - // This is needed because there are many valid representations of zero in an Unum environment. - public bool IsZero() => - (UnumBits & UncertaintyBitMask) == _environment.EmptyBitMask && - (UnumBits & FractionMask()) == _environment.EmptyBitMask && - (UnumBits & ExponentMask()) == _environment.EmptyBitMask; + #endregion - #endregion + #region Unum numeric states - #region Methods for Utag independent Masks and values + public bool IsExact() => (UnumBits & UncertaintyBitMask) == _environment.EmptyBitMask; - public byte ExponentSize() => (byte)(((UnumBits & ExponentSizeMask) >> FractionSizeSize) + 1).Lowest32Bits; + public bool IsPositive() => (UnumBits & SignBitMask) == _environment.EmptyBitMask; - public ushort FractionSize() => (ushort)((UnumBits & FractionSizeMask) + 1).Lowest32Bits; + // This is needed because there are many valid representations of zero in an Unum environment. + public bool IsZero() => + (UnumBits & UncertaintyBitMask) == _environment.EmptyBitMask && + (UnumBits & FractionMask()) == _environment.EmptyBitMask && + (UnumBits & ExponentMask()) == _environment.EmptyBitMask; - public BitMask FractionMask() - { - var fractionMask = new BitMask(1, Size); - return ((fractionMask << FractionSize()) - 1) << UnumTagSize; - } + #endregion - public BitMask ExponentMask() - { - var exponentMask = new BitMask(1, Size); - return ((exponentMask << ExponentSize()) - 1) << (FractionSize() + UnumTagSize); - } + #region Methods for Utag independent Masks and values - #endregion + public byte ExponentSize() => (byte)(((UnumBits & ExponentSizeMask) >> FractionSizeSize) + 1).Lowest32Bits; - #region Methods for Utag dependent Masks and values + public ushort FractionSize() => (ushort)((UnumBits & FractionSizeMask) + 1).Lowest32Bits; - public BitMask Exponent() => (ExponentMask() & UnumBits) >> (UnumTagSize + FractionSize()); + public BitMask FractionMask() + { + var fractionMask = new BitMask(1, Size); + return ((fractionMask << FractionSize()) - 1) << UnumTagSize; + } - public BitMask Fraction() => (FractionMask() & UnumBits) >> UnumTagSize; + public BitMask ExponentMask() + { + var exponentMask = new BitMask(1, Size); + return ((exponentMask << ExponentSize()) - 1) << (FractionSize() + UnumTagSize); + } - public BitMask FractionWithHiddenBit() => - HiddenBitIsOne() ? Fraction().SetOne(FractionSize()) : Fraction(); + #endregion - public ushort FractionSizeWithHiddenBit() => HiddenBitIsOne() ? (ushort)(FractionSize() + 1) : FractionSize(); + #region Methods for Utag dependent Masks and values - public int Bias() => (1 << (ExponentSize() - 1)) - 1; + public BitMask Exponent() => (ExponentMask() & UnumBits) >> (UnumTagSize + FractionSize()); - public bool HiddenBitIsOne() => Exponent().Lowest32Bits > 0; + public BitMask Fraction() => (FractionMask() & UnumBits) >> UnumTagSize; - public int ExponentValueWithBias() => (int)Exponent().Lowest32Bits - Bias() + (HiddenBitIsOne() ? 0 : 1); + public BitMask FractionWithHiddenBit() => + HiddenBitIsOne() ? Fraction().SetOne(FractionSize()) : Fraction(); - public bool IsNan() => UnumBits == SignalingNotANumber || UnumBits == QuietNotANumber; + public ushort FractionSizeWithHiddenBit() => HiddenBitIsOne() ? (ushort)(FractionSize() + 1) : FractionSize(); - public bool IsPositiveInfinity() => UnumBits == PositiveInfinity; + public int Bias() => (1 << (ExponentSize() - 1)) - 1; - public bool IsNegativeInfinity() => UnumBits == NegativeInfinity; + public bool HiddenBitIsOne() => Exponent().Lowest32Bits > 0; - #endregion + public int ExponentValueWithBias() => (int)Exponent().Lowest32Bits - Bias() + (HiddenBitIsOne() ? 0 : 1); - #region Operations for exact Unums + public bool IsNan() => UnumBits == SignalingNotANumber || UnumBits == QuietNotANumber; - [SuppressMessage( - "Critical Code Smell", - "S3776:Cognitive Complexity of methods should not be too high", - Justification = "Not currently posisble due to TypeConverter limitations.")] - // See: https://github.com/Lombiq/Hastlayer-SDK/issues/62 - public static Unum AddExactUnums(Unum left, Unum right) - { - // Handling special cases first. - if (left.IsNan() || - right.IsNan() || - (left.IsPositiveInfinity() && right.IsNegativeInfinity()) || - (left.IsNegativeInfinity() && right.IsPositiveInfinity())) - { - return new Unum(left._environment, left.QuietNotANumber); - } + public bool IsPositiveInfinity() => UnumBits == PositiveInfinity; - if (left.IsPositiveInfinity() || right.IsPositiveInfinity()) - { - return new Unum(left._environment, left.PositiveInfinity); - } + public bool IsNegativeInfinity() => UnumBits == NegativeInfinity; - if (left.IsNegativeInfinity() || right.IsNegativeInfinity()) - { - return new Unum(left._environment, left.NegativeInfinity); - } + #endregion - AddExactUnumsInner( - left, - right, - out var scratchPad, - out var resultExponentValue, - out var smallerBitsMovedToLeft, - out var resultSignBit); - - // Calculating how the addition changed the exponent of the result. - var exponentChange = scratchPad.FindMostSignificantOnePosition() - (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.FindMostSignificantOnePosition() == 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.FindMostSignificantOnePosition() - 1); - } + #region Operations for exact Unums - if (resultExponent.FindMostSignificantOnePosition() != 0) - { - // Erase the hidden bit if it is set. - scratchPad = scratchPad.SetZero((ushort)(scratchPad.FindMostSignificantOnePosition() - 1)); - resultFractionSize = (ushort)(resultFractionSize == 0 ? 0 : resultFractionSize - 1); - } + [SuppressMessage( + "Critical Code Smell", + "S3776:Cognitive Complexity of methods should not be too high", + Justification = "Not currently posisble due to TypeConverter limitations.")] + // See: https://github.com/Lombiq/Hastlayer-SDK/issues/62 + public static Unum AddExactUnums(Unum left, Unum right) + { + // Handling special cases first. + if (left.IsNan() || + right.IsNan() || + (left.IsPositiveInfinity() && right.IsNegativeInfinity()) || + (left.IsNegativeInfinity() && right.IsPositiveInfinity())) + { + return new Unum(left._environment, left.QuietNotANumber); + } - // 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; + if (left.IsPositiveInfinity() || right.IsPositiveInfinity()) + { + return new Unum(left._environment, left.PositiveInfinity); + } - // Setting the parts of the result Unum to the calculated values. - var resultBitMask = left.AssembleUnumBits( - resultSignBit, - resultExponent, - scratchPad, - resultUbit, - resultExponentSize, - resultFractionSize); + if (left.IsNegativeInfinity() || right.IsNegativeInfinity()) + { + return new Unum(left._environment, left.NegativeInfinity); + } - return new Unum(left._environment, resultBitMask); + AddExactUnumsInner( + left, + right, + out var scratchPad, + out var resultExponentValue, + out var smallerBitsMovedToLeft, + out var resultSignBit); + + // Calculating how the addition changed the exponent of the result. + var exponentChange = scratchPad.FindMostSignificantOnePosition() - (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.FindMostSignificantOnePosition() == 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.FindMostSignificantOnePosition() - 1); } - private static void AddExactUnumsInner( - Unum left, - Unum right, - out BitMask scratchPad, - out int resultExponentValue, - out int smallerBitsMovedToLeft, - out bool resultSignBit) + if (resultExponent.FindMostSignificantOnePosition() != 0) { - var exponentValueDifference = left.ExponentValueWithBias() - right.ExponentValueWithBias(); - var signBitsMatch = left.IsPositive() == right.IsPositive(); - int biggerBitsMovedToLeft; + // Erase the hidden bit if it is set. + scratchPad = scratchPad.SetZero((ushort)(scratchPad.FindMostSignificantOnePosition() - 1)); + resultFractionSize = (ushort)(resultFractionSize == 0 ? 0 : resultFractionSize - 1); + } - 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); - - return; - } + // 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; - if (exponentValueDifference < 0) - { - // 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); - - return; - } + // Setting the parts of the result Unum to the calculated values. + var resultBitMask = left.AssembleUnumBits( + resultSignBit, + resultExponent, + scratchPad, + resultUbit, + resultExponentSize, + resultFractionSize); - // Exponents are equal. - resultExponentValue = left.ExponentValueWithBias(); + return new Unum(left._environment, resultBitMask); + } - // 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. + private static void AddExactUnumsInner( + Unum left, + Unum right, + out BitMask scratchPad, + out int resultExponentValue, + out int smallerBitsMovedToLeft, + out bool resultSignBit) + { + var exponentValueDifference = left.ExponentValueWithBias() - right.ExponentValueWithBias(); + var signBitsMatch = left.IsPositive() == right.IsPositive(); + int biggerBitsMovedToLeft; + + 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); + smallerBitsMovedToLeft = left.FractionSizeMax + 1 - (right.FractionSize() + 1) - exponentValueDifference; + + scratchPad = left.FractionWithHiddenBit() << biggerBitsMovedToLeft; // Adding the aligned Fractions. scratchPad = AddAlignedFractions( - left.FractionWithHiddenBit() << biggerBitsMovedToLeft, + scratchPad, right.FractionWithHiddenBit() << smallerBitsMovedToLeft, signBitsMatch); - if (!signBitsMatch) - { - // False Positive. + return; + } + + if (exponentValueDifference < 0) + { + // 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); + + return; + } + + // 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) + { + // False Positive. #pragma warning disable S3240 // The simplest possible condition syntax should be used - if (left.HiddenBitIsOne() == right.HiddenBitIsOne()) - { - // If the value of the Hidden Bits match we just compare the fractions, - // and get the Sign of the bigger one. - resultSignBit = left.Fraction() >= right.Fraction() - ? !left.IsPositive() // Left Fraction is bigger. - : !right.IsPositive(); // Right Fraction is bigger. - } - else - { - // Otherwise we get the Sign of the number that has a Hidden Bit set. - resultSignBit = left.HiddenBitIsOne() ? !left.IsPositive() : !right.IsPositive(); - } -#pragma warning restore S3240 // The simplest possible condition syntax should be used + if (left.HiddenBitIsOne() == right.HiddenBitIsOne()) + { + // If the value of the Hidden Bits match we just compare the fractions, + // and get the Sign of the bigger one. + resultSignBit = left.Fraction() >= right.Fraction() + ? !left.IsPositive() // Left Fraction is bigger. + : !right.IsPositive(); // Right Fraction is bigger. } else { - resultSignBit = !left.IsPositive(); + // Otherwise we get the Sign of the number that has a Hidden Bit set. + resultSignBit = left.HiddenBitIsOne() ? !left.IsPositive() : !right.IsPositive(); } +#pragma warning restore S3240 // The simplest possible condition syntax should be used } + else + { + resultSignBit = !left.IsPositive(); + } + } - public static Unum SubtractExactUnums(Unum left, Unum right) => AddExactUnums(left, NegateExactUnum(right)); - - public static Unum NegateExactUnum(Unum input) => input.Negate(); + public static Unum SubtractExactUnums(Unum left, Unum right) => AddExactUnums(left, NegateExactUnum(right)); - public static bool AreEqualExactUnums(Unum left, Unum right) => - (left.IsZero() && right.IsZero()) || left.UnumBits == right.UnumBits; + public static Unum NegateExactUnum(Unum input) => input.Negate(); - #endregion + public static bool AreEqualExactUnums(Unum left, Unum right) => + (left.IsZero() && right.IsZero()) || left.UnumBits == right.UnumBits; - #region Helper methods for operations and conversions + #endregion - 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 + #region Helper methods for operations and conversions - if (value < 0) - { - exponent -= (uint)(-2 * value); - } + 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 - return exponent; + if (value < 0) + { + exponent -= (uint)(-2 * value); } - public static byte ExponentValueToExponentSize(int value) - { - byte size = 1; + return exponent; + } - if (value > 0) while (value > 1 << (size - 1)) size++; - else while (-value >= 1 << (size - 1)) size++; + public static byte ExponentValueToExponentSize(int value) + { + byte size = 1; - return size; - } + if (value > 0) while (value > 1 << (size - 1)) size++; + else while (-value >= 1 << (size - 1)) size++; - public static BitMask AddAlignedFractions(BitMask left, BitMask right, bool signBitsMatch) - { - if (signBitsMatch) return left + right; + return size; + } - var mask = left > right ? left - right : right - left; - return mask; - } + public static BitMask AddAlignedFractions(BitMask left, BitMask right, bool signBitsMatch) + { + if (signBitsMatch) return left + right; - #endregion + var mask = left > right ? left - right : right - left; + return mask; + } - #region Operators + #endregion - public static Unum operator +(Unum left, Unum right) => AddExactUnums(left, right); + #region Operators - public static Unum operator -(Unum x) => NegateExactUnum(x); + public static Unum operator +(Unum left, Unum right) => AddExactUnums(left, right); - public static Unum operator -(Unum left, Unum right) => SubtractExactUnums(left, right); + public static Unum operator -(Unum x) => NegateExactUnum(x); - public static bool operator ==(Unum left, Unum right) => AreEqualExactUnums(left, right); + public static Unum operator -(Unum left, Unum right) => SubtractExactUnums(left, right); - public static bool operator !=(Unum left, Unum right) => !(left == right); + public static bool operator ==(Unum left, Unum right) => AreEqualExactUnums(left, right); - // Converting from an Unum to int results in information loss, so only allowing it explicitly (with a cast). - public static explicit operator int(Unum x) - { - uint result; + public static bool operator !=(Unum left, Unum right) => !(left == right); - if ((x.ExponentValueWithBias() + x.FractionSizeWithHiddenBit()) < 31) // The Unum fits into the range. - result = (x.FractionWithHiddenBit() << (x.ExponentValueWithBias() - x.FractionSize())).Lowest32Bits; - else return x.IsPositive() ? int.MaxValue : int.MinValue; // The absolute value of the Unum is too large. + // Converting from an Unum to int results in information loss, so only allowing it explicitly (with a cast). + public static explicit operator int(Unum x) + { + uint result; - return x.IsPositive() ? (int)result : -(int)result; - } + if ((x.ExponentValueWithBias() + x.FractionSizeWithHiddenBit()) < 31) // The Unum fits into the range. + result = (x.FractionWithHiddenBit() << (x.ExponentValueWithBias() - x.FractionSize())).Lowest32Bits; + else return x.IsPositive() ? int.MaxValue : int.MinValue; // The absolute value of the Unum is too large. - public static explicit operator uint(Unum x) => - (x.FractionWithHiddenBit() << (x.ExponentValueWithBias() - x.FractionSize())).Lowest32Bits; + return x.IsPositive() ? (int)result : -(int)result; + } - // This is not well tested yet. - public static explicit operator float(Unum x) - { - // Handling special cases first. - if (x.IsNan()) return float.NaN; - if (x.IsNegativeInfinity()) return float.NegativeInfinity; - if (x.IsPositiveInfinity()) return float.PositiveInfinity; - if (x.ExponentValueWithBias() > 127) // Exponent is too big for float format. - return x.IsPositive() ? float.PositiveInfinity : float.NegativeInfinity; - if (x.ExponentValueWithBias() < -126) return x.IsPositive() ? 0 : -0; // Exponent is too small for float format. - - var result = (x.Fraction() << (23 - x.FractionSize())).Lowest32Bits; - result |= (uint)(x.ExponentValueWithBias() + 127) << 23; - - return x.IsPositive() ? - BitConverter.ToSingle(BitConverter.GetBytes(result), 0) : - -BitConverter.ToSingle(BitConverter.GetBytes(result), 0); - } + public static explicit operator uint(Unum x) => + (x.FractionWithHiddenBit() << (x.ExponentValueWithBias() - x.FractionSize())).Lowest32Bits; + + // This is not well tested yet. + public static explicit operator float(Unum x) + { + // Handling special cases first. + if (x.IsNan()) return float.NaN; + if (x.IsNegativeInfinity()) return float.NegativeInfinity; + if (x.IsPositiveInfinity()) return float.PositiveInfinity; + if (x.ExponentValueWithBias() > 127) // Exponent is too big for float format. + return x.IsPositive() ? float.PositiveInfinity : float.NegativeInfinity; + if (x.ExponentValueWithBias() < -126) return x.IsPositive() ? 0 : -0; // Exponent is too small for float format. + + var result = (x.Fraction() << (23 - x.FractionSize())).Lowest32Bits; + result |= (uint)(x.ExponentValueWithBias() + 127) << 23; + + return x.IsPositive() ? + BitConverter.ToSingle(BitConverter.GetBytes(result), 0) : + -BitConverter.ToSingle(BitConverter.GetBytes(result), 0); + } - #endregion + #endregion - #region Overrides - public override bool Equals(object obj) => obj is Unum other && this == other; + #region Overrides + public override bool Equals(object obj) => obj is Unum other && this == other; - public bool Equals(Unum other) => this == other; + public bool Equals(Unum other) => this == other; - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - return ((_environment != null ? _environment.GetHashCode() : 0) * 397) ^ UnumBits.GetHashCode(); - } + return ((_environment != null ? _environment.GetHashCode() : 0) * 397) ^ UnumBits.GetHashCode(); } + } - public override string ToString() => $"{nameof(Unum)}(Bits:{UnumBits};Environment:{_environment})"; + public override string ToString() => $"{nameof(Unum)}(Bits:{UnumBits};Environment:{_environment})"; - #endregion - } + #endregion } diff --git a/Unum/UnumConfiguration.cs b/Unum/UnumConfiguration.cs index 22268de..21be3b8 100644 --- a/Unum/UnumConfiguration.cs +++ b/Unum/UnumConfiguration.cs @@ -1,41 +1,40 @@ -namespace Lombiq.Arithmetics -{ - public class UnumConfiguration - { - /// - /// Gets the number of bits in the exponent. - /// - public byte ExponentSize { get; } - - /// - /// Gets the number of bits in the fraction. - /// - public byte FractionSize { get; } +namespace Lombiq.Arithmetics; - public UnumConfiguration(byte exponentSize, byte fractionSize) - { - ExponentSize = exponentSize; - FractionSize = fractionSize; - } +public class UnumConfiguration +{ + /// + /// Gets the number of bits in the exponent. + /// + public byte ExponentSize { get; } - public static UnumConfiguration FromIeeeConfiguration(IeeeConfiguration configuration) => - configuration switch - { - IeeeConfiguration.HalfPrecision => new UnumConfiguration(5, 10), - IeeeConfiguration.SinglePrecision => new UnumConfiguration(8, 23), - IeeeConfiguration.DoublePrecision => new UnumConfiguration(11, 52), - IeeeConfiguration.ExtendedPrecision => new UnumConfiguration(15, 64), - IeeeConfiguration.QuadPrecision => new UnumConfiguration(15, 112), - _ => new UnumConfiguration(0, 0), - }; - } + /// + /// Gets the number of bits in the fraction. + /// + public byte FractionSize { get; } - public enum IeeeConfiguration + public UnumConfiguration(byte exponentSize, byte fractionSize) { - HalfPrecision, // 16-bit. - SinglePrecision, // 32-bit. - DoublePrecision, // 64-bit. - ExtendedPrecision, // 80-bit (Intel x87). - QuadPrecision, // 128-bit. + ExponentSize = exponentSize; + FractionSize = fractionSize; } + + public static UnumConfiguration FromIeeeConfiguration(IeeeConfiguration configuration) => + configuration switch + { + IeeeConfiguration.HalfPrecision => new UnumConfiguration(5, 10), + IeeeConfiguration.SinglePrecision => new UnumConfiguration(8, 23), + IeeeConfiguration.DoublePrecision => new UnumConfiguration(11, 52), + IeeeConfiguration.ExtendedPrecision => new UnumConfiguration(15, 64), + IeeeConfiguration.QuadPrecision => new UnumConfiguration(15, 112), + _ => new UnumConfiguration(0, 0), + }; +} + +public enum IeeeConfiguration +{ + HalfPrecision, // 16-bit. + SinglePrecision, // 32-bit. + DoublePrecision, // 64-bit. + ExtendedPrecision, // 80-bit (Intel x87). + QuadPrecision, // 128-bit. } diff --git a/Unum/UnumEnvironment.cs b/Unum/UnumEnvironment.cs index 11ae948..fd2fe57 100644 --- a/Unum/UnumEnvironment.cs +++ b/Unum/UnumEnvironment.cs @@ -1,214 +1,213 @@ using System.Diagnostics.CodeAnalysis; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +public class UnumEnvironment { - public class UnumEnvironment + #region Unum structure + + /// + /// Gets the number of bits allocated to store the maximum number of bits in the exponent field of a unum. + /// + public byte ExponentSizeSize { get; } // "esizesize" + + /// + /// Gets the number of bits allocated to store the maximum number of bits in the fraction field of a unum. + /// + public byte FractionSizeSize { get; } // "fsizesize" + + /// + /// Gets the maximum number of bits usable to store the exponent. + /// + public byte ExponentSizeMax { get; } // "esizemax" + + /// + /// Gets the maximum number of bits usable to store the fraction. + /// + public ushort FractionSizeMax { get; } // "fsizemax" + + /// + /// Gets the number of bits that are used for storing the utag. + /// + public byte UnumTagSize { get; } // "utagsize" + + /// + /// Gets the maximum number of bits used by the environment. + /// + public ushort Size { get; } // "maxubits" + #endregion + + #region Unum masks + + /// + /// Gets an empty BitMask the size of the environment. + /// + public BitMask EmptyBitMask { get; } + + /// + /// Gets a BitMask for picking out the UncertainityBit. + /// + public BitMask UncertaintyBitMask { get; } // "ubitmask" + + /// + /// Gets a BitMask for picking out the ExponentSize. + /// + public BitMask ExponentSizeMask { get; } // "esizemask" + + /// + /// Gets a BitMask for picking out the FractionSize. + /// + public BitMask FractionSizeMask { get; } // "fsizemask" + + /// + /// Gets a BitMask for picking out the ExponentSize and FractionSize. + /// + public BitMask ExponentAndFractionSizeMask { get; } // "efsizemask" + + /// + /// Gets a BitMask for picking out the utag. + /// + public BitMask UnumTagMask { get; } // "utagmask" + + /// + /// Gets a BitMask for picking out the SignBit. + /// + public BitMask SignBitMask { get; } // "signbigu" + #endregion + + #region Unum special values + + /// + /// Gets a BitMask for the Unit in the Last Place or Unit of Least Precision. + /// + [SuppressMessage( + "Minor Code Smell", + "S100:Methods and properties should be named in PascalCase", + Justification = "This is an acronym.")] + public BitMask ULP { get; } + + /// + /// Gets the positive infinity for the given unum environment. + /// + public BitMask PositiveInfinity { get; } // "posinfu" + + /// + /// Gets the negative infinity for the given unum environment. + /// + public BitMask NegativeInfinity { get; } // "neginfu" + + /// + /// Gets a BitMask for the notation of a quiet NaN value in the environment. + /// + public BitMask QuietNotANumber { get; } // "qNaNu" + + /// + /// Gets a BitMask for the notation of a signaling NaN value in the environment. + /// + public BitMask SignalingNotANumber { get; } // "sNaNu" + + /// + /// Gets the largest magnitude positive real number. One ULP less than infinity. + /// + public BitMask LargestPositive { get; } // "maxrealu" + + /// + /// Gets the smallest magnitude positive real number. One ULP more than 0. + /// + public BitMask SmallestPositive { get; } // "smallsubnormalu" + + /// + /// Gets the largest magnitude negative real number. One ULP more than negative infinity. + /// + public BitMask LargestNegative { get; } // "negbigu" + + /// + /// Gets a BitMask for the largest magnitude negative unum in the environment. + /// + public BitMask MinRealU { get; } // "minrealu" + + #endregion + + public UnumEnvironment(byte exponentSizeSize, byte fractionSizeSize) { - #region Unum structure - - /// - /// Gets the number of bits allocated to store the maximum number of bits in the exponent field of a unum. - /// - public byte ExponentSizeSize { get; } // "esizesize" - - /// - /// Gets the number of bits allocated to store the maximum number of bits in the fraction field of a unum. - /// - public byte FractionSizeSize { get; } // "fsizesize" - - /// - /// Gets the maximum number of bits usable to store the exponent. - /// - public byte ExponentSizeMax { get; } // "esizemax" - - /// - /// Gets the maximum number of bits usable to store the fraction. - /// - public ushort FractionSizeMax { get; } // "fsizemax" - - /// - /// Gets the number of bits that are used for storing the utag. - /// - public byte UnumTagSize { get; } // "utagsize" - - /// - /// Gets the maximum number of bits used by the environment. - /// - public ushort Size { get; } // "maxubits" - #endregion - - #region Unum masks - - /// - /// Gets an empty BitMask the size of the environment. - /// - public BitMask EmptyBitMask { get; } - - /// - /// Gets a BitMask for picking out the UncertainityBit. - /// - public BitMask UncertaintyBitMask { get; } // "ubitmask" - - /// - /// Gets a BitMask for picking out the ExponentSize. - /// - public BitMask ExponentSizeMask { get; } // "esizemask" - - /// - /// Gets a BitMask for picking out the FractionSize. - /// - public BitMask FractionSizeMask { get; } // "fsizemask" - - /// - /// Gets a BitMask for picking out the ExponentSize and FractionSize. - /// - public BitMask ExponentAndFractionSizeMask { get; } // "efsizemask" - - /// - /// Gets a BitMask for picking out the utag. - /// - public BitMask UnumTagMask { get; } // "utagmask" - - /// - /// Gets a BitMask for picking out the SignBit. - /// - public BitMask SignBitMask { get; } // "signbigu" - #endregion - - #region Unum special values - - /// - /// Gets a BitMask for the Unit in the Last Place or Unit of Least Precision. - /// - [SuppressMessage( - "Minor Code Smell", - "S100:Methods and properties should be named in PascalCase", - Justification = "This is an acronym.")] - public BitMask ULP { get; } - - /// - /// Gets the positive infinity for the given unum environment. - /// - public BitMask PositiveInfinity { get; } // "posinfu" - - /// - /// Gets the negative infinity for the given unum environment. - /// - public BitMask NegativeInfinity { get; } // "neginfu" - - /// - /// Gets a BitMask for the notation of a quiet NaN value in the environment. - /// - public BitMask QuietNotANumber { get; } // "qNaNu" - - /// - /// Gets a BitMask for the notation of a signaling NaN value in the environment. - /// - public BitMask SignalingNotANumber { get; } // "sNaNu" - - /// - /// Gets the largest magnitude positive real number. One ULP less than infinity. - /// - public BitMask LargestPositive { get; } // "maxrealu" - - /// - /// Gets the smallest magnitude positive real number. One ULP more than 0. - /// - public BitMask SmallestPositive { get; } // "smallsubnormalu" - - /// - /// Gets the largest magnitude negative real number. One ULP more than negative infinity. - /// - public BitMask LargestNegative { get; } // "negbigu" - - /// - /// Gets a BitMask for the largest magnitude negative unum in the environment. - /// - public BitMask MinRealU { get; } // "minrealu" - - #endregion - - public UnumEnvironment(byte exponentSizeSize, byte fractionSizeSize) - { - // Initializing structure. - ExponentSizeSize = exponentSizeSize; - FractionSizeSize = fractionSizeSize; - - ExponentSizeMax = (byte)UnumHelper.SegmentSizeSizeToSegmentSize(ExponentSizeSize); - FractionSizeMax = UnumHelper.SegmentSizeSizeToSegmentSize(FractionSizeSize); + // Initializing structure. + ExponentSizeSize = exponentSizeSize; + FractionSizeSize = fractionSizeSize; - UnumTagSize = (byte)(1 + ExponentSizeSize + FractionSizeSize); - Size = (ushort)(1 + ExponentSizeMax + FractionSizeMax + UnumTagSize); + ExponentSizeMax = (byte)UnumHelper.SegmentSizeSizeToSegmentSize(ExponentSizeSize); + FractionSizeMax = UnumHelper.SegmentSizeSizeToSegmentSize(FractionSizeSize); - // Initializing masks. - EmptyBitMask = new BitMask(Size); + UnumTagSize = (byte)(1 + ExponentSizeSize + FractionSizeSize); + Size = (ushort)(1 + ExponentSizeMax + FractionSizeMax + UnumTagSize); - UncertaintyBitMask = new BitMask(Size).SetOne((ushort)(UnumTagSize - 1)); + // Initializing masks. + EmptyBitMask = new BitMask(Size); - FractionSizeMask = new BitMask(Size).SetOne(FractionSizeSize) - 1; + UncertaintyBitMask = new BitMask(Size).SetOne((ushort)(UnumTagSize - 1)); - ExponentSizeMask = UncertaintyBitMask - 1 - FractionSizeMask; + FractionSizeMask = new BitMask(Size).SetOne(FractionSizeSize) - 1; - ExponentAndFractionSizeMask = ExponentSizeMask | FractionSizeMask; - UnumTagMask = UncertaintyBitMask + ExponentAndFractionSizeMask; + ExponentSizeMask = UncertaintyBitMask - 1 - FractionSizeMask; - SignBitMask = new BitMask(Size).SetOne((ushort)(Size - 1)); + ExponentAndFractionSizeMask = ExponentSizeMask | FractionSizeMask; + UnumTagMask = UncertaintyBitMask + ExponentAndFractionSizeMask; - // Initializing environment. - ULP = new BitMask(Size).SetOne(UnumTagSize); + SignBitMask = new BitMask(Size).SetOne((ushort)(Size - 1)); - PositiveInfinity = new BitMask(Size).SetOne((ushort)(Size - 1)) - 1 - UncertaintyBitMask; + // Initializing environment. + ULP = new BitMask(Size).SetOne(UnumTagSize); - NegativeInfinity = new BitMask(Size).SetOne((ushort)(Size - 1)) + PositiveInfinity; + PositiveInfinity = new BitMask(Size).SetOne((ushort)(Size - 1)) - 1 - UncertaintyBitMask; - LargestPositive = PositiveInfinity - ULP; - SmallestPositive = ExponentAndFractionSizeMask + ULP; + NegativeInfinity = new BitMask(Size).SetOne((ushort)(Size - 1)) + PositiveInfinity; - LargestNegative = NegativeInfinity - ULP; + LargestPositive = PositiveInfinity - ULP; + SmallestPositive = ExponentAndFractionSizeMask + ULP; - MinRealU = LargestPositive + (1U << (Size - 1)); + LargestNegative = NegativeInfinity - ULP; - QuietNotANumber = PositiveInfinity + UncertaintyBitMask; - SignalingNotANumber = NegativeInfinity + UncertaintyBitMask; - } + MinRealU = LargestPositive + (1U << (Size - 1)); - public override string ToString() => - $"{nameof(UnumEnvironment)}(Exponent:{ExponentSizeSize};Fraction:{FractionSizeSize})"; + QuietNotANumber = PositiveInfinity + UncertaintyBitMask; + SignalingNotANumber = NegativeInfinity + UncertaintyBitMask; + } - public static UnumEnvironment FromConfigurationValues(byte eSize, ushort fSize) => - new(UnumHelper.SegmentSizeToSegmentSizeSize(eSize), UnumHelper.SegmentSizeToSegmentSizeSize(fSize)); + public override string ToString() => + $"{nameof(UnumEnvironment)}(Exponent:{ExponentSizeSize};Fraction:{FractionSizeSize})"; - public static UnumEnvironment FromConfiguration(UnumConfiguration configuration) => - FromConfigurationValues(configuration.ExponentSize, configuration.FractionSize); + public static UnumEnvironment FromConfigurationValues(byte eSize, ushort fSize) => + new(UnumHelper.SegmentSizeToSegmentSizeSize(eSize), UnumHelper.SegmentSizeToSegmentSizeSize(fSize)); - public static UnumEnvironment FromStandardEnvironment(StandardEnvironment environment) => - environment switch - { - StandardEnvironment.Warlpiri => - new UnumEnvironment(0, 0), - StandardEnvironment.HalfPrecisionLike => - FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.HalfPrecision)), - StandardEnvironment.SinglePrecisionLike => - FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.SinglePrecision)), - StandardEnvironment.DoublePrecisionLike => - FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.DoublePrecision)), - StandardEnvironment.ExtendedPrecisionLike => - FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.ExtendedPrecision)), - StandardEnvironment.QuadPrecisionLike => - FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.QuadPrecision)), - _ => FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.SinglePrecision)), - }; + public static UnumEnvironment FromConfiguration(UnumConfiguration configuration) => + FromConfigurationValues(configuration.ExponentSize, configuration.FractionSize); - public static UnumEnvironment GetDefaultEnvironment() => FromStandardEnvironment(StandardEnvironment.SinglePrecisionLike); - } + public static UnumEnvironment FromStandardEnvironment(StandardEnvironment environment) => + environment switch + { + StandardEnvironment.Warlpiri => + new UnumEnvironment(0, 0), + StandardEnvironment.HalfPrecisionLike => + FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.HalfPrecision)), + StandardEnvironment.SinglePrecisionLike => + FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.SinglePrecision)), + StandardEnvironment.DoublePrecisionLike => + FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.DoublePrecision)), + StandardEnvironment.ExtendedPrecisionLike => + FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.ExtendedPrecision)), + StandardEnvironment.QuadPrecisionLike => + FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.QuadPrecision)), + _ => FromConfiguration(UnumConfiguration.FromIeeeConfiguration(IeeeConfiguration.SinglePrecision)), + }; + + public static UnumEnvironment GetDefaultEnvironment() => FromStandardEnvironment(StandardEnvironment.SinglePrecisionLike); +} - public enum StandardEnvironment - { - Warlpiri, // 4-bit. - HalfPrecisionLike, // 33-bit. - SinglePrecisionLike, // 50-bit. - DoublePrecisionLike, // 92-bit. - ExtendedPrecisionLike, // 92-bit. - QuadPrecisionLike, // 157-bit. - } +public enum StandardEnvironment +{ + Warlpiri, // 4-bit. + HalfPrecisionLike, // 33-bit. + SinglePrecisionLike, // 50-bit. + DoublePrecisionLike, // 92-bit. + ExtendedPrecisionLike, // 92-bit. + QuadPrecisionLike, // 157-bit. } diff --git a/Unum/UnumException.cs b/Unum/UnumException.cs index fdd2ae3..c147a5e 100644 --- a/Unum/UnumException.cs +++ b/Unum/UnumException.cs @@ -1,22 +1,21 @@ using System; using System.Runtime.Serialization; -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +[Serializable] +public class UnumException : Exception { - [Serializable] - public class UnumException : Exception - { - public UnumException(string message) - : base(message) { } + public UnumException(string message) + : base(message) { } - public UnumException(string message, Exception innerException) - : base(message, innerException) { } + public UnumException(string message, Exception innerException) + : base(message, innerException) { } - public UnumException() { } + public UnumException() { } - protected UnumException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } + protected UnumException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } diff --git a/Unum/UnumHelper.cs b/Unum/UnumHelper.cs index 44c8f11..c8f0e1a 100644 --- a/Unum/UnumHelper.cs +++ b/Unum/UnumHelper.cs @@ -1,101 +1,100 @@ -namespace Lombiq.Arithmetics +namespace Lombiq.Arithmetics; + +public static class UnumHelper { - public static class UnumHelper + /// + /// Calculates the maximum number of bits to describe the size of the given segment, + /// e.g. "eSizeSize" for "eSize", which is essentially the binary logarithm of the segment size. + /// + /// The size of the unum segment (fraction or exponent). + /// The maximum size of the unum segment size. + public static byte SegmentSizeToSegmentSizeSize(ushort segmentSize) { - /// - /// Calculates the maximum number of bits to describe the size of the given segment, - /// e.g. "eSizeSize" for "eSize", which is essentially the binary logarithm of the segment size. - /// - /// The size of the unum segment (fraction or exponent). - /// The maximum size of the unum segment size. - public static byte SegmentSizeToSegmentSizeSize(ushort segmentSize) - { - if (segmentSize is 0 or 1) return 0; + if (segmentSize is 0 or 1) return 0; - segmentSize--; + segmentSize--; - byte position = 15; // Position of the most significant 1-bit. - while ((segmentSize >> position) == 0) { position--; } - position++; + byte position = 15; // Position of the most significant 1-bit. + while ((segmentSize >> position) == 0) { position--; } + position++; - return position; - } + return position; + } - /// - /// Calculates the maximum number of bits of a segment given its "segment size size", - /// which is essentially 2 to the power of "segmentSizeSize". - /// - /// The size of the segment size. - /// The maximum number of bits of a segment. - public static ushort SegmentSizeSizeToSegmentSize(byte segmentSizeSize) => - (ushort)(1 << segmentSizeSize); + /// + /// Calculates the maximum number of bits of a segment given its "segment size size", + /// which is essentially 2 to the power of "segmentSizeSize". + /// + /// The size of the segment size. + /// The maximum number of bits of a segment. + public static ushort SegmentSizeSizeToSegmentSize(byte segmentSizeSize) => + (ushort)(1 << segmentSizeSize); - /// - /// Calculates whether a unum with the given configuration of exponent and fraction size can fit - /// into the given number of bits. - /// - /// The maximum size of the exponent. - /// The maximum size of the fraction. - /// The maximum size allowed for the unum. - /// Whether the number of bits required to store the unum - /// with the given configuration fits the desired maximum size. - public static bool ConfigurationFitsSize(byte eSize, ushort fSize, ushort maximumSize) => - ConfigurationRequiredMaximumBits(eSize, fSize) <= maximumSize; + /// + /// Calculates whether a unum with the given configuration of exponent and fraction size can fit + /// into the given number of bits. + /// + /// The maximum size of the exponent. + /// The maximum size of the fraction. + /// The maximum size allowed for the unum. + /// Whether the number of bits required to store the unum + /// with the given configuration fits the desired maximum size. + public static bool ConfigurationFitsSize(byte eSize, ushort fSize, ushort maximumSize) => + ConfigurationRequiredMaximumBits(eSize, fSize) <= maximumSize; - /// - /// Calculates the maximum necessary number of bits that a unum with the given configuration requires. - /// - /// The maximum size of the exponent. - /// The maximum size of the fraction. - /// The maximum number of bits for the given configuration. - public static ushort ConfigurationRequiredMaximumBits(byte eSize, ushort fSize) => - // Sign bit + exponent size + fraction size + - // uncertainty bit + exponent size size + fraction size size. - (ushort)(1 + eSize + fSize + - 1 + SegmentSizeToSegmentSizeSize(eSize) + SegmentSizeToSegmentSizeSize(fSize)); + /// + /// Calculates the maximum necessary number of bits that a unum with the given configuration requires. + /// + /// The maximum size of the exponent. + /// The maximum size of the fraction. + /// The maximum number of bits for the given configuration. + public static ushort ConfigurationRequiredMaximumBits(byte eSize, ushort fSize) => + // Sign bit + exponent size + fraction size + + // uncertainty bit + exponent size size + fraction size size. + (ushort)(1 + eSize + fSize + + 1 + SegmentSizeToSegmentSizeSize(eSize) + SegmentSizeToSegmentSizeSize(fSize)); - /// - /// Calculates the maximum number of bits required for the given unum environment. - /// - /// The size of the maximum size of the exponent. - /// The size of the maximum size of the fraction. - /// The maximum size allowed for the unum. - /// Whether the unum of the given environment fits the desired number of bits. - public static bool EnvironmentFitsSize(byte eSizeSize, byte fSizeSize, ushort maximumSize) => - EnvironmentRequiredMaximumBits(eSizeSize, fSizeSize) <= maximumSize; + /// + /// Calculates the maximum number of bits required for the given unum environment. + /// + /// The size of the maximum size of the exponent. + /// The size of the maximum size of the fraction. + /// The maximum size allowed for the unum. + /// Whether the unum of the given environment fits the desired number of bits. + public static bool EnvironmentFitsSize(byte eSizeSize, byte fSizeSize, ushort maximumSize) => + EnvironmentRequiredMaximumBits(eSizeSize, fSizeSize) <= maximumSize; - /// - /// Calculates the maximum necessary number of bits that a unum with the given environment requires. - /// - /// The size of the maximum size of the exponent. - /// The size of the maximum size of the fraction. - /// The maximum number of bits for the given environment. - public static ushort EnvironmentRequiredMaximumBits(byte eSizeSize, byte fSizeSize) => - // Sign bit + exponent size + fraction size + - // uncertainty bit + exponent size size + fraction size size. - (ushort)(1 + SegmentSizeSizeToSegmentSize(eSizeSize) + SegmentSizeSizeToSegmentSize(fSizeSize) + - 1 + eSizeSize + fSizeSize); + /// + /// Calculates the maximum necessary number of bits that a unum with the given environment requires. + /// + /// The size of the maximum size of the exponent. + /// The size of the maximum size of the fraction. + /// The maximum number of bits for the given environment. + public static ushort EnvironmentRequiredMaximumBits(byte eSizeSize, byte fSizeSize) => + // Sign bit + exponent size + fraction size + + // uncertainty bit + exponent size size + fraction size size. + (ushort)(1 + SegmentSizeSizeToSegmentSize(eSizeSize) + SegmentSizeSizeToSegmentSize(fSizeSize) + + 1 + eSizeSize + fSizeSize); - public static int BitsRequiredByLargestExpressablePositiveInteger(UnumEnvironment environment) => - (1 << (environment.ExponentSizeMax - 1)) + 1; + public static int BitsRequiredByLargestExpressablePositiveInteger(UnumEnvironment environment) => + (1 << (environment.ExponentSizeMax - 1)) + 1; - /// - /// Calculates the biggest expressible integer in the given environment in an integer-like notation. - /// Returns an empty BitMask if the calculated number would be too big to fit in a BitMask of - /// the size of the environment. - /// - /// The environment thats Largest Expressible Integer needs to be calculated. - /// - /// The biggest expressible integer in the given environment if it fits in a BitMask the size of the - /// environment, an empty BitMask otherwise. - /// - public static BitMask LargestExpressablePositiveInteger(UnumEnvironment environment) - { - if (BitsRequiredByLargestExpressablePositiveInteger(environment) > - environment.EmptyBitMask.SegmentCount * 32) return environment.EmptyBitMask; + /// + /// Calculates the biggest expressible integer in the given environment in an integer-like notation. + /// Returns an empty BitMask if the calculated number would be too big to fit in a BitMask of + /// the size of the environment. + /// + /// The environment thats Largest Expressible Integer needs to be calculated. + /// + /// The biggest expressible integer in the given environment if it fits in a BitMask the size of the + /// environment, an empty BitMask otherwise. + /// + public static BitMask LargestExpressablePositiveInteger(UnumEnvironment environment) + { + if (BitsRequiredByLargestExpressablePositiveInteger(environment) > + environment.EmptyBitMask.SegmentCount * 32) return environment.EmptyBitMask; - return (environment.EmptyBitMask.SetOne(environment.FractionSizeMax) - 1) << - ((1 << (environment.ExponentSizeMax - 1)) - environment.FractionSizeMax + 1); - } + return (environment.EmptyBitMask.SetOne(environment.FractionSizeMax) - 1) << + ((1 << (environment.ExponentSizeMax - 1)) - environment.FractionSizeMax + 1); } } From e521350d60a5f1e3e1fbff5406d58dd59f78be12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Leh=C3=B3czky?= Date: Sun, 27 Mar 2022 16:30:35 +0200 Subject: [PATCH 3/3] Re-wrapping, mostly comments --- BitMask/BitMask.cs | 26 +++-- .../PositTests/PositTests.cs | 4 +- .../Properties/AssemblyInfo.cs | 15 ++- .../UnumTests/UnumEnvironmentTests.cs | 52 +++++----- .../UnumTests/UnumTests.cs | 10 +- Posit/Posit.cs | 16 +-- Posit/Posit32.cs | 27 +++--- Posit/Quire.cs | 4 +- Properties/AssemblyInfo.cs | 15 ++- Unum/Unum.cs | 97 +++++++++---------- Unum/UnumEnvironment.cs | 10 +- Unum/UnumHelper.cs | 33 +++---- 12 files changed, 152 insertions(+), 157 deletions(-) diff --git a/BitMask/BitMask.cs b/BitMask/BitMask.cs index 2fb95ae..59e4052 100644 --- a/BitMask/BitMask.cs +++ b/BitMask/BitMask.cs @@ -59,8 +59,8 @@ public BitMask(ushort size, bool allOne = false) SegmentCount = (ushort)((size >> 5) + (partialSegment == 0 ? 0 : 1)); Size = size; - // Creating a temporary array, so the items aren't added using ImmutableArray.Add, because that instantiates - // a new array for each execution. + // Creating a temporary array, so the items aren't added using ImmutableArray.Add, because that instantiates a + // new array for each execution. var segments = new uint[SegmentCount]; if (allOne) @@ -82,7 +82,7 @@ public BitMask(BitMask source) Segments = source.Segments; } - #endregion + #endregion Constructors #region Static factories @@ -94,7 +94,7 @@ public static BitMask FromImmutableArray(ImmutableArray segments, ushort s return new BitMask(intermediarySegments, size); } - #endregion + #endregion Static factories #region BitMask manipulation functions @@ -150,8 +150,8 @@ public BitMask ShiftOutLeastSignificantZeros() /// /// Sets the segment on the given index to the segment given as an argument. /// - /// /// The index of the Segment to set. - /// /// The segment that the BitMask's segment on the given index will be set to. + /// The index of the Segment to set. + /// The segment that the BitMask's segment on the given index will be set to. /// A BitMask where the trailing zeros are shifted out to the right. public BitMask SetSegment(int index, uint segment) { @@ -160,7 +160,7 @@ public BitMask SetSegment(int index, uint segment) return FromImmutableArray(Segments.SetItem(index, segment)); } - #endregion + #endregion BitMask manipulation functions #region Operators @@ -384,15 +384,14 @@ public BitMask SetSegment(int index, uint segment) return new BitMask(segments); } - #endregion + #endregion Operators #region Helper functions /// /// Finds the most significant 1-bit. /// - /// Returns the position (not index!) of the most significant 1-bit - /// or zero if there is none. + /// Returns the position (not index!) of the most significant 1-bit or zero if there is none. public ushort FindMostSignificantOnePosition() { ushort position = 0; @@ -438,8 +437,7 @@ public ushort LengthOfRunOfBits(ushort startingPosition) /// /// Finds the least significant 1-bit. /// - /// Returns the position (not index!) of the least significant 1-bit - /// or zero if there is none. + /// Returns the position (not index!) of the least significant 1-bit or zero if there is none. public ushort FindLeastSignificantOnePosition() { ushort position = 1; @@ -470,7 +468,7 @@ public ushort FindLeastSignificantOnePosition() // Array indexer is not supported by Hastlayer yet. //// public uint this[int i] => Segments[i]; - #endregion + #endregion Helper functions #region Overrides @@ -488,5 +486,5 @@ public override int GetHashCode() public override string ToString() => string.Join(", ", Segments); - #endregion + #endregion Overrides } diff --git a/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs b/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs index 31773ca..7d10ab7 100644 --- a/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs +++ b/Lombiq.Arithmetics.Tests/PositTests/PositTests.cs @@ -80,8 +80,8 @@ public void PositIsCorrectlyConstructedFromUint() new Posit(_environment_8_2, 90U).PositBits.ShouldBe(new BitMask(0x6A, _environment_12_2.Size)); new Posit(_environment_8_2, 82U).PositBits.ShouldBe(new BitMask(0x69, _environment_12_2.Size)); - // Numbers out of range don't get rounded up infinity. They get rounded to the biggest representable - // finite value (MaxValue). + // Numbers out of range don't get rounded up infinity. They get rounded to the biggest representable finite + // value (MaxValue). new Posit(_environment_6_1, 500U).PositBits.ShouldBe(_environment_6_1.MaxValueBitMask); } diff --git a/Lombiq.Arithmetics.Tests/Properties/AssemblyInfo.cs b/Lombiq.Arithmetics.Tests/Properties/AssemblyInfo.cs index e4c2189..28a9ea0 100644 --- a/Lombiq.Arithmetics.Tests/Properties/AssemblyInfo.cs +++ b/Lombiq.Arithmetics.Tests/Properties/AssemblyInfo.cs @@ -1,9 +1,8 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. +// General Information about an assembly is controlled through the following set of attributes. Change these attribute +// values to modify the information associated with an assembly. [assembly: AssemblyTitle("Lombiq.Arithmetics.Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] @@ -13,9 +12,8 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. +// Setting ComVisible to false makes the types in this assembly not visible to COM components. If you need to access a +// type in this assembly from COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM @@ -28,8 +26,7 @@ // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: +// You can specify all the values or you can default the Build and Revision Numbers by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs b/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs index 08c6fe1..d05a844 100644 --- a/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs +++ b/Lombiq.Arithmetics.Tests/UnumTests/UnumEnvironmentTests.cs @@ -79,13 +79,13 @@ public void UnumSizeIsCorrect() [Fact] public void UnumUncertaintyBitMaskIsCorrect() { - // 0 0000 0000 0000 1 000 00 + // 0 0000 0000 0000 1 000 00 Assert.AreEqual( new BitMask(new uint[] { 0x20 }, _unum_3_2.Size), _unum_3_2.UncertaintyBitMask, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.UncertaintyBitMask))); - // 0 0000 0000 0000 0000 0000 0000 1 000 0000 + // 0 0000 0000 0000 0000 0000 0000 1 000 0000 Assert.AreEqual( new BitMask(new uint[] { 0x80, 0 }, _unum_3_4.Size), _unum_3_4.UncertaintyBitMask, @@ -95,13 +95,13 @@ public void UnumUncertaintyBitMaskIsCorrect() [Fact] public void UnumExponentSizeMaskIsCorrect() { - // 0 0000 0000 0000 0 111 00 + // 0 0000 0000 0000 0 111 00 Assert.AreEqual( new BitMask(new uint[] { 0x1C }, _unum_3_2.Size), _unum_3_2.ExponentSizeMask, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.ExponentSizeMask))); - // 0 0000 0000 0000 0000 0000 0000 0 111 0000 + // 0 0000 0000 0000 0000 0000 0000 0 111 0000 Assert.AreEqual( new BitMask(new uint[] { 0x70, 0 }, _unum_3_4.Size), _unum_3_4.ExponentSizeMask, @@ -111,13 +111,13 @@ public void UnumExponentSizeMaskIsCorrect() [Fact] public void UnumFractionSizeMaskIsCorrect() { - // 0 0000 0000 0000 0 000 11 + // 0 0000 0000 0000 0 000 11 Assert.AreEqual( new BitMask(new uint[] { 3 }, _unum_3_2.Size), _unum_3_2.FractionSizeMask, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.FractionSizeMask))); - // 0 0000 0000 0000 0000 0000 0000 0 000 1111 + // 0 0000 0000 0000 0000 0000 0000 0 000 1111 Assert.AreEqual( new BitMask(new uint[] { 0xF, 0 }, _unum_3_4.Size), _unum_3_4.FractionSizeMask, @@ -127,13 +127,13 @@ public void UnumFractionSizeMaskIsCorrect() [Fact] public void UnumExponentAndFractionSizeMaskIsCorrect() { - // 0 0000 0000 0000 0 111 11 + // 0 0000 0000 0000 0 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x1F }, _unum_3_2.Size), _unum_3_2.ExponentAndFractionSizeMask, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.ExponentAndFractionSizeMask))); - // 0 0000 0000 0000 0000 0000 0000 0 111 1111 + // 0 0000 0000 0000 0000 0000 0000 0 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0x7F, 0 }, _unum_3_4.Size), _unum_3_4.ExponentAndFractionSizeMask, @@ -143,13 +143,13 @@ public void UnumExponentAndFractionSizeMaskIsCorrect() [Fact] public void UnumTagMaskIsCorrect() { - // 0 0000 0000 0000 1 111 11 + // 0 0000 0000 0000 1 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x3F }, _unum_3_2.Size), _unum_3_2.UnumTagMask, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.UnumTagMask))); - // 0 0000 0000 0000 0000 0000 0000 1 111 1111 + // 0 0000 0000 0000 0000 0000 0000 1 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFF, 0 }, _unum_3_4.Size), _unum_3_4.UnumTagMask, @@ -159,13 +159,13 @@ public void UnumTagMaskIsCorrect() [Fact] public void UnumSignBitMaskIsCorrect() { - // 1 0000 0000 0000 0 000 00 + // 1 0000 0000 0000 0 000 00 Assert.AreEqual( new BitMask(new uint[] { 0x40000 }, _unum_3_2.Size), _unum_3_2.SignBitMask, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SignBitMask))); - // 1 0000 0000 0000 0000 0000 0000 0 000 0000 + // 1 0000 0000 0000 0000 0000 0000 0 000 0000 Assert.AreEqual( new BitMask(new uint[] { 0, 1 }, _unum_3_4.Size), _unum_3_4.SignBitMask, @@ -175,13 +175,13 @@ public void UnumSignBitMaskIsCorrect() [Fact] public void UnumPositiveInfinityIsCorrect() { - // 0 1111 1111 1111 0 111 11 + // 0 1111 1111 1111 0 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x3FFDF }, _unum_3_2.Size), _unum_3_2.PositiveInfinity, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.PositiveInfinity))); - // 0 1111 1111 1111 1111 1111 1111 0 111 1111 + // 0 1111 1111 1111 1111 1111 1111 0 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFFFFFF7F, 0 }, _unum_3_4.Size), _unum_3_4.PositiveInfinity, @@ -191,13 +191,13 @@ public void UnumPositiveInfinityIsCorrect() [Fact] public void UnumNegativeInfinityIsCorrect() { - // 1 1111 1111 1111 0 111 11 + // 1 1111 1111 1111 0 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x7FFDF }, _unum_3_2.Size), _unum_3_2.NegativeInfinity, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.NegativeInfinity))); - // 1 1111 1111 1111 1111 1111 1111 0 111 1111 + // 1 1111 1111 1111 1111 1111 1111 0 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFFFFFF7F, 1 }, _unum_3_4.Size), _unum_3_4.NegativeInfinity, @@ -207,13 +207,13 @@ public void UnumNegativeInfinityIsCorrect() [Fact] public void UnumQuietNotANumberIsCorrect() { - // 0 1111 1111 1111 1 111 11 + // 0 1111 1111 1111 1 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x3FFFF }, _unum_3_2.Size), _unum_3_2.QuietNotANumber, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.QuietNotANumber))); - // 0 1111 1111 1111 1111 1111 1111 1 111 1111 + // 0 1111 1111 1111 1111 1111 1111 1 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFFFFFFFF, 0 }, _unum_3_4.Size), _unum_3_4.QuietNotANumber, @@ -223,13 +223,13 @@ public void UnumQuietNotANumberIsCorrect() [Fact] public void UnumSignalingNotANumberIsCorrect() { - // 1 1111 1111 1111 1 111 11 + // 1 1111 1111 1111 1 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x7FFFF }, _unum_3_2.Size), _unum_3_2.SignalingNotANumber, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SignalingNotANumber))); - // 1 1111 1111 1111 1111 1111 1111 1 111 1111 + // 1 1111 1111 1111 1111 1111 1111 1 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFFFFFFFF, 1 }, _unum_3_4.Size), _unum_3_4.SignalingNotANumber, @@ -239,13 +239,13 @@ public void UnumSignalingNotANumberIsCorrect() [Fact] public void UnumLargestPositiveIsCorrect() { - // 0 1111 1111 1110 0 111 11 + // 0 1111 1111 1110 0 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x3FF9F }, _unum_3_2.Size), _unum_3_2.LargestPositive, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.LargestPositive))); - // 0 1111 1111 1111 1111 1111 1110 0 111 1111 + // 0 1111 1111 1111 1111 1111 1110 0 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFFFFFE7F, 0 }, _unum_3_4.Size), _unum_3_4.LargestPositive, @@ -255,13 +255,13 @@ public void UnumLargestPositiveIsCorrect() [Fact] public void UnumSmallestPositiveIsCorrect() { - // 0 0000 0000 0001 0 111 11 + // 0 0000 0000 0001 0 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x5F }, _unum_3_2.Size), _unum_3_2.SmallestPositive, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.SmallestPositive))); - // 0 0000 0000 0000 0000 0000 0001 0 111 1111 + // 0 0000 0000 0000 0000 0000 0001 0 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0x17F, 0 }, _unum_3_4.Size), _unum_3_4.SmallestPositive, @@ -271,13 +271,13 @@ public void UnumSmallestPositiveIsCorrect() [Fact] public void UnumLargestNegativeIsCorrect() { - // 1 1111 1111 1110 0 111 11 + // 1 1111 1111 1110 0 111 11 Assert.AreEqual( new BitMask(new uint[] { 0x7FF9F }, _unum_3_2.Size), _unum_3_2.LargestNegative, TestFailureMessageBuilder(_unum_3_2, nameof(_unum_3_2.LargestNegative))); - // 1 1111 1111 1111 1111 1111 1110 0 111 1111 + // 1 1111 1111 1111 1111 1111 1110 0 111 1111 Assert.AreEqual( new BitMask(new uint[] { 0xFFFFFE7F, 1 }, _unum_3_4.Size), _unum_3_4.LargestNegative, diff --git a/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs b/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs index ccd1baa..26b477a 100644 --- a/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs +++ b/Lombiq.Arithmetics.Tests/UnumTests/UnumTests.cs @@ -309,7 +309,7 @@ public void UnumIsCorrectlyConstructedFromUInt() [Fact] public void IsExactIsCorrect() { - // 0 0000 0000 0000 1 000 00 + // 0 0000 0000 0000 1 000 00 var bitMask_3_2_uncertain = new BitMask(new uint[] { 0x20 }, 19); var unum_3_2_uncertain = new Unum(_environment_3_2, bitMask_3_2_uncertain); Assert.AreEqual(actual: false, unum_3_2_uncertain.IsExact()); @@ -358,13 +358,13 @@ public void ExponentSizeIsCorrect() [Fact] public void FractionMaskIsCorrect() { - // 0 0000 0000 1111 0000 00 + // 0 0000 0000 1111 0000 00 var bitMask_3_2_allOne = new BitMask(19, allOne: true); var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); var bitMask_3_2_FractionMask = new BitMask(new uint[] { 0x3C0 }, 19); Assert.AreEqual(bitMask_3_2_FractionMask, unum_3_2_allOne.FractionMask()); - // 0 0000 0000 1111 1111 1111 1111 0000 0000 + // 0 0000 0000 1111 1111 1111 1111 0000 0000 var bitMask_3_4_allOne = new BitMask(33, allOne: true); var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); var bitMask_3_4_FractionMask = new BitMask(new uint[] { 0xFFFF00 }, 33); @@ -374,13 +374,13 @@ public void FractionMaskIsCorrect() [Fact] public void ExponentMaskIsCorrect() { - // 0 1111 1111 0000 0 000 00 + // 0 1111 1111 0000 0 000 00 var bitMask_3_2_allOne = new BitMask(19, allOne: true); var unum_3_2_allOne = new Unum(_environment_3_2, bitMask_3_2_allOne); var bitMask_3_2_ExponentMask = new BitMask(new uint[] { 0x3FC00 }, 19); Assert.AreEqual(bitMask_3_2_ExponentMask, unum_3_2_allOne.ExponentMask()); - // 0 1111 1111 0000 0000 0000 0000 0 000 0000 + // 0 1111 1111 0000 0000 0000 0000 0 000 0000 var bitMask_3_4_allOne = new BitMask(33, allOne: true); var unum_3_4_allOne = new Unum(_environment_3_4, bitMask_3_4_allOne); var bitMask_3_4_ExponentMask = new BitMask(new[] { 0xFF000000 }, 33); diff --git a/Posit/Posit.cs b/Posit/Posit.cs index 861992d..38ad824 100644 --- a/Posit/Posit.cs +++ b/Posit/Posit.cs @@ -9,12 +9,13 @@ namespace Lombiq.Arithmetics; public BitMask PositBits { get; } #region Posit structure + public byte MaximumExponentSize => _environment.MaximumExponentSize; public ushort Size => _environment.Size; public uint Useed => _environment.Useed; public ushort FirstRegimeBitIndex => _environment.FirstRegimeBitIndex; - #endregion + #endregion Posit structure #region Posit Masks @@ -30,7 +31,7 @@ namespace Lombiq.Arithmetics; public BitMask NaNBitMask => _environment.NaNBitMask; - #endregion + #endregion Posit Masks #region Posit constructors @@ -74,7 +75,7 @@ public Posit(PositEnvironment environment, int value) new Posit(environment, (uint)-value).PositBits.GetTwosComplement(_environment.Size); } - #endregion + #endregion Posit constructors #region Posit numeric states @@ -84,7 +85,7 @@ public Posit(PositEnvironment environment, int value) public bool IsZero() => PositBits == EmptyBitMask; - #endregion + #endregion Posit numeric states #region Methods to handle parts of the Posit @@ -177,7 +178,7 @@ public uint FractionSize() return fractionSize > 0 ? (uint)fractionSize : 0; } - #endregion + #endregion Methods to handle parts of the Posit #region Helper methods for operations and conversions @@ -208,7 +209,7 @@ private static void CaclulateRounding(int shiftedLeftBy, ref BitMask bits, ref B } } - #endregion + #endregion Helper methods for operations and conversions #region operators @@ -400,6 +401,5 @@ public override int GetHashCode() } } - #endregion - + #endregion operators } diff --git a/Posit/Posit32.cs b/Posit/Posit32.cs index e0a69cf..c02c10c 100644 --- a/Posit/Posit32.cs +++ b/Posit/Posit32.cs @@ -29,7 +29,7 @@ namespace Lombiq.Arithmetics; public const short QuireSize = 512; - #endregion + #endregion Posit structure #region Posit Masks @@ -57,7 +57,7 @@ namespace Lombiq.Arithmetics; public const ulong Double64HiddenBitMask = 0x_0010_0000_0000_0000; - #endregion + #endregion Posit Masks #region Posit constructors @@ -233,7 +233,7 @@ public Posit32(double doubleBits) PositBits = AssemblePositBitsWithRounding(signBit, regimeKValue, exponentValue, fractionBits); } - #endregion + #endregion Posit constructors #region Posit numeric states @@ -246,7 +246,7 @@ public Posit32(double doubleBits) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsZero() => PositBits == EmptyBitMask; - #endregion + #endregion Posit numeric states #region Methods to handle parts of the Posit @@ -409,7 +409,7 @@ public static uint FractionSizeWithoutSignCheck(byte lengthOfRunOfBits) return fractionSize > 0 ? (uint)fractionSize : 0; } - #endregion + #endregion Methods to handle parts of the Posit #region Helper methods for operations and conversions @@ -493,7 +493,7 @@ public static Quire MultiplyIntoQuire(Posit32 left, Posit32 right) return !resultSignBit ? resultQuire : (~resultQuire) + 1; } - #endregion + #endregion Helper methods for operations and conversions #region Bit level Helper Methods @@ -556,7 +556,7 @@ public static byte LengthOfRunOfBits(uint bits, byte startingPosition) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint GetTwosComplement(uint bits) => ~bits + 1; - #endregion + #endregion Bit level Helper Methods #region Algebraic functions @@ -609,7 +609,7 @@ public static Posit32 Sqrt(Posit32 number) fromBitMask: true); } - #endregion + #endregion Algebraic functions #region Fused operations @@ -694,7 +694,8 @@ public static Posit32 FusedMultiplyMultiplySubtract(Posit32 a, Posit32 b, Posit3 return FusedDotProduct(positArray1, positArray2); } - #endregion + + #endregion Fused operations #region Operators @@ -1032,13 +1033,13 @@ public static explicit operator Quire(Posit32 x) quireArray[0] = x.FractionWithHiddenBit(); var resultQuire = new Quire(quireArray); resultQuire <<= (int)(240 - x.FractionSize() + x.CalculateScaleFactor()); - // This is not a conditional expression return because Hastlayer would throw a "You can't at the moment - // assign to a variable that you previously assigned to using a reference type-holding variable." + // This is not a conditional expression return because Hastlayer would throw a "You can't at the moment assign + // to a variable that you previously assigned to using a reference type-holding variable." if (x.IsPositive()) return resultQuire; return (~resultQuire) + 1; } - #endregion + #endregion Operators #region Support methods @@ -1115,5 +1116,5 @@ public static bool TryParse(string number, out Posit32 positResult) public override int GetHashCode() => (int)PositBits; - #endregion + #endregion Support methods } diff --git a/Posit/Quire.cs b/Posit/Quire.cs index 3c6cfc4..244b652 100644 --- a/Posit/Quire.cs +++ b/Posit/Quire.cs @@ -8,7 +8,6 @@ namespace Lombiq.Arithmetics; "Major Code Smell", "S4035:Classes implementing \"IEquatable\" should be sealed", Justification = "False positive, it actually implements IEqualityComparer.")] - public class Quire : IEqualityComparer { private const ulong SegmentMaskWithLeadingOne = 0x_8000_0000_0000_0000; @@ -88,6 +87,7 @@ public Quire(uint firstSegment, ushort size) } public static Quire operator +(Quire left, uint right) => left + new Quire(right, (ushort)(left.SegmentCount << 6)); + public static Quire operator -(Quire left, Quire right) { if (left.SegmentCount == 0 || right.SegmentCount == 0) return left; @@ -193,7 +193,9 @@ public Quire(uint firstSegment, ushort size) public static explicit operator uint(Quire x) => (uint)x.Segments[0]; protected bool Equals(Quire other) => this == other; + public bool Equals(Quire x, Quire y) => x == y; + public override bool Equals(object obj) => obj is Quire other && this == other; public int GetHashCode(Quire obj) => obj.GetHashCode(); diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 8304a8a..219eba7 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -1,9 +1,8 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. +// General Information about an assembly is controlled through the following set of attributes. Change these attribute +// values to modify the information associated with an assembly. [assembly: AssemblyTitle("Lombiq.Arithmetics")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] @@ -13,9 +12,8 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. +// Setting ComVisible to false makes the types in this assembly not visible to COM components. If you need to access a +// type in this assembly from COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM @@ -28,8 +26,7 @@ // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: +// You can specify all the values or you can default the Build and Revision Numbers by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Unum/Unum.cs b/Unum/Unum.cs index bb98228..94e2b01 100644 --- a/Unum/Unum.cs +++ b/Unum/Unum.cs @@ -42,7 +42,7 @@ namespace Lombiq.Arithmetics; /// public ushort Size => _environment.Size; // "maxubits" - #endregion + #endregion Unum structure #region Unum masks @@ -76,7 +76,7 @@ namespace Lombiq.Arithmetics; /// public BitMask SignBitMask => _environment.SignBitMask; // "signbigu" - #endregion + #endregion Unum masks #region Unum environment @@ -126,7 +126,7 @@ namespace Lombiq.Arithmetics; /// public BitMask MinRealU => _environment.MinRealU; // "minrealu" - #endregion + #endregion Unum environment #region Unum constructors @@ -146,16 +146,16 @@ public Unum(UnumEnvironment environment, BitMask bits) } /// - /// Initializes a new instance of the struct. - /// Creates a Unum of the given environment initialized with the value of the uint. + /// Initializes a new instance of the struct. Creates a Unum of the given environment initialized + /// with the value of the uint. /// /// The Unum environment. /// The uint value to initialize the new Unum with. 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. + // 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; @@ -163,13 +163,13 @@ public Unum(UnumEnvironment environment, uint value) } /// - /// Initializes a new instance of the struct. - /// Creates a Unum initialized with a value that is defined by the bits in a uint array. + /// Initializes a new instance of the struct. Creates a Unum initialized with a value that is + /// defined by the bits in a uint array. /// /// The Unum environment. /// - /// 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. + /// 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. /// /// Defines whether the number is positive or not. public Unum(UnumEnvironment environment, uint[] value, bool negative = false) @@ -199,8 +199,7 @@ public Unum(UnumEnvironment environment, uint[] value, bool negative = false) // Calculating the number of bits needed to represent the value of the exponent. var exponentSize = exponentValue.FindMostSignificantOnePosition(); - // If the value of the exponent is not a power of 2, - // then one more bit is needed to represent the biased value. + // 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.Lowest32Bits & (exponentValue.Lowest32Bits - 1)) > 0) exponentSize++; // Handling input numbers that don't fit in the range of the given environment. @@ -255,8 +254,8 @@ public Unum(UnumEnvironment environment, int 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. + // 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]; if (value >= 0) @@ -271,7 +270,7 @@ public Unum(UnumEnvironment environment, int value) } } - #endregion + #endregion Unum constructors #region Methods to set the values of individual Unum structure elements @@ -282,8 +281,12 @@ public Unum(UnumEnvironment environment, int value) /// The biased notation of the exponent of the Unum. /// The fraction of the Unum without the hidden bit. /// The value of the uncertainity bit (Ubit). - /// The Unum's exponent size, in a notation that is one less than the actual value. - /// The Unum's fraction size, in a notation that is one less than the actual value. + /// + /// The Unum's exponent size, in a notation that is one less than the actual value. + /// + /// + /// The Unum's fraction size, in a notation that is one less than the actual value. + /// /// The BitMask representing the whole Unum with all the parts set. private BitMask AssembleUnumBits( bool signBit, @@ -355,9 +358,7 @@ public Unum SetFractionBits(BitMask fraction) /// /// Sets the fractionSize to the given value and leaves everything else as is. /// - /// - /// The desired fractionSize in a notation that is one less than the actual value. - /// + /// The desired fractionSize in a notation that is one less than the actual value. /// The BitMask representing the Unum with its fractionSize set to the given value. public Unum SetFractionSizeBits(byte fractionSize) { @@ -377,17 +378,17 @@ public Unum SetExponentSizeBits(byte exponentSize) return new Unum(_environment, newUnumBits); } - #endregion + #endregion Methods to set the values of individual Unum structure elements #region Binary data extraction /// - /// Copies the actual integer value represented by the Unum into an array of unsigned integers with the - /// most significant bit of the last element functioning as the signbit. + /// Copies the actual integer value represented by the Unum into an array of unsigned integers with the most + /// significant bit of the last element functioning as the signbit. /// /// - /// An array of unsigned integers that together represent the integer value of the Unum with the most - /// significant bit of the last uint functioning as a signbit. + /// An array of unsigned integers that together represent the integer value of the Unum with the most significant + /// bit of the last uint functioning as a signbit. /// public uint[] FractionToUintArray() { @@ -408,7 +409,7 @@ public uint[] FractionToUintArray() return result; } - #endregion + #endregion Binary data extraction #region Binary data manipulation @@ -418,7 +419,7 @@ public Unum Negate() return new Unum(_environment, newUnumBits); } - #endregion + #endregion Binary data manipulation #region Unum numeric states @@ -432,9 +433,9 @@ public bool IsZero() => (UnumBits & FractionMask()) == _environment.EmptyBitMask && (UnumBits & ExponentMask()) == _environment.EmptyBitMask; - #endregion + #endregion Unum numeric states - #region Methods for Utag independent Masks and values + #region Methods for Utag independent Masks and values public byte ExponentSize() => (byte)(((UnumBits & ExponentSizeMask) >> FractionSizeSize) + 1).Lowest32Bits; @@ -452,7 +453,7 @@ public BitMask ExponentMask() return ((exponentMask << ExponentSize()) - 1) << (FractionSize() + UnumTagSize); } - #endregion + #endregion Methods for Utag independent Masks and values #region Methods for Utag dependent Masks and values @@ -477,7 +478,7 @@ public BitMask FractionWithHiddenBit() => public bool IsNegativeInfinity() => UnumBits == NegativeInfinity; - #endregion + #endregion Methods for Utag dependent Masks and values #region Operations for exact Unums @@ -485,7 +486,6 @@ public BitMask FractionWithHiddenBit() => "Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "Not currently posisble due to TypeConverter limitations.")] - // See: https://github.com/Lombiq/Hastlayer-SDK/issues/62 public static Unum AddExactUnums(Unum left, Unum right) { // Handling special cases first. @@ -578,10 +578,9 @@ private static void AddExactUnumsInner( 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. + // 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); @@ -599,10 +598,9 @@ private static void AddExactUnumsInner( if (exponentValueDifference < 0) { - // 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. + // 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); @@ -621,8 +619,8 @@ private static void AddExactUnumsInner( // 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. + // 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. @@ -637,8 +635,8 @@ private static void AddExactUnumsInner( #pragma warning disable S3240 // The simplest possible condition syntax should be used if (left.HiddenBitIsOne() == right.HiddenBitIsOne()) { - // If the value of the Hidden Bits match we just compare the fractions, - // and get the Sign of the bigger one. + // If the value of the Hidden Bits match we just compare the fractions, and get the Sign of the bigger + // one. resultSignBit = left.Fraction() >= right.Fraction() ? !left.IsPositive() // Left Fraction is bigger. : !right.IsPositive(); // Right Fraction is bigger. @@ -663,7 +661,7 @@ private static void AddExactUnumsInner( public static bool AreEqualExactUnums(Unum left, Unum right) => (left.IsZero() && right.IsZero()) || left.UnumBits == right.UnumBits; - #endregion + #endregion Operations for exact Unums #region Helper methods for operations and conversions @@ -699,7 +697,7 @@ public static BitMask AddAlignedFractions(BitMask left, BitMask right, bool sign return mask; } - #endregion + #endregion Helper methods for operations and conversions #region Operators @@ -747,9 +745,10 @@ public static explicit operator float(Unum x) -BitConverter.ToSingle(BitConverter.GetBytes(result), 0); } - #endregion + #endregion Operators #region Overrides + public override bool Equals(object obj) => obj is Unum other && this == other; public bool Equals(Unum other) => this == other; @@ -764,5 +763,5 @@ public override int GetHashCode() public override string ToString() => $"{nameof(Unum)}(Bits:{UnumBits};Environment:{_environment})"; - #endregion + #endregion Overrides } diff --git a/Unum/UnumEnvironment.cs b/Unum/UnumEnvironment.cs index fd2fe57..8140c57 100644 --- a/Unum/UnumEnvironment.cs +++ b/Unum/UnumEnvironment.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace Lombiq.Arithmetics; @@ -35,7 +35,8 @@ public class UnumEnvironment /// Gets the maximum number of bits used by the environment. /// public ushort Size { get; } // "maxubits" - #endregion + + #endregion Unum structure #region Unum masks @@ -73,7 +74,8 @@ public class UnumEnvironment /// Gets a BitMask for picking out the SignBit. /// public BitMask SignBitMask { get; } // "signbigu" - #endregion + + #endregion Unum masks #region Unum special values @@ -126,7 +128,7 @@ public class UnumEnvironment /// public BitMask MinRealU { get; } // "minrealu" - #endregion + #endregion Unum special values public UnumEnvironment(byte exponentSizeSize, byte fractionSizeSize) { diff --git a/Unum/UnumHelper.cs b/Unum/UnumHelper.cs index c8f0e1a..3ac1b0b 100644 --- a/Unum/UnumHelper.cs +++ b/Unum/UnumHelper.cs @@ -3,8 +3,8 @@ namespace Lombiq.Arithmetics; public static class UnumHelper { /// - /// Calculates the maximum number of bits to describe the size of the given segment, - /// e.g. "eSizeSize" for "eSize", which is essentially the binary logarithm of the segment size. + /// Calculates the maximum number of bits to describe the size of the given segment, e.g. "eSizeSize" for "eSize", + /// which is essentially the binary logarithm of the segment size. /// /// The size of the unum segment (fraction or exponent). /// The maximum size of the unum segment size. @@ -22,8 +22,8 @@ public static byte SegmentSizeToSegmentSizeSize(ushort segmentSize) } /// - /// Calculates the maximum number of bits of a segment given its "segment size size", - /// which is essentially 2 to the power of "segmentSizeSize". + /// Calculates the maximum number of bits of a segment given its "segment size size", which is essentially 2 to the + /// power of "segmentSizeSize". /// /// The size of the segment size. /// The maximum number of bits of a segment. @@ -31,14 +31,16 @@ public static ushort SegmentSizeSizeToSegmentSize(byte segmentSizeSize) => (ushort)(1 << segmentSizeSize); /// - /// Calculates whether a unum with the given configuration of exponent and fraction size can fit - /// into the given number of bits. + /// Calculates whether a unum with the given configuration of exponent and fraction size can fit into the given + /// number of bits. /// /// The maximum size of the exponent. /// The maximum size of the fraction. /// The maximum size allowed for the unum. - /// Whether the number of bits required to store the unum - /// with the given configuration fits the desired maximum size. + /// + /// Whether the number of bits required to store the unum with the given configuration fits the desired maximum + /// size. + /// public static bool ConfigurationFitsSize(byte eSize, ushort fSize, ushort maximumSize) => ConfigurationRequiredMaximumBits(eSize, fSize) <= maximumSize; @@ -49,8 +51,7 @@ public static bool ConfigurationFitsSize(byte eSize, ushort fSize, ushort maximu /// The maximum size of the fraction. /// The maximum number of bits for the given configuration. public static ushort ConfigurationRequiredMaximumBits(byte eSize, ushort fSize) => - // Sign bit + exponent size + fraction size + - // uncertainty bit + exponent size size + fraction size size. + // Sign bit + exponent size + fraction size + uncertainty bit + exponent size size + fraction size size. (ushort)(1 + eSize + fSize + 1 + SegmentSizeToSegmentSizeSize(eSize) + SegmentSizeToSegmentSizeSize(fSize)); @@ -71,8 +72,7 @@ public static bool EnvironmentFitsSize(byte eSizeSize, byte fSizeSize, ushort ma /// The size of the maximum size of the fraction. /// The maximum number of bits for the given environment. public static ushort EnvironmentRequiredMaximumBits(byte eSizeSize, byte fSizeSize) => - // Sign bit + exponent size + fraction size + - // uncertainty bit + exponent size size + fraction size size. + // Sign bit + exponent size + fraction size + uncertainty bit + exponent size size + fraction size size. (ushort)(1 + SegmentSizeSizeToSegmentSize(eSizeSize) + SegmentSizeSizeToSegmentSize(fSizeSize) + 1 + eSizeSize + fSizeSize); @@ -80,14 +80,13 @@ public static int BitsRequiredByLargestExpressablePositiveInteger(UnumEnvironmen (1 << (environment.ExponentSizeMax - 1)) + 1; /// - /// Calculates the biggest expressible integer in the given environment in an integer-like notation. - /// Returns an empty BitMask if the calculated number would be too big to fit in a BitMask of - /// the size of the environment. + /// Calculates the biggest expressible integer in the given environment in an integer-like notation. Returns an + /// empty BitMask if the calculated number would be too big to fit in a BitMask of the size of the environment. /// /// The environment thats Largest Expressible Integer needs to be calculated. /// - /// The biggest expressible integer in the given environment if it fits in a BitMask the size of the - /// environment, an empty BitMask otherwise. + /// The biggest expressible integer in the given environment if it fits in a BitMask the size of the environment, an + /// empty BitMask otherwise. /// public static BitMask LargestExpressablePositiveInteger(UnumEnvironment environment) {