diff --git a/QuadrupleLib.Tests/Utilities/UInt256Tests.cs b/QuadrupleLib.Tests/Utilities/UInt256Tests.cs
new file mode 100644
index 0000000..17d46b3
--- /dev/null
+++ b/QuadrupleLib.Tests/Utilities/UInt256Tests.cs
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2026 Chosen Few Software
+ * This file is part of QuadrupleLib.
+ *
+ * QuadrupleLib is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QuadrupleLib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with QuadrupleLib. If not, see .
+ */
+
+using QuadrupleLib.Utilities;
+using Xunit;
+
+namespace QuadrupleLib.Tests.Utilities
+{
+ public class UInt256Tests
+ {
+ [Fact]
+ public void IsAddWithoutCarryCorrect()
+ {
+ UInt256 one = 1UL;
+ UInt256 two = 2UL;
+ Assert.Equal(3UL, one + two);
+ }
+
+ [Fact]
+ public void IsAddWithCarryCorrect()
+ {
+ UInt256 n = UInt256.One + UInt128.MaxValue;
+ Assert.Equal((UInt128.Zero, UInt128.One), (n._lo, n._hi));
+ }
+
+ [Fact]
+ public void IsAddWithOverflowZero()
+ {
+ UInt256 n = UInt256.MaxValue + UInt256.One;
+ Assert.Equal(UInt256.Zero, n);
+ }
+
+ [Fact]
+ public void IsSubtractWithoutBorrowCorrect()
+ {
+ UInt256 one = 1UL;
+ UInt256 three = 3UL;
+ Assert.Equal(2UL, three - one);
+ }
+
+ [Fact]
+ public void IsSubtractWithBorrowCorrect()
+ {
+ UInt256 n = UInt256.One + UInt128.MaxValue, m = n - UInt256.One;
+ Assert.Equal((UInt128.MaxValue, UInt128.Zero), (m._lo, m._hi));
+ }
+
+ [Fact]
+ public void IsSubtractWithUnderflowMaximum()
+ {
+ UInt256 n = UInt256.Zero - UInt256.One;
+ Assert.Equal(UInt256.MaxValue, n);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0UL, 0)]
+ [InlineData(0UL, 0UL, 1)]
+ [InlineData(0UL, 0UL, 2)]
+ [InlineData(1UL, 1UL, 0)]
+ [InlineData(1UL, 2UL, 1)]
+ [InlineData(1UL, 4UL, 2)]
+ [InlineData(2UL, 2UL, 0)]
+ [InlineData(2UL, 4UL, 1)]
+ [InlineData(2UL, 8UL, 2)]
+ public void IsSmallShiftLeftCorrect(ulong n, ulong m, int amt)
+ {
+ UInt256 N = n; N <<= amt;
+ Assert.Equal(m, N);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0UL, 0)]
+ [InlineData(0UL, 0UL, 1)]
+ [InlineData(0UL, 0UL, 2)]
+ [InlineData(1UL, 1UL, 0)]
+ [InlineData(1UL, 2UL, 1)]
+ [InlineData(1UL, 4UL, 2)]
+ [InlineData(2UL, 2UL, 0)]
+ [InlineData(2UL, 4UL, 1)]
+ [InlineData(2UL, 8UL, 2)]
+ public void IsLargeShiftLeftCorrect(ulong n, ulong m, int amt)
+ {
+ UInt256 N = n; N <<= 128 + amt;
+ UInt256 M = m; M <<= 128;
+ Assert.Equal(M, N);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0)]
+ [InlineData(0UL, 1)]
+ [InlineData(0UL, 2)]
+ [InlineData(1UL, 0)]
+ [InlineData(1UL, 1)]
+ [InlineData(1UL, 2)]
+ [InlineData(2UL, 0)]
+ [InlineData(2UL, 1)]
+ [InlineData(2UL, 2)]
+ public void IsExtraLargeShiftLeftZero(ulong n, int amt)
+ {
+ UInt256 N = n; N <<= 256 + amt;
+ Assert.Equal(UInt256.Zero, N);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0UL, 0)]
+ [InlineData(0UL, 0UL, 1)]
+ [InlineData(0UL, 0UL, 2)]
+ [InlineData(2UL, 2UL, 0)]
+ [InlineData(2UL, 1UL, 1)]
+ [InlineData(2UL, 0UL, 2)]
+ [InlineData(4UL, 4UL, 0)]
+ [InlineData(4UL, 2UL, 1)]
+ [InlineData(4UL, 1UL, 2)]
+ public void IsSmallShiftRightCorrect(ulong n, ulong m, int amt)
+ {
+ UInt256 N = n; N >>= amt;
+ Assert.Equal(m, N);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0UL, 0)]
+ [InlineData(0UL, 0UL, 1)]
+ [InlineData(0UL, 0UL, 2)]
+ [InlineData(2UL, 2UL, 0)]
+ [InlineData(2UL, 1UL, 1)]
+ [InlineData(2UL, 0UL, 2)]
+ [InlineData(4UL, 4UL, 0)]
+ [InlineData(4UL, 2UL, 1)]
+ [InlineData(4UL, 1UL, 2)]
+ public void IsLargeShiftRightCorrect(ulong n, ulong m, int amt)
+ {
+ UInt256 N = (UInt256)n << 128; N >>= 128 + amt;
+ Assert.Equal(m, N);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0)]
+ [InlineData(0UL, 1)]
+ [InlineData(0UL, 2)]
+ [InlineData(2UL, 0)]
+ [InlineData(2UL, 1)]
+ [InlineData(2UL, 2)]
+ [InlineData(4UL, 0)]
+ [InlineData(4UL, 1)]
+ [InlineData(4UL, 2)]
+ public void IsExtraLargeShiftRightZero(ulong n, int amt)
+ {
+ UInt256 N = (UInt256)n << 128; N >>= 256 + amt;
+ Assert.Equal(UInt256.Zero, N);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0UL, 0)]
+ [InlineData(0UL, 1UL, -1)]
+ [InlineData(0UL, 2UL, -1)]
+ [InlineData(1UL, 0UL, 1)]
+ [InlineData(1UL, 1UL, 0)]
+ [InlineData(1UL, 2UL, -1)]
+ [InlineData(2UL, 0UL, 1)]
+ [InlineData(2UL, 1UL, 1)]
+ [InlineData(2UL, 2UL, 0)]
+ public void IsSmallCompareToCorrect(ulong n, ulong m, int s)
+ {
+ UInt256 N = n, M = m;
+ int S = System.Math.Sign(N.CompareTo(M));
+ Assert.Equal(s, S);
+ }
+
+ [Theory]
+ [InlineData(0UL, 0UL, 0)]
+ [InlineData(0UL, 1UL, -1)]
+ [InlineData(0UL, 2UL, -1)]
+ [InlineData(1UL, 0UL, 1)]
+ [InlineData(1UL, 1UL, 0)]
+ [InlineData(1UL, 2UL, -1)]
+ [InlineData(2UL, 0UL, 1)]
+ [InlineData(2UL, 1UL, 1)]
+ [InlineData(2UL, 2UL, 0)]
+ public void IsLargeCompareToCorrect(ulong n, ulong m, int s)
+ {
+ UInt256 N = (UInt256)n << 128, M = (UInt256)m << 128;
+ int S = System.Math.Sign(N.CompareTo(M));
+ Assert.Equal(s, S);
+ }
+ }
+}
diff --git a/QuadrupleLib/AssemblyInfo.cs b/QuadrupleLib/AssemblyInfo.cs
new file mode 100644
index 0000000..1c0e937
--- /dev/null
+++ b/QuadrupleLib/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("QuadrupleLib.Tests")]
diff --git a/QuadrupleLib/UInt256.cs b/QuadrupleLib/Utilities/UInt256.cs
similarity index 94%
rename from QuadrupleLib/UInt256.cs
rename to QuadrupleLib/Utilities/UInt256.cs
index 8c8a31e..06e74dc 100644
--- a/QuadrupleLib/UInt256.cs
+++ b/QuadrupleLib/Utilities/UInt256.cs
@@ -16,8 +16,12 @@
* along with QuadrupleLib. If not, see .
*/
-namespace QuadrupleLib
+using System.Numerics;
+using System.Runtime.InteropServices;
+
+namespace QuadrupleLib.Utilities
{
+ [StructLayout(LayoutKind.Sequential)]
internal struct UInt256 : IEquatable, IComparable, IComparable
{
private static readonly UInt256 _zero = new();
@@ -34,11 +38,11 @@ internal struct UInt256 : IEquatable, IComparable, IComparable
#if BIGENDIAN
- private readonly UInt128 _hi;
- private readonly UInt128 _lo;
+ public readonly UInt128 _hi;
+ public readonly UInt128 _lo;
#else
- private readonly UInt128 _lo;
- private readonly UInt128 _hi;
+ public readonly UInt128 _lo;
+ public readonly UInt128 _hi;
#endif
private UInt256(UInt128 lo, UInt128 hi)
{
@@ -263,5 +267,12 @@ public override int GetHashCode()
{
return HashCode.Combine(_lo, _hi);
}
+
+ public override string ToString()
+ {
+ BigInteger n = _hi;
+ n = (n << 128) | _lo;
+ return n.ToString();
+ }
}
}
\ No newline at end of file