diff --git a/MathEngine/MathEngine/AST/Nodes/NodeFactory.cs b/MathEngine/MathEngine/AST/Nodes/NodeFactory.cs
index d7115cd..33109ff 100644
--- a/MathEngine/MathEngine/AST/Nodes/NodeFactory.cs
+++ b/MathEngine/MathEngine/AST/Nodes/NodeFactory.cs
@@ -32,7 +32,7 @@ namespace MathEngine.AST.Nodes
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
case TokenType.Exponentiation:
throw new NotImplementedException("Exponentiation is not supported at this time!");
- return new BinaryNode(LeftBranch, RightBranch, (a, b) => a ^ b);
+ // return new BinaryNode(LeftBranch, RightBranch, (a, b) => a ^ b);
default:
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
}
diff --git a/MathEngine/MathEngine/MMU/Memory.cs b/MathEngine/MathEngine/MMU/Memory.cs
new file mode 100644
index 0000000..fe75030
--- /dev/null
+++ b/MathEngine/MathEngine/MMU/Memory.cs
@@ -0,0 +1,56 @@
+using System.Runtime.CompilerServices;
+using System.Text;
+using UnmanagedMMU;
+
+
+namespace MathEngine.MemoryManagement
+{
+ internal unsafe class Memory
+ {
+ public static readonly SegmentedPool ScratchWorkspace;
+
+ static Memory()
+ {
+ ScratchWorkspace = new SegmentedPool(initialSegments: 16, zeroMemory: true);
+ }
+
+ ///
+ /// Copies a range of elements from the specified source buffer to the specified destination buffer.
+ ///
+ /// The buffer to copy elements from.
+ /// The zero-based index in at which copying begins.
+ /// The buffer to copy elements to.
+ /// The zero-based index in at which storing begins.
+ /// The number of elements to copy.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void MemCopy(UInt32* source, int sourceIndex, UInt32* destination, int destinationIndex, int count)
+ {
+ // Calculate byte offsets from element indices
+ UInt32* srcPtr = source + sourceIndex;
+ UInt32* destPtr = destination + destinationIndex;
+
+ Unsafe.CopyBlock(destPtr, srcPtr, (uint)(count * sizeof(UInt32)));
+ }
+
+#if DEBUG
+ ///
+ /// Prints the contents of the unmanaged memory block pointed to by
+ ///
+ /// * pointer to the memory block to print
+ /// The length of the memory block pointed to by
+ private static void PrintUnmanagedArray(T* arr, int len) where T : unmanaged
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("[");
+ for (int i = 0; i < len - 1; i++)
+ {
+ sb.Append(arr[i]);
+ sb.Append(", ");
+ }
+ sb.Append(arr[len - 1]);
+ sb.Append("]");
+ Console.WriteLine(sb.ToString());
+ }
+#endif
+ }
+}
diff --git a/MathEngine/MathEngine/MathEngine.csproj b/MathEngine/MathEngine/MathEngine.csproj
index 5e22321..738b201 100644
--- a/MathEngine/MathEngine/MathEngine.csproj
+++ b/MathEngine/MathEngine/MathEngine.csproj
@@ -5,6 +5,7 @@
enable
enable
True
+ true
@@ -21,4 +22,10 @@
+
+
+ ..\common\UnmanagedMMU.dll
+
+
+
diff --git a/MathEngine/MathEngine/types/BigInteger.cs b/MathEngine/MathEngine/types/BigInteger.cs
new file mode 100644
index 0000000..6ed18df
--- /dev/null
+++ b/MathEngine/MathEngine/types/BigInteger.cs
@@ -0,0 +1,247 @@
+using MathEngine.MemoryManagement;
+
+namespace MathEngine.types
+{
+ public unsafe struct BigInteger
+ {
+ private UInt32* _num;
+ private int _len;
+ private int _sgn;
+
+ private static BigInteger _zero = new BigInteger(0);
+
+ public BigInteger(int val)
+ {
+ _num = Memory.ScratchWorkspace.AllocateAsPointer(16);
+ _len = 1;
+ if (val < 0)
+ {
+ _sgn = -1;
+ _num[0] = (UInt32)(-val);
+ return;
+ }
+ if (val > 0)
+ {
+ _sgn = 1;
+ _num[0] = (UInt32)(val);
+ return;
+ }
+ else
+ {
+ _sgn = 0;
+ _num[0] = 0;
+ return;
+ }
+ }
+
+ public BigInteger(UInt32 val)
+ {
+ _num = Memory.ScratchWorkspace.AllocateAsPointer(16);
+ _len = 1;
+ if (val > 0)
+ {
+ _sgn = 1;
+ _num[0] = val;
+ return;
+ }
+ else
+ {
+ _sgn = 0;
+ _num[0] = 0;
+ return;
+ }
+ }
+
+ private static unsafe int CompareAbs(in BigInteger X, in BigInteger Y)
+ {
+ if (X._len != Y._len)
+ return X._len.CompareTo(Y._len);
+ for (int i = X._len - 1; i >= 0; i--)
+ {
+ if (X._num[i] != Y._num[i])
+ return X._num[i].CompareTo(Y._num[i]);
+ }
+ return 0;
+ }
+
+ public static BigInteger Add(BigInteger X, BigInteger Y)
+ {
+ if (X._sgn == 0)
+ {
+ return Y;
+ }
+ if (Y._sgn == 0)
+ {
+ return X;
+ }
+
+ if (X._sgn == Y._sgn)
+ {
+ int n = X._len;
+ int m = Y._len;
+ int len = Math.Max(n, m);
+ UInt32* res = Memory.ScratchWorkspace.AllocateAsPointer(len + 1);
+
+ ulong carry = 0;
+ int i = 0;
+ for (; i < Math.Min(n, m); i++)
+ {
+ ulong sum = (ulong)X._num[i] + Y._num[i] + carry;
+ res[i] = (UInt32)sum;
+ carry = sum >> 32;
+ }
+
+ UInt32* longer = n > m ? X._num : Y._num;
+ for (; i < len; i++)
+ {
+ ulong sum = (ulong)longer[i] + carry;
+ res[i] = (UInt32)sum;
+ carry = sum >> 32;
+ }
+
+ if (carry != 0)
+ res[len++] = (UInt32)carry;
+
+ BigInteger result;
+ result._num = res;
+ result._len = len;
+ result._sgn = X._sgn;
+ return result;
+ }
+
+ int cmp = CompareAbs(X, Y);
+ BigInteger bigger, smaller;
+ int resultSign;
+
+ if (cmp >= 0)
+ {
+ bigger = X;
+ smaller = Y;
+ resultSign = X._sgn;
+ }
+ else
+ {
+ bigger = Y;
+ smaller = X;
+ resultSign = Y._sgn;
+ }
+
+ // Perform magnitude subtraction: bigger - smaller
+ int nB = bigger._len, nS = smaller._len;
+ UInt32* resSub = Memory.ScratchWorkspace.AllocateAsPointer(nB);
+
+ long borrow = 0;
+ int iSub = 0;
+ for (; iSub < nS; iSub++)
+ {
+ long diff = (long)bigger._num[iSub] - smaller._num[iSub] - borrow;
+ if (diff < 0)
+ {
+ diff += 1L << 32;
+ borrow = 1;
+ }
+ else
+ {
+ borrow = 0;
+ }
+ resSub[iSub] = (UInt32)diff;
+ }
+
+ for (; iSub < nB; iSub++)
+ {
+ long diff = (long)bigger._num[iSub] - borrow;
+ if (diff < 0)
+ {
+ diff += 1L << 32;
+ borrow = 1;
+ }
+ else
+ {
+ borrow = 0;
+ }
+ resSub[iSub] = (UInt32)diff;
+ }
+
+ // Trim leading zeros
+ int lenSub = nB;
+ while (lenSub > 0 && resSub[lenSub - 1] == 0) lenSub--;
+
+ BigInteger resultSub;
+ resultSub._num = resSub;
+ resultSub._len = lenSub;
+ resultSub._sgn = (lenSub == 0) ? 0 : resultSign;
+ return resultSub;
+ }
+
+ public static BigInteger Subtract(BigInteger X, BigInteger Y)
+ {
+ BigInteger negY = Y;
+ negY._sgn = (Y._sgn == 0) ? 0 : -Y._sgn;
+ return Add(X, negY);
+ }
+
+ public static BigInteger Multiply(BigInteger X, BigInteger Y)
+ {
+ int n = X._len, m = Y._len;
+ if (n == 0 || m == 0)
+ {
+ BigInteger zero;
+ zero._num = Memory.ScratchWorkspace.AllocateAsPointer(1);
+ zero._num[0] = 0;
+ zero._len = 0;
+ zero._sgn = 0;
+ return zero;
+ }
+
+ int len = n + m;
+ UInt32* res = Memory.ScratchWorkspace.AllocateAsPointer(len);
+ for (int i = 0; i < len; i++) res[i] = 0;
+
+ for (int i = 0; i < n; i++)
+ {
+ ulong carry = 0;
+ ulong xi = X._num[i];
+ for (int j = 0; j < m; j++)
+ {
+ ulong prod = (ulong)res[i + j] + xi * Y._num[j] + carry;
+ res[i + j] = (UInt32)prod;
+ carry = prod >> 32;
+ }
+ res[i + m] = (UInt32)((ulong)res[i + m] + carry);
+ }
+
+ // Trim leading zeros
+ int finalLen = len;
+ while (finalLen > 0 && res[finalLen - 1] == 0) finalLen--;
+
+ BigInteger result;
+ result._num = res;
+ result._len = finalLen;
+ result._sgn = X._sgn * Y._sgn;
+ return result;
+ }
+
+
+ public static BigInteger Divide(BigInteger X, BigInteger Y)
+ {
+ if (Y == zero)
+ }
+
+ public static BigInteger operator *(BigInteger X, BigInteger Y)
+ {
+ return Multiply(X, Y);
+ }
+
+ public override string ToString()
+ {
+ // create a copy of the underlying number
+ // we want to keep immutability
+ if (_len == 0)
+ {
+ return "0";
+ }
+ return DecimalBuilder.ConvertBigIntegerToString(_num, _len);
+ }
+ }
+
+}
diff --git a/MathEngine/MathEngine/types/DecimalBuilder.cs b/MathEngine/MathEngine/types/DecimalBuilder.cs
new file mode 100644
index 0000000..7761355
--- /dev/null
+++ b/MathEngine/MathEngine/types/DecimalBuilder.cs
@@ -0,0 +1,264 @@
+using MathEngine.MemoryManagement;
+using System;
+using System.Runtime.InteropServices.Marshalling;
+using System.Text;
+
+namespace MathEngine.types
+{
+ ///
+ /// Class that converts a representation to its decimal base 10 representaiton
+ ///
+ internal unsafe static class DecimalBuilder
+ {
+ private const UInt32 DECBASE = 1_000_000_000;
+ private const int THRESHOLD = 8;
+
+
+ ///
+ /// Performs simple division of by base 10^9using Knuth's algorithm.
+ ///
+ /// Pointer to a LSW ordered Uint32 array containing the digits to divide
+ /// The length of the array pointed to by
+ /// When this function returns, contains the base 10^9 representation of
+ /// Then length of
+ private static int SimpleDiv(UInt32* x, int xLen, out UInt32* result)
+ {
+ // possible over allocation, oh well!
+ result = Memory.ScratchWorkspace.AllocateAsPointer(THRESHOLD);
+ int digitIndex = 0;
+ while (xLen > 0)
+ {
+ ulong rem = 0;
+ for (int i = xLen - 1; i >= 0; i--)
+ {
+ ulong cur = (rem << 32) + x[i];
+ x[i] = (UInt32)(cur / DECBASE);
+ rem = cur % DECBASE;
+ }
+
+ result[digitIndex] = (UInt32)rem;
+ digitIndex++;
+
+ while (xLen > 0 && x[xLen - 1] == 0)
+ {
+ xLen--;
+ }
+ }
+
+ if (digitIndex == 0)
+ {
+ result[0] = 0;
+ digitIndex++;
+ }
+ return digitIndex;
+ }
+
+ ///
+ /// Performs multiplication of two of and in base 10^9.
+ ///
+ /// Pointer to a LSW ordered Uint32 array containing the digits to be multiplied by
+ /// The number of elements that contains
+ /// Pointer to a LSW ordered Uint32 array containing the digits to be multiplied by
+ /// The number of elements that contains
+ /// When this function returns, contains the base 10^9 representation of the multiplicaiton of and
+ /// Then length of
+ private static int DecMultiply(UInt32* x, int xLen, UInt32* y, int yLen, out UInt32* result)
+ {
+ int tmpLen = (xLen + yLen);
+ UInt64* tmp = Memory.ScratchWorkspace.AllocateAsPointer(xLen + yLen);
+
+ for (int i = 0; i < xLen; i++)
+ {
+ ulong carry = 0;
+ for (int j = 0; j < yLen; j++)
+ {
+ ulong cur = tmp[i + j] + (ulong)x[i] * y[j] + carry;
+ tmp[i + j] = cur % DECBASE;
+ carry = cur / DECBASE;
+ }
+ int k = i + yLen;
+ while (carry != 0)
+ {
+ ulong cur = tmp[k] + carry;
+ tmp[k] = cur % DECBASE;
+ carry = cur / DECBASE;
+ k++;
+ }
+ }
+
+ //convert to uint and trim leading zeros
+ result = Memory.ScratchWorkspace.AllocateAsPointer(tmpLen);
+ UInt32[] res = new UInt32[tmpLen];
+ for (int i = 0; i < tmpLen; i++)
+ {
+ result[i] = (UInt32)(tmp[i]);
+ }
+
+ int sz = res.Length;
+ while (sz > 1 && result[sz - 1] == 0)
+ {
+ sz--;
+ }
+ return sz;
+ }
+
+ ///
+ /// Performs addition of two of and in base 10^9.
+ ///
+ /// Pointer to a LSW ordered Uint32 array containing the digits to be added to by
+ /// The number of elements that contains
+ /// Pointer to a LSW ordered Uint32 array containing the digits to be added to by
+ /// The number of elements that contains
+ /// When this function returns, contains the base 10^9 representation of the addition of and
+ /// Then length of
+ private static int DecAdd(UInt32* x, int xLen, UInt32* y, int yLen, out UInt32* result)
+ {
+ int sz = Math.Max(xLen, yLen); // Test against with xLen ^ ((xLen ^ yLen) & ((xLen - yLen) >> 31))
+
+ result = Memory.ScratchWorkspace.AllocateAsPointer(sz + 1);
+
+ ulong carry = 0;
+
+ for (int i = 0; i < sz; i++)
+ {
+ ulong xv = i < xLen ? x[i] : 0;
+ ulong yv = i < yLen ? y[i] : 0;
+ ulong cur = xv + yv + carry;
+ result[i] = (UInt32)(cur % DECBASE);
+ carry = cur / DECBASE;
+ }
+
+ if (carry != 0)
+ {
+ result[sz] = (UInt32)carry;
+ return sz + 1;
+ }
+ //else
+ //{
+ // Array.Resize(ref res, sz); //?
+ //}
+ return sz;
+ }
+
+ ///
+ /// Performs addition of two of and in base 10^9.
+ ///
+ /// Pointer to a LSW ordered Uint32 array containing the digits to be added to by
+ /// The number of elements that contains
+ /// Pointer to a LSW ordered Uint32 array containing the digits to be added to by
+ /// The number of elements that contains
+ /// When this function returns, contains the base 10^9 representation of the addition of and
+ /// Then length of
+ private static int PowerBtoN(int k, out UInt32* result)
+ {
+ const ulong B = 1UL << 32;
+ result = Memory.ScratchWorkspace.AllocateAsPointer(1);
+ result[0] = 1;
+ int resultLen = 1;
+
+ // repeat multiply by B k times;
+ // in prod this can be simplified
+
+ for (int i = 0; i < k; i++)
+ {
+ resultLen = MultiplyByWord(result, resultLen, B, out UInt32* tResult);
+ // assign the multiplication result back into result and go again
+ result = tResult;
+ }
+ return resultLen;
+ }
+
+ private static int MultiplyByWord(UInt32* x, int xLen, ulong b, out UInt32* result)
+ {
+ result = Memory.ScratchWorkspace.AllocateAsPointer(xLen + 2);
+ ulong carry = 0;
+
+ for (int i = 0; i < xLen; i++)
+ {
+ ulong cur = (ulong)x[i] * b + carry;
+ result[i] = (UInt32)(cur % DECBASE);
+ carry = cur / DECBASE;
+ }
+
+ int pos = xLen;
+
+ while (carry != 0)
+ {
+ result[pos++] = (UInt32)(carry % DECBASE);
+ carry /= DECBASE;
+ }
+
+ //trim zeros
+ int sz = pos;
+ while (sz > 1 && result[sz - 1] == 0)
+ {
+ sz--;
+ }
+ return sz;
+ }
+
+ ///
+ /// Computes the base 10^9 representation of _num recursively if the number of digits is large
+ ///
+ /// Pointer to a LSW ordered Uint32 array containing the digits to convert
+ /// The length of the array pointed to by
+ /// When this function returns, contains the base 10^9 representation of
+ ///
+ private static int ToBase10_9(UInt32* digits, int len, out UInt32* result)
+ {
+ while (len > 0 && digits[len - 1] == 0)
+ {
+ len--;
+ }
+
+ if (len == 0)
+ {
+ result = Memory.ScratchWorkspace.AllocateAsPointer(1);
+ result[0] = 0;
+ return 1;
+ }
+ if (len < THRESHOLD)
+ {
+ return SimpleDiv(digits, len, out result);
+ }
+ int n = len / 2;
+ UInt32* lo = Memory.ScratchWorkspace.AllocateAsPointer(n);
+ UInt32* hi = Memory.ScratchWorkspace.AllocateAsPointer(len - n);
+ Memory.MemCopy(digits, 0, lo, 0, n);
+ Memory.MemCopy(digits, n, hi, 0, len - n);
+
+ int dloLen = ToBase10_9(lo, n, out UInt32* dlo);
+ int dhiLen = ToBase10_9(hi, len - n, out UInt32* dhi);
+
+ int powLen = PowerBtoN(n, out UInt32* pow);
+
+ int dhiScaledLen = DecMultiply(dhi, dhiLen, pow, powLen, out UInt32* dhiScaled);
+ return DecAdd(dhiScaled, dhiScaledLen, dlo, dloLen, out result);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static string ConvertBigIntegerToString(UInt32* num, int numLen)
+ {
+
+ UInt32* cpy = Memory.ScratchWorkspace.AllocateAsPointer(numLen);
+ Memory.MemCopy(num, 0, cpy, 0, numLen);
+ int dLen = ToBase10_9(cpy, numLen, out UInt32* digits);
+
+ StringBuilder sb = new();
+
+ sb.Append(digits[dLen - 1].ToString());
+
+ for (int i = dLen - 2; i >= 0; i--)
+ {
+ sb.Append(digits[i].ToString("D9"));
+ }
+
+ return sb.ToString();
+ }
+ }
+}
diff --git a/MathEngine/MathRunner/Program.cs b/MathEngine/MathRunner/Program.cs
index 6f010bb..774441b 100644
--- a/MathEngine/MathRunner/Program.cs
+++ b/MathEngine/MathRunner/Program.cs
@@ -1,4 +1,5 @@
-using MathEngine.Expression;
+using MathEngine.types;
+using MathEngine.Expression;
namespace MathRunner
{
@@ -6,6 +7,12 @@ namespace MathRunner
{
static void Main(string[] args)
{
+ BigInteger x = new(123456);
+ for (int i = 0; i < 4; i++)
+ {
+ x = x * x;
+ }
+ Console.WriteLine(x.ToString());
Console.WriteLine("Evaluting expression...");
Expression exp = new("54+2+1");
Console.WriteLine(exp.Evaluate());
diff --git a/MathEngine/common/UnmanagedMMU.dll b/MathEngine/common/UnmanagedMMU.dll
new file mode 100644
index 0000000..0d235d0
Binary files /dev/null and b/MathEngine/common/UnmanagedMMU.dll differ