DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="5.8.0" />

 Number

public static class Number
Represents Generic Math extensions.
using System; using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; namespace DotNext.Numerics { public static class Number { public static TResult FromBits<TResult>(this ReadOnlySpan<bool> bits) where TResult : struct, IBinaryInteger<TResult> { TResult val = TResult.get_Zero(); for (int i = 0; i < bits.Length; i++) { if (bits[i]) val |= TResult.get_One() << i; } return val; } public unsafe static void GetBits<[IsUnmanaged] T>(this T value, Span<bool> bits) where T : struct, IBinaryInteger<T> { int num = sizeof(T) * 8; ArgumentOutOfRangeException.ThrowIfLessThan<uint>((uint)bits.Length, (uint)num, "bits"); if (Vector256.get_IsHardwareAccelerated() && int.IsEvenInteger(sizeof(T))) Get16Bits(ref Unsafe.As<T, byte>(ref value), (IntPtr)sizeof(T), ref MemoryMarshal.GetReference(bits)); else if (Vector128.get_IsHardwareAccelerated()) { Get8Bits(ref Unsafe.As<T, byte>(ref value), (IntPtr)sizeof(T), ref MemoryMarshal.GetReference(bits)); } else { for (int i = 0; i < num; i++) { bits[i] = ((value & (T.get_One() << i)) != T.get_Zero()); } } } private unsafe static void Get8Bits(ref byte input, IntPtr length, ref bool output) { for (IntPtr intPtr = (IntPtr)0; (long)intPtr < (long)length; intPtr = (IntPtr)(void*)((long)intPtr + 1)) { Get8Bits(Vector128.Create(Unsafe.Add<byte>(ref input, intPtr)), ref Unsafe.Add<bool>(ref output, (IntPtr)(void*)((long)intPtr * 8))); } } private static void Get8Bits(Vector128<byte> input, ref bool output) { Vector128<byte> vector = Vector128.Create((byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1, (byte)1); Vector128<byte> vector2 = Vector128.Create(1, 2, 4, 8, 16, 32, 64, 128, 0, 0, 0, 0, 0, 0, 0, 0); Vector64.StoreUnsafe<byte>(Vector128.Min<byte>(input & vector2, vector).GetLower(), ref Unsafe.As<bool, byte>(ref output)); } private unsafe static void Get16Bits(ref byte input, IntPtr length, ref bool output) { for (IntPtr intPtr = (IntPtr)0; (long)intPtr < (long)length; intPtr = (IntPtr)(void*)((long)intPtr + 2)) { Get16Bits(Vector256.Create(Unsafe.ReadUnaligned<ushort>(ref Unsafe.Add<byte>(ref input, intPtr))), ref Unsafe.Add<bool>(ref output, (IntPtr)(void*)((long)intPtr * 8))); } } private static void Get16Bits(Vector256<ushort> input, ref bool output) { Vector256<ushort> vector = Vector256.Create((ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1, (ushort)1); Vector256<ushort> vector2 = Vector256.Create(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768); Vector256<byte> vector3 = Vector256.Create(0, 2, 4, 6, 8, 10, 12, 14, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, 16, 18, 20, 22, 24, 26, 28, 30, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); Vector256<byte> vector4 = Vector256.Shuffle(Vector256.Min<ushort>(input & vector2, vector).AsByte(), vector3); Vector64.StoreUnsafe<byte>(vector4.GetLower().GetLower(), ref Unsafe.As<bool, byte>(ref output)); Vector64.StoreUnsafe<byte>(vector4.GetUpper().GetLower(), ref Unsafe.Add<byte>(ref Unsafe.As<bool, byte>(ref output), 8)); } [NullableContext(1)] public static bool IsSigned<T>() where T : INumberBase<T> { return T.IsNegative(-T.get_One()); } [NullableContext(1)] public static int GetMaxByteCount<T>() where T : IBinaryInteger<T> { if (!typeof(T).IsPrimitive) return T.get_AllBitsSet().GetByteCount(); return Unsafe.SizeOf<T>(); } public static TOutput Normalize<TInput, TOutput>(this TInput value, TInput min, TInput max) where TInput : struct, INumberBase<TInput>, IComparisonOperators<TInput, TInput, bool> where TOutput : struct, IFloatingPoint<TOutput> { TOutput val = TOutput.CreateChecked<TInput>(value); TInput val2; if (value > TInput.get_Zero()) val2 = max; else { val2 = min; val = -val; } return val / TOutput.CreateChecked<TInput>(val2); } [CLSCompliant(false)] public static double Normalize(this ulong value) { return BitConverter.UInt64BitsToDouble(9007199254740991 & value) / BitConverter.UInt64BitsToDouble(9007199254740992); } public static double Normalize(this long value) { return ((ulong)value).Normalize(); } [CLSCompliant(false)] public static float Normalize(this uint value) { return BitConverter.UInt32BitsToSingle(16777215 & value) / BitConverter.UInt32BitsToSingle(16777216); } public static float Normalize(this int value) { return ((uint)value).Normalize(); } public static bool IsPrime<T>(T value) where T : struct, IBinaryInteger<T>, ISignedNumber<T> { ArgumentOutOfRangeException.ThrowIfNegativeOrZero<T>(value, "value"); if (value == T.get_One()) return false; T val = T.get_One() << 1; if ((value & T.get_One()) != T.get_Zero()) { T val2 = val + T.get_One(); T val3 = <IsPrime>g__Sqrt|13_0(value); while (val2 <= val3) { if (value % val2 == T.get_Zero()) return false; val2 += val; } return true; } return value == val; } [EditorBrowsable(EditorBrowsableState.Never)] public static T GetPrime<T>(T lowerBound, ReadOnlySpan<T> cachedPrimes = default(ReadOnlySpan<T>)) where T : struct, IBinaryInteger<T>, ISignedNumber<T>, IMinMaxValue<T> { ArgumentOutOfRangeException.ThrowIfNegativeOrZero<T>(lowerBound, "lowerBound"); if (<GetPrime>g__TryGetFromTable|14_0(cachedPrimes, lowerBound, out T result)) return result; result = (lowerBound | T.get_One()); while (result < T.get_MaxValue()) { if (IsPrime(result)) return result; result += T.get_One() + T.get_One(); } throw new OverflowException(); } } }