Resolve "Migrate to INumber" #11
555
FastRng/HugeInteger.cs
Normal file
555
FastRng/HugeInteger.cs
Normal 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;
|
||||
}
|
29
FastRng/IntegerMathTools.cs
Normal file
29
FastRng/IntegerMathTools.cs
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user