Resolve "Migrate to INumber" #11

Merged
thorsten merged 15 commits from 1-migrate-to-inumber into main 2023-07-10 17:42:08 +00:00
2 changed files with 584 additions and 0 deletions
Showing only changes of commit 6b656b90e3 - Show all commits

555
FastRng/HugeInteger.cs Normal file
View File

@ -0,0 +1,555 @@
using System;
using System.Globalization;
using System.Linq;
using System.Numerics;
namespace FastRng;
public struct HugeInteger<TOtherNum> :
IBinaryInteger<HugeInteger<TOtherNum>>,
IComparisonOperators<HugeInteger<TOtherNum>, TOtherNum, HugeInteger<TOtherNum>>,
IMultiplyOperators<HugeInteger<TOtherNum>, TOtherNum, HugeInteger<TOtherNum>>
where TOtherNum : IBinaryInteger<TOtherNum>
{
private ulong value = default;
public HugeInteger(ulong value) => this.value = value;
#region IBinaryInteger
#region Implementation of IComparable
/// <inheritdoc />
public int CompareTo(object obj) => this.value.CompareTo(obj);
#endregion
#region Implementation of IComparable<in HugeInteger>
/// <inheritdoc />
public int CompareTo(HugeInteger<TOtherNum> other) => this.value.CompareTo(other.value);
#endregion
#region Implementation of IEquatable<HugeInteger>
/// <inheritdoc />
public bool Equals(HugeInteger<TOtherNum> other) => this.value.Equals(other.value);
#endregion
#region Implementation of IFormattable
/// <inheritdoc />
public string ToString(string format, IFormatProvider formatProvider) => this.value.ToString(format, formatProvider);
#endregion
#region Implementation of IParsable<HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> Parse(string s, IFormatProvider provider) => new(ulong.Parse(s, provider));
/// <inheritdoc />
public static bool TryParse(string s, IFormatProvider provider, out HugeInteger<TOtherNum> result)
{
if (ulong.TryParse(s, NumberStyles.Integer, provider, out var value))
{
result = new HugeInteger<TOtherNum>(value);
return true;
}
result = default;
return false;
}
#endregion
#region Implementation of ISpanFormattable
/// <inheritdoc />
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider) => this.value.TryFormat(destination, out charsWritten, format, provider);
#endregion
#region Implementation of ISpanParsable<HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> Parse(ReadOnlySpan<char> s, IFormatProvider provider) => new(ulong.Parse(s, provider));
/// <inheritdoc />
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out HugeInteger<TOtherNum> result)
{
if (ulong.TryParse(s, NumberStyles.Integer, provider, out var value))
{
result = new HugeInteger<TOtherNum>(value);
return true;
}
result = default;
return false;
}
#endregion
#region Implementation of IAdditionOperators<HugeInteger,HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator +(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value + right.value);
#endregion
#region Implementation of IAdditiveIdentity<HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> AdditiveIdentity => new(0);
#endregion
#region Implementation of IBitwiseOperators<HugeInteger,HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator &(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value & right.value);
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator |(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value | right.value);
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator ^(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value ^ right.value);
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator ~(HugeInteger<TOtherNum> value) => new(~value.value);
#endregion
#region Implementation of IEqualityOperators<HugeInteger,HugeInteger,bool>
/// <inheritdoc />
public static bool operator ==(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => left.value == right.value;
/// <inheritdoc />
public static bool operator !=(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => left.value != right.value;
#endregion
#region Implementation of IComparisonOperators<HugeInteger,HugeInteger,bool>
/// <inheritdoc />
public static bool operator >(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => left.value > right.value;
/// <inheritdoc />
public static bool operator >=(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => left.value >= right.value;
/// <inheritdoc />
public static bool operator <(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => left.value < right.value;
/// <inheritdoc />
public static bool operator <=(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => left.value <= right.value;
#endregion
#region Implementation of IDecrementOperators<HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator --(HugeInteger<TOtherNum> value)
{
value.value--;
return value;
}
#endregion
#region Implementation of IDivisionOperators<HugeInteger,HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator /(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value / right.value);
#endregion
#region Implementation of IIncrementOperators<HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator ++(HugeInteger<TOtherNum> value)
{
value.value++;
return value;
}
#endregion
#region Implementation of IModulusOperators<HugeInteger,HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator %(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value % right.value);
#endregion
#region Implementation of IMultiplicativeIdentity<HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> MultiplicativeIdentity => new(1);
#endregion
#region Implementation of IMultiplyOperators<HugeInteger,HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator *(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value * right.value);
#endregion
#region Implementation of ISubtractionOperators<HugeInteger,HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator -(HugeInteger<TOtherNum> left, HugeInteger<TOtherNum> right) => new(left.value - right.value);
#endregion
#region Implementation of IUnaryNegationOperators<HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator -(HugeInteger<TOtherNum> value) => throw new NotImplementedException();
#endregion
#region Implementation of IUnaryPlusOperators<HugeInteger,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator +(HugeInteger<TOtherNum> value) => throw new NotImplementedException();
#endregion
#region Implementation of INumberBase<HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> Abs(HugeInteger<TOtherNum> value) => value;
/// <inheritdoc />
public static bool IsCanonical(HugeInteger<TOtherNum> value) => true;
/// <inheritdoc />
public static bool IsComplexNumber(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsEvenInteger(HugeInteger<TOtherNum> value) => ulong.IsEvenInteger(value.value);
/// <inheritdoc />
public static bool IsFinite(HugeInteger<TOtherNum> value) => true;
/// <inheritdoc />
public static bool IsImaginaryNumber(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsInfinity(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsInteger(HugeInteger<TOtherNum> value) => true;
/// <inheritdoc />
public static bool IsNaN(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsNegative(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsNegativeInfinity(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsNormal(HugeInteger<TOtherNum> value) => true;
/// <inheritdoc />
public static bool IsOddInteger(HugeInteger<TOtherNum> value) => ulong.IsOddInteger(value.value);
/// <inheritdoc />
public static bool IsPositive(HugeInteger<TOtherNum> value) => true;
/// <inheritdoc />
public static bool IsPositiveInfinity(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsRealNumber(HugeInteger<TOtherNum> value) => true;
/// <inheritdoc />
public static bool IsSubnormal(HugeInteger<TOtherNum> value) => false;
/// <inheritdoc />
public static bool IsZero(HugeInteger<TOtherNum> value) => value.value == 0;
/// <inheritdoc />
public static HugeInteger<TOtherNum> MaxMagnitude(HugeInteger<TOtherNum> x, HugeInteger<TOtherNum> y) => x.value > y.value ? x : y;
/// <inheritdoc />
public static HugeInteger<TOtherNum> MaxMagnitudeNumber(HugeInteger<TOtherNum> x, HugeInteger<TOtherNum> y) => x.value > y.value ? x : y;
/// <inheritdoc />
public static HugeInteger<TOtherNum> MinMagnitude(HugeInteger<TOtherNum> x, HugeInteger<TOtherNum> y) => x.value < y.value ? x : y;
/// <inheritdoc />
public static HugeInteger<TOtherNum> MinMagnitudeNumber(HugeInteger<TOtherNum> x, HugeInteger<TOtherNum> y) => x.value < y.value ? x : y;
/// <inheritdoc />
public static HugeInteger<TOtherNum> Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider) => new(ulong.Parse(s, style, provider));
/// <inheritdoc />
public static HugeInteger<TOtherNum> Parse(string s, NumberStyles style, IFormatProvider provider) => new(ulong.Parse(s, style, provider));
/// <inheritdoc />
public static bool TryConvertFromChecked<TOther>(TOther value, out HugeInteger<TOtherNum> result) where TOther : INumberBase<TOther>
{
result = new HugeInteger<TOtherNum>(ulong.CreateChecked(value));
return true;
}
/// <inheritdoc />
public static bool TryConvertFromSaturating<TOther>(TOther value, out HugeInteger<TOtherNum> result) where TOther : INumberBase<TOther>
{
result = new HugeInteger<TOtherNum>(ulong.CreateSaturating(value));
return true;
}
/// <inheritdoc />
public static bool TryConvertFromTruncating<TOther>(TOther value, out HugeInteger<TOtherNum> result) where TOther : INumberBase<TOther>
{
result = new HugeInteger<TOtherNum>(ulong.CreateTruncating(value));
return true;
}
/// <inheritdoc />
public static bool TryConvertToChecked<TOther>(HugeInteger<TOtherNum> value, out TOther result) where TOther : INumberBase<TOther>
{
result = TOther.CreateChecked(value.value);
return true;
}
/// <inheritdoc />
public static bool TryConvertToSaturating<TOther>(HugeInteger<TOtherNum> value, out TOther result) where TOther : INumberBase<TOther>
{
result = TOther.CreateSaturating(value.value);
return true;
}
/// <inheritdoc />
public static bool TryConvertToTruncating<TOther>(HugeInteger<TOtherNum> value, out TOther result) where TOther : INumberBase<TOther>
{
result = TOther.CreateTruncating(value.value);
return true;
}
/// <inheritdoc />
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider provider, out HugeInteger<TOtherNum> result)
{
var state = ulong.TryParse(s, style, provider, out var value);
if(state)
result = new HugeInteger<TOtherNum>(value);
else
result = default;
return state;
}
/// <inheritdoc />
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out HugeInteger<TOtherNum> result)
{
var state = ulong.TryParse(s, style, provider, out var value);
if(state)
result = new HugeInteger<TOtherNum>(value);
else
result = default;
return state;
}
/// <inheritdoc />
public static HugeInteger<TOtherNum> One => new(1);
/// <inheritdoc />
public static int Radix => 2;
/// <inheritdoc />
public static HugeInteger<TOtherNum> Zero => new(0);
#endregion
#region Implementation of IBinaryNumber<HugeInteger>
/// <inheritdoc />
public static bool IsPow2(HugeInteger<TOtherNum> value) => ulong.IsPow2(value.value);
/// <inheritdoc />
public static HugeInteger<TOtherNum> Log2(HugeInteger<TOtherNum> value) => new(ulong.Log2(value.value));
#endregion
#region Implementation of IShiftOperators<HugeInteger,int,HugeInteger>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator <<(HugeInteger<TOtherNum> value, int shiftAmount) => new(value.value << shiftAmount);
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator >> (HugeInteger<TOtherNum> value, int shiftAmount) => new(value.value >> shiftAmount);
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator >>> (HugeInteger<TOtherNum> value, int shiftAmount) => new(value.value >>> shiftAmount);
#endregion
#region Implementation of IBinaryInteger<HugeInteger>
/// <inheritdoc />
public int GetByteCount() => sizeof(ulong);
/// <inheritdoc />
public int GetShortestBitLength() => (sizeof(ulong) * 8) - BitOperations.LeadingZeroCount(this.value);
/// <inheritdoc />
public static HugeInteger<TOtherNum> PopCount(HugeInteger<TOtherNum> value) => new((ulong)BitOperations.PopCount(value.value));
/// <inheritdoc />
public static HugeInteger<TOtherNum> TrailingZeroCount(HugeInteger<TOtherNum> value) => new((ulong)BitOperations.TrailingZeroCount(value.value));
/// <inheritdoc />
public static bool TryReadBigEndian(ReadOnlySpan<byte> source, bool isUnsigned, out HugeInteger<TOtherNum> value)
{
if (!isUnsigned)
{
value = default;
return false;
}
if(source.Length != sizeof(ulong))
{
value = default;
return false;
}
var sourceBytes = source.ToArray();
if (BitConverter.IsLittleEndian)
sourceBytes = sourceBytes.Reverse().ToArray();
value = new HugeInteger<TOtherNum>(BitConverter.ToUInt64(sourceBytes));
return true;
}
/// <inheritdoc />
public static bool TryReadLittleEndian(ReadOnlySpan<byte> source, bool isUnsigned, out HugeInteger<TOtherNum> value)
{
if (!isUnsigned)
{
value = default;
return false;
}
if(source.Length != sizeof(ulong))
{
value = default;
return false;
}
var sourceBytes = source.ToArray();
if (!BitConverter.IsLittleEndian)
sourceBytes = sourceBytes.Reverse().ToArray();
value = new HugeInteger<TOtherNum>(BitConverter.ToUInt64(sourceBytes));
return true;
}
/// <inheritdoc />
public bool TryWriteBigEndian(Span<byte> destination, out int bytesWritten)
{
var bytes = BitConverter.GetBytes(this.value);
if (BitConverter.IsLittleEndian)
bytes = bytes.Reverse().ToArray();
bytes.CopyTo(destination);
bytesWritten = bytes.Length;
return true;
}
/// <inheritdoc />
public bool TryWriteLittleEndian(Span<byte> destination, out int bytesWritten)
{
var bytes = BitConverter.GetBytes(this.value);
if (!BitConverter.IsLittleEndian)
bytes = bytes.Reverse().ToArray();
bytes.CopyTo(destination);
bytesWritten = bytes.Length;
return true;
}
#endregion
#endregion
#region Necessary extra operators
#region Implementation of IEqualityOperators<HugeInteger<TOtherNum>,TOtherNum,HugeInteger<TOtherNum>>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator ==(HugeInteger<TOtherNum> left, TOtherNum right)
{
return left == right;
}
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator !=(HugeInteger<TOtherNum> left, TOtherNum right)
{
return left != right;
}
#endregion
#region Implementation of IComparisonOperators<HugeInteger<TOtherNum>,TOtherNum,HugeInteger<TOtherNum>>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator >(HugeInteger<TOtherNum> left, TOtherNum right)
{
return left > right;
}
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator >=(HugeInteger<TOtherNum> left, TOtherNum right)
{
return left >= right;
}
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator <(HugeInteger<TOtherNum> left, TOtherNum right)
{
return left < right;
}
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator <=(HugeInteger<TOtherNum> left, TOtherNum right)
{
return left <= right;
}
#endregion
#region Implementation of IMultiplyOperators<HugeInteger<TOtherNum>,TOtherNum,HugeInteger<TOtherNum>>
/// <inheritdoc />
public static HugeInteger<TOtherNum> operator *(HugeInteger<TOtherNum> left, TOtherNum right)
{
// Would work, but TOtherNum might not be able to hold the result! Thus, we cannot convert
// left to TOtherNum, and we cannot convert right to HugeInteger<TOtherNum>.
// return new HugeInteger<TOtherNum>(ulong.CreateSaturating(TOtherNum.CreateSaturating(left.value) * right));
return left * right;
}
#endregion
#endregion
/// <summary>
/// Converts a ulong to a HugeInteger.
/// </summary>
public static implicit operator HugeInteger<TOtherNum>(ulong value) => new(value);
/// <summary>
/// Converts a HugeInteger to a ulong.
/// </summary>
public static implicit operator ulong(HugeInteger<TOtherNum> value) => value.value;
}

View File

@ -0,0 +1,29 @@
using System;
using System.Numerics;
namespace FastRng;
/// <summary>
/// Provides some mathematical function, which are not available within in .NET itself.
/// </summary>
public static class IntegerMathTools<TNum> where TNum : IBinaryInteger<TNum>, IComparisonOperators<HugeInteger<TNum>, TNum, HugeInteger<TNum>>, IMultiplyOperators<HugeInteger<TNum>, TNum, HugeInteger<TNum>>
{
private static readonly TNum CONST20 = TNum.CreateChecked(20);
/// <summary>
/// The mathematical factorial function for integer numbers.
/// </summary>
/// <param name="x">The value, for which you want to know the factorial.</param>
/// <exception cref="ArgumentOutOfRangeException">Throws, when x is greater than 20. Due to limitations of 64bit ulong type.</exception>
public static ulong Factorial(TNum x)
{
if (x > CONST20)
throw new ArgumentOutOfRangeException(nameof(x), $"Cannot compute {x}!, since ulong.max is 18_446_744_073_709_551_615.");
var accumulator = new HugeInteger<TNum>(1);
for (var factor = TNum.One; factor <= x; factor++)
accumulator *= factor;
return accumulator;
}
}