mirror of
https://github.com/0xJ1M/MathsEngine.git
synced 2026-06-05 03:20:07 +00:00
WIP
This commit is contained in:
@@ -32,7 +32,7 @@ namespace MathEngine.AST.Nodes
|
|||||||
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
|
return new BinaryNode(LeftBranch, RightBranch, (a, b) => a / b);
|
||||||
case TokenType.Exponentiation:
|
case TokenType.Exponentiation:
|
||||||
throw new NotImplementedException("Exponentiation is not supported at this time!");
|
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:
|
default:
|
||||||
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
|
throw new NotImplementedException("Attempted to create a BinaryNode with an invalid operation!");
|
||||||
}
|
}
|
||||||
|
|||||||
56
MathEngine/MathEngine/MMU/Memory.cs
Normal file
56
MathEngine/MathEngine/MMU/Memory.cs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies a range of elements from the specified source buffer to the specified destination buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The buffer to copy elements from.</param>
|
||||||
|
/// <param name="sourceIndex">The zero-based index in <paramref name="source"/> at which copying begins.</param>
|
||||||
|
/// <param name="destination">The buffer to copy elements to.</param>
|
||||||
|
/// <param name="destinationIndex">The zero-based index in <paramref name="destination"/> at which storing begins.</param>
|
||||||
|
/// <param name="count">The number of elements to copy.</param>
|
||||||
|
[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
|
||||||
|
/// <summary>
|
||||||
|
/// Prints the contents of the unmanaged <typeparamref name="T"/> memory block pointed to by <paramref name="arr"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="arr"><typeparamref name="T"/>* pointer to the memory block to print</param>
|
||||||
|
/// <param name="len">The length of the memory block pointed to by <paramref name="arr"/></param>
|
||||||
|
private static void PrintUnmanagedArray<T>(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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -21,4 +22,10 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="UnmanagedMMU">
|
||||||
|
<HintPath>..\common\UnmanagedMMU.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
247
MathEngine/MathEngine/types/BigInteger.cs
Normal file
247
MathEngine/MathEngine/types/BigInteger.cs
Normal file
@@ -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<UInt32>(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<UInt32>(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<UInt32>(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<UInt32>(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<UInt32>(1);
|
||||||
|
zero._num[0] = 0;
|
||||||
|
zero._len = 0;
|
||||||
|
zero._sgn = 0;
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = n + m;
|
||||||
|
UInt32* res = Memory.ScratchWorkspace.AllocateAsPointer<UInt32>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
264
MathEngine/MathEngine/types/DecimalBuilder.cs
Normal file
264
MathEngine/MathEngine/types/DecimalBuilder.cs
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
using MathEngine.MemoryManagement;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices.Marshalling;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MathEngine.types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class that converts a <see cref="BigInteger"/> representation to its decimal base 10 representaiton
|
||||||
|
/// </summary>
|
||||||
|
internal unsafe static class DecimalBuilder
|
||||||
|
{
|
||||||
|
private const UInt32 DECBASE = 1_000_000_000;
|
||||||
|
private const int THRESHOLD = 8;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs simple division of <paramref name="x"/> by base 10^9using Knuth's algorithm.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">Pointer to a LSW ordered Uint32 array containing the digits to divide</param>
|
||||||
|
/// <param name="xLen">The length of the array pointed to by <paramref name="x"/></param>
|
||||||
|
/// <param name="result">When this function returns, contains the base 10^9 representation of <paramref name="x"/></param>
|
||||||
|
/// <returns>Then length of <paramref name="result"/> </returns>
|
||||||
|
private static int SimpleDiv(UInt32* x, int xLen, out UInt32* result)
|
||||||
|
{
|
||||||
|
// possible over allocation, oh well!
|
||||||
|
result = Memory.ScratchWorkspace.AllocateAsPointer<UInt32>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs multiplication of two of <paramref name="x"/> and <paramref name="y"/> in base 10^9.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">Pointer to a LSW ordered Uint32 array containing the digits to be multiplied by <paramref name="y"/></param>
|
||||||
|
/// <param name="xLen">The number of elements that <paramref name="x"/> contains</param>
|
||||||
|
/// <param name="y">Pointer to a LSW ordered Uint32 array containing the digits to be multiplied by <paramref name="x"/></param>
|
||||||
|
/// <param name="yLen">The number of elements that <paramref name="y"/> contains</param>
|
||||||
|
/// <param name="result">When this function returns, contains the base 10^9 representation of the multiplicaiton of <paramref name="x"/> and <paramref name="y"/></param>
|
||||||
|
/// <returns>Then length of <paramref name="result"/> </returns>
|
||||||
|
private static int DecMultiply(UInt32* x, int xLen, UInt32* y, int yLen, out UInt32* result)
|
||||||
|
{
|
||||||
|
int tmpLen = (xLen + yLen);
|
||||||
|
UInt64* tmp = Memory.ScratchWorkspace.AllocateAsPointer<UInt64>(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<UInt32>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs addition of two of <paramref name="x"/> and <paramref name="y"/> in base 10^9.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">Pointer to a LSW ordered Uint32 array containing the digits to be added to by <paramref name="y"/></param>
|
||||||
|
/// <param name="xLen">The number of elements that <paramref name="x"/> contains</param>
|
||||||
|
/// <param name="y">Pointer to a LSW ordered Uint32 array containing the digits to be added to by <paramref name="x"/></param>
|
||||||
|
/// <param name="yLen">The number of elements that <paramref name="y"/> contains</param>
|
||||||
|
/// <param name="result">When this function returns, contains the base 10^9 representation of the addition of <paramref name="x"/> and <paramref name="y"/></param>
|
||||||
|
/// <returns>Then length of <paramref name="result"/> </returns>
|
||||||
|
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<UInt32>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs addition of two of <paramref name="x"/> and <paramref name="y"/> in base 10^9.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">Pointer to a LSW ordered Uint32 array containing the digits to be added to by <paramref name="y"/></param>
|
||||||
|
/// <param name="xLen">The number of elements that <paramref name="x"/> contains</param>
|
||||||
|
/// <param name="y">Pointer to a LSW ordered Uint32 array containing the digits to be added to by <paramref name="x"/></param>
|
||||||
|
/// <param name="yLen">The number of elements that <paramref name="y"/> contains</param>
|
||||||
|
/// <param name="result">When this function returns, contains the base 10^9 representation of the addition of <paramref name="x"/> and <paramref name="y"/></param>
|
||||||
|
/// <returns>Then length of <paramref name="result"/> </returns>
|
||||||
|
private static int PowerBtoN(int k, out UInt32* result)
|
||||||
|
{
|
||||||
|
const ulong B = 1UL << 32;
|
||||||
|
result = Memory.ScratchWorkspace.AllocateAsPointer<UInt32>(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<UInt32>(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the base 10^9 representation of _num recursively if the number of digits is large
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="digits">Pointer to a LSW ordered Uint32 array containing the digits to convert</param>
|
||||||
|
/// <param name="len">The length of the array pointed to by <paramref name="digits"/></param>
|
||||||
|
/// <param name="result">When this function returns, contains the base 10^9 representation of <paramref name="digits"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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<UInt32>(1);
|
||||||
|
result[0] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (len < THRESHOLD)
|
||||||
|
{
|
||||||
|
return SimpleDiv(digits, len, out result);
|
||||||
|
}
|
||||||
|
int n = len / 2;
|
||||||
|
UInt32* lo = Memory.ScratchWorkspace.AllocateAsPointer<UInt32>(n);
|
||||||
|
UInt32* hi = Memory.ScratchWorkspace.AllocateAsPointer<UInt32>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="num"></param>
|
||||||
|
/// <param name="numLen"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ConvertBigIntegerToString(UInt32* num, int numLen)
|
||||||
|
{
|
||||||
|
|
||||||
|
UInt32* cpy = Memory.ScratchWorkspace.AllocateAsPointer<UInt32>(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using MathEngine.Expression;
|
using MathEngine.types;
|
||||||
|
using MathEngine.Expression;
|
||||||
|
|
||||||
namespace MathRunner
|
namespace MathRunner
|
||||||
{
|
{
|
||||||
@@ -6,6 +7,12 @@ namespace MathRunner
|
|||||||
{
|
{
|
||||||
static void Main(string[] args)
|
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...");
|
Console.WriteLine("Evaluting expression...");
|
||||||
Expression exp = new("54+2+1");
|
Expression exp = new("54+2+1");
|
||||||
Console.WriteLine(exp.Evaluate());
|
Console.WriteLine(exp.Evaluate());
|
||||||
|
|||||||
BIN
MathEngine/common/UnmanagedMMU.dll
Normal file
BIN
MathEngine/common/UnmanagedMMU.dll
Normal file
Binary file not shown.
Reference in New Issue
Block a user