Rdtsc.cs

Rdtsc 32 and 64 Bit In C#

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
public static class Rdtsc
{
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate ulong FuncUInt64();
private const uint PAGE_READWRITE = 0x04;
private const uint PAGE_EXECUTE = 0x10;
private const uint PAGE_EXECUTE_READWRITE = 0x40;
private const uint MEM_COMMIT = 0x1000;
private const uint MEM_RELEASE = 0x8000;
public static readonly FuncUInt64 Timestamp;
public static readonly FuncUInt64 TimestampP;
public static readonly bool IsRdtscSupported;
public static readonly bool IsRdtscPSupported;
static Rdtsc()
{
SystemInfo systemInfo;
GetNativeSystemInfo(out systemInfo);
if (systemInfo.wProcessorArchitecture != 0 && systemInfo.wProcessorArchitecture != 9)
{
Timestamp = StopwatchGetTimestamp;
TimestampP = StopwatchGetTimestamp;
IsRdtscSupported = false;
IsRdtscPSupported = false;
return;
}
byte[] cpuid;
byte[] rdtsc;
byte[] rdtscp;
byte[] rdtsccpuid;
IsRdtscSupported = true;
if (Is64Bit())
{
cpuid = new byte[]
{
0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x16, 0x89, 0xD8,
0x48, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xA2, 0x89, 0xC8, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x09, 0xD0, 0xEB,
0x03, 0x48, 0x31, 0xC0, 0x5B, 0xC3
};
rdtsc = new byte[] {0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3};
rdtscp = new byte[] {0x0F, 0x01, 0xF9, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3};
rdtsccpuid = new byte[]
{0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x5B, 0xC3};
}
else
{
cpuid = new byte[]
{
0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x0A, 0x89, 0xD8,
0x0F, 0xA2, 0x89, 0xD0, 0x89, 0xCA, 0xEB, 0x04, 0x31, 0xC0, 0x31, 0xD2, 0x5B, 0xC3
};
rdtsc = new byte[] {0x0F, 0x31, 0xC3};
rdtscp = new byte[] {0x0F, 0x01, 0xF9, 0xC3};
rdtsccpuid = new byte[] {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x5B, 0xC3};
}
var buf = IntPtr.Zero;
try
{
var cpuidLength = (cpuid.Length & 63) != 0 ? (cpuid.Length | 63) + 1 : cpuid.Length;
var rdtscLength = (rdtsc.Length & 63) != 0 ? (rdtsc.Length | 63) + 1 : rdtsc.Length;
var rdtscpLength = (rdtscp.Length & 63) != 0 ? (rdtscp.Length | 63) + 1 : rdtscp.Length;
var rdtsccpuidLength = (rdtsccpuid.Length & 63) != 0 ? (rdtsccpuid.Length | 63) + 1 : rdtsccpuid.Length;
var totalLength = cpuidLength + rdtscLength + Math.Max(rdtscpLength, rdtsccpuidLength);
buf = VirtualAlloc(IntPtr.Zero, (IntPtr) totalLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (buf != IntPtr.Zero)
{
Marshal.Copy(cpuid, 0, buf, cpuid.Length);
for (var i = cpuid.Length; i < cpuidLength; i++)
Marshal.WriteByte(buf, i, 0x90);
Marshal.Copy(rdtsc, 0, buf + cpuidLength, rdtsc.Length);
for (var i = rdtsc.Length; i < rdtscLength; i++)
Marshal.WriteByte(buf, cpuidLength + i, 0x90);
var cpuidFunc = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf, typeof(FuncUInt64));
var supportedFeatures = cpuidFunc();
byte[] rdtscpSelected;
int rdtscpSelectedLength;
if ((supportedFeatures & (1L << 27)) != 0)
{
rdtscpSelected = rdtscp;
rdtscpSelectedLength = rdtscpLength;
IsRdtscPSupported = true;
}
else
{
rdtscpSelected = rdtsccpuid;
rdtscpSelectedLength = rdtsccpuidLength;
IsRdtscPSupported = false;
}
Marshal.Copy(rdtscpSelected, 0, buf + cpuidLength + rdtscLength, rdtscpSelected.Length);
for (var i = rdtscpSelected.Length; i < rdtscpSelectedLength; i++)
Marshal.WriteByte(buf, cpuidLength + rdtscLength + i, 0x90);
var result = VirtualProtect(buf, (IntPtr) totalLength, PAGE_EXECUTE, out var oldProtection);
if (result)
{
Timestamp = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength, typeof(FuncUInt64));
TimestampP = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength + rdtscLength,
typeof(FuncUInt64));
buf = IntPtr.Zero;
}
}
}
finally
{
if (buf != IntPtr.Zero)
VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
}
}
private static bool Is64Bit()
{
return Marshal.SizeOf(typeof(IntPtr)) == 8;
}
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
private static ulong StopwatchGetTimestamp()
{
return unchecked((ulong) Stopwatch.GetTimestamp());
}
[StructLayout(LayoutKind.Sequential)]
private struct SystemInfo
{
public readonly ushort wProcessorArchitecture;
public readonly ushort wReserved;
public readonly uint dwPageSize;
public readonly IntPtr lpMinimumApplicationAddress;
public readonly IntPtr lpMaximumApplicationAddress;
public readonly IntPtr dwActiveProcessorMask;
public readonly uint dwNumberOfProcessors;
public readonly uint dwProcessorType;
public readonly uint dwAllocationGranularity;
public readonly ushort wProcessorLevel;
public readonly ushort wProcessorRevision;
}
}
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security; public static class Rdtsc { [SuppressUnmanagedCodeSecurity] [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate ulong FuncUInt64(); private const uint PAGE_READWRITE = 0x04; private const uint PAGE_EXECUTE = 0x10; private const uint PAGE_EXECUTE_READWRITE = 0x40; private const uint MEM_COMMIT = 0x1000; private const uint MEM_RELEASE = 0x8000; public static readonly FuncUInt64 Timestamp; public static readonly FuncUInt64 TimestampP; public static readonly bool IsRdtscSupported; public static readonly bool IsRdtscPSupported; static Rdtsc() { SystemInfo systemInfo; GetNativeSystemInfo(out systemInfo); if (systemInfo.wProcessorArchitecture != 0 && systemInfo.wProcessorArchitecture != 9) { Timestamp = StopwatchGetTimestamp; TimestampP = StopwatchGetTimestamp; IsRdtscSupported = false; IsRdtscPSupported = false; return; } byte[] cpuid; byte[] rdtsc; byte[] rdtscp; byte[] rdtsccpuid; IsRdtscSupported = true; if (Is64Bit()) { cpuid = new byte[] { 0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x16, 0x89, 0xD8, 0x48, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xA2, 0x89, 0xC8, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x09, 0xD0, 0xEB, 0x03, 0x48, 0x31, 0xC0, 0x5B, 0xC3 }; rdtsc = new byte[] {0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3}; rdtscp = new byte[] {0x0F, 0x01, 0xF9, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3}; rdtsccpuid = new byte[] {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x5B, 0xC3}; } else { cpuid = new byte[] { 0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x0A, 0x89, 0xD8, 0x0F, 0xA2, 0x89, 0xD0, 0x89, 0xCA, 0xEB, 0x04, 0x31, 0xC0, 0x31, 0xD2, 0x5B, 0xC3 }; rdtsc = new byte[] {0x0F, 0x31, 0xC3}; rdtscp = new byte[] {0x0F, 0x01, 0xF9, 0xC3}; rdtsccpuid = new byte[] {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x5B, 0xC3}; } var buf = IntPtr.Zero; try { var cpuidLength = (cpuid.Length & 63) != 0 ? (cpuid.Length | 63) + 1 : cpuid.Length; var rdtscLength = (rdtsc.Length & 63) != 0 ? (rdtsc.Length | 63) + 1 : rdtsc.Length; var rdtscpLength = (rdtscp.Length & 63) != 0 ? (rdtscp.Length | 63) + 1 : rdtscp.Length; var rdtsccpuidLength = (rdtsccpuid.Length & 63) != 0 ? (rdtsccpuid.Length | 63) + 1 : rdtsccpuid.Length; var totalLength = cpuidLength + rdtscLength + Math.Max(rdtscpLength, rdtsccpuidLength); buf = VirtualAlloc(IntPtr.Zero, (IntPtr) totalLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (buf != IntPtr.Zero) { Marshal.Copy(cpuid, 0, buf, cpuid.Length); for (var i = cpuid.Length; i < cpuidLength; i++) Marshal.WriteByte(buf, i, 0x90); Marshal.Copy(rdtsc, 0, buf + cpuidLength, rdtsc.Length); for (var i = rdtsc.Length; i < rdtscLength; i++) Marshal.WriteByte(buf, cpuidLength + i, 0x90); var cpuidFunc = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf, typeof(FuncUInt64)); var supportedFeatures = cpuidFunc(); byte[] rdtscpSelected; int rdtscpSelectedLength; if ((supportedFeatures & (1L << 27)) != 0) { rdtscpSelected = rdtscp; rdtscpSelectedLength = rdtscpLength; IsRdtscPSupported = true; } else { rdtscpSelected = rdtsccpuid; rdtscpSelectedLength = rdtsccpuidLength; IsRdtscPSupported = false; } Marshal.Copy(rdtscpSelected, 0, buf + cpuidLength + rdtscLength, rdtscpSelected.Length); for (var i = rdtscpSelected.Length; i < rdtscpSelectedLength; i++) Marshal.WriteByte(buf, cpuidLength + rdtscLength + i, 0x90); var result = VirtualProtect(buf, (IntPtr) totalLength, PAGE_EXECUTE, out var oldProtection); if (result) { Timestamp = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength, typeof(FuncUInt64)); TimestampP = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength + rdtscLength, typeof(FuncUInt64)); buf = IntPtr.Zero; } } } finally { if (buf != IntPtr.Zero) VirtualFree(buf, IntPtr.Zero, MEM_RELEASE); } } private static bool Is64Bit() { return Marshal.SizeOf(typeof(IntPtr)) == 8; } [DllImport("kernel32.dll", ExactSpelling = true)] private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo); [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect); [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType); private static ulong StopwatchGetTimestamp() { return unchecked((ulong) Stopwatch.GetTimestamp()); } [StructLayout(LayoutKind.Sequential)] private struct SystemInfo { public readonly ushort wProcessorArchitecture; public readonly ushort wReserved; public readonly uint dwPageSize; public readonly IntPtr lpMinimumApplicationAddress; public readonly IntPtr lpMaximumApplicationAddress; public readonly IntPtr dwActiveProcessorMask; public readonly uint dwNumberOfProcessors; public readonly uint dwProcessorType; public readonly uint dwAllocationGranularity; public readonly ushort wProcessorLevel; public readonly ushort wProcessorRevision; } }
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
public static class Rdtsc
{
    [SuppressUnmanagedCodeSecurity]
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate ulong FuncUInt64();
    private const          uint       PAGE_READWRITE         = 0x04;
    private const          uint       PAGE_EXECUTE           = 0x10;
    private const          uint       PAGE_EXECUTE_READWRITE = 0x40;
    private const          uint       MEM_COMMIT             = 0x1000;
    private const          uint       MEM_RELEASE            = 0x8000;
    public static readonly FuncUInt64 Timestamp;
    public static readonly FuncUInt64 TimestampP;
    public static readonly bool       IsRdtscSupported;
    public static readonly bool       IsRdtscPSupported;
    static Rdtsc()
    {
        SystemInfo systemInfo;
        GetNativeSystemInfo(out systemInfo);
        if (systemInfo.wProcessorArchitecture != 0 && systemInfo.wProcessorArchitecture != 9)
        {
            Timestamp         = StopwatchGetTimestamp;
            TimestampP        = StopwatchGetTimestamp;
            IsRdtscSupported  = false;
            IsRdtscPSupported = false;
            return;
        }
        byte[] cpuid;
        byte[] rdtsc;
        byte[] rdtscp;
        byte[] rdtsccpuid;
        IsRdtscSupported = true;
        if (Is64Bit())
        {
            cpuid = new byte[]
            {
                0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x16, 0x89, 0xD8,
                0x48, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xA2, 0x89, 0xC8, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x09, 0xD0, 0xEB,
                0x03, 0x48, 0x31, 0xC0, 0x5B, 0xC3
            };
            rdtsc  = new byte[] {0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3};
            rdtscp = new byte[] {0x0F, 0x01, 0xF9, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3};
            rdtsccpuid = new byte[]
                {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x5B, 0xC3};
        }
        else
        {
            cpuid = new byte[]
            {
                0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x0A, 0x89, 0xD8,
                0x0F, 0xA2, 0x89, 0xD0, 0x89, 0xCA, 0xEB, 0x04, 0x31, 0xC0, 0x31, 0xD2, 0x5B, 0xC3
            };
            rdtsc      = new byte[] {0x0F, 0x31, 0xC3};
            rdtscp     = new byte[] {0x0F, 0x01, 0xF9, 0xC3};
            rdtsccpuid = new byte[] {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x5B, 0xC3};
        }
        var buf = IntPtr.Zero;
        try
        {
            var cpuidLength      = (cpuid.Length      & 63) != 0 ? (cpuid.Length      | 63) + 1 : cpuid.Length;
            var rdtscLength      = (rdtsc.Length      & 63) != 0 ? (rdtsc.Length      | 63) + 1 : rdtsc.Length;
            var rdtscpLength     = (rdtscp.Length     & 63) != 0 ? (rdtscp.Length     | 63) + 1 : rdtscp.Length;
            var rdtsccpuidLength = (rdtsccpuid.Length & 63) != 0 ? (rdtsccpuid.Length | 63) + 1 : rdtsccpuid.Length;
            var totalLength      = cpuidLength + rdtscLength + Math.Max(rdtscpLength, rdtsccpuidLength);
            buf = VirtualAlloc(IntPtr.Zero, (IntPtr) totalLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            if (buf != IntPtr.Zero)
            {
                Marshal.Copy(cpuid, 0, buf, cpuid.Length);
                for (var i = cpuid.Length; i < cpuidLength; i++)
                    Marshal.WriteByte(buf, i, 0x90);
                Marshal.Copy(rdtsc, 0, buf + cpuidLength, rdtsc.Length);
                for (var i = rdtsc.Length; i < rdtscLength; i++)
                    Marshal.WriteByte(buf, cpuidLength + i, 0x90);
                var    cpuidFunc         = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf, typeof(FuncUInt64));
                var    supportedFeatures = cpuidFunc();
                byte[] rdtscpSelected;
                int    rdtscpSelectedLength;
                if ((supportedFeatures & (1L << 27)) != 0)
                {
                    rdtscpSelected       = rdtscp;
                    rdtscpSelectedLength = rdtscpLength;
                    IsRdtscPSupported    = true;
                }
                else
                {
                    rdtscpSelected       = rdtsccpuid;
                    rdtscpSelectedLength = rdtsccpuidLength;
                    IsRdtscPSupported    = false;
                }
                Marshal.Copy(rdtscpSelected, 0, buf + cpuidLength + rdtscLength, rdtscpSelected.Length);
                for (var i = rdtscpSelected.Length; i < rdtscpSelectedLength; i++)
                    Marshal.WriteByte(buf, cpuidLength + rdtscLength + i, 0x90);
                var result = VirtualProtect(buf, (IntPtr) totalLength, PAGE_EXECUTE, out var oldProtection);
                if (result)
                {
                    Timestamp = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength, typeof(FuncUInt64));
                    TimestampP = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength + rdtscLength,
                        typeof(FuncUInt64));
                    buf = IntPtr.Zero;
                }
            }
        }
        finally
        {
            if (buf != IntPtr.Zero)
                VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
        }
    }
    private static bool Is64Bit()
    {
        return Marshal.SizeOf(typeof(IntPtr)) == 8;
    }
    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
    private static ulong StopwatchGetTimestamp()
    {
        return unchecked((ulong) Stopwatch.GetTimestamp());
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct SystemInfo
    {
        public readonly ushort wProcessorArchitecture;
        public readonly ushort wReserved;
        public readonly uint   dwPageSize;
        public readonly IntPtr lpMinimumApplicationAddress;
        public readonly IntPtr lpMaximumApplicationAddress;
        public readonly IntPtr dwActiveProcessorMask;
        public readonly uint   dwNumberOfProcessors;
        public readonly uint   dwProcessorType;
        public readonly uint   dwAllocationGranularity;
        public readonly ushort wProcessorLevel;
        public readonly ushort wProcessorRevision;
    }
}

ChiSquared.cs

Chi Squared Data/Byte/Text Test

Updated: Jan-19,2021

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
public static class ChiSquared
{
/// <summary>
/// Calculated from an English word dictionary containing over 466,000 words.
/// </summary>
private static readonly float[] _expectedPercentages = {.0846f, .0189f, .0420f, .0353f, .1098f, .0125f, .0243f, .0274f, .0864f, .0018f, .0089f, .0574f, .0292f, .0715f, .0709f, .0310f, .0019f, .0704f, .0705f, .0647f, .0363f, .0099f, .0085f, .0028f, .0192f, .0041f};
/// <summary>
/// Not accurate 100% all of the time.
/// </summary>
/// <param name="path"></param>
public static bool IsFileCompressed(this string path)
{
var arr = File.ReadAllBytes(path);
var r1 = arr.ChiSquaredTest();
return r1.isRandom;
}
/// <summary>
/// Tests a buffer for randomness. Returns chi squared values.
/// isRandom - is the buffer a random sequence.
/// Quality - Less than 1 or greater than 1 is off target. Observed is off expected.
/// Entropy - Calculates a 8 bit Entropy level of the buffer as a percentage of perfect disorder 100%
/// ExpectedChiSq - The expected chi squared value.
/// LowLimit - (R - (2*sqrt(R)))
/// chiSqValue - The observed chi squared value.
/// UpperLimit - (R + (2*sqrt(R)))
/// </summary>
/// <param name="bArr">The byte Array</param>
public static (bool isRandom, float Quality, float Entropy, int ExpectedChiSq, float LowLimit, float chiSqValue, float UpperLimit) ChiSquaredTest(this byte[] bArr)
{
if (bArr != null)
{
var iArr = Ia(bArr);
var ent = Entropy(bArr);
if (ent < 80)
return (false, 0, ent, 0, 0, 0, 0);
var aLen = iArr.Length;
var rLim = aLen / 10;
var n = aLen;
var r = rLim - 1;
var freq = new ConcurrentDictionary<int, int>();
iArr.AsParallel().WithDegreeOfParallelism(2).ForAll(I =>
{
var iT = Math.Abs(Math.Abs(I) % rLim - rLim);
if (!freq.ContainsKey(iT))
freq.TryAdd(iT, 1);
else
freq[iT] += 1;
});
var t = freq.Sum(e => (float) Math.Pow(e.Value, 2));
var cS = Math.Abs(r * t / n - n);
var fL = r - 2.0f * (float) Math.Sqrt(r);
var fH = r + 2.0f * (float) Math.Sqrt(r);
var iR = (fL < cS) & (fH > cS);
var q = cS / r;
var nfL = 0;
var nfH = fH - fL;
var ncS = cS - fL;
return (iR, q, ent, (int)(r-fL), (int)nfL, (int)ncS, (int)nfH);
}
return default;
}
private static int[] Ia(byte[] ba)
{
var bal = ba.Length;
var dWordCount = bal / 4 + (bal % 4 == 0 ? 0 : 1);
var arr = new int[dWordCount];
Buffer.BlockCopy(ba, 0, arr, 0, bal);
return arr;
}
private static float Entropy(byte[] s)
{
float len = s.Length;
var map = new int[256];
for (var i = 0; i < (int) len; i++)
map[s[i]]++;
var result = 0f;
for (var idx = 0; idx < map.Length; idx++)
{
var frequency = map[idx] / len;
if (frequency > 0)
result -= frequency * (float) Math.Log(frequency, 2);
}
return result / 8f * 100f;
}
public static int ChiSquaredCount(this byte[] s, byte b)
{
float len = s.Length;
var map = new int[256];
for (var i = 0; i < (int) len; i++)
map[s[i]]++;
return map[b];
}
public static int ChiSquaredCount(this string s, char b)
{
float len = s.Length;
var map = new int[256];
for (var i = 0; i < (int) len; i++)
map[s[i]]++;
return map[b];
}
public static float ChiSquaredAsPercent(this string s, char b)
{
float len = s.Length;
var map = new int[256];
for (var i = 0; i < (int) len; i++)
map[s[i]]++;
return map[b] / len;
}
/// <summary>
/// Compute the letter frequencies within the English language.
/// Use a large English language text block for accurate testing.
/// </summary>
/// <param name="s">String that contains the large English text</param>
public static KeyValuePair<char, float>[] ChiSquaredTextAsPercent(this string s)
{
float len = s.Length;
s = s.ToLower(CultureInfo.CurrentCulture);
var lst = new Dictionary<char, float>();
var map = new int[256];
for (var i = 0; i < (int) len; i++)
if (s[i].IsLetter())
map[s[i]]++;
var t = map.Sum(e => e);
foreach (var l in "abcdefghijklmnopqrstuvwxyz")
lst.Add(l, map[l] / (float) t);
var klst = lst.OrderBy(e => e.Key).ToArray();
var KeyList = "";
var ValueList = "";
foreach (var kv in klst)
{
KeyList += $"{kv.Key},";
ValueList += $"{kv.Value:.0000},";
}
var nlst = lst.OrderBy(e => e.Value).ToArray();
return nlst;
}
public static float ChiSquaredTextTest(this string s)
{
var realLen = 0;
s = s.ToLower(CultureInfo.CurrentCulture);
var observed = new Dictionary<char, int>();
foreach (var c in s)
if (c.IsLetter())
{
if (!observed.ContainsKey(c))
observed.Add(c, 1);
else
observed[c]++;
realLen++;
}
var expected = new Dictionary<char, float>();
for (var i = 0; i < 26; i++)
expected.Add((char) (i + 97), _expectedPercentages[i] * realLen);
var cSList = new List<float>();
foreach (var item in expected)
{
var c = item.Key;
if (observed.ContainsKey(c))
cSList.Add((float) Math.Pow(observed[c] - expected[c], 2) / expected[c]);
}
return cSList.Sum(e => e) / realLen * 100f;
}
/// <summary>
/// The value of 10 as a combined chi-squared total distance
/// percentage threshold is subjective. Determined from
/// about 40 test runs of over 1 million mixed files. Most
/// non-text files have readings in the 100's
/// </summary>
/// <param name="path">Path to the file to test</param>
public static bool IsTextFile(this string path)
{
return File.ReadAllText(path).ChiSquaredTextTest() < 10;
}
}
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; public static class ChiSquared { /// <summary> /// Calculated from an English word dictionary containing over 466,000 words. /// </summary> private static readonly float[] _expectedPercentages = {.0846f, .0189f, .0420f, .0353f, .1098f, .0125f, .0243f, .0274f, .0864f, .0018f, .0089f, .0574f, .0292f, .0715f, .0709f, .0310f, .0019f, .0704f, .0705f, .0647f, .0363f, .0099f, .0085f, .0028f, .0192f, .0041f}; /// <summary> /// Not accurate 100% all of the time. /// </summary> /// <param name="path"></param> public static bool IsFileCompressed(this string path) { var arr = File.ReadAllBytes(path); var r1 = arr.ChiSquaredTest(); return r1.isRandom; } /// <summary> /// Tests a buffer for randomness. Returns chi squared values. /// isRandom - is the buffer a random sequence. /// Quality - Less than 1 or greater than 1 is off target. Observed is off expected. /// Entropy - Calculates a 8 bit Entropy level of the buffer as a percentage of perfect disorder 100% /// ExpectedChiSq - The expected chi squared value. /// LowLimit - (R - (2*sqrt(R))) /// chiSqValue - The observed chi squared value. /// UpperLimit - (R + (2*sqrt(R))) /// </summary> /// <param name="bArr">The byte Array</param> public static (bool isRandom, float Quality, float Entropy, int ExpectedChiSq, float LowLimit, float chiSqValue, float UpperLimit) ChiSquaredTest(this byte[] bArr) { if (bArr != null) { var iArr = Ia(bArr); var ent = Entropy(bArr); if (ent < 80) return (false, 0, ent, 0, 0, 0, 0); var aLen = iArr.Length; var rLim = aLen / 10; var n = aLen; var r = rLim - 1; var freq = new ConcurrentDictionary<int, int>(); iArr.AsParallel().WithDegreeOfParallelism(2).ForAll(I => { var iT = Math.Abs(Math.Abs(I) % rLim - rLim); if (!freq.ContainsKey(iT)) freq.TryAdd(iT, 1); else freq[iT] += 1; }); var t = freq.Sum(e => (float) Math.Pow(e.Value, 2)); var cS = Math.Abs(r * t / n - n); var fL = r - 2.0f * (float) Math.Sqrt(r); var fH = r + 2.0f * (float) Math.Sqrt(r); var iR = (fL < cS) & (fH > cS); var q = cS / r; var nfL = 0; var nfH = fH - fL; var ncS = cS - fL; return (iR, q, ent, (int)(r-fL), (int)nfL, (int)ncS, (int)nfH); } return default; } private static int[] Ia(byte[] ba) { var bal = ba.Length; var dWordCount = bal / 4 + (bal % 4 == 0 ? 0 : 1); var arr = new int[dWordCount]; Buffer.BlockCopy(ba, 0, arr, 0, bal); return arr; } private static float Entropy(byte[] s) { float len = s.Length; var map = new int[256]; for (var i = 0; i < (int) len; i++) map[s[i]]++; var result = 0f; for (var idx = 0; idx < map.Length; idx++) { var frequency = map[idx] / len; if (frequency > 0) result -= frequency * (float) Math.Log(frequency, 2); } return result / 8f * 100f; } public static int ChiSquaredCount(this byte[] s, byte b) { float len = s.Length; var map = new int[256]; for (var i = 0; i < (int) len; i++) map[s[i]]++; return map[b]; } public static int ChiSquaredCount(this string s, char b) { float len = s.Length; var map = new int[256]; for (var i = 0; i < (int) len; i++) map[s[i]]++; return map[b]; } public static float ChiSquaredAsPercent(this string s, char b) { float len = s.Length; var map = new int[256]; for (var i = 0; i < (int) len; i++) map[s[i]]++; return map[b] / len; } /// <summary> /// Compute the letter frequencies within the English language. /// Use a large English language text block for accurate testing. /// </summary> /// <param name="s">String that contains the large English text</param> public static KeyValuePair<char, float>[] ChiSquaredTextAsPercent(this string s) { float len = s.Length; s = s.ToLower(CultureInfo.CurrentCulture); var lst = new Dictionary<char, float>(); var map = new int[256]; for (var i = 0; i < (int) len; i++) if (s[i].IsLetter()) map[s[i]]++; var t = map.Sum(e => e); foreach (var l in "abcdefghijklmnopqrstuvwxyz") lst.Add(l, map[l] / (float) t); var klst = lst.OrderBy(e => e.Key).ToArray(); var KeyList = ""; var ValueList = ""; foreach (var kv in klst) { KeyList += $"{kv.Key},"; ValueList += $"{kv.Value:.0000},"; } var nlst = lst.OrderBy(e => e.Value).ToArray(); return nlst; } public static float ChiSquaredTextTest(this string s) { var realLen = 0; s = s.ToLower(CultureInfo.CurrentCulture); var observed = new Dictionary<char, int>(); foreach (var c in s) if (c.IsLetter()) { if (!observed.ContainsKey(c)) observed.Add(c, 1); else observed[c]++; realLen++; } var expected = new Dictionary<char, float>(); for (var i = 0; i < 26; i++) expected.Add((char) (i + 97), _expectedPercentages[i] * realLen); var cSList = new List<float>(); foreach (var item in expected) { var c = item.Key; if (observed.ContainsKey(c)) cSList.Add((float) Math.Pow(observed[c] - expected[c], 2) / expected[c]); } return cSList.Sum(e => e) / realLen * 100f; } /// <summary> /// The value of 10 as a combined chi-squared total distance /// percentage threshold is subjective. Determined from /// about 40 test runs of over 1 million mixed files. Most /// non-text files have readings in the 100's /// </summary> /// <param name="path">Path to the file to test</param> public static bool IsTextFile(this string path) { return File.ReadAllText(path).ChiSquaredTextTest() < 10; } }
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
public static class ChiSquared
{
    /// <summary>
    ///     Calculated from an English word dictionary containing over 466,000 words.
    /// </summary>
    private static readonly float[] _expectedPercentages = {.0846f, .0189f, .0420f, .0353f, .1098f, .0125f, .0243f, .0274f, .0864f, .0018f, .0089f, .0574f, .0292f, .0715f, .0709f, .0310f, .0019f, .0704f, .0705f, .0647f, .0363f, .0099f, .0085f, .0028f, .0192f, .0041f};
    /// <summary>
    ///     Not accurate 100% all of the time.
    /// </summary>
    /// <param name="path"></param>
    public static bool IsFileCompressed(this string path)
    {
        var arr = File.ReadAllBytes(path);
        var r1  = arr.ChiSquaredTest();
        return r1.isRandom;
    }
    /// <summary>
    ///     Tests a buffer for randomness. Returns chi squared values.
    ///     isRandom - is the buffer a random sequence.
    ///     Quality - Less than 1 or greater than 1 is off target. Observed is off expected.
    ///     Entropy - Calculates a 8 bit Entropy level of the buffer as a percentage of perfect disorder 100%
    ///     ExpectedChiSq - The expected chi squared value.
    ///     LowLimit - (R - (2*sqrt(R)))
    ///     chiSqValue - The observed chi squared value.
    ///     UpperLimit - (R + (2*sqrt(R)))
    /// </summary>
    /// <param name="bArr">The byte Array</param>
    public static (bool isRandom, float Quality, float Entropy, int ExpectedChiSq, float LowLimit, float chiSqValue, float UpperLimit) ChiSquaredTest(this byte[] bArr)
    {
        if (bArr != null)
        {
            var iArr = Ia(bArr);
            var ent  = Entropy(bArr);
            if (ent < 80)
                return (false, 0, ent, 0, 0, 0, 0);
            var aLen = iArr.Length;
            var rLim = aLen / 10;
            var n    = aLen;
            var r    = rLim - 1;
            var freq = new ConcurrentDictionary<int, int>();
            iArr.AsParallel().WithDegreeOfParallelism(2).ForAll(I =>
            {
                var iT = Math.Abs(Math.Abs(I) % rLim - rLim);
                if (!freq.ContainsKey(iT))
                    freq.TryAdd(iT, 1);
                else
                    freq[iT] += 1;
            });
            var t  = freq.Sum(e => (float) Math.Pow(e.Value, 2));
            var cS = Math.Abs(r * t / n - n);
            var fL = r - 2.0f * (float) Math.Sqrt(r);
            var fH = r + 2.0f * (float) Math.Sqrt(r);
            var iR = (fL < cS) & (fH > cS);
            var q  = cS / r;
            var nfL = 0;
            var nfH = fH - fL;
            var ncS = cS - fL;
            return (iR, q, ent, (int)(r-fL), (int)nfL, (int)ncS, (int)nfH);
        }
        return default;
    }
    private static int[] Ia(byte[] ba)
    {
        var bal        = ba.Length;
        var dWordCount = bal / 4 + (bal % 4 == 0 ? 0 : 1);
        var arr        = new int[dWordCount];
        Buffer.BlockCopy(ba, 0, arr, 0, bal);
        return arr;
    }
    private static float Entropy(byte[] s)
    {
        float len = s.Length;
        var   map = new int[256];
        for (var i = 0; i < (int) len; i++)
            map[s[i]]++;
        var result = 0f;
        for (var idx = 0; idx < map.Length; idx++)
        {
            var frequency = map[idx] / len;
            if (frequency > 0)
                result -= frequency * (float) Math.Log(frequency, 2);
        }
        return result / 8f * 100f;
    }
    public static int ChiSquaredCount(this byte[] s, byte b)
    {
        float len = s.Length;
        var   map = new int[256];
        for (var i = 0; i < (int) len; i++)
            map[s[i]]++;
        return map[b];
    }
    public static int ChiSquaredCount(this string s, char b)
    {
        float len = s.Length;
        var   map = new int[256];
        for (var i = 0; i < (int) len; i++)
            map[s[i]]++;
        return map[b];
    }
    public static float ChiSquaredAsPercent(this string s, char b)
    {
        float len = s.Length;
        var   map = new int[256];
        for (var i = 0; i < (int) len; i++)
            map[s[i]]++;
        return map[b] / len;
    }
    /// <summary>
    ///     Compute the letter frequencies within the English language.
    ///     Use a large English language text block for accurate testing.
    /// </summary>
    /// <param name="s">String that contains the large English text</param>
    public static KeyValuePair<char, float>[] ChiSquaredTextAsPercent(this string s)
    {
        float len = s.Length;
        s = s.ToLower(CultureInfo.CurrentCulture);
        var lst = new Dictionary<char, float>();
        var map = new int[256];
        for (var i = 0; i < (int) len; i++)
            if (s[i].IsLetter())
                map[s[i]]++;
        var t = map.Sum(e => e);
        foreach (var l in "abcdefghijklmnopqrstuvwxyz")
            lst.Add(l, map[l] / (float) t);
        var klst      = lst.OrderBy(e => e.Key).ToArray();
        var KeyList   = "";
        var ValueList = "";
        foreach (var kv in klst)
        {
            KeyList   += $"{kv.Key},";
            ValueList += $"{kv.Value:.0000},";
        }
        var nlst = lst.OrderBy(e => e.Value).ToArray();
        return nlst;
    }
    public static float ChiSquaredTextTest(this string s)
    {
        var realLen = 0;
        s = s.ToLower(CultureInfo.CurrentCulture);
        var observed = new Dictionary<char, int>();
        foreach (var c in s)
            if (c.IsLetter())
            {
                if (!observed.ContainsKey(c))
                    observed.Add(c, 1);
                else
                    observed[c]++;
                realLen++;
            }
        var expected = new Dictionary<char, float>();
        for (var i = 0; i < 26; i++)
            expected.Add((char) (i + 97), _expectedPercentages[i] * realLen);
        var cSList = new List<float>();
        foreach (var item in expected)
        {
            var c = item.Key;
            if (observed.ContainsKey(c))
                cSList.Add((float) Math.Pow(observed[c] - expected[c], 2) / expected[c]);
        }
        return cSList.Sum(e => e) / realLen * 100f;
    }
    /// <summary>
    ///     The value of 10 as a combined chi-squared total distance
    ///     percentage threshold is subjective. Determined from
    ///     about 40 test runs of over 1 million mixed files. Most
    ///     non-text files have readings in the 100's
    /// </summary>
    /// <param name="path">Path to the file to test</param>
    public static bool IsTextFile(this string path)
    {
        return File.ReadAllText(path).ChiSquaredTextTest() < 10;
    }
    
}

(Obsolete) FixedBigInteger.cs

Adjustable Fixed Bit Width Signed Integer 32,64,128,256,…

Jun-11,2021: Obsolete Use xIntX Instead.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(FixedBigIntegerConverter))]
[DebuggerDisplay("{DDisplay}")]
public class FixedBigInteger : IComparable<FixedBigInteger>, IComparable, IEquatable<FixedBigInteger>, IConvertible, IFormattable, ISerializable
{
private const int DefaultDataBitWidth = 2048;
private const int DataSize = sizeof(uint);
private const int DataShiftCount = 5;
private const uint AllBits = ~(uint) 0;
private const int DataSizeBits = sizeof(uint) * 8;
private const uint HiNeg = (uint) 1 << (DataSizeBits - 1);
private static int DataBitWidth;
private static int DataLength;
public static readonly FixedBigInteger One = new FixedBigInteger(1, DataBitWidth);
public static readonly FixedBigInteger Two = new FixedBigInteger(2, DataBitWidth);
public static readonly FixedBigInteger Zero = new FixedBigInteger(0, DataBitWidth);
public static readonly FixedBigInteger Ten = new FixedBigInteger(10, DataBitWidth);
public static readonly FixedBigInteger Three = new FixedBigInteger(3, DataBitWidth);
private readonly SerializationInfo SInfo;
public uint[] Data;
public FixedBigInteger(FixedBigInteger value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
CalculateMinDataLength(value.Data.Length);
Data = new uint[DataLength];
value.Data.CopyTo(Data, 0);
}
public FixedBigInteger(string value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
if (!TryParse(value, out var result))
throw new Exception("TryParse Failed.");
CalculateMinDataLength(result.Data.Length);
Data = new uint[DataLength];
result.Data.CopyTo(Data, 0);
}
public FixedBigInteger(byte value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[0] = value;
}
public FixedBigInteger(bool value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[0] = (uint) (value ? 1 : 0);
}
public FixedBigInteger(char value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[0] = value;
}
public FixedBigInteger(BigDecimal value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
var ba = value.WholePart.ToByteArray();
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
var len = ba.Length / DataSize;
CalculateMinDataLength(len);
Data = new uint[DataLength];
for (var i = 0; i < Data.Length; i++)
Data[i] = BitConverter.ToUInt32(ba, i * DataSize);
}
public FixedBigInteger(decimal value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
CalculateMinDataLength(3);
Data = new uint[DataLength];
if (value < 0)
{
var n = -new FixedBigInteger(-value, DataBitWidth);
n.Data.CopyTo(Data, 0);
return;
}
var bits = decimal.GetBits(value);
Data[2] = (uint) bits[2];
Data[1] = (uint) bits[1];
Data[0] = (uint) bits[0];
}
public FixedBigInteger(double value, int bitLength = 0) : this((decimal) value, bitLength)
{
}
public FixedBigInteger(float value, int bitLength = 0) : this((decimal) value, bitLength)
{
}
public FixedBigInteger(short value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
if (value < 0)
{
var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
n.Data.CopyTo(Data, 0);
return;
}
Data[0] = (uint) value;
}
public FixedBigInteger()
{
DataBitWidth = DefaultDataBitWidth;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[0] = 0;
}
public FixedBigInteger(int value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
if (value < 0)
{
var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
n.Data.CopyTo(Data, 0);
return;
}
Data[0] = (uint) value;
}
public FixedBigInteger(long value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 64)
bitLength = 64;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
if (value < 0)
{
var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
n.Data.CopyTo(Data, 0);
return;
}
Data[1] = (uint) ((value >> 32) & 0xffffffff);
Data[0] = (uint) (value & 0xffffffff);
}
public FixedBigInteger(sbyte value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
if (value < 0)
{
var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
n.Data.CopyTo(Data, 0);
return;
}
Data[0] = (uint) value;
}
public FixedBigInteger(ushort value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[0] = value;
}
public FixedBigInteger(uint value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 32)
bitLength = 32;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[0] = value;
}
public FixedBigInteger(ulong value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
if (bitLength < 96)
bitLength = 96;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
Data = new uint[DataLength];
Data[1] = (uint) ((value >> 32) & 0xffffffff);
Data[0] = (uint) (value & 0xffffffff);
}
public FixedBigInteger(BigInteger value, int bitLength = 0) : this(value.ToByteArray(), bitLength)
{
}
public FixedBigInteger(Guid value, int bitLength = 0) : this(value.ToByteArray(), bitLength)
{
}
public FixedBigInteger(byte[] value, int bitLength = 0)
{
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
var minSize = value.Length / DataSize;
if (value == null)
throw new ArgumentNullException("value");
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
CalculateMinDataLength(minSize);
var byteCount = value.Length;
var isNegative = byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80;
var unalignedBytes = byteCount % DataSize;
var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1);
Data = new uint[Math.Max(dwordCount, DataLength)];
if (byteCount == 0)
return;
int curDword, curByte, byteInDword;
curByte = 3;
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
{
byteInDword = 0;
while (byteInDword < DataSize)
{
Data[curDword] <<= 8;
Data[curDword] |= value[curByte];
curByte--;
byteInDword++;
}
curByte += 8;
}
if (unalignedBytes != 0)
{
if (isNegative)
Data[dwordCount - 1] = 0xffffffff;
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
{
Data[curDword] <<= 8;
Data[curDword] |= value[curByte];
}
}
}
public FixedBigInteger(int sign, uint[] array, int bitLength = 0)
{
if (array == null)
throw new Exception("Array cannot be null.");
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
CalculateMinDataLength(array.Length);
if (array.Length != DataLength)
Array.Resize(ref array, DataLength);
Data = new uint[DataLength];
var ba = new byte[DataSize];
for (var i = 0; i < Data.Length; i++)
{
Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
Data[i] = BitConverter.ToUInt32(ba, 0);
}
if (sign < 0)
Data[DataLength - 1] |= HiNeg;
else
Data[DataLength - 1] &= ~HiNeg;
}
public FixedBigInteger(uint[] array, int bitLength = 0)
{
if (array == null)
throw new Exception("Array cannot be null.");
if (bitLength == 0)
bitLength = DefaultDataBitWidth;
DataBitWidth = bitLength;
DataLength = DataBitWidth >> DataShiftCount;
if (array.Length != DataLength)
Array.Resize(ref array, DataLength);
Data = new uint[DataLength];
var ba = new byte[DataSize];
for (var i = 0; i < Data.Length; i++)
{
Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
Data[i] = BitConverter.ToUInt32(ba, 0);
}
}
protected FixedBigInteger(SerializationInfo info, StreamingContext context)
{
SInfo = info;
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DDisplay => ToString();
public FixedBigInteger MaxValue
{
get
{
var r = new FixedBigInteger(0, DataBitWidth);
for (var i = 0; i < r.Data.Length; ++i)
r.Data[i] = uint.MaxValue;
r.Data[r.Data.Length - 1] = int.MaxValue;
return r;
}
}
public int BitWidth
{
get
{
FixedBigInteger bw = 1;
var v = new FixedBigInteger(this);
while ((v >>= 1) > 0)
bw++;
if (bw < 8)
bw = 8;
while (bw % 8 != 0)
bw++;
return (int) bw;
}
}
public int Sign
{
get
{
var allZero = true;
var ba = Data;
for (var i = 0; i < ba.Length; i++)
if (ba[i] != 0)
{
allZero = false;
break;
}
if (allZero)
return 0;
return (Data[Data.Length - 1] & HiNeg) == 0 ? 1 : -1;
}
}
public bool IsOne => this == 1;
public bool IsEven => (this & 1) == 0;
public bool IsNegative => Sign < 0;
public bool IsZero
{
get
{
for (var i = 0; i < Data.Length; i++)
if (Data[i] != 0)
return false;
return true;
}
}
public int DataUsed
{
get
{
var DataUsed = Data.Length;
if (!IsNegative)
{
while (DataUsed > 1 && Data[DataUsed - 1] == 0)
--DataUsed;
if (DataUsed == 0)
DataUsed = 1;
}
return DataUsed;
}
}
int IComparable.CompareTo(object obj)
{
return Compare(this, obj);
}
public int CompareTo(FixedBigInteger value)
{
return Compare(this, value);
}
TypeCode IConvertible.GetTypeCode()
{
return TypeCode.Object;
}
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return (bool) this;
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return (byte) this;
}
char IConvertible.ToChar(IFormatProvider provider)
{
return (char) this;
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
throw new InvalidCastException();
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return (decimal) this;
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return (double) this;
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return (short) this;
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return (int) this;
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return (long) this;
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return (sbyte) this;
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return (float) this;
}
string IConvertible.ToString(IFormatProvider provider)
{
return ToString(null, provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
object value;
if (TryConvert(conversionType, provider, out value))
return value;
throw new InvalidCastException();
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
if (Data[1] != 0)
throw new OverflowException();
return Convert.ToUInt16(Data[0]);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
if (Data[1] != 0)
throw new OverflowException();
return Convert.ToUInt32(Data[0]);
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
if (Data[1] != 0)
return ((ulong) Data[1] << 32) | Data[0];
return Data[0];
}
public bool Equals(FixedBigInteger obj)
{
if (ReferenceEquals(obj, null))
return false;
if (ReferenceEquals(this, obj))
return true;
if (Data.Length != obj.Data.Length)
{
var len = Math.Max(Data.Length, obj.Data.Length);
if (Data.Length < len)
{
var tData = new uint[len];
Array.Copy(Data, 0, tData, 0, Data.Length);
Data = tData;
}
if (obj.Data.Length < len)
Resize(ref obj, len);
}
if (Sign != obj.Sign)
return false;
for (var i = 0; i < Data.Length; i++)
if (Data[i] != obj.Data[i])
return false;
return true;
}
public string ToString(string format, IFormatProvider formatProvider)
{
if (formatProvider == null)
formatProvider = CultureInfo.CurrentCulture;
if (!string.IsNullOrEmpty(format))
{
var ch = format[0];
if (ch == 'x' || ch == 'X')
{
int.TryParse(format.Substring(1).Trim(), out var min);
return ToHexString(ch == 'X');
}
if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
throw new NotSupportedException("Not supported format: " + format);
}
return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)), 10);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Bits", DataBitWidth);
info.AddValue("Data", Data, typeof(uint[]));
}
private static void CalculateMinDataLength(int minSize)
{
if (minSize > DataLength)
{
DataBitWidth = 32 * minSize;
DataLength = minSize;
}
}
public void OnDeserialization(object sender)
{
if (SInfo == null)
return;
DataBitWidth = SInfo.GetInt32("Bits");
if (DataBitWidth != 0)
{
DataLength = DataBitWidth >> DataShiftCount;
var array = (uint[]) SInfo.GetValue("Data", typeof(uint[]));
if (array == null)
throw new Exception("Array cannot be null.");
if (array.Length != DataLength)
Array.Resize(ref array, DataLength);
Data = new uint[DataLength];
var ba = new byte[4];
for (var i = 0; i < DataLength; i++)
{
Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
Data[i] = BitConverter.ToUInt32(ba, 0);
}
}
}
public static int GetSign(uint[] value)
{
var allZero = true;
for (var i = 0; i < value.Length; i++)
if (value[i] != 0)
{
allZero = false;
break;
}
if (allZero)
return 0;
return (value[value.Length - 1] & HiNeg) == 0 ? 1 : -1;
}
private static int GetDataUsed(uint[] array)
{
var neg = GetSign(array) < 0;
var DataUsed = array.Length;
if (!neg)
{
while (DataUsed > 1 && array[DataUsed - 1] == 0)
--DataUsed;
if (DataUsed == 0)
DataUsed = 1;
}
return DataUsed;
}
public int GetDecimalPlaces()
{
var dPlaces = 0;
if (Sign == 0)
return 1;
var a = new FixedBigInteger(this);
if (Sign < 0)
try
{
a = -a;
}
catch (Exception ex)
{
return 0;
}
var biRadix = new FixedBigInteger(10, DataBitWidth);
while (a > 0)
try
{
Divide(a, biRadix, out var remainder, out var quotient);
a = quotient;
dPlaces++;
}
catch (Exception ex)
{
break;
}
return dPlaces;
}
private uint[] TwosComplement(uint[] d)
{
var i = 0;
uint v = 0;
for (; i < d.Length; i++)
{
v = ~d[i] + 1;
d[i] = v;
if (v != 0)
{
i++;
break;
}
}
if (v != 0)
{
for (; i < d.Length; i++)
d[i] = ~d[i];
}
else
{
Array.Resize(ref d, d.Length + 1);
d[d.Length - 1] = 1;
}
return d;
}
public void ConstructFromArray(byte[] array)
{
if (array == null)
throw new ArgumentNullException("value");
var byteCount = array.Length;
var isNegative = byteCount > 0 && (array[byteCount - 1] & 0x80) == 0x80;
var unalignedBytes = byteCount % DataSize;
var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1);
Data = new uint[Math.Max(dwordCount, DataLength)];
if (byteCount == 0)
return;
int curDword, curByte, byteInDword;
curByte = 3;
for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
{
byteInDword = 0;
while (byteInDword < DataSize)
{
Data[curDword] <<= 8;
Data[curDword] |= array[curByte];
curByte--;
byteInDword++;
}
curByte += 8;
}
if (unalignedBytes != 0)
{
if (isNegative)
Data[dwordCount - 1] = 0xffffffff;
for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
{
Data[curDword] <<= 8;
Data[curDword] |= array[curByte];
}
}
}
private static byte[] ToByteArray(ulong[] value)
{
var ba = new byte[value.Length << 3];
Buffer.BlockCopy(value, 0, ba, 0, value.Length << 3);
return ba;
}
private static byte[] ToByteArray(uint[] value)
{
var ba = new byte[value.Length << 2];
Buffer.BlockCopy(value, 0, ba, 0, value.Length << 2);
return ba;
}
public override int GetHashCode()
{
var hash = 0x811c9dc5;
for (var i = 0; i < Data.Length; i++)
{
hash ^= ((hash << 13) | (hash >> 19)) ^ Data[i];
hash *= 0x1000193;
}
return (int) hash;
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override string ToString()
{
return ToString(null, null);
}
public string ToString(string format)
{
return ToString(format, null);
}
public string ToHexString(bool caps)
{
var bytes = ToByteArray().Invert();
var sb = new StringBuilder();
var x = caps ? "X" : "x";
foreach (var b in bytes)
{
var hex = b.ToString($"{x}2");
sb.Append(hex);
}
return sb.ToString();
}
private string ToString(NumberFormatInfo info, int radix)
{
if (radix < 2 || radix > 36)
throw new ArgumentOutOfRangeException("radix");
if (Sign == 0)
return "0";
var negative = Sign < 0;
var a = new FixedBigInteger(this);
if (negative)
try
{
a = -a;
}
catch (Exception ex)
{
}
var biRadix = new FixedBigInteger(radix, DataBitWidth);
const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz";
var al = new ArrayList();
while (a > 0)
try
{
Divide(a, biRadix, out var remainder, out var quotient);
al.Insert(0, charSet[(int) remainder.Data[0]]);
a = quotient;
}
catch (Exception ex)
{
break;
}
var result = new string((char[]) al.ToArray(typeof(char)));
if (radix == 10 && negative)
return "-" + result;
return result;
}
public static FixedBigInteger Abs(FixedBigInteger value)
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException("value");
if (value.Sign < 0)
return -value;
return value;
}
public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
{
if (conversionType == typeof(bool))
{
value = (bool) this;
return true;
}
if (conversionType == typeof(byte))
{
value = (byte) this;
return true;
}
if (conversionType == typeof(char))
{
value = (char) this;
return true;
}
if (conversionType == typeof(decimal))
{
value = (decimal) this;
return true;
}
if (conversionType == typeof(double))
{
value = (double) this;
return true;
}
if (conversionType == typeof(short))
{
value = (short) this;
return true;
}
if (conversionType == typeof(int))
{
value = (int) this;
return true;
}
if (conversionType == typeof(long))
{
value = (long) this;
return true;
}
if (conversionType == typeof(sbyte))
{
value = (sbyte) this;
return true;
}
if (conversionType == typeof(float))
{
value = (float) this;
return true;
}
if (conversionType == typeof(string))
{
value = ToString(null, provider);
return true;
}
if (conversionType == typeof(ushort))
{
value = (ushort) this;
return true;
}
if (conversionType == typeof(uint))
{
value = (uint) this;
return true;
}
if (conversionType == typeof(ulong))
{
value = (ulong) this;
return true;
}
if (conversionType == typeof(byte[]))
{
value = ToByteArray();
return true;
}
if (conversionType == typeof(Guid))
{
value = new Guid(ToByteArray());
return true;
}
value = null;
return false;
}
public static FixedBigInteger Parse(string value)
{
return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
public static FixedBigInteger Parse(string value, NumberStyles style)
{
return Parse(value, style, NumberFormatInfo.CurrentInfo);
}
public static FixedBigInteger Parse(string value, IFormatProvider provider)
{
return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}
public static FixedBigInteger Parse(string value, NumberStyles style, IFormatProvider provider)
{
if (!TryParse(value, style, provider, out var result))
throw new Exception($"TryParse value {value} failure.");
return result;
}
public static bool TryParse(string value, out FixedBigInteger result)
{
return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
}
public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out FixedBigInteger result)
{
result = 0;
if (string.IsNullOrEmpty(value))
return false;
if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
{
style |= NumberStyles.AllowHexSpecifier;
value = value.Substring(1);
}
else
{
if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
style |= NumberStyles.AllowHexSpecifier;
value = value.Substring(2);
}
}
if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
return TryParseNum(value, 16, out result);
return TryParseNum(value, 10, out result);
}
public static bool TryParseNum(string digits, int radix, out FixedBigInteger result)
{
result = new FixedBigInteger(0, DataBitWidth);
if (digits == null)
return false;
var multiplier = new FixedBigInteger(1, DataBitWidth);
digits = digits.ToUpper(CultureInfo.CurrentCulture).Trim();
var nDigits = digits[0] == '-' ? 1 : 0;
for (var idx = digits.Length - 1; idx >= nDigits; idx--)
{
var d = (int) digits[idx];
if (d >= '0' && d <= '9')
d -= '0';
else if (d >= 'A' && d <= 'Z')
d = d - 'A' + 10;
else
return false;
if (d >= radix)
return false;
result += multiplier * d;
multiplier *= radix;
}
if (digits[0] == '-')
result = -result;
return true;
}
public static int Compare(FixedBigInteger left, object right)
{
if (right is FixedBigInteger)
return Compare(left, (FixedBigInteger) right);
if (right is bool)
return Compare(left, new FixedBigInteger((bool) right, DataBitWidth));
if (right is byte)
return Compare(left, new FixedBigInteger((byte) right, DataBitWidth));
if (right is char)
return Compare(left, new FixedBigInteger((char) right, DataBitWidth));
if (right is decimal)
return Compare(left, new FixedBigInteger((decimal) right, DataBitWidth));
if (right is double)
return Compare(left, new FixedBigInteger((double) right, DataBitWidth));
if (right is short)
return Compare(left, new FixedBigInteger((short) right, DataBitWidth));
if (right is int)
return Compare(left, new FixedBigInteger((int) right, DataBitWidth));
if (right is long)
return Compare(left, new FixedBigInteger((long) right, DataBitWidth));
if (right is sbyte)
return Compare(left, new FixedBigInteger((sbyte) right, DataBitWidth));
if (right is float)
return Compare(left, new FixedBigInteger((float) right, DataBitWidth));
if (right is ushort)
return Compare(left, new FixedBigInteger((ushort) right, DataBitWidth));
if (right is uint)
return Compare(left, new FixedBigInteger((uint) right, DataBitWidth));
if (right is ulong)
return Compare(left, new FixedBigInteger((ulong) right, DataBitWidth));
var bytes = right as byte[];
if (bytes != null)
return Compare(left, new FixedBigInteger(bytes, DataBitWidth));
if (right is Guid)
return Compare(left, new FixedBigInteger((Guid) right, DataBitWidth));
throw new ArgumentException();
}
public static int Compare(FixedBigInteger left, FixedBigInteger right)
{
MakeLikeLengths(ref left, ref right);
if (ReferenceEquals(left, right))
return 0;
if (left.Sign >= 0 && right.Sign < 0)
return 1;
if (left.Sign < 0 && right.Sign >= 0)
return -1;
for (var i = left.Data.Length - 1; i > 0; i--)
if (left.Data[i] != right.Data[i])
return left.Data[i].CompareTo(right.Data[i]);
return left.Data[0].CompareTo(right.Data[0]);
}
public static implicit operator FixedBigInteger(bool value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(byte value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(char value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static explicit operator FixedBigInteger(decimal value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static explicit operator FixedBigInteger(double value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(short value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(int value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(long value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(sbyte value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static explicit operator FixedBigInteger(float value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(ushort value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(uint value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(ulong value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(BigInteger value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static implicit operator FixedBigInteger(BigDecimal value)
{
return new FixedBigInteger(value, DataBitWidth);
}
public static explicit operator bool(FixedBigInteger value)
{
return (byte) value.Data[0] != 0;
}
public static explicit operator byte(FixedBigInteger value)
{
return (byte) value.Data[0];
}
public static explicit operator char(FixedBigInteger value)
{
return (char) (ushort) value.Data[0];
}
public static explicit operator decimal(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
if (value.Data.Length == 1)
return new decimal((int) value.Data[0], 0, 0, value.Sign < 0, 0);
if (value.Data.Length == 2)
return new decimal((int) value.Data[0], (int) value.Data[1], 0, value.Sign < 0, 0);
if (value.Data.Length == 3)
return new decimal((int) value.Data[0], (int) value.Data[1], (int) value.Data[2], value.Sign < 0, 0);
throw new ArgumentException("Value length exceeds decimal length.");
}
public static explicit operator double(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
var nfi = CultureInfo.InvariantCulture.NumberFormat;
if (!double.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var d))
throw new OverflowException();
return d;
}
public static explicit operator float(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
var nfi = CultureInfo.InvariantCulture.NumberFormat;
if (!float.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var f))
throw new OverflowException();
return f;
}
public static explicit operator short(FixedBigInteger value)
{
if (value.Data[0] > 0x8000)
throw new OverflowException();
if (value.Data[0] == 0x8000 && value.Sign > 0)
throw new OverflowException();
return (short) ((int) value.Data[0] * value.Sign);
}
public static explicit operator int(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
return (int) value.Data[0] * value.Sign;
}
public static explicit operator long(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
if (value.Data[0] > int.MaxValue)
throw new OverflowException();
if (value.Data.Length > 1)
if (value.Data[1] != 0)
return (long) (((ulong) value.Data[1] << 32) | value.Data[0]) * value.Sign;
return value.Data[0] * value.Sign;
}
public static explicit operator uint(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
return value.Data[0];
}
public static explicit operator ushort(FixedBigInteger value)
{
if (value.Sign == 0)
return 0;
return (ushort) value.Data[0];
}
public static explicit operator ulong(FixedBigInteger value)
{
if (value.Data.Length > 1)
if (value.Data[1] != 0)
return ((ulong) value.Data[1] << 32) | value.Data[0];
return value.Data[0];
}
public static explicit operator BigInteger(FixedBigInteger value)
{
return new BigInteger(value.ToByteArray());
}
public static bool operator >(FixedBigInteger left, FixedBigInteger right)
{
return left.CompareTo(right) > 0;
}
private static void MakeLikeLengths(ref FixedBigInteger left, ref FixedBigInteger right)
{
if (left.Data.Length != right.Data.Length)
{
var len = Math.Max(left.Data.Length, right.Data.Length);
Resize(ref left, len);
Resize(ref right, len);
}
}
private static void Resize(ref FixedBigInteger value, int newSize)
{
var IsNeg = value.IsNegative;
var nData = new uint[newSize];
var len = value.Data.Length;
for (var i = 0; i < len; i++)
{
nData[i] = value.Data[i];
if (IsNeg && i == len - 1)
nData[i] &= ~HiNeg;
}
if (IsNeg)
nData[nData.Length - 1] |= HiNeg;
value.Data = (uint[]) nData.Clone();
}
public static bool operator <(FixedBigInteger left, FixedBigInteger right)
{
return Compare(left, right) < 0;
}
public static bool operator >=(FixedBigInteger left, FixedBigInteger right)
{
return Compare(left, right) >= 0;
}
public static bool operator <=(FixedBigInteger left, FixedBigInteger right)
{
return Compare(left, right) <= 0;
}
public static bool operator !=(FixedBigInteger left, FixedBigInteger right)
{
return !left.Equals(right);
}
public static bool operator ==(FixedBigInteger left, FixedBigInteger right)
{
return left.Equals(right);
}
public static FixedBigInteger operator +(FixedBigInteger value)
{
return value;
}
public static FixedBigInteger operator ~(FixedBigInteger value)
{
var da = new uint[DataLength];
for (var idx = 0; idx < DataLength; idx++)
da[idx] = ~value.Data[idx];
return new FixedBigInteger(da, DataBitWidth);
}
public static FixedBigInteger operator -(FixedBigInteger value)
{
if (ReferenceEquals(value, null))
throw new ArgumentNullException("value");
if (value.IsZero)
return Zero;
var da = new uint[DataLength];
for (var i = 0; i < da.Length; i++)
da[i] = ~value.Data[i];
var carry = true;
var index = 0;
while (carry && index < da.Length)
{
var val = (long) da[index] + 1;
da[index] = (uint) (val & AllBits);
carry = val >> DataSizeBits > 0;
index++;
}
return new FixedBigInteger(da, DataBitWidth);
}
public static FixedBigInteger operator ++(FixedBigInteger value)
{
return value + 1;
}
public static FixedBigInteger operator --(FixedBigInteger value)
{
return value - 1;
}
public static FixedBigInteger Negate(FixedBigInteger value)
{
var ldata = (uint[]) value.Data.Clone();
for (var i = 0; i < value.Data.Length; i++)
ldata[i] = ~value.Data[i];
return new FixedBigInteger(value.Sign, ldata, DataBitWidth);
}
public static FixedBigInteger operator +(FixedBigInteger left, FixedBigInteger right)
{
if (right.IsZero)
return left;
if (left.IsZero)
return right;
MakeLikeLengths(ref left, ref right);
var dl = left.Data.Length > right.Data.Length ? left.Data.Length : right.Data.Length;
var result = new uint[dl];
long carry = 0;
for (var i = 0; i < dl; i++)
{
var sum = left.Data[i] + (long) right.Data[i] + carry;
carry = sum >> 32;
result[i] = (uint) (sum & 0xFFFFFFFF);
}
if (carry != 0)
{
var idx = 0;
while (idx < result.Length - 1)
{
if (result[idx] == 0)
break;
idx++;
}
result[idx] = (uint) carry;
}
return new FixedBigInteger(left.Sign * right.Sign, result, DataBitWidth);
}
public static FixedBigInteger operator -(FixedBigInteger left, FixedBigInteger right)
{
if (right.IsZero)
return left;
if (left.IsZero)
return -right;
MakeLikeLengths(ref left, ref right);
var da = new uint[DataLength];
long carry = 0;
for (var i = 0; i < DataLength && i < left.Data.Length && i < right.Data.Length; i++)
{
var diff = left.Data[i] - (long) right.Data[i] - carry;
da[i] = (uint) (diff & AllBits);
carry = diff < 0 ? 1 : 0;
}
return new FixedBigInteger(da, DataBitWidth);
}
public static FixedBigInteger Add(FixedBigInteger left, FixedBigInteger right)
{
return left + right;
}
public static FixedBigInteger Subtract(FixedBigInteger left, FixedBigInteger right)
{
return left - right;
}
public static FixedBigInteger Divide(FixedBigInteger dividend, FixedBigInteger divisor)
{
if (divisor == 0)
throw new DivideByZeroException();
return DivRem(dividend, divisor, out var integer);
}
public static void Divide(FixedBigInteger dividend, FixedBigInteger divisor, out FixedBigInteger remainder, out FixedBigInteger quotient)
{
if (divisor == 0)
throw new DivideByZeroException();
DivRem(dividend.Data, divisor.Data, out var quo, out var rem);
remainder = new FixedBigInteger(1, rem, DataBitWidth);
quotient = new FixedBigInteger(dividend.Sign * divisor.Sign, quo, DataBitWidth);
}
public static FixedBigInteger DivRem(FixedBigInteger dividend, FixedBigInteger divisor, out FixedBigInteger remainder)
{
if (divisor == 0)
throw new DivideByZeroException();
DivRem(dividend.Data, divisor.Data, out var quotient, out var rem);
remainder = new FixedBigInteger(1, rem, DataBitWidth);
return new FixedBigInteger(dividend.Sign * divisor.Sign, quotient, DataBitWidth);
}
private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
{
const ulong hiBit = 0x100000000;
var divisorLen = GetLength(divisor);
var dividendLen = GetLength(dividend);
if (divisorLen <= 1)
{
ulong rem = 0;
var div = divisor[0];
quotient = new uint[dividendLen];
remainder = new uint[1];
for (var i = dividendLen - 1; i >= 0; i--)
{
rem *= hiBit;
rem += dividend[i];
var q = rem / div;
rem -= q * div;
quotient[i] = (uint) q;
}
remainder[0] = (uint) rem;
return;
}
if (dividendLen >= divisorLen)
{
var shift = GetNormalizeShift(divisor[divisorLen - 1]);
var normDividend = new uint[dividendLen + 1];
var normDivisor = new uint[divisorLen];
Normalize(dividend, dividendLen, normDividend, shift);
Normalize(divisor, divisorLen, normDivisor, shift);
quotient = new uint[dividendLen - divisorLen + 1];
for (var j = dividendLen - divisorLen; j >= 0; j--)
{
var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
var qj = dx / normDivisor[divisorLen - 1];
dx -= qj * normDivisor[divisorLen - 1];
do
{
if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
break;
qj -= 1L;
dx += normDivisor[divisorLen - 1];
} while (dx < hiBit);
ulong di = 0;
ulong dj;
var index = 0;
while (index < divisorLen)
{
var dqj = normDivisor[index] * qj;
dj = normDividend[index + j] - (uint) dqj - di;
normDividend[index + j] = (uint) dj;
dqj = dqj >> 32;
dj = dj >> 32;
di = dqj - dj;
index++;
}
dj = normDividend[j + divisorLen] - di;
normDividend[j + divisorLen] = (uint) dj;
quotient[j] = (uint) qj;
if ((long) dj < 0)
{
quotient[j]--;
ulong sum = 0;
for (index = 0; index < divisorLen; index++)
{
sum = normDivisor[index] + normDividend[j + index] + sum;
normDividend[j + index] = (uint) sum;
sum = sum >> 32;
}
sum += normDividend[j + divisorLen];
normDividend[j + divisorLen] = (uint) sum;
}
}
remainder = Unnormalize(normDividend, shift);
return;
}
quotient = new uint[1];
remainder = dividend;
}
private static int GetLength(uint[] uints)
{
var index = uints.Length - 1;
while (index >= 0 && uints[index] == 0)
index--;
return index + 1;
}
private static int GetNormalizeShift(uint ui)
{
var shift = 0;
if ((ui & 0xffff0000) == 0)
{
ui = ui << 16;
shift += 16;
}
if ((ui & 0xff000000) == 0)
{
ui = ui << 8;
shift += 8;
}
if ((ui & 0xf0000000) == 0)
{
ui = ui << 4;
shift += 4;
}
if ((ui & 0xc0000000) == 0)
{
ui = ui << 2;
shift += 2;
}
if ((ui & 0x80000000) == 0)
shift++;
return shift;
}
private static uint[] Unnormalize(uint[] normalized, int shift)
{
var len = GetLength(normalized);
var unnormalized = new uint[len];
if (shift > 0)
{
var rshift = 32 - shift;
uint r = 0;
for (var i = len - 1; i >= 0; i--)
{
unnormalized[i] = (normalized[i] >> shift) | r;
r = normalized[i] << rshift;
}
}
else
{
for (var j = 0; j < len; j++)
unnormalized[j] = normalized[j];
}
return unnormalized;
}
private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
{
int i;
uint n = 0;
if (shift > 0)
{
var rShift = 32 - shift;
for (i = 0; i < len; i++)
{
normalized[i] = (unormalized[i] << shift) | n;
n = unormalized[i] >> rShift;
}
}
else
{
i = 0;
while (i < len)
{
normalized[i] = unormalized[i];
i++;
}
}
while (i < normalized.Length)
normalized[i++] = 0;
if (n != 0)
normalized[len] = n;
}
public static FixedBigInteger Remainder(FixedBigInteger dividend, FixedBigInteger divisor)
{
DivRem(dividend, divisor, out var remainder);
return remainder;
}
public static FixedBigInteger Max(FixedBigInteger left, FixedBigInteger right)
{
return left.CompareTo(right) < 0 ? right : left;
}
public static FixedBigInteger Min(FixedBigInteger left, FixedBigInteger right)
{
return left.CompareTo(right) <= 0 ? left : right;
}
public static int GetBitWidth(FixedBigInteger n)
{
FixedBigInteger bw = 1;
var v = n;
while ((v >>= 1) > 0)
bw++;
if (bw < 8)
bw = 8;
while (bw % 8 != 0)
bw++;
return (int) bw;
}
public static int GetBitWidth<T>(T n)
{
ulong bw = 1;
dynamic v = new FixedBigInteger((dynamic) n, 0);
while ((v >>= 1) > 0)
bw++;
if (bw < 8)
bw = 8;
while (bw % 8 != 0)
bw++;
return (int) bw;
}
public static FixedBigInteger operator %(FixedBigInteger dividend, FixedBigInteger divisor)
{
return Remainder(dividend, divisor);
}
public static FixedBigInteger operator /(FixedBigInteger dividend, FixedBigInteger divisor)
{
return Divide(dividend, divisor);
}
public ulong[] ToUIn64Array()
{
var al = Data.Length >> 1;
if (al * 2 != Data.Length)
al++;
var arr = new ulong[al];
Buffer.BlockCopy(Data, 0, arr, 0, Data.Length << 2);
return arr;
}
public uint[] ToUIn32Array()
{
return Data;
}
public byte[] ToByteArray()
{
var ba = new byte[DataUsed * DataSize];
Buffer.BlockCopy(Data, 0, ba, 0, DataUsed * DataSize);
return ba;
}
private void TrimToMsb()
{
var dataUsed = Data.Length;
while (dataUsed > 1 && Data[dataUsed - 1] == 0)
--dataUsed;
if (dataUsed != Data.Length)
{
var tData = new uint[dataUsed];
for (var i = 0; i < dataUsed; i++)
tData[i] = Data[i];
Data = (uint[]) tData.Clone();
}
}
public static FixedBigInteger Multiply(FixedBigInteger left, FixedBigInteger right)
{
if (left == 0 || right == 0)
return Zero;
if (left == 1 && right != 1)
return right;
if (left != 1 && right == 1)
return left;
if (left == 1 && right == 1)
return One;
var xInts = left.Data;
var yInts = right.Data;
var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1];
for (var i = 0; i < xInts.Length; i++)
{
var index = i;
ulong remainder = 0;
foreach (var yi in yInts)
{
remainder = remainder + (ulong) xInts[i] * yi + mulInts[index];
mulInts[index++] = (uint) remainder;
remainder = remainder >> 32;
}
while (remainder != 0)
{
remainder += mulInts[index];
mulInts[index++] = (uint) remainder;
remainder = remainder >> 32;
}
}
var du = GetDataUsed(mulInts);
Array.Resize(ref mulInts, du);
return new FixedBigInteger(left.Sign * right.Sign, mulInts);
}
public static FixedBigInteger operator *(FixedBigInteger left, FixedBigInteger right)
{
return Multiply(left, right);
}
public static FixedBigInteger operator >>(FixedBigInteger value, int shift)
{
if (shift == 0)
return value;
if (shift == int.MinValue)
return value << int.MaxValue << 1;
if (shift < 0)
return value << -shift;
var xd = value.Data;
var shiftAmount = 32;
var invShift = 0;
var bufLen = xd.Length;
while (bufLen > 1 && xd[bufLen - 1] == 0)
bufLen--;
for (var count = shift; count > 0; count -= shiftAmount)
{
if (count < shiftAmount)
{
shiftAmount = count;
invShift = 32 - shiftAmount;
}
ulong carry = 0;
for (var i = bufLen - 1; i >= 0; i--)
{
var val = (ulong) xd[i] >> shiftAmount;
val |= carry;
carry = (ulong) xd[i] << invShift;
xd[i] = (uint) val;
}
}
return new FixedBigInteger(value.Sign, xd, DataBitWidth);
}
public static FixedBigInteger operator <<(FixedBigInteger value, int shift)
{
if (shift == 0)
return value;
if (shift == int.MinValue)
return value >> int.MaxValue >> 1;
if (shift < 0)
return value >> -shift;
var digitShift = shift / 32;
var smallShift = shift - digitShift * 32;
var xd = value.Data;
var xl = xd.Length;
var zd = new uint[xl + digitShift + 1];
if (smallShift == 0)
{
for (var index = 0; index < xl; ++index)
zd[index + digitShift] = xd[index];
}
else
{
var carryShift = 32 - smallShift;
uint carry = 0;
int index;
for (index = 0; index < xl; ++index)
{
var rot = xd[index];
zd[index + digitShift] = (rot << smallShift) | carry;
carry = rot >> carryShift;
}
zd[index + digitShift] = carry;
}
return new FixedBigInteger(value.Sign, zd, DataBitWidth);
}
public static FixedBigInteger operator |(FixedBigInteger left, FixedBigInteger right)
{
if (left == 0)
return right;
if (right == 0)
return left;
var z = new uint[Math.Max(left.Data.Length, right.Data.Length)];
var lExt = left.Sign < 0 ? uint.MaxValue : 0U;
var rExt = right.Sign < 0 ? uint.MaxValue : 0U;
for (var i = 0; i < z.Length; i++)
{
var xu = i < left.Data.Length ? left.Data[i] : lExt;
var yu = i < right.Data.Length ? right.Data[i] : rExt;
z[i] = xu | yu;
}
return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth);
}
public static FixedBigInteger operator ^(FixedBigInteger left, FixedBigInteger right)
{
var z = new uint[Math.Max(left.Data.Length, right.Data.Length)];
var lExt = left.Sign < 0 ? uint.MaxValue : 0U;
var rExt = right.Sign < 0 ? uint.MaxValue : 0U;
for (var i = 0; i < z.Length; i++)
{
var xu = i < left.Data.Length ? left.Data[i] : lExt;
var yu = i < right.Data.Length ? right.Data[i] : rExt;
z[i] = xu ^ yu;
}
return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth);
}
public static FixedBigInteger operator &(FixedBigInteger left, FixedBigInteger right)
{
if (left == 0 || right == 0)
return 0;
var z = new uint[Math.Max(left.Data.Length, right.Data.Length)];
var lExt = left.Sign < 0 ? uint.MaxValue : 0U;
var rExt = right.Sign < 0 ? uint.MaxValue : 0U;
for (var i = 0; i < z.Length; i++)
{
var xu = i < left.Data.Length ? left.Data[i] : lExt;
var yu = i < right.Data.Length ? right.Data[i] : rExt;
z[i] = xu & yu;
}
return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth);
}
public FixedBigInteger Sqrt()
{
var n = this;
var q = One << ((int) Math.Ceiling(Log(n, 2)) >> 1);
var steps = 0;
var m = Zero;
while (Abs(q - m) >= 1)
{
m = q;
q = (m + n / m) >> 1;
steps++;
}
return q;
}
public FixedBigInteger Pow(int e)
{
var ans = this;
if (e == 1)
return ans;
if (e == 0)
return 1;
for (var i = 1; i != e; i++)
ans *= this;
return ans;
}
public static FixedBigInteger ModPow(FixedBigInteger n, FixedBigInteger e, FixedBigInteger m)
{
var n1 = new BigIntX(n);
var e1 = new BigIntX(e);
var m1 = new BigIntX(m);
var r = new BigIntX(1);
while (e1 != 0)
{
if (e1 % 2 == 1)
r = r * n1 % m1;
e1 >>= 1;
n1 = n1 * n1 % m1;
}
return new FixedBigInteger(r.ToByteArray(), DataBitWidth);
}
public bool Fermat(FixedBigInteger candidate)
{
uint[] wits = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
var pmo = candidate - 1;
for (var i = 0; i < wits.Length; i++)
{
var r = ModPow(wits[i], pmo, candidate);
if (r != One)
return false;
}
return true;
}
private static bool MillerRabin(FixedBigInteger candidate)
{
uint[] w = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
var s = 0;
var d = candidate - One;
while ((d & 1) == 0)
{
d >>= 1;
++s;
}
if (s == 0)
return false;
var nmo = candidate - One;
for (var i = 0; i < w.Length; ++i)
{
var x = ModPow(w[i], nmo, candidate);
if (!(x == 1) && !(x == nmo))
{
for (var r = 1; r < s; ++r)
{
x = ModPow(x, 2, candidate);
if (x == 1)
return false;
if (x == nmo)
break;
}
if (!(x == nmo))
return false;
}
}
return true;
}
public bool IsPrime()
{
return MillerRabin(this);
}
public static double Log(FixedBigInteger value, double baseValue)
{
var c = 0.0;
var d = 0.5;
//var dataLength = Length(value.Data);
var dataLength = value.Data[value.Data.Length - 1] != 0U ? value.Data.Length : value.Data.Length - 1;
var topBits = 0; //BitLengthOfUInt(value.Data[dataLength - 1]);
var x = value.Data[dataLength - 1];
while (x > 0)
{
x >>= 1;
topBits++;
}
var bitLength = (dataLength - 1) * 32 + topBits;
var bit = (uint) (1 << (topBits - 1));
for (var index = dataLength - 1; index >= 0; --index)
{
for (; bit != 0U; bit >>= 1)
{
if (((int) value.Data[index] & (int) bit) != 0)
c += d;
d *= 0.5;
}
bit = 2147483648U;
}
return (Math.Log(c) + 0.69314718055994530941723212145818 * bitLength) / Math.Log(baseValue);
}
public static List<FixedBigInteger> GetFactors(FixedBigInteger n)
{
var Factors = new List<FixedBigInteger>();
var s = n.Sqrt();
var a = Three;
while (a < s)
{
if (n % a == 0)
{
Factors.Add(a);
if (a * a != n)
Factors.Add(n / a);
}
a += 2;
}
return Factors;
}
public static FixedBigInteger GreatestCommonDivisor(FixedBigInteger a, FixedBigInteger b)
{
while (b > 0)
{
var r = a % b;
a = b;
b = r;
}
return a;
}
public static FixedBigInteger LeastCommonMultiple(FixedBigInteger a, FixedBigInteger b)
{
return a * b / a.Gcd(b);
}
public static double Log10(FixedBigInteger value)
{
return Log(value, 10.0);
}
public static double LogN(FixedBigInteger value)
{
return Log(value, 2.0);
}
private class FixedBigIntegerConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value != null)
if (TryParse($"{value}", out var i))
return i;
return new FixedBigInteger(0, DataBitWidth);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType);
}
}
}
public class FixedBigIntegerComparer : IComparer<FixedBigInteger>
{
public int Compare(FixedBigInteger left, FixedBigInteger right)
{
return left.CompareTo(right);
}
public bool Equals(FixedBigInteger left, FixedBigInteger right)
{
if (left == null || right == null)
return false;
return left.Equals(right);
}
public int GetHashCode(FixedBigInteger obj)
{
return obj.GetHashCode();
}
}
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Numerics; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; [Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] [TypeConverter(typeof(FixedBigIntegerConverter))] [DebuggerDisplay("{DDisplay}")] public class FixedBigInteger : IComparable<FixedBigInteger>, IComparable, IEquatable<FixedBigInteger>, IConvertible, IFormattable, ISerializable { private const int DefaultDataBitWidth = 2048; private const int DataSize = sizeof(uint); private const int DataShiftCount = 5; private const uint AllBits = ~(uint) 0; private const int DataSizeBits = sizeof(uint) * 8; private const uint HiNeg = (uint) 1 << (DataSizeBits - 1); private static int DataBitWidth; private static int DataLength; public static readonly FixedBigInteger One = new FixedBigInteger(1, DataBitWidth); public static readonly FixedBigInteger Two = new FixedBigInteger(2, DataBitWidth); public static readonly FixedBigInteger Zero = new FixedBigInteger(0, DataBitWidth); public static readonly FixedBigInteger Ten = new FixedBigInteger(10, DataBitWidth); public static readonly FixedBigInteger Three = new FixedBigInteger(3, DataBitWidth); private readonly SerializationInfo SInfo; public uint[] Data; public FixedBigInteger(FixedBigInteger value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; CalculateMinDataLength(value.Data.Length); Data = new uint[DataLength]; value.Data.CopyTo(Data, 0); } public FixedBigInteger(string value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; if (!TryParse(value, out var result)) throw new Exception("TryParse Failed."); CalculateMinDataLength(result.Data.Length); Data = new uint[DataLength]; result.Data.CopyTo(Data, 0); } public FixedBigInteger(byte value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[0] = value; } public FixedBigInteger(bool value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[0] = (uint) (value ? 1 : 0); } public FixedBigInteger(char value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[0] = value; } public FixedBigInteger(BigDecimal value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; var ba = value.WholePart.ToByteArray(); DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; var len = ba.Length / DataSize; CalculateMinDataLength(len); Data = new uint[DataLength]; for (var i = 0; i < Data.Length; i++) Data[i] = BitConverter.ToUInt32(ba, i * DataSize); } public FixedBigInteger(decimal value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; CalculateMinDataLength(3); Data = new uint[DataLength]; if (value < 0) { var n = -new FixedBigInteger(-value, DataBitWidth); n.Data.CopyTo(Data, 0); return; } var bits = decimal.GetBits(value); Data[2] = (uint) bits[2]; Data[1] = (uint) bits[1]; Data[0] = (uint) bits[0]; } public FixedBigInteger(double value, int bitLength = 0) : this((decimal) value, bitLength) { } public FixedBigInteger(float value, int bitLength = 0) : this((decimal) value, bitLength) { } public FixedBigInteger(short value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; if (value < 0) { var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1; n.Data.CopyTo(Data, 0); return; } Data[0] = (uint) value; } public FixedBigInteger() { DataBitWidth = DefaultDataBitWidth; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[0] = 0; } public FixedBigInteger(int value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; if (value < 0) { var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1; n.Data.CopyTo(Data, 0); return; } Data[0] = (uint) value; } public FixedBigInteger(long value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 64) bitLength = 64; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; if (value < 0) { var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1; n.Data.CopyTo(Data, 0); return; } Data[1] = (uint) ((value >> 32) & 0xffffffff); Data[0] = (uint) (value & 0xffffffff); } public FixedBigInteger(sbyte value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; if (value < 0) { var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1; n.Data.CopyTo(Data, 0); return; } Data[0] = (uint) value; } public FixedBigInteger(ushort value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[0] = value; } public FixedBigInteger(uint value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 32) bitLength = 32; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[0] = value; } public FixedBigInteger(ulong value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; if (bitLength < 96) bitLength = 96; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; Data = new uint[DataLength]; Data[1] = (uint) ((value >> 32) & 0xffffffff); Data[0] = (uint) (value & 0xffffffff); } public FixedBigInteger(BigInteger value, int bitLength = 0) : this(value.ToByteArray(), bitLength) { } public FixedBigInteger(Guid value, int bitLength = 0) : this(value.ToByteArray(), bitLength) { } public FixedBigInteger(byte[] value, int bitLength = 0) { if (bitLength == 0) bitLength = DefaultDataBitWidth; var minSize = value.Length / DataSize; if (value == null) throw new ArgumentNullException("value"); DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; CalculateMinDataLength(minSize); var byteCount = value.Length; var isNegative = byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80; var unalignedBytes = byteCount % DataSize; var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1); Data = new uint[Math.Max(dwordCount, DataLength)]; if (byteCount == 0) return; int curDword, curByte, byteInDword; curByte = 3; for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) { byteInDword = 0; while (byteInDword < DataSize) { Data[curDword] <<= 8; Data[curDword] |= value[curByte]; curByte--; byteInDword++; } curByte += 8; } if (unalignedBytes != 0) { if (isNegative) Data[dwordCount - 1] = 0xffffffff; for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) { Data[curDword] <<= 8; Data[curDword] |= value[curByte]; } } } public FixedBigInteger(int sign, uint[] array, int bitLength = 0) { if (array == null) throw new Exception("Array cannot be null."); if (bitLength == 0) bitLength = DefaultDataBitWidth; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; CalculateMinDataLength(array.Length); if (array.Length != DataLength) Array.Resize(ref array, DataLength); Data = new uint[DataLength]; var ba = new byte[DataSize]; for (var i = 0; i < Data.Length; i++) { Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize); Data[i] = BitConverter.ToUInt32(ba, 0); } if (sign < 0) Data[DataLength - 1] |= HiNeg; else Data[DataLength - 1] &= ~HiNeg; } public FixedBigInteger(uint[] array, int bitLength = 0) { if (array == null) throw new Exception("Array cannot be null."); if (bitLength == 0) bitLength = DefaultDataBitWidth; DataBitWidth = bitLength; DataLength = DataBitWidth >> DataShiftCount; if (array.Length != DataLength) Array.Resize(ref array, DataLength); Data = new uint[DataLength]; var ba = new byte[DataSize]; for (var i = 0; i < Data.Length; i++) { Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize); Data[i] = BitConverter.ToUInt32(ba, 0); } } protected FixedBigInteger(SerializationInfo info, StreamingContext context) { SInfo = info; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DDisplay => ToString(); public FixedBigInteger MaxValue { get { var r = new FixedBigInteger(0, DataBitWidth); for (var i = 0; i < r.Data.Length; ++i) r.Data[i] = uint.MaxValue; r.Data[r.Data.Length - 1] = int.MaxValue; return r; } } public int BitWidth { get { FixedBigInteger bw = 1; var v = new FixedBigInteger(this); while ((v >>= 1) > 0) bw++; if (bw < 8) bw = 8; while (bw % 8 != 0) bw++; return (int) bw; } } public int Sign { get { var allZero = true; var ba = Data; for (var i = 0; i < ba.Length; i++) if (ba[i] != 0) { allZero = false; break; } if (allZero) return 0; return (Data[Data.Length - 1] & HiNeg) == 0 ? 1 : -1; } } public bool IsOne => this == 1; public bool IsEven => (this & 1) == 0; public bool IsNegative => Sign < 0; public bool IsZero { get { for (var i = 0; i < Data.Length; i++) if (Data[i] != 0) return false; return true; } } public int DataUsed { get { var DataUsed = Data.Length; if (!IsNegative) { while (DataUsed > 1 && Data[DataUsed - 1] == 0) --DataUsed; if (DataUsed == 0) DataUsed = 1; } return DataUsed; } } int IComparable.CompareTo(object obj) { return Compare(this, obj); } public int CompareTo(FixedBigInteger value) { return Compare(this, value); } TypeCode IConvertible.GetTypeCode() { return TypeCode.Object; } bool IConvertible.ToBoolean(IFormatProvider provider) { return (bool) this; } byte IConvertible.ToByte(IFormatProvider provider) { return (byte) this; } char IConvertible.ToChar(IFormatProvider provider) { return (char) this; } DateTime IConvertible.ToDateTime(IFormatProvider provider) { throw new InvalidCastException(); } decimal IConvertible.ToDecimal(IFormatProvider provider) { return (decimal) this; } double IConvertible.ToDouble(IFormatProvider provider) { return (double) this; } short IConvertible.ToInt16(IFormatProvider provider) { return (short) this; } int IConvertible.ToInt32(IFormatProvider provider) { return (int) this; } long IConvertible.ToInt64(IFormatProvider provider) { return (long) this; } sbyte IConvertible.ToSByte(IFormatProvider provider) { return (sbyte) this; } float IConvertible.ToSingle(IFormatProvider provider) { return (float) this; } string IConvertible.ToString(IFormatProvider provider) { return ToString(null, provider); } public object ToType(Type conversionType, IFormatProvider provider) { object value; if (TryConvert(conversionType, provider, out value)) return value; throw new InvalidCastException(); } ushort IConvertible.ToUInt16(IFormatProvider provider) { if (Data[1] != 0) throw new OverflowException(); return Convert.ToUInt16(Data[0]); } uint IConvertible.ToUInt32(IFormatProvider provider) { if (Data[1] != 0) throw new OverflowException(); return Convert.ToUInt32(Data[0]); } ulong IConvertible.ToUInt64(IFormatProvider provider) { if (Data[1] != 0) return ((ulong) Data[1] << 32) | Data[0]; return Data[0]; } public bool Equals(FixedBigInteger obj) { if (ReferenceEquals(obj, null)) return false; if (ReferenceEquals(this, obj)) return true; if (Data.Length != obj.Data.Length) { var len = Math.Max(Data.Length, obj.Data.Length); if (Data.Length < len) { var tData = new uint[len]; Array.Copy(Data, 0, tData, 0, Data.Length); Data = tData; } if (obj.Data.Length < len) Resize(ref obj, len); } if (Sign != obj.Sign) return false; for (var i = 0; i < Data.Length; i++) if (Data[i] != obj.Data[i]) return false; return true; } public string ToString(string format, IFormatProvider formatProvider) { if (formatProvider == null) formatProvider = CultureInfo.CurrentCulture; if (!string.IsNullOrEmpty(format)) { var ch = format[0]; if (ch == 'x' || ch == 'X') { int.TryParse(format.Substring(1).Trim(), out var min); return ToHexString(ch == 'X'); } if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd') throw new NotSupportedException("Not supported format: " + format); } return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)), 10); } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Bits", DataBitWidth); info.AddValue("Data", Data, typeof(uint[])); } private static void CalculateMinDataLength(int minSize) { if (minSize > DataLength) { DataBitWidth = 32 * minSize; DataLength = minSize; } } public void OnDeserialization(object sender) { if (SInfo == null) return; DataBitWidth = SInfo.GetInt32("Bits"); if (DataBitWidth != 0) { DataLength = DataBitWidth >> DataShiftCount; var array = (uint[]) SInfo.GetValue("Data", typeof(uint[])); if (array == null) throw new Exception("Array cannot be null."); if (array.Length != DataLength) Array.Resize(ref array, DataLength); Data = new uint[DataLength]; var ba = new byte[4]; for (var i = 0; i < DataLength; i++) { Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize); Data[i] = BitConverter.ToUInt32(ba, 0); } } } public static int GetSign(uint[] value) { var allZero = true; for (var i = 0; i < value.Length; i++) if (value[i] != 0) { allZero = false; break; } if (allZero) return 0; return (value[value.Length - 1] & HiNeg) == 0 ? 1 : -1; } private static int GetDataUsed(uint[] array) { var neg = GetSign(array) < 0; var DataUsed = array.Length; if (!neg) { while (DataUsed > 1 && array[DataUsed - 1] == 0) --DataUsed; if (DataUsed == 0) DataUsed = 1; } return DataUsed; } public int GetDecimalPlaces() { var dPlaces = 0; if (Sign == 0) return 1; var a = new FixedBigInteger(this); if (Sign < 0) try { a = -a; } catch (Exception ex) { return 0; } var biRadix = new FixedBigInteger(10, DataBitWidth); while (a > 0) try { Divide(a, biRadix, out var remainder, out var quotient); a = quotient; dPlaces++; } catch (Exception ex) { break; } return dPlaces; } private uint[] TwosComplement(uint[] d) { var i = 0; uint v = 0; for (; i < d.Length; i++) { v = ~d[i] + 1; d[i] = v; if (v != 0) { i++; break; } } if (v != 0) { for (; i < d.Length; i++) d[i] = ~d[i]; } else { Array.Resize(ref d, d.Length + 1); d[d.Length - 1] = 1; } return d; } public void ConstructFromArray(byte[] array) { if (array == null) throw new ArgumentNullException("value"); var byteCount = array.Length; var isNegative = byteCount > 0 && (array[byteCount - 1] & 0x80) == 0x80; var unalignedBytes = byteCount % DataSize; var dwordCount = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1); Data = new uint[Math.Max(dwordCount, DataLength)]; if (byteCount == 0) return; int curDword, curByte, byteInDword; curByte = 3; for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++) { byteInDword = 0; while (byteInDword < DataSize) { Data[curDword] <<= 8; Data[curDword] |= array[curByte]; curByte--; byteInDword++; } curByte += 8; } if (unalignedBytes != 0) { if (isNegative) Data[dwordCount - 1] = 0xffffffff; for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--) { Data[curDword] <<= 8; Data[curDword] |= array[curByte]; } } } private static byte[] ToByteArray(ulong[] value) { var ba = new byte[value.Length << 3]; Buffer.BlockCopy(value, 0, ba, 0, value.Length << 3); return ba; } private static byte[] ToByteArray(uint[] value) { var ba = new byte[value.Length << 2]; Buffer.BlockCopy(value, 0, ba, 0, value.Length << 2); return ba; } public override int GetHashCode() { var hash = 0x811c9dc5; for (var i = 0; i < Data.Length; i++) { hash ^= ((hash << 13) | (hash >> 19)) ^ Data[i]; hash *= 0x1000193; } return (int) hash; } public override bool Equals(object obj) { return base.Equals(obj); } public override string ToString() { return ToString(null, null); } public string ToString(string format) { return ToString(format, null); } public string ToHexString(bool caps) { var bytes = ToByteArray().Invert(); var sb = new StringBuilder(); var x = caps ? "X" : "x"; foreach (var b in bytes) { var hex = b.ToString($"{x}2"); sb.Append(hex); } return sb.ToString(); } private string ToString(NumberFormatInfo info, int radix) { if (radix < 2 || radix > 36) throw new ArgumentOutOfRangeException("radix"); if (Sign == 0) return "0"; var negative = Sign < 0; var a = new FixedBigInteger(this); if (negative) try { a = -a; } catch (Exception ex) { } var biRadix = new FixedBigInteger(radix, DataBitWidth); const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz"; var al = new ArrayList(); while (a > 0) try { Divide(a, biRadix, out var remainder, out var quotient); al.Insert(0, charSet[(int) remainder.Data[0]]); a = quotient; } catch (Exception ex) { break; } var result = new string((char[]) al.ToArray(typeof(char))); if (radix == 10 && negative) return "-" + result; return result; } public static FixedBigInteger Abs(FixedBigInteger value) { if (ReferenceEquals(value, null)) throw new ArgumentNullException("value"); if (value.Sign < 0) return -value; return value; } public bool TryConvert(Type conversionType, IFormatProvider provider, out object value) { if (conversionType == typeof(bool)) { value = (bool) this; return true; } if (conversionType == typeof(byte)) { value = (byte) this; return true; } if (conversionType == typeof(char)) { value = (char) this; return true; } if (conversionType == typeof(decimal)) { value = (decimal) this; return true; } if (conversionType == typeof(double)) { value = (double) this; return true; } if (conversionType == typeof(short)) { value = (short) this; return true; } if (conversionType == typeof(int)) { value = (int) this; return true; } if (conversionType == typeof(long)) { value = (long) this; return true; } if (conversionType == typeof(sbyte)) { value = (sbyte) this; return true; } if (conversionType == typeof(float)) { value = (float) this; return true; } if (conversionType == typeof(string)) { value = ToString(null, provider); return true; } if (conversionType == typeof(ushort)) { value = (ushort) this; return true; } if (conversionType == typeof(uint)) { value = (uint) this; return true; } if (conversionType == typeof(ulong)) { value = (ulong) this; return true; } if (conversionType == typeof(byte[])) { value = ToByteArray(); return true; } if (conversionType == typeof(Guid)) { value = new Guid(ToByteArray()); return true; } value = null; return false; } public static FixedBigInteger Parse(string value) { return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } public static FixedBigInteger Parse(string value, NumberStyles style) { return Parse(value, style, NumberFormatInfo.CurrentInfo); } public static FixedBigInteger Parse(string value, IFormatProvider provider) { return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); } public static FixedBigInteger Parse(string value, NumberStyles style, IFormatProvider provider) { if (!TryParse(value, style, provider, out var result)) throw new Exception($"TryParse value {value} failure."); return result; } public static bool TryParse(string value, out FixedBigInteger result) { return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out FixedBigInteger result) { result = 0; if (string.IsNullOrEmpty(value)) return false; if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase)) { style |= NumberStyles.AllowHexSpecifier; value = value.Substring(1); } else { if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { style |= NumberStyles.AllowHexSpecifier; value = value.Substring(2); } } if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier) return TryParseNum(value, 16, out result); return TryParseNum(value, 10, out result); } public static bool TryParseNum(string digits, int radix, out FixedBigInteger result) { result = new FixedBigInteger(0, DataBitWidth); if (digits == null) return false; var multiplier = new FixedBigInteger(1, DataBitWidth); digits = digits.ToUpper(CultureInfo.CurrentCulture).Trim(); var nDigits = digits[0] == '-' ? 1 : 0; for (var idx = digits.Length - 1; idx >= nDigits; idx--) { var d = (int) digits[idx]; if (d >= '0' && d <= '9') d -= '0'; else if (d >= 'A' && d <= 'Z') d = d - 'A' + 10; else return false; if (d >= radix) return false; result += multiplier * d; multiplier *= radix; } if (digits[0] == '-') result = -result; return true; } public static int Compare(FixedBigInteger left, object right) { if (right is FixedBigInteger) return Compare(left, (FixedBigInteger) right); if (right is bool) return Compare(left, new FixedBigInteger((bool) right, DataBitWidth)); if (right is byte) return Compare(left, new FixedBigInteger((byte) right, DataBitWidth)); if (right is char) return Compare(left, new FixedBigInteger((char) right, DataBitWidth)); if (right is decimal) return Compare(left, new FixedBigInteger((decimal) right, DataBitWidth)); if (right is double) return Compare(left, new FixedBigInteger((double) right, DataBitWidth)); if (right is short) return Compare(left, new FixedBigInteger((short) right, DataBitWidth)); if (right is int) return Compare(left, new FixedBigInteger((int) right, DataBitWidth)); if (right is long) return Compare(left, new FixedBigInteger((long) right, DataBitWidth)); if (right is sbyte) return Compare(left, new FixedBigInteger((sbyte) right, DataBitWidth)); if (right is float) return Compare(left, new FixedBigInteger((float) right, DataBitWidth)); if (right is ushort) return Compare(left, new FixedBigInteger((ushort) right, DataBitWidth)); if (right is uint) return Compare(left, new FixedBigInteger((uint) right, DataBitWidth)); if (right is ulong) return Compare(left, new FixedBigInteger((ulong) right, DataBitWidth)); var bytes = right as byte[]; if (bytes != null) return Compare(left, new FixedBigInteger(bytes, DataBitWidth)); if (right is Guid) return Compare(left, new FixedBigInteger((Guid) right, DataBitWidth)); throw new ArgumentException(); } public static int Compare(FixedBigInteger left, FixedBigInteger right) { MakeLikeLengths(ref left, ref right); if (ReferenceEquals(left, right)) return 0; if (left.Sign >= 0 && right.Sign < 0) return 1; if (left.Sign < 0 && right.Sign >= 0) return -1; for (var i = left.Data.Length - 1; i > 0; i--) if (left.Data[i] != right.Data[i]) return left.Data[i].CompareTo(right.Data[i]); return left.Data[0].CompareTo(right.Data[0]); } public static implicit operator FixedBigInteger(bool value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(byte value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(char value) { return new FixedBigInteger(value, DataBitWidth); } public static explicit operator FixedBigInteger(decimal value) { return new FixedBigInteger(value, DataBitWidth); } public static explicit operator FixedBigInteger(double value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(short value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(int value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(long value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(sbyte value) { return new FixedBigInteger(value, DataBitWidth); } public static explicit operator FixedBigInteger(float value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(ushort value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(uint value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(ulong value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(BigInteger value) { return new FixedBigInteger(value, DataBitWidth); } public static implicit operator FixedBigInteger(BigDecimal value) { return new FixedBigInteger(value, DataBitWidth); } public static explicit operator bool(FixedBigInteger value) { return (byte) value.Data[0] != 0; } public static explicit operator byte(FixedBigInteger value) { return (byte) value.Data[0]; } public static explicit operator char(FixedBigInteger value) { return (char) (ushort) value.Data[0]; } public static explicit operator decimal(FixedBigInteger value) { if (value.Sign == 0) return 0; if (value.Data.Length == 1) return new decimal((int) value.Data[0], 0, 0, value.Sign < 0, 0); if (value.Data.Length == 2) return new decimal((int) value.Data[0], (int) value.Data[1], 0, value.Sign < 0, 0); if (value.Data.Length == 3) return new decimal((int) value.Data[0], (int) value.Data[1], (int) value.Data[2], value.Sign < 0, 0); throw new ArgumentException("Value length exceeds decimal length."); } public static explicit operator double(FixedBigInteger value) { if (value.Sign == 0) return 0; var nfi = CultureInfo.InvariantCulture.NumberFormat; if (!double.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var d)) throw new OverflowException(); return d; } public static explicit operator float(FixedBigInteger value) { if (value.Sign == 0) return 0; var nfi = CultureInfo.InvariantCulture.NumberFormat; if (!float.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var f)) throw new OverflowException(); return f; } public static explicit operator short(FixedBigInteger value) { if (value.Data[0] > 0x8000) throw new OverflowException(); if (value.Data[0] == 0x8000 && value.Sign > 0) throw new OverflowException(); return (short) ((int) value.Data[0] * value.Sign); } public static explicit operator int(FixedBigInteger value) { if (value.Sign == 0) return 0; return (int) value.Data[0] * value.Sign; } public static explicit operator long(FixedBigInteger value) { if (value.Sign == 0) return 0; if (value.Data[0] > int.MaxValue) throw new OverflowException(); if (value.Data.Length > 1) if (value.Data[1] != 0) return (long) (((ulong) value.Data[1] << 32) | value.Data[0]) * value.Sign; return value.Data[0] * value.Sign; } public static explicit operator uint(FixedBigInteger value) { if (value.Sign == 0) return 0; return value.Data[0]; } public static explicit operator ushort(FixedBigInteger value) { if (value.Sign == 0) return 0; return (ushort) value.Data[0]; } public static explicit operator ulong(FixedBigInteger value) { if (value.Data.Length > 1) if (value.Data[1] != 0) return ((ulong) value.Data[1] << 32) | value.Data[0]; return value.Data[0]; } public static explicit operator BigInteger(FixedBigInteger value) { return new BigInteger(value.ToByteArray()); } public static bool operator >(FixedBigInteger left, FixedBigInteger right) { return left.CompareTo(right) > 0; } private static void MakeLikeLengths(ref FixedBigInteger left, ref FixedBigInteger right) { if (left.Data.Length != right.Data.Length) { var len = Math.Max(left.Data.Length, right.Data.Length); Resize(ref left, len); Resize(ref right, len); } } private static void Resize(ref FixedBigInteger value, int newSize) { var IsNeg = value.IsNegative; var nData = new uint[newSize]; var len = value.Data.Length; for (var i = 0; i < len; i++) { nData[i] = value.Data[i]; if (IsNeg && i == len - 1) nData[i] &= ~HiNeg; } if (IsNeg) nData[nData.Length - 1] |= HiNeg; value.Data = (uint[]) nData.Clone(); } public static bool operator <(FixedBigInteger left, FixedBigInteger right) { return Compare(left, right) < 0; } public static bool operator >=(FixedBigInteger left, FixedBigInteger right) { return Compare(left, right) >= 0; } public static bool operator <=(FixedBigInteger left, FixedBigInteger right) { return Compare(left, right) <= 0; } public static bool operator !=(FixedBigInteger left, FixedBigInteger right) { return !left.Equals(right); } public static bool operator ==(FixedBigInteger left, FixedBigInteger right) { return left.Equals(right); } public static FixedBigInteger operator +(FixedBigInteger value) { return value; } public static FixedBigInteger operator ~(FixedBigInteger value) { var da = new uint[DataLength]; for (var idx = 0; idx < DataLength; idx++) da[idx] = ~value.Data[idx]; return new FixedBigInteger(da, DataBitWidth); } public static FixedBigInteger operator -(FixedBigInteger value) { if (ReferenceEquals(value, null)) throw new ArgumentNullException("value"); if (value.IsZero) return Zero; var da = new uint[DataLength]; for (var i = 0; i < da.Length; i++) da[i] = ~value.Data[i]; var carry = true; var index = 0; while (carry && index < da.Length) { var val = (long) da[index] + 1; da[index] = (uint) (val & AllBits); carry = val >> DataSizeBits > 0; index++; } return new FixedBigInteger(da, DataBitWidth); } public static FixedBigInteger operator ++(FixedBigInteger value) { return value + 1; } public static FixedBigInteger operator --(FixedBigInteger value) { return value - 1; } public static FixedBigInteger Negate(FixedBigInteger value) { var ldata = (uint[]) value.Data.Clone(); for (var i = 0; i < value.Data.Length; i++) ldata[i] = ~value.Data[i]; return new FixedBigInteger(value.Sign, ldata, DataBitWidth); } public static FixedBigInteger operator +(FixedBigInteger left, FixedBigInteger right) { if (right.IsZero) return left; if (left.IsZero) return right; MakeLikeLengths(ref left, ref right); var dl = left.Data.Length > right.Data.Length ? left.Data.Length : right.Data.Length; var result = new uint[dl]; long carry = 0; for (var i = 0; i < dl; i++) { var sum = left.Data[i] + (long) right.Data[i] + carry; carry = sum >> 32; result[i] = (uint) (sum & 0xFFFFFFFF); } if (carry != 0) { var idx = 0; while (idx < result.Length - 1) { if (result[idx] == 0) break; idx++; } result[idx] = (uint) carry; } return new FixedBigInteger(left.Sign * right.Sign, result, DataBitWidth); } public static FixedBigInteger operator -(FixedBigInteger left, FixedBigInteger right) { if (right.IsZero) return left; if (left.IsZero) return -right; MakeLikeLengths(ref left, ref right); var da = new uint[DataLength]; long carry = 0; for (var i = 0; i < DataLength && i < left.Data.Length && i < right.Data.Length; i++) { var diff = left.Data[i] - (long) right.Data[i] - carry; da[i] = (uint) (diff & AllBits); carry = diff < 0 ? 1 : 0; } return new FixedBigInteger(da, DataBitWidth); } public static FixedBigInteger Add(FixedBigInteger left, FixedBigInteger right) { return left + right; } public static FixedBigInteger Subtract(FixedBigInteger left, FixedBigInteger right) { return left - right; } public static FixedBigInteger Divide(FixedBigInteger dividend, FixedBigInteger divisor) { if (divisor == 0) throw new DivideByZeroException(); return DivRem(dividend, divisor, out var integer); } public static void Divide(FixedBigInteger dividend, FixedBigInteger divisor, out FixedBigInteger remainder, out FixedBigInteger quotient) { if (divisor == 0) throw new DivideByZeroException(); DivRem(dividend.Data, divisor.Data, out var quo, out var rem); remainder = new FixedBigInteger(1, rem, DataBitWidth); quotient = new FixedBigInteger(dividend.Sign * divisor.Sign, quo, DataBitWidth); } public static FixedBigInteger DivRem(FixedBigInteger dividend, FixedBigInteger divisor, out FixedBigInteger remainder) { if (divisor == 0) throw new DivideByZeroException(); DivRem(dividend.Data, divisor.Data, out var quotient, out var rem); remainder = new FixedBigInteger(1, rem, DataBitWidth); return new FixedBigInteger(dividend.Sign * divisor.Sign, quotient, DataBitWidth); } private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder) { const ulong hiBit = 0x100000000; var divisorLen = GetLength(divisor); var dividendLen = GetLength(dividend); if (divisorLen <= 1) { ulong rem = 0; var div = divisor[0]; quotient = new uint[dividendLen]; remainder = new uint[1]; for (var i = dividendLen - 1; i >= 0; i--) { rem *= hiBit; rem += dividend[i]; var q = rem / div; rem -= q * div; quotient[i] = (uint) q; } remainder[0] = (uint) rem; return; } if (dividendLen >= divisorLen) { var shift = GetNormalizeShift(divisor[divisorLen - 1]); var normDividend = new uint[dividendLen + 1]; var normDivisor = new uint[divisorLen]; Normalize(dividend, dividendLen, normDividend, shift); Normalize(divisor, divisorLen, normDivisor, shift); quotient = new uint[dividendLen - divisorLen + 1]; for (var j = dividendLen - divisorLen; j >= 0; j--) { var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1]; var qj = dx / normDivisor[divisorLen - 1]; dx -= qj * normDivisor[divisorLen - 1]; do { if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2]) break; qj -= 1L; dx += normDivisor[divisorLen - 1]; } while (dx < hiBit); ulong di = 0; ulong dj; var index = 0; while (index < divisorLen) { var dqj = normDivisor[index] * qj; dj = normDividend[index + j] - (uint) dqj - di; normDividend[index + j] = (uint) dj; dqj = dqj >> 32; dj = dj >> 32; di = dqj - dj; index++; } dj = normDividend[j + divisorLen] - di; normDividend[j + divisorLen] = (uint) dj; quotient[j] = (uint) qj; if ((long) dj < 0) { quotient[j]--; ulong sum = 0; for (index = 0; index < divisorLen; index++) { sum = normDivisor[index] + normDividend[j + index] + sum; normDividend[j + index] = (uint) sum; sum = sum >> 32; } sum += normDividend[j + divisorLen]; normDividend[j + divisorLen] = (uint) sum; } } remainder = Unnormalize(normDividend, shift); return; } quotient = new uint[1]; remainder = dividend; } private static int GetLength(uint[] uints) { var index = uints.Length - 1; while (index >= 0 && uints[index] == 0) index--; return index + 1; } private static int GetNormalizeShift(uint ui) { var shift = 0; if ((ui & 0xffff0000) == 0) { ui = ui << 16; shift += 16; } if ((ui & 0xff000000) == 0) { ui = ui << 8; shift += 8; } if ((ui & 0xf0000000) == 0) { ui = ui << 4; shift += 4; } if ((ui & 0xc0000000) == 0) { ui = ui << 2; shift += 2; } if ((ui & 0x80000000) == 0) shift++; return shift; } private static uint[] Unnormalize(uint[] normalized, int shift) { var len = GetLength(normalized); var unnormalized = new uint[len]; if (shift > 0) { var rshift = 32 - shift; uint r = 0; for (var i = len - 1; i >= 0; i--) { unnormalized[i] = (normalized[i] >> shift) | r; r = normalized[i] << rshift; } } else { for (var j = 0; j < len; j++) unnormalized[j] = normalized[j]; } return unnormalized; } private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift) { int i; uint n = 0; if (shift > 0) { var rShift = 32 - shift; for (i = 0; i < len; i++) { normalized[i] = (unormalized[i] << shift) | n; n = unormalized[i] >> rShift; } } else { i = 0; while (i < len) { normalized[i] = unormalized[i]; i++; } } while (i < normalized.Length) normalized[i++] = 0; if (n != 0) normalized[len] = n; } public static FixedBigInteger Remainder(FixedBigInteger dividend, FixedBigInteger divisor) { DivRem(dividend, divisor, out var remainder); return remainder; } public static FixedBigInteger Max(FixedBigInteger left, FixedBigInteger right) { return left.CompareTo(right) < 0 ? right : left; } public static FixedBigInteger Min(FixedBigInteger left, FixedBigInteger right) { return left.CompareTo(right) <= 0 ? left : right; } public static int GetBitWidth(FixedBigInteger n) { FixedBigInteger bw = 1; var v = n; while ((v >>= 1) > 0) bw++; if (bw < 8) bw = 8; while (bw % 8 != 0) bw++; return (int) bw; } public static int GetBitWidth<T>(T n) { ulong bw = 1; dynamic v = new FixedBigInteger((dynamic) n, 0); while ((v >>= 1) > 0) bw++; if (bw < 8) bw = 8; while (bw % 8 != 0) bw++; return (int) bw; } public static FixedBigInteger operator %(FixedBigInteger dividend, FixedBigInteger divisor) { return Remainder(dividend, divisor); } public static FixedBigInteger operator /(FixedBigInteger dividend, FixedBigInteger divisor) { return Divide(dividend, divisor); } public ulong[] ToUIn64Array() { var al = Data.Length >> 1; if (al * 2 != Data.Length) al++; var arr = new ulong[al]; Buffer.BlockCopy(Data, 0, arr, 0, Data.Length << 2); return arr; } public uint[] ToUIn32Array() { return Data; } public byte[] ToByteArray() { var ba = new byte[DataUsed * DataSize]; Buffer.BlockCopy(Data, 0, ba, 0, DataUsed * DataSize); return ba; } private void TrimToMsb() { var dataUsed = Data.Length; while (dataUsed > 1 && Data[dataUsed - 1] == 0) --dataUsed; if (dataUsed != Data.Length) { var tData = new uint[dataUsed]; for (var i = 0; i < dataUsed; i++) tData[i] = Data[i]; Data = (uint[]) tData.Clone(); } } public static FixedBigInteger Multiply(FixedBigInteger left, FixedBigInteger right) { if (left == 0 || right == 0) return Zero; if (left == 1 && right != 1) return right; if (left != 1 && right == 1) return left; if (left == 1 && right == 1) return One; var xInts = left.Data; var yInts = right.Data; var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1]; for (var i = 0; i < xInts.Length; i++) { var index = i; ulong remainder = 0; foreach (var yi in yInts) { remainder = remainder + (ulong) xInts[i] * yi + mulInts[index]; mulInts[index++] = (uint) remainder; remainder = remainder >> 32; } while (remainder != 0) { remainder += mulInts[index]; mulInts[index++] = (uint) remainder; remainder = remainder >> 32; } } var du = GetDataUsed(mulInts); Array.Resize(ref mulInts, du); return new FixedBigInteger(left.Sign * right.Sign, mulInts); } public static FixedBigInteger operator *(FixedBigInteger left, FixedBigInteger right) { return Multiply(left, right); } public static FixedBigInteger operator >>(FixedBigInteger value, int shift) { if (shift == 0) return value; if (shift == int.MinValue) return value << int.MaxValue << 1; if (shift < 0) return value << -shift; var xd = value.Data; var shiftAmount = 32; var invShift = 0; var bufLen = xd.Length; while (bufLen > 1 && xd[bufLen - 1] == 0) bufLen--; for (var count = shift; count > 0; count -= shiftAmount) { if (count < shiftAmount) { shiftAmount = count; invShift = 32 - shiftAmount; } ulong carry = 0; for (var i = bufLen - 1; i >= 0; i--) { var val = (ulong) xd[i] >> shiftAmount; val |= carry; carry = (ulong) xd[i] << invShift; xd[i] = (uint) val; } } return new FixedBigInteger(value.Sign, xd, DataBitWidth); } public static FixedBigInteger operator <<(FixedBigInteger value, int shift) { if (shift == 0) return value; if (shift == int.MinValue) return value >> int.MaxValue >> 1; if (shift < 0) return value >> -shift; var digitShift = shift / 32; var smallShift = shift - digitShift * 32; var xd = value.Data; var xl = xd.Length; var zd = new uint[xl + digitShift + 1]; if (smallShift == 0) { for (var index = 0; index < xl; ++index) zd[index + digitShift] = xd[index]; } else { var carryShift = 32 - smallShift; uint carry = 0; int index; for (index = 0; index < xl; ++index) { var rot = xd[index]; zd[index + digitShift] = (rot << smallShift) | carry; carry = rot >> carryShift; } zd[index + digitShift] = carry; } return new FixedBigInteger(value.Sign, zd, DataBitWidth); } public static FixedBigInteger operator |(FixedBigInteger left, FixedBigInteger right) { if (left == 0) return right; if (right == 0) return left; var z = new uint[Math.Max(left.Data.Length, right.Data.Length)]; var lExt = left.Sign < 0 ? uint.MaxValue : 0U; var rExt = right.Sign < 0 ? uint.MaxValue : 0U; for (var i = 0; i < z.Length; i++) { var xu = i < left.Data.Length ? left.Data[i] : lExt; var yu = i < right.Data.Length ? right.Data[i] : rExt; z[i] = xu | yu; } return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth); } public static FixedBigInteger operator ^(FixedBigInteger left, FixedBigInteger right) { var z = new uint[Math.Max(left.Data.Length, right.Data.Length)]; var lExt = left.Sign < 0 ? uint.MaxValue : 0U; var rExt = right.Sign < 0 ? uint.MaxValue : 0U; for (var i = 0; i < z.Length; i++) { var xu = i < left.Data.Length ? left.Data[i] : lExt; var yu = i < right.Data.Length ? right.Data[i] : rExt; z[i] = xu ^ yu; } return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth); } public static FixedBigInteger operator &(FixedBigInteger left, FixedBigInteger right) { if (left == 0 || right == 0) return 0; var z = new uint[Math.Max(left.Data.Length, right.Data.Length)]; var lExt = left.Sign < 0 ? uint.MaxValue : 0U; var rExt = right.Sign < 0 ? uint.MaxValue : 0U; for (var i = 0; i < z.Length; i++) { var xu = i < left.Data.Length ? left.Data[i] : lExt; var yu = i < right.Data.Length ? right.Data[i] : rExt; z[i] = xu & yu; } return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth); } public FixedBigInteger Sqrt() { var n = this; var q = One << ((int) Math.Ceiling(Log(n, 2)) >> 1); var steps = 0; var m = Zero; while (Abs(q - m) >= 1) { m = q; q = (m + n / m) >> 1; steps++; } return q; } public FixedBigInteger Pow(int e) { var ans = this; if (e == 1) return ans; if (e == 0) return 1; for (var i = 1; i != e; i++) ans *= this; return ans; } public static FixedBigInteger ModPow(FixedBigInteger n, FixedBigInteger e, FixedBigInteger m) { var n1 = new BigIntX(n); var e1 = new BigIntX(e); var m1 = new BigIntX(m); var r = new BigIntX(1); while (e1 != 0) { if (e1 % 2 == 1) r = r * n1 % m1; e1 >>= 1; n1 = n1 * n1 % m1; } return new FixedBigInteger(r.ToByteArray(), DataBitWidth); } public bool Fermat(FixedBigInteger candidate) { uint[] wits = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}; var pmo = candidate - 1; for (var i = 0; i < wits.Length; i++) { var r = ModPow(wits[i], pmo, candidate); if (r != One) return false; } return true; } private static bool MillerRabin(FixedBigInteger candidate) { uint[] w = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}; var s = 0; var d = candidate - One; while ((d & 1) == 0) { d >>= 1; ++s; } if (s == 0) return false; var nmo = candidate - One; for (var i = 0; i < w.Length; ++i) { var x = ModPow(w[i], nmo, candidate); if (!(x == 1) && !(x == nmo)) { for (var r = 1; r < s; ++r) { x = ModPow(x, 2, candidate); if (x == 1) return false; if (x == nmo) break; } if (!(x == nmo)) return false; } } return true; } public bool IsPrime() { return MillerRabin(this); } public static double Log(FixedBigInteger value, double baseValue) { var c = 0.0; var d = 0.5; //var dataLength = Length(value.Data); var dataLength = value.Data[value.Data.Length - 1] != 0U ? value.Data.Length : value.Data.Length - 1; var topBits = 0; //BitLengthOfUInt(value.Data[dataLength - 1]); var x = value.Data[dataLength - 1]; while (x > 0) { x >>= 1; topBits++; } var bitLength = (dataLength - 1) * 32 + topBits; var bit = (uint) (1 << (topBits - 1)); for (var index = dataLength - 1; index >= 0; --index) { for (; bit != 0U; bit >>= 1) { if (((int) value.Data[index] & (int) bit) != 0) c += d; d *= 0.5; } bit = 2147483648U; } return (Math.Log(c) + 0.69314718055994530941723212145818 * bitLength) / Math.Log(baseValue); } public static List<FixedBigInteger> GetFactors(FixedBigInteger n) { var Factors = new List<FixedBigInteger>(); var s = n.Sqrt(); var a = Three; while (a < s) { if (n % a == 0) { Factors.Add(a); if (a * a != n) Factors.Add(n / a); } a += 2; } return Factors; } public static FixedBigInteger GreatestCommonDivisor(FixedBigInteger a, FixedBigInteger b) { while (b > 0) { var r = a % b; a = b; b = r; } return a; } public static FixedBigInteger LeastCommonMultiple(FixedBigInteger a, FixedBigInteger b) { return a * b / a.Gcd(b); } public static double Log10(FixedBigInteger value) { return Log(value, 10.0); } public static double LogN(FixedBigInteger value) { return Log(value, 2.0); } private class FixedBigIntegerConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value != null) if (TryParse($"{value}", out var i)) return i; return new FixedBigInteger(0, DataBitWidth); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return destinationType == typeof(string) || base.CanConvertTo(context, destinationType); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType); } } } public class FixedBigIntegerComparer : IComparer<FixedBigInteger> { public int Compare(FixedBigInteger left, FixedBigInteger right) { return left.CompareTo(right); } public bool Equals(FixedBigInteger left, FixedBigInteger right) { if (left == null || right == null) return false; return left.Equals(right); } public int GetHashCode(FixedBigInteger obj) { return obj.GetHashCode(); } }
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(FixedBigIntegerConverter))]
[DebuggerDisplay("{DDisplay}")]
public class FixedBigInteger : IComparable<FixedBigInteger>, IComparable, IEquatable<FixedBigInteger>, IConvertible, IFormattable, ISerializable
{
    private const          int               DefaultDataBitWidth = 2048;
    private const          int               DataSize            = sizeof(uint);
    private const          int               DataShiftCount      = 5;
    private const          uint              AllBits             = ~(uint) 0;
    private const          int               DataSizeBits        = sizeof(uint) * 8;
    private const          uint              HiNeg               = (uint) 1 << (DataSizeBits - 1);
    private static         int               DataBitWidth;
    private static         int               DataLength;
    public static readonly FixedBigInteger   One   = new FixedBigInteger(1,  DataBitWidth);
    public static readonly FixedBigInteger   Two   = new FixedBigInteger(2,  DataBitWidth);
    public static readonly FixedBigInteger   Zero  = new FixedBigInteger(0,  DataBitWidth);
    public static readonly FixedBigInteger   Ten   = new FixedBigInteger(10, DataBitWidth);
    public static readonly FixedBigInteger   Three = new FixedBigInteger(3,  DataBitWidth);
    private readonly       SerializationInfo SInfo;
    public                 uint[]            Data;
    public FixedBigInteger(FixedBigInteger value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        CalculateMinDataLength(value.Data.Length);
        Data = new uint[DataLength];
        value.Data.CopyTo(Data, 0);
    }
    public FixedBigInteger(string value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        if (!TryParse(value, out var result))
            throw new Exception("TryParse Failed.");
        CalculateMinDataLength(result.Data.Length);
        Data = new uint[DataLength];
        result.Data.CopyTo(Data, 0);
    }
    public FixedBigInteger(byte value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[0]      = value;
    }
    public FixedBigInteger(bool value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[0]      = (uint) (value ? 1 : 0);
    }
    public FixedBigInteger(char value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[0]      = value;
    }
    public FixedBigInteger(BigDecimal value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        var ba = value.WholePart.ToByteArray();
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        var len = ba.Length / DataSize;
        CalculateMinDataLength(len);
        Data = new uint[DataLength];
        for (var i = 0; i < Data.Length; i++)
            Data[i] = BitConverter.ToUInt32(ba, i * DataSize);
    }
    public FixedBigInteger(decimal value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        CalculateMinDataLength(3);
        Data = new uint[DataLength];
        if (value < 0)
        {
            var n = -new FixedBigInteger(-value, DataBitWidth);
            n.Data.CopyTo(Data, 0);
            return;
        }
        var bits = decimal.GetBits(value);
        Data[2] = (uint) bits[2];
        Data[1] = (uint) bits[1];
        Data[0] = (uint) bits[0];
    }
    public FixedBigInteger(double value, int bitLength = 0) : this((decimal) value, bitLength)
    {
    }
    public FixedBigInteger(float value, int bitLength = 0) : this((decimal) value, bitLength)
    {
    }
    public FixedBigInteger(short value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        if (value < 0)
        {
            var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
            n.Data.CopyTo(Data, 0);
            return;
        }
        Data[0] = (uint) value;
    }
    public FixedBigInteger()
    {
        DataBitWidth = DefaultDataBitWidth;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[0]      = 0;
    }
    public FixedBigInteger(int value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        if (value < 0)
        {
            var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
            n.Data.CopyTo(Data, 0);
            return;
        }
        Data[0] = (uint) value;
    }
    public FixedBigInteger(long value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 64)
            bitLength = 64;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        if (value < 0)
        {
            var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
            n.Data.CopyTo(Data, 0);
            return;
        }
        Data[1] = (uint) ((value >> 32) & 0xffffffff);
        Data[0] = (uint) (value         & 0xffffffff);
    }
    public FixedBigInteger(sbyte value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        if (value < 0)
        {
            var n = -new FixedBigInteger(-(value + 1), DataBitWidth) - 1;
            n.Data.CopyTo(Data, 0);
            return;
        }
        Data[0] = (uint) value;
    }
    public FixedBigInteger(ushort value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[0]      = value;
    }
    public FixedBigInteger(uint value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 32)
            bitLength = 32;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[0]      = value;
    }
    public FixedBigInteger(ulong value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        if (bitLength < 96)
            bitLength = 96;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        Data         = new uint[DataLength];
        Data[1]      = (uint) ((value >> 32) & 0xffffffff);
        Data[0]      = (uint) (value         & 0xffffffff);
    }
    public FixedBigInteger(BigInteger value, int bitLength = 0) : this(value.ToByteArray(), bitLength)
    {
    }
    public FixedBigInteger(Guid value, int bitLength = 0) : this(value.ToByteArray(), bitLength)
    {
    }
    public FixedBigInteger(byte[] value, int bitLength = 0)
    {
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        var minSize = value.Length / DataSize;
        if (value == null)
            throw new ArgumentNullException("value");
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        CalculateMinDataLength(minSize);
        var byteCount      = value.Length;
        var isNegative     = byteCount > 0 && (value[byteCount - 1] & 0x80) == 0x80;
        var unalignedBytes = byteCount % DataSize;
        var dwordCount     = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1);
        Data = new uint[Math.Max(dwordCount, DataLength)];
        if (byteCount == 0)
            return;
        int curDword, curByte, byteInDword;
        curByte = 3;
        for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
        {
            byteInDword = 0;
            while (byteInDword < DataSize)
            {
                Data[curDword] <<= 8;
                Data[curDword] |=  value[curByte];
                curByte--;
                byteInDword++;
            }
            curByte += 8;
        }
        if (unalignedBytes != 0)
        {
            if (isNegative)
                Data[dwordCount - 1] = 0xffffffff;
            for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
            {
                Data[curDword] <<= 8;
                Data[curDword] |=  value[curByte];
            }
        }
    }
    public FixedBigInteger(int sign, uint[] array, int bitLength = 0)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        CalculateMinDataLength(array.Length);
        if (array.Length != DataLength)
            Array.Resize(ref array, DataLength);
        Data = new uint[DataLength];
        var ba = new byte[DataSize];
        for (var i = 0; i < Data.Length; i++)
        {
            Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
            Data[i] = BitConverter.ToUInt32(ba, 0);
        }
        if (sign < 0)
            Data[DataLength - 1] |= HiNeg;
        else
            Data[DataLength - 1] &= ~HiNeg;
    }
    public FixedBigInteger(uint[] array, int bitLength = 0)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        if (bitLength == 0)
            bitLength = DefaultDataBitWidth;
        DataBitWidth = bitLength;
        DataLength   = DataBitWidth >> DataShiftCount;
        if (array.Length != DataLength)
            Array.Resize(ref array, DataLength);
        Data = new uint[DataLength];
        var ba = new byte[DataSize];
        for (var i = 0; i < Data.Length; i++)
        {
            Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
            Data[i] = BitConverter.ToUInt32(ba, 0);
        }
    }
    protected FixedBigInteger(SerializationInfo info, StreamingContext context)
    {
        SInfo = info;
    }
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();
    public FixedBigInteger MaxValue
    {
        get
        {
            var r = new FixedBigInteger(0, DataBitWidth);
            for (var i = 0; i < r.Data.Length; ++i)
                r.Data[i] = uint.MaxValue;
            r.Data[r.Data.Length - 1] = int.MaxValue;
            return r;
        }
    }
    public int BitWidth
    {
        get
        {
            FixedBigInteger bw = 1;
            var             v  = new FixedBigInteger(this);
            while ((v >>= 1) > 0)
                bw++;
            if (bw < 8)
                bw = 8;
            while (bw % 8 != 0)
                bw++;
            return (int) bw;
        }
    }
    public int Sign
    {
        get
        {
            var allZero = true;
            var ba      = Data;
            for (var i = 0; i < ba.Length; i++)
                if (ba[i] != 0)
                {
                    allZero = false;
                    break;
                }
            if (allZero)
                return 0;
            return (Data[Data.Length - 1] & HiNeg) == 0 ? 1 : -1;
        }
    }
    public bool IsOne      => this       == 1;
    public bool IsEven     => (this & 1) == 0;
    public bool IsNegative => Sign       < 0;
    public bool IsZero
    {
        get
        {
            for (var i = 0; i < Data.Length; i++)
                if (Data[i] != 0)
                    return false;
            return true;
        }
    }
    public int DataUsed
    {
        get
        {
            var DataUsed = Data.Length;
            if (!IsNegative)
            {
                while (DataUsed > 1 && Data[DataUsed - 1] == 0)
                    --DataUsed;
                if (DataUsed == 0)
                    DataUsed = 1;
            }
            return DataUsed;
        }
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public int CompareTo(FixedBigInteger value)
    {
        return Compare(this, value);
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (long) this;
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        if (Data[1] != 0)
            throw new OverflowException();
        return Convert.ToUInt16(Data[0]);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        if (Data[1] != 0)
            throw new OverflowException();
        return Convert.ToUInt32(Data[0]);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        if (Data[1] != 0)
            return ((ulong) Data[1] << 32) | Data[0];
        return Data[0];
    }
    public bool Equals(FixedBigInteger obj)
    {
        if (ReferenceEquals(obj, null))
            return false;
        if (ReferenceEquals(this, obj))
            return true;
        if (Data.Length != obj.Data.Length)
        {
            var len = Math.Max(Data.Length, obj.Data.Length);
            if (Data.Length < len)
            {
                var tData = new uint[len];
                Array.Copy(Data, 0, tData, 0, Data.Length);
                Data = tData;
            }
            if (obj.Data.Length < len)
                Resize(ref obj, len);
        }
        if (Sign != obj.Sign)
            return false;
        for (var i = 0; i < Data.Length; i++)
            if (Data[i] != obj.Data[i])
                return false;
        return true;
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int.TryParse(format.Substring(1).Trim(), out var min);
                return ToHexString(ch == 'X');
            }
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)), 10);
    }
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Bits", DataBitWidth);
        info.AddValue("Data", Data, typeof(uint[]));
    }
    private static void CalculateMinDataLength(int minSize)
    {
        if (minSize > DataLength)
        {
            DataBitWidth = 32 * minSize;
            DataLength   = minSize;
        }
    }
    public void OnDeserialization(object sender)
    {
        if (SInfo == null)
            return;
        DataBitWidth = SInfo.GetInt32("Bits");
        if (DataBitWidth != 0)
        {
            DataLength = DataBitWidth >> DataShiftCount;
            var array = (uint[]) SInfo.GetValue("Data", typeof(uint[]));
            if (array == null)
                throw new Exception("Array cannot be null.");
            if (array.Length != DataLength)
                Array.Resize(ref array, DataLength);
            Data = new uint[DataLength];
            var ba = new byte[4];
            for (var i = 0; i < DataLength; i++)
            {
                Array.Copy(BitConverter.GetBytes(array[i]), 0, ba, 0, DataSize);
                Data[i] = BitConverter.ToUInt32(ba, 0);
            }
        }
    }
    public static int GetSign(uint[] value)
    {
        var allZero = true;
        for (var i = 0; i < value.Length; i++)
            if (value[i] != 0)
            {
                allZero = false;
                break;
            }
        if (allZero)
            return 0;
        return (value[value.Length - 1] & HiNeg) == 0 ? 1 : -1;
    }
    private static int GetDataUsed(uint[] array)
    {
        var neg      = GetSign(array) < 0;
        var DataUsed = array.Length;
        if (!neg)
        {
            while (DataUsed > 1 && array[DataUsed - 1] == 0)
                --DataUsed;
            if (DataUsed == 0)
                DataUsed = 1;
        }
        return DataUsed;
    }
    public int GetDecimalPlaces()
    {
        var dPlaces = 0;
        if (Sign == 0)
            return 1;
        var a = new FixedBigInteger(this);
        if (Sign < 0)
            try
            {
                a = -a;
            }
            catch (Exception ex)
            {
                return 0;
            }
        var biRadix = new FixedBigInteger(10, DataBitWidth);
        while (a > 0)
            try
            {
                Divide(a, biRadix, out var remainder, out var quotient);
                a = quotient;
                dPlaces++;
            }
            catch (Exception ex)
            {
                break;
            }
        return dPlaces;
    }
    private uint[] TwosComplement(uint[] d)
    {
        var  i = 0;
        uint v = 0;
        for (; i < d.Length; i++)
        {
            v    = ~d[i] + 1;
            d[i] = v;
            if (v != 0)
            {
                i++;
                break;
            }
        }
        if (v != 0)
        {
            for (; i < d.Length; i++)
                d[i] = ~d[i];
        }
        else
        {
            Array.Resize(ref d, d.Length + 1);
            d[d.Length - 1] = 1;
        }
        return d;
    }
    public void ConstructFromArray(byte[] array)
    {
        if (array == null)
            throw new ArgumentNullException("value");
        var byteCount      = array.Length;
        var isNegative     = byteCount > 0 && (array[byteCount - 1] & 0x80) == 0x80;
        var unalignedBytes = byteCount % DataSize;
        var dwordCount     = byteCount / DataSize + (unalignedBytes == 0 ? 0 : 1);
        Data = new uint[Math.Max(dwordCount, DataLength)];
        if (byteCount == 0)
            return;
        int curDword, curByte, byteInDword;
        curByte = 3;
        for (curDword = 0; curDword < dwordCount - (unalignedBytes == 0 ? 0 : 1); curDword++)
        {
            byteInDword = 0;
            while (byteInDword < DataSize)
            {
                Data[curDword] <<= 8;
                Data[curDword] |=  array[curByte];
                curByte--;
                byteInDword++;
            }
            curByte += 8;
        }
        if (unalignedBytes != 0)
        {
            if (isNegative)
                Data[dwordCount - 1] = 0xffffffff;
            for (curByte = byteCount - 1; curByte >= byteCount - unalignedBytes; curByte--)
            {
                Data[curDword] <<= 8;
                Data[curDword] |=  array[curByte];
            }
        }
    }
    private static byte[] ToByteArray(ulong[] value)
    {
        var ba = new byte[value.Length << 3];
        Buffer.BlockCopy(value, 0, ba, 0, value.Length << 3);
        return ba;
    }
    private static byte[] ToByteArray(uint[] value)
    {
        var ba = new byte[value.Length << 2];
        Buffer.BlockCopy(value, 0, ba, 0, value.Length << 2);
        return ba;
    }
    public override int GetHashCode()
    {
        var hash = 0x811c9dc5;
        for (var i = 0; i < Data.Length; i++)
        {
            hash ^= ((hash << 13) | (hash >> 19)) ^ Data[i];
            hash *= 0x1000193;
        }
        return (int) hash;
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    public string ToHexString(bool caps)
    {
        var bytes = ToByteArray().Invert();
        var sb    = new StringBuilder();
        var x     = caps ? "X" : "x";
        foreach (var b in bytes)
        {
            var hex = b.ToString($"{x}2");
            sb.Append(hex);
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info, int radix)
    {
        if (radix < 2 || radix > 36)
            throw new ArgumentOutOfRangeException("radix");
        if (Sign == 0)
            return "0";
        var negative = Sign < 0;
        var a        = new FixedBigInteger(this);
        if (negative)
            try
            {
                a = -a;
            }
            catch (Exception ex)
            {
            }
        var          biRadix = new FixedBigInteger(radix, DataBitWidth);
        const string charSet = "0123456789abcdefghijklmnopqrstuvwxyz";
        var          al      = new ArrayList();
        while (a > 0)
            try
            {
                Divide(a, biRadix, out var remainder, out var quotient);
                al.Insert(0, charSet[(int) remainder.Data[0]]);
                a = quotient;
            }
            catch (Exception ex)
            {
                break;
            }
        var result = new string((char[]) al.ToArray(typeof(char)));
        if (radix == 10 && negative)
            return "-" + result;
        return result;
    }
    public static FixedBigInteger Abs(FixedBigInteger value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        if (value.Sign < 0)
            return -value;
        return value;
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    public static FixedBigInteger Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static FixedBigInteger Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static FixedBigInteger Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static FixedBigInteger Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        if (!TryParse(value, style, provider, out var result))
            throw new Exception($"TryParse value {value} failure.");
        return result;
    }
    public static bool TryParse(string value, out FixedBigInteger result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out FixedBigInteger result)
    {
        result = 0;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value =  value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value =  value.Substring(2);
            }
        }
        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseNum(value, 16, out result);
        return TryParseNum(value, 10, out result);
    }
    public static bool TryParseNum(string digits, int radix, out FixedBigInteger result)
    {
        result = new FixedBigInteger(0, DataBitWidth);
        if (digits == null)
            return false;
        var multiplier = new FixedBigInteger(1, DataBitWidth);
        digits = digits.ToUpper(CultureInfo.CurrentCulture).Trim();
        var nDigits = digits[0] == '-' ? 1 : 0;
        for (var idx = digits.Length - 1; idx >= nDigits; idx--)
        {
            var d = (int) digits[idx];
            if (d >= '0' && d <= '9')
                d -= '0';
            else if (d >= 'A' && d <= 'Z')
                d = d - 'A' + 10;
            else
                return false;
            if (d >= radix)
                return false;
            result     += multiplier * d;
            multiplier *= radix;
        }
        if (digits[0] == '-')
            result = -result;
        return true;
    }
    public static int Compare(FixedBigInteger left, object right)
    {
        if (right is FixedBigInteger)
            return Compare(left, (FixedBigInteger) right);
        if (right is bool)
            return Compare(left, new FixedBigInteger((bool) right, DataBitWidth));
        if (right is byte)
            return Compare(left, new FixedBigInteger((byte) right, DataBitWidth));
        if (right is char)
            return Compare(left, new FixedBigInteger((char) right, DataBitWidth));
        if (right is decimal)
            return Compare(left, new FixedBigInteger((decimal) right, DataBitWidth));
        if (right is double)
            return Compare(left, new FixedBigInteger((double) right, DataBitWidth));
        if (right is short)
            return Compare(left, new FixedBigInteger((short) right, DataBitWidth));
        if (right is int)
            return Compare(left, new FixedBigInteger((int) right, DataBitWidth));
        if (right is long)
            return Compare(left, new FixedBigInteger((long) right, DataBitWidth));
        if (right is sbyte)
            return Compare(left, new FixedBigInteger((sbyte) right, DataBitWidth));
        if (right is float)
            return Compare(left, new FixedBigInteger((float) right, DataBitWidth));
        if (right is ushort)
            return Compare(left, new FixedBigInteger((ushort) right, DataBitWidth));
        if (right is uint)
            return Compare(left, new FixedBigInteger((uint) right, DataBitWidth));
        if (right is ulong)
            return Compare(left, new FixedBigInteger((ulong) right, DataBitWidth));
        var bytes = right as byte[];
        if (bytes != null)
            return Compare(left, new FixedBigInteger(bytes, DataBitWidth));
        if (right is Guid)
            return Compare(left, new FixedBigInteger((Guid) right, DataBitWidth));
        throw new ArgumentException();
    }
    public static int Compare(FixedBigInteger left, FixedBigInteger right)
    {
        MakeLikeLengths(ref left, ref right);
        if (ReferenceEquals(left, right))
            return 0;
        if (left.Sign >= 0 && right.Sign < 0)
            return 1;
        if (left.Sign < 0 && right.Sign >= 0)
            return -1;
        for (var i = left.Data.Length - 1; i > 0; i--)
            if (left.Data[i] != right.Data[i])
                return left.Data[i].CompareTo(right.Data[i]);
        return left.Data[0].CompareTo(right.Data[0]);
    }
    public static implicit operator FixedBigInteger(bool value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(byte value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(char value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static explicit operator FixedBigInteger(decimal value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static explicit operator FixedBigInteger(double value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(short value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(int value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(long value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(sbyte value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static explicit operator FixedBigInteger(float value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(ushort value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(uint value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(ulong value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(BigInteger value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static implicit operator FixedBigInteger(BigDecimal value)
    {
        return new FixedBigInteger(value, DataBitWidth);
    }
    public static explicit operator bool(FixedBigInteger value)
    {
        return (byte) value.Data[0] != 0;
    }
    public static explicit operator byte(FixedBigInteger value)
    {
        return (byte) value.Data[0];
    }
    public static explicit operator char(FixedBigInteger value)
    {
        return (char) (ushort) value.Data[0];
    }
    public static explicit operator decimal(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Data.Length == 1)
            return new decimal((int) value.Data[0], 0, 0, value.Sign < 0, 0);
        if (value.Data.Length == 2)
            return new decimal((int) value.Data[0], (int) value.Data[1], 0, value.Sign < 0, 0);
        if (value.Data.Length == 3)
            return new decimal((int) value.Data[0], (int) value.Data[1], (int) value.Data[2], value.Sign < 0, 0);
        throw new ArgumentException("Value length exceeds decimal length.");
    }
    public static explicit operator double(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi, 10), NumberStyles.Number, nfi, out var f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(FixedBigInteger value)
    {
        if (value.Data[0] > 0x8000)
            throw new OverflowException();
        if (value.Data[0] == 0x8000 && value.Sign > 0)
            throw new OverflowException();
        return (short) ((int) value.Data[0] * value.Sign);
    }
    public static explicit operator int(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        return (int) value.Data[0] * value.Sign;
    }
    public static explicit operator long(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        if (value.Data[0] > int.MaxValue)
            throw new OverflowException();
        if (value.Data.Length > 1)
            if (value.Data[1] != 0)
                return (long) (((ulong) value.Data[1] << 32) | value.Data[0]) * value.Sign;
        return value.Data[0] * value.Sign;
    }
    public static explicit operator uint(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        return value.Data[0];
    }
    public static explicit operator ushort(FixedBigInteger value)
    {
        if (value.Sign == 0)
            return 0;
        return (ushort) value.Data[0];
    }
    public static explicit operator ulong(FixedBigInteger value)
    {
        if (value.Data.Length > 1)
            if (value.Data[1] != 0)
                return ((ulong) value.Data[1] << 32) | value.Data[0];
        return value.Data[0];
    }
    public static explicit operator BigInteger(FixedBigInteger value)
    {
        return new BigInteger(value.ToByteArray());
    }
    public static bool operator >(FixedBigInteger left, FixedBigInteger right)
    {
        return left.CompareTo(right) > 0;
    }
    private static void MakeLikeLengths(ref FixedBigInteger left, ref FixedBigInteger right)
    {
        if (left.Data.Length != right.Data.Length)
        {
            var len = Math.Max(left.Data.Length, right.Data.Length);
            Resize(ref left,  len);
            Resize(ref right, len);
        }
    }
    private static void Resize(ref FixedBigInteger value, int newSize)
    {
        var IsNeg = value.IsNegative;
        var nData = new uint[newSize];
        var len   = value.Data.Length;
        for (var i = 0; i < len; i++)
        {
            nData[i] = value.Data[i];
            if (IsNeg && i == len - 1)
                nData[i] &= ~HiNeg;
        }
        if (IsNeg)
            nData[nData.Length - 1] |= HiNeg;
        value.Data = (uint[]) nData.Clone();
    }
    public static bool operator <(FixedBigInteger left, FixedBigInteger right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(FixedBigInteger left, FixedBigInteger right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(FixedBigInteger left, FixedBigInteger right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(FixedBigInteger left, FixedBigInteger right)
    {
        return !left.Equals(right);
    }
    public static bool operator ==(FixedBigInteger left, FixedBigInteger right)
    {
        return left.Equals(right);
    }
    public static FixedBigInteger operator +(FixedBigInteger value)
    {
        return value;
    }
    public static FixedBigInteger operator ~(FixedBigInteger value)
    {
        var da = new uint[DataLength];
        for (var idx = 0; idx < DataLength; idx++)
            da[idx] = ~value.Data[idx];
        return new FixedBigInteger(da, DataBitWidth);
    }
    public static FixedBigInteger operator -(FixedBigInteger value)
    {
        if (ReferenceEquals(value, null))
            throw new ArgumentNullException("value");
        if (value.IsZero)
            return Zero;
        var da = new uint[DataLength];
        for (var i = 0; i < da.Length; i++)
            da[i] = ~value.Data[i];
        var carry = true;
        var index = 0;
        while (carry && index < da.Length)
        {
            var val = (long) da[index] + 1;
            da[index] = (uint) (val & AllBits);
            carry     = val >> DataSizeBits > 0;
            index++;
        }
        return new FixedBigInteger(da, DataBitWidth);
    }
    public static FixedBigInteger operator ++(FixedBigInteger value)
    {
        return value + 1;
    }
    public static FixedBigInteger operator --(FixedBigInteger value)
    {
        return value - 1;
    }
    public static FixedBigInteger Negate(FixedBigInteger value)
    {
        var ldata = (uint[]) value.Data.Clone();
        for (var i = 0; i < value.Data.Length; i++)
            ldata[i] = ~value.Data[i];
        return new FixedBigInteger(value.Sign, ldata, DataBitWidth);
    }
    public static FixedBigInteger operator +(FixedBigInteger left, FixedBigInteger right)
    {
        if (right.IsZero)
            return left;
        if (left.IsZero)
            return right;
        MakeLikeLengths(ref left, ref right);
        var  dl     = left.Data.Length > right.Data.Length ? left.Data.Length : right.Data.Length;
        var  result = new uint[dl];
        long carry  = 0;
        for (var i = 0; i < dl; i++)
        {
            var sum = left.Data[i] + (long) right.Data[i] + carry;
            carry     = sum >> 32;
            result[i] = (uint) (sum & 0xFFFFFFFF);
        }
        if (carry != 0)
        {
            var idx = 0;
            while (idx < result.Length - 1)
            {
                if (result[idx] == 0)
                    break;
                idx++;
            }
            result[idx] = (uint) carry;
        }
        return new FixedBigInteger(left.Sign * right.Sign, result, DataBitWidth);
    }
    public static FixedBigInteger operator -(FixedBigInteger left, FixedBigInteger right)
    {
        if (right.IsZero)
            return left;
        if (left.IsZero)
            return -right;
        MakeLikeLengths(ref left, ref right);
        var  da    = new uint[DataLength];
        long carry = 0;
        for (var i = 0; i < DataLength && i < left.Data.Length && i < right.Data.Length; i++)
        {
            var diff = left.Data[i] - (long) right.Data[i] - carry;
            da[i] = (uint) (diff & AllBits);
            carry = diff < 0 ? 1 : 0;
        }
        return new FixedBigInteger(da, DataBitWidth);
    }
    public static FixedBigInteger Add(FixedBigInteger left, FixedBigInteger right)
    {
        return left + right;
    }
    public static FixedBigInteger Subtract(FixedBigInteger left, FixedBigInteger right)
    {
        return left - right;
    }
    public static FixedBigInteger Divide(FixedBigInteger dividend, FixedBigInteger divisor)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        return DivRem(dividend, divisor, out var integer);
    }
    public static void Divide(FixedBigInteger dividend, FixedBigInteger divisor, out FixedBigInteger remainder, out FixedBigInteger quotient)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.Data, divisor.Data, out var quo, out var rem);
        remainder = new FixedBigInteger(1,                            rem, DataBitWidth);
        quotient  = new FixedBigInteger(dividend.Sign * divisor.Sign, quo, DataBitWidth);
    }
    public static FixedBigInteger DivRem(FixedBigInteger dividend, FixedBigInteger divisor, out FixedBigInteger remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.Data, divisor.Data, out var quotient, out var rem);
        remainder = new FixedBigInteger(1, rem, DataBitWidth);
        return new FixedBigInteger(dividend.Sign * divisor.Sign, quotient, DataBitWidth);
    }
    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit       = 0x100000000;
        var         divisorLen  = GetLength(divisor);
        var         dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var   div = divisor[0];
            quotient  = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem         -= q * div;
                quotient[i] =  (uint) q;
            }
            remainder[0] = (uint) rem;
            return;
        }
        if (dividendLen >= divisorLen)
        {
            var shift        = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor  = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor,  divisorLen,  normDivisor,  shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen                                        - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);
                ulong di = 0;
                ulong dj;
                var   index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj                      = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj                     = dqj >> 32;
                    dj                      = dj  >> 32;
                    di                      = dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if ((long) dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum                     = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum                     = sum >> 32;
                    }
                    sum += normDividend[j + divisorLen];
                    normDividend[j        + divisorLen] = (uint) sum;
                }
            }
            remainder = Unnormalize(normDividend, shift);
            return;
        }
        quotient  = new uint[1];
        remainder = dividend;
    }
    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }
    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui    =  ui << 16;
            shift += 16;
        }
        if ((ui & 0xff000000) == 0)
        {
            ui    =  ui << 8;
            shift += 8;
        }
        if ((ui & 0xf0000000) == 0)
        {
            ui    =  ui << 4;
            shift += 4;
        }
        if ((ui & 0xc0000000) == 0)
        {
            ui    =  ui << 2;
            shift += 2;
        }
        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }
    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len          = GetLength(normalized);
        var unnormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unnormalized[i] = (normalized[i] >> shift) | r;
                r               = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unnormalized[j] = normalized[j];
        }
        return unnormalized;
    }
    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int  i;
        uint n = 0;
        if (shift > 0)
        {
            var rShift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n             = unormalized[i] >> rShift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }
        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }
    public static FixedBigInteger Remainder(FixedBigInteger dividend, FixedBigInteger divisor)
    {
        DivRem(dividend, divisor, out var remainder);
        return remainder;
    }
    public static FixedBigInteger Max(FixedBigInteger left, FixedBigInteger right)
    {
        return left.CompareTo(right) < 0 ? right : left;
    }
    public static FixedBigInteger Min(FixedBigInteger left, FixedBigInteger right)
    {
        return left.CompareTo(right) <= 0 ? left : right;
    }
    public static int GetBitWidth(FixedBigInteger n)
    {
        FixedBigInteger bw = 1;
        var             v  = n;
        while ((v >>= 1) > 0)
            bw++;
        if (bw < 8)
            bw = 8;
        while (bw % 8 != 0)
            bw++;
        return (int) bw;
    }
    public static int GetBitWidth<T>(T n)
    {
        ulong   bw = 1;
        dynamic v  = new FixedBigInteger((dynamic) n, 0);
        while ((v >>= 1) > 0)
            bw++;
        if (bw < 8)
            bw = 8;
        while (bw % 8 != 0)
            bw++;
        return (int) bw;
    }
    public static FixedBigInteger operator %(FixedBigInteger dividend, FixedBigInteger divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static FixedBigInteger operator /(FixedBigInteger dividend, FixedBigInteger divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        var al = Data.Length >> 1;
        if (al * 2 != Data.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(Data, 0, arr, 0, Data.Length << 2);
        return arr;
    }
    public uint[] ToUIn32Array()
    {
        return Data;
    }
    public byte[] ToByteArray()
    {
        var ba = new byte[DataUsed * DataSize];
        Buffer.BlockCopy(Data, 0, ba, 0, DataUsed * DataSize);
        return ba;
    }
    private void TrimToMsb()
    {
        var dataUsed = Data.Length;
        while (dataUsed > 1 && Data[dataUsed - 1] == 0)
            --dataUsed;
        if (dataUsed != Data.Length)
        {
            var tData = new uint[dataUsed];
            for (var i = 0; i < dataUsed; i++)
                tData[i] = Data[i];
            Data = (uint[]) tData.Clone();
        }
    }
    public static FixedBigInteger Multiply(FixedBigInteger left, FixedBigInteger right)
    {
        if (left == 0 || right == 0)
            return Zero;
        if (left == 1 && right != 1)
            return right;
        if (left != 1 && right == 1)
            return left;
        if (left == 1 && right == 1)
            return One;
        var xInts   = left.Data;
        var yInts   = right.Data;
        var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1];
        for (var i = 0; i < xInts.Length; i++)
        {
            var   index     = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder        = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder        = remainder >> 32;
            }
            while (remainder != 0)
            {
                remainder        += mulInts[index];
                mulInts[index++] =  (uint) remainder;
                remainder        =  remainder >> 32;
            }
        }
        var du = GetDataUsed(mulInts);
        Array.Resize(ref mulInts, du);
        return new FixedBigInteger(left.Sign * right.Sign, mulInts);
    }
    public static FixedBigInteger operator *(FixedBigInteger left, FixedBigInteger right)
    {
        return Multiply(left, right);
    }
    public static FixedBigInteger operator >>(FixedBigInteger value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift == int.MinValue)
            return value << int.MaxValue << 1;
        if (shift < 0)
            return value << -shift;
        var xd          = value.Data;
        var shiftAmount = 32;
        var invShift    = 0;
        var bufLen      = xd.Length;
        while (bufLen > 1 && xd[bufLen - 1] == 0)
            bufLen--;
        for (var count = shift; count > 0; count -= shiftAmount)
        {
            if (count < shiftAmount)
            {
                shiftAmount = count;
                invShift    = 32 - shiftAmount;
            }
            ulong carry = 0;
            for (var i = bufLen - 1; i >= 0; i--)
            {
                var val = (ulong) xd[i] >> shiftAmount;
                val   |= carry;
                carry =  (ulong) xd[i] << invShift;
                xd[i] =  (uint) val;
            }
        }
        return new FixedBigInteger(value.Sign, xd, DataBitWidth);
    }
    public static FixedBigInteger operator <<(FixedBigInteger value, int shift)
    {
        if (shift == 0)
            return value;
        if (shift == int.MinValue)
            return value >> int.MaxValue >> 1;
        if (shift < 0)
            return value >> -shift;
        var digitShift = shift / 32;
        var smallShift = shift - digitShift * 32;
        var xd         = value.Data;
        var xl         = xd.Length;
        var zd         = new uint[xl + digitShift + 1];
        if (smallShift == 0)
        {
            for (var index = 0; index < xl; ++index)
                zd[index + digitShift] = xd[index];
        }
        else
        {
            var  carryShift = 32 - smallShift;
            uint carry      = 0;
            int  index;
            for (index = 0; index < xl; ++index)
            {
                var rot = xd[index];
                zd[index + digitShift] = (rot << smallShift) | carry;
                carry                  = rot >> carryShift;
            }
            zd[index + digitShift] = carry;
        }
        return new FixedBigInteger(value.Sign, zd, DataBitWidth);
    }
    public static FixedBigInteger operator |(FixedBigInteger left, FixedBigInteger right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var z    = new uint[Math.Max(left.Data.Length, right.Data.Length)];
        var lExt = left.Sign  < 0 ? uint.MaxValue : 0U;
        var rExt = right.Sign < 0 ? uint.MaxValue : 0U;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < left.Data.Length ? left.Data[i] : lExt;
            var yu = i < right.Data.Length ? right.Data[i] : rExt;
            z[i] = xu | yu;
        }
        return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth);
    }
    public static FixedBigInteger operator ^(FixedBigInteger left, FixedBigInteger right)
    {
        var z    = new uint[Math.Max(left.Data.Length, right.Data.Length)];
        var lExt = left.Sign  < 0 ? uint.MaxValue : 0U;
        var rExt = right.Sign < 0 ? uint.MaxValue : 0U;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < left.Data.Length ? left.Data[i] : lExt;
            var yu = i < right.Data.Length ? right.Data[i] : rExt;
            z[i] = xu ^ yu;
        }
        return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth);
    }
    public static FixedBigInteger operator &(FixedBigInteger left, FixedBigInteger right)
    {
        if (left == 0 || right == 0)
            return 0;
        var z    = new uint[Math.Max(left.Data.Length, right.Data.Length)];
        var lExt = left.Sign  < 0 ? uint.MaxValue : 0U;
        var rExt = right.Sign < 0 ? uint.MaxValue : 0U;
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < left.Data.Length ? left.Data[i] : lExt;
            var yu = i < right.Data.Length ? right.Data[i] : rExt;
            z[i] = xu & yu;
        }
        return new FixedBigInteger(left.Sign * right.Sign, z, DataBitWidth);
    }
    public FixedBigInteger Sqrt()
    {
        var n     = this;
        var q     = One << ((int) Math.Ceiling(Log(n, 2)) >> 1);
        var steps = 0;
        var m     = Zero;
        while (Abs(q - m) >= 1)
        {
            m = q;
            q = (m + n / m) >> 1;
            steps++;
        }
        return q;
    }
    public FixedBigInteger Pow(int e)
    {
        var ans = this;
        if (e == 1)
            return ans;
        if (e == 0)
            return 1;
        for (var i = 1; i != e; i++)
            ans *= this;
        return ans;
    }
    public static FixedBigInteger ModPow(FixedBigInteger n, FixedBigInteger e, FixedBigInteger m)
    {
        var n1 = new BigIntX(n);
        var e1 = new BigIntX(e);
        var m1 = new BigIntX(m);
        var r  = new BigIntX(1);
        while (e1 != 0)
        {
            if (e1 % 2 == 1)
                r = r * n1 % m1;
            e1 >>= 1;
            n1 =   n1 * n1 % m1;
        }
        return new FixedBigInteger(r.ToByteArray(), DataBitWidth);
    }
    public bool Fermat(FixedBigInteger candidate)
    {
        uint[] wits = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
        var    pmo  = candidate - 1;
        for (var i = 0; i < wits.Length; i++)
        {
            var r = ModPow(wits[i], pmo, candidate);
            if (r != One)
                return false;
        }
        return true;
    }
    private static bool MillerRabin(FixedBigInteger candidate)
    {
        uint[] w = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41};
        var    s = 0;
        var    d = candidate - One;
        while ((d & 1) == 0)
        {
            d >>= 1;
            ++s;
        }
        if (s == 0)
            return false;
        var nmo = candidate - One;
        for (var i = 0; i < w.Length; ++i)
        {
            var x = ModPow(w[i], nmo, candidate);
            if (!(x == 1) && !(x == nmo))
            {
                for (var r = 1; r < s; ++r)
                {
                    x = ModPow(x, 2, candidate);
                    if (x == 1)
                        return false;
                    if (x == nmo)
                        break;
                }
                if (!(x == nmo))
                    return false;
            }
        }
        return true;
    }
    public bool IsPrime()
    {
        return MillerRabin(this);
    }
    public static double Log(FixedBigInteger value, double baseValue)
    {
        var c = 0.0;
        var d = 0.5;
        //var dataLength = Length(value.Data);
        var dataLength = value.Data[value.Data.Length - 1] != 0U ? value.Data.Length : value.Data.Length - 1;
        var topBits    = 0; //BitLengthOfUInt(value.Data[dataLength - 1]);
        var x          = value.Data[dataLength - 1];
        while (x > 0)
        {
            x >>= 1;
            topBits++;
        }
        var bitLength = (dataLength - 1) * 32 + topBits;
        var bit       = (uint) (1 << (topBits - 1));
        for (var index = dataLength - 1; index >= 0; --index)
        {
            for (; bit != 0U; bit >>= 1)
            {
                if (((int) value.Data[index] & (int) bit) != 0)
                    c += d;
                d *= 0.5;
            }
            bit = 2147483648U;
        }
        return (Math.Log(c) + 0.69314718055994530941723212145818 * bitLength) / Math.Log(baseValue);
    }
    public static List<FixedBigInteger> GetFactors(FixedBigInteger n)
    {
        var Factors = new List<FixedBigInteger>();
        var s       = n.Sqrt();
        var a       = Three;
        while (a < s)
        {
            if (n % a == 0)
            {
                Factors.Add(a);
                if (a * a != n)
                    Factors.Add(n / a);
            }
            a += 2;
        }
        return Factors;
    }
    public static FixedBigInteger GreatestCommonDivisor(FixedBigInteger a, FixedBigInteger b)
    {
        while (b > 0)
        {
            var r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
    public static FixedBigInteger LeastCommonMultiple(FixedBigInteger a, FixedBigInteger b)
    {
        return a * b / a.Gcd(b);
    }
    public static double Log10(FixedBigInteger value)
    {
        return Log(value, 10.0);
    }
    public static double LogN(FixedBigInteger value)
    {
        return Log(value, 2.0);
    }
    private class FixedBigIntegerConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
                if (TryParse($"{value}", out var i))
                    return i;
            return new FixedBigInteger(0, DataBitWidth);
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType);
        }
    }
}
public class FixedBigIntegerComparer : IComparer<FixedBigInteger>
{
    public int Compare(FixedBigInteger left, FixedBigInteger right)
    {
        return left.CompareTo(right);
    }
    public bool Equals(FixedBigInteger left, FixedBigInteger right)
    {
        if (left == null || right == null)
            return false;
        return left.Equals(right);
    }
    public int GetHashCode(FixedBigInteger obj)
    {
        return obj.GetHashCode();
    }
}

Random64.cs

64 Bit RNG using RngJitterSource.cs

Updated: Dec-26,2020

Example Code:
Add a 256x256 panel to a form.
var lrng = new Random64(65536, 256, 2);
var g = panel1.CreateGraphics();
var bm = new Bitmap(256, 256);
var buf = lrng.GetNextBoolArrayLimit(65536);
var ptr = 0;
for (var y = 0; y < 256; y++)
for (var x = 0; x < 256; x++)
{
var r = buf[ptr++];
if (r)
{
bm.SetPixel(x, y, Color.White);
}
else
{
bm.SetPixel(x, y, Color.Black);
}
}
g.DrawImageUnscaled(bm, 0, 0);
Example Code: Add a 256x256 panel to a form. var lrng = new Random64(65536, 256, 2); var g = panel1.CreateGraphics(); var bm = new Bitmap(256, 256); var buf = lrng.GetNextBoolArrayLimit(65536); var ptr = 0; for (var y = 0; y < 256; y++) for (var x = 0; x < 256; x++) { var r = buf[ptr++]; if (r) { bm.SetPixel(x, y, Color.White); } else { bm.SetPixel(x, y, Color.Black); } } g.DrawImageUnscaled(bm, 0, 0);
Example Code:
Add a 256x256 panel to a form.

            var lrng = new Random64(65536, 256, 2);
            var g = panel1.CreateGraphics();
            var bm  = new Bitmap(256, 256);
            var buf = lrng.GetNextBoolArrayLimit(65536);
            var ptr = 0;
            for (var y = 0; y < 256; y++)
            for (var x = 0; x < 256; x++)
            {
                var r = buf[ptr++];
                if (r)
                {
                    bm.SetPixel(x, y, Color.White);
                }
                else
                {
                    bm.SetPixel(x, y, Color.Black);
                }
            }
            g.DrawImageUnscaled(bm, 0, 0);
using System;
using System.Security.Cryptography;
[Serializable]
public class Random64 : RandomNumberGenerator
{
private byte[] _buffer;
public RngJitterSource _crng;
private double _dBi;
private ulong UpperLimit = ulong.MaxValue;
public Random64()
{
SetDataUse = 8;
_crng = new RngJitterSource();
}
public Random64(int cacheSize)
{
SetDataUse = 8;
_crng = new RngJitterSource(cacheSize * 8, 256, 256, 4);
}
public Random64(int cacheSize, int seedSize)
{
SetDataUse = 8;
_crng = new RngJitterSource(cacheSize * 8, seedSize, 256, 4);
}
public Random64(int cacheSize, int seedSize, int dataSize, int sha3Size = 256, int sha3Rounds = 4)
{
SetDataUse = dataSize;
_crng = new RngJitterSource(cacheSize * dataSize, seedSize, sha3Size, sha3Rounds);
}
public int SetDataUse
{
get => _buffer.Length;
set
{
var v = value;
if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7)
throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8");
switch (v)
{
case 1:
_dBi = 1.0D / byte.MaxValue;
UpperLimit = byte.MaxValue;
_buffer = new byte[1];
break;
case 2:
_dBi = 1.0D / ushort.MaxValue;
UpperLimit = ushort.MaxValue;
_buffer = new byte[2];
break;
case 4:
_dBi = 1.0D / uint.MaxValue;
UpperLimit = uint.MaxValue;
_buffer = new byte[4];
break;
case 8:
_dBi = 1.0D / ulong.MaxValue;
UpperLimit = ulong.MaxValue;
_buffer = new byte[8];
break;
default:
_dBi = 1.0D / ulong.MaxValue;
UpperLimit = ulong.MaxValue;
_buffer = new byte[8];
break;
}
}
}
public bool OddsOnly
{
get;
set;
}
private double Sample()
{
ulong Internal()
{
_crng.GetBytes(_buffer);
return BufferToLong(_buffer);
}
return Internal() * _dBi;
}
public ulong Next(ulong minValue, ulong maxValue)
{
var sa = Sample();
var fi = (double) (maxValue - minValue + minValue);
var n = (ulong) (sa * fi);
n = !OddsOnly ? n : n | 1;
if (n < minValue)
return Next(minValue, maxValue);
return n;
}
public ulong Next(ulong maxValue)
{
return Next(0, maxValue);
}
public ulong Next()
{
return Next(0, UpperLimit);
}
public unsafe double NextDouble()
{
var buf = new byte[8];
GetBytes(buf);
fixed (byte* ptr = buf)
{
return *(ulong*) ptr * _dBi * ulong.MaxValue;
}
}
public char[] GetNextCharArray(int size)
{
var xbc = new byte[1];
var ca = new char[size];
var ptr = 0;
do
{
_crng.GetBytes(xbc);
var c = xbc[0];
if (c >= 32 && c <= 127)
ca[ptr++] = (char) c;
} while (ptr < size);
return ca;
}
public char[] GetNextCharArrayX(int size)
{
var xbc = new byte[2];
var ca = new char[size];
var ptr = 0;
do
{
_crng.GetBytes(xbc);
ca[ptr++] = Convert.ToChar(xbc.ToShort());
} while (ptr < size);
return ca;
}
public byte[] GetNextByteArray(int size)
{
var ba = new byte[size];
_crng.GetBytes(ba);
return ba;
}
public bool[] GetNextBoolArrayLimit(int size)
{
var ba = new bool[size];
const uint ll = uint.MaxValue >> 1;
for (var i = 0; i < size; ++i)
ba[i] = Next(0, uint.MaxValue) > ll;
return ba;
}
public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue)
{
var ba = new byte[size];
for (var i = 0; i < size; ++i)
ba[i] = (byte) Next(minValue, maxValue);
return ba;
}
public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue)
{
var ba = new ushort[size];
for (var i = 0; i < size; ++i)
ba[i] = (ushort) Next(minValue, maxValue);
return ba;
}
public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue)
{
var ba = new uint[size];
for (var i = 0; i < size; ++i)
ba[i] = (uint) Next(minValue, maxValue);
return ba;
}
public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue)
{
var ba = new ulong[size];
for (var i = 0; i < size; ++i)
ba[i] = Next(minValue, maxValue);
return ba;
}
public string GetRandomString(int minLen, int maxLen)
{
if (minLen == maxLen)
return new string(GetNextCharArray(minLen));
return new string(GetNextCharArray((int) Next((ulong) minLen, (ulong) maxLen)));
}
public override void GetBytes(byte[] data)
{
if (data == null)
throw new ArgumentException("The buffer cannot be null.");
_crng.GetBytes(data);
}
public void NextBytes(byte[] buffer)
{
if (buffer == null)
throw new ArgumentNullException("The buffer cannot be null.");
for (var index = 0; index < buffer.Length; ++index)
buffer[index] = (byte) (Sample() * byte.MaxValue + 1);
}
public override void GetNonZeroBytes(byte[] buffer)
{
if (buffer == null)
throw new ArgumentNullException("The buffer cannot be null.");
var index = 0;
do
{
var v = (byte) (Sample() * byte.MaxValue + 1);
if (v > 0)
{
buffer[index] = v;
index++;
}
} while (index < buffer.Length);
}
private unsafe ulong BufferToLong(byte[] buffer)
{
var len = buffer.Length;
if (len < 1 || len > 8)
throw new ArgumentException($"The array length {len} must be between 1 and 8");
fixed (byte* Ptr = &buffer[0])
{
switch (len)
{
case 1:
return *Ptr;
case 2:
return (uint) (*Ptr | (Ptr[1] << 8));
case 3:
return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16));
case 4:
return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24));
case 5:
return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) Ptr[4] << 32);
case 6:
return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8)) << 32);
case 7:
return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32);
case 8:
return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32);
default:
return 0;
}
}
}
}
using System; using System.Security.Cryptography; [Serializable] public class Random64 : RandomNumberGenerator { private byte[] _buffer; public RngJitterSource _crng; private double _dBi; private ulong UpperLimit = ulong.MaxValue; public Random64() { SetDataUse = 8; _crng = new RngJitterSource(); } public Random64(int cacheSize) { SetDataUse = 8; _crng = new RngJitterSource(cacheSize * 8, 256, 256, 4); } public Random64(int cacheSize, int seedSize) { SetDataUse = 8; _crng = new RngJitterSource(cacheSize * 8, seedSize, 256, 4); } public Random64(int cacheSize, int seedSize, int dataSize, int sha3Size = 256, int sha3Rounds = 4) { SetDataUse = dataSize; _crng = new RngJitterSource(cacheSize * dataSize, seedSize, sha3Size, sha3Rounds); } public int SetDataUse { get => _buffer.Length; set { var v = value; if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7) throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8"); switch (v) { case 1: _dBi = 1.0D / byte.MaxValue; UpperLimit = byte.MaxValue; _buffer = new byte[1]; break; case 2: _dBi = 1.0D / ushort.MaxValue; UpperLimit = ushort.MaxValue; _buffer = new byte[2]; break; case 4: _dBi = 1.0D / uint.MaxValue; UpperLimit = uint.MaxValue; _buffer = new byte[4]; break; case 8: _dBi = 1.0D / ulong.MaxValue; UpperLimit = ulong.MaxValue; _buffer = new byte[8]; break; default: _dBi = 1.0D / ulong.MaxValue; UpperLimit = ulong.MaxValue; _buffer = new byte[8]; break; } } } public bool OddsOnly { get; set; } private double Sample() { ulong Internal() { _crng.GetBytes(_buffer); return BufferToLong(_buffer); } return Internal() * _dBi; } public ulong Next(ulong minValue, ulong maxValue) { var sa = Sample(); var fi = (double) (maxValue - minValue + minValue); var n = (ulong) (sa * fi); n = !OddsOnly ? n : n | 1; if (n < minValue) return Next(minValue, maxValue); return n; } public ulong Next(ulong maxValue) { return Next(0, maxValue); } public ulong Next() { return Next(0, UpperLimit); } public unsafe double NextDouble() { var buf = new byte[8]; GetBytes(buf); fixed (byte* ptr = buf) { return *(ulong*) ptr * _dBi * ulong.MaxValue; } } public char[] GetNextCharArray(int size) { var xbc = new byte[1]; var ca = new char[size]; var ptr = 0; do { _crng.GetBytes(xbc); var c = xbc[0]; if (c >= 32 && c <= 127) ca[ptr++] = (char) c; } while (ptr < size); return ca; } public char[] GetNextCharArrayX(int size) { var xbc = new byte[2]; var ca = new char[size]; var ptr = 0; do { _crng.GetBytes(xbc); ca[ptr++] = Convert.ToChar(xbc.ToShort()); } while (ptr < size); return ca; } public byte[] GetNextByteArray(int size) { var ba = new byte[size]; _crng.GetBytes(ba); return ba; } public bool[] GetNextBoolArrayLimit(int size) { var ba = new bool[size]; const uint ll = uint.MaxValue >> 1; for (var i = 0; i < size; ++i) ba[i] = Next(0, uint.MaxValue) > ll; return ba; } public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new byte[size]; for (var i = 0; i < size; ++i) ba[i] = (byte) Next(minValue, maxValue); return ba; } public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new ushort[size]; for (var i = 0; i < size; ++i) ba[i] = (ushort) Next(minValue, maxValue); return ba; } public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new uint[size]; for (var i = 0; i < size; ++i) ba[i] = (uint) Next(minValue, maxValue); return ba; } public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue) { var ba = new ulong[size]; for (var i = 0; i < size; ++i) ba[i] = Next(minValue, maxValue); return ba; } public string GetRandomString(int minLen, int maxLen) { if (minLen == maxLen) return new string(GetNextCharArray(minLen)); return new string(GetNextCharArray((int) Next((ulong) minLen, (ulong) maxLen))); } public override void GetBytes(byte[] data) { if (data == null) throw new ArgumentException("The buffer cannot be null."); _crng.GetBytes(data); } public void NextBytes(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("The buffer cannot be null."); for (var index = 0; index < buffer.Length; ++index) buffer[index] = (byte) (Sample() * byte.MaxValue + 1); } public override void GetNonZeroBytes(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("The buffer cannot be null."); var index = 0; do { var v = (byte) (Sample() * byte.MaxValue + 1); if (v > 0) { buffer[index] = v; index++; } } while (index < buffer.Length); } private unsafe ulong BufferToLong(byte[] buffer) { var len = buffer.Length; if (len < 1 || len > 8) throw new ArgumentException($"The array length {len} must be between 1 and 8"); fixed (byte* Ptr = &buffer[0]) { switch (len) { case 1: return *Ptr; case 2: return (uint) (*Ptr | (Ptr[1] << 8)); case 3: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16)); case 4: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)); case 5: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) Ptr[4] << 32); case 6: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8)) << 32); case 7: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32); case 8: return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32); default: return 0; } } } }
using System;
using System.Security.Cryptography;
[Serializable]
public class Random64 : RandomNumberGenerator
{
    private byte[]          _buffer;
    public  RngJitterSource _crng;
    private double          _dBi;
    private ulong           UpperLimit = ulong.MaxValue;
    public Random64()
    {
        SetDataUse = 8;
        _crng      = new RngJitterSource();
    }
    public Random64(int cacheSize)
    {
        SetDataUse = 8;
        _crng      = new RngJitterSource(cacheSize * 8, 256, 256, 4);
    }
    public Random64(int cacheSize, int seedSize)
    {
        SetDataUse = 8;
        _crng      = new RngJitterSource(cacheSize * 8, seedSize, 256, 4);
    }
    public Random64(int cacheSize, int seedSize, int dataSize, int sha3Size = 256, int sha3Rounds = 4)
    {
        SetDataUse = dataSize;
        _crng      = new RngJitterSource(cacheSize * dataSize, seedSize, sha3Size, sha3Rounds);
    }
    public int SetDataUse
    {
        get => _buffer.Length;
        set
        {
            var v = value;
            if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7)
                throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8");
            switch (v)
            {
                case 1:
                    _dBi       = 1.0D / byte.MaxValue;
                    UpperLimit = byte.MaxValue;
                    _buffer    = new byte[1];
                    break;
                case 2:
                    _dBi       = 1.0D / ushort.MaxValue;
                    UpperLimit = ushort.MaxValue;
                    _buffer    = new byte[2];
                    break;
                case 4:
                    _dBi       = 1.0D / uint.MaxValue;
                    UpperLimit = uint.MaxValue;
                    _buffer    = new byte[4];
                    break;
                case 8:
                    _dBi       = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer    = new byte[8];
                    break;
                default:
                    _dBi       = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer    = new byte[8];
                    break;
            }
        }
    }
    public bool OddsOnly
    {
        get;
        set;
    }
    private double Sample()
    {
        ulong Internal()
        {
            _crng.GetBytes(_buffer);
            return BufferToLong(_buffer);
        }
        return Internal() * _dBi;
    }
    public ulong Next(ulong minValue, ulong maxValue)
    {
        var sa = Sample();
        var fi = (double) (maxValue - minValue + minValue);
        var n  = (ulong) (sa * fi);
        n = !OddsOnly ? n : n | 1;
        if (n < minValue)
            return Next(minValue, maxValue);
        return n;
    }
    public ulong Next(ulong maxValue)
    {
        return Next(0, maxValue);
    }
    public ulong Next()
    {
        return Next(0, UpperLimit);
    }
    public unsafe double NextDouble()
    {
        var buf = new byte[8];
        GetBytes(buf);
        fixed (byte* ptr = buf)
        {
            return *(ulong*) ptr * _dBi * ulong.MaxValue;
        }
    }
    public char[] GetNextCharArray(int size)
    {
        var xbc = new byte[1];
        var ca  = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            var c = xbc[0];
            if (c >= 32 && c <= 127)
                ca[ptr++] = (char) c;
        } while (ptr < size);
        return ca;
    }
    public char[] GetNextCharArrayX(int size)
    {
        var xbc = new byte[2];
        var ca  = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            ca[ptr++] = Convert.ToChar(xbc.ToShort());
        } while (ptr < size);
        return ca;
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _crng.GetBytes(ba);
        return ba;
    }
    public bool[] GetNextBoolArrayLimit(int size)
    {
        var        ba = new bool[size];
        const uint ll = uint.MaxValue >> 1;
        for (var i = 0; i < size; ++i)
            ba[i] = Next(0, uint.MaxValue) > ll;
        return ba;
    }
    public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new byte[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (byte) Next(minValue, maxValue);
        return ba;
    }
    public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ushort[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (ushort) Next(minValue, maxValue);
        return ba;
    }
    public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new uint[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (uint) Next(minValue, maxValue);
        return ba;
    }
    public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ulong[size];
        for (var i = 0; i < size; ++i)
            ba[i] = Next(minValue, maxValue);
        return ba;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int) Next((ulong) minLen, (ulong) maxLen)));
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public void NextBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        for (var index = 0; index < buffer.Length; ++index)
            buffer[index] = (byte) (Sample() * byte.MaxValue + 1);
    }
    public override void GetNonZeroBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        var index = 0;
        do
        {
            var v = (byte) (Sample() * byte.MaxValue + 1);
            if (v > 0)
            {
                buffer[index] = v;
                index++;
            }
        } while (index < buffer.Length);
    }
    private unsafe ulong BufferToLong(byte[] buffer)
    {
        var len = buffer.Length;
        if (len < 1 || len > 8)
            throw new ArgumentException($"The array length {len} must be between 1 and 8");
        fixed (byte* Ptr = &buffer[0])
        {
            switch (len)
            {
                case 1:
                    return *Ptr;
                case 2:
                    return (uint) (*Ptr | (Ptr[1] << 8));
                case 3:
                    return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16));
                case 4:
                    return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24));
                case 5:
                    return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) Ptr[4] << 32);
                case 6:
                    return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8)) << 32);
                case 7:
                    return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32);
                case 8:
                    return (uint) (*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong) (Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32);
                default:
                    return 0;
            }
        }
    }
}

JitterCacheRng.cs

using System;
using System.Security.Cryptography;
using System.Threading;
[Serializable]
public class JitterCacheRng : RandomNumberGenerator
{
private const int ReSecureThreshold = 10;
private readonly SHA3ModInt _algorithm;
private readonly JitterEx _jit;
private readonly int _moveSize;
private int _availableCacheBytes;
private byte[] _cache;
private byte[] _cacheBuffer;
private int _cacheSize;
private int _ptr;
public int cacheFills;
public JitterCacheRng() : this(1048576, 256, 256, 4)
{
}
public JitterCacheRng(int cacheSize) : this(cacheSize, 256, 256, 4)
{
}
public JitterCacheRng(int cacheSize, int seedSize) : this(cacheSize, seedSize, 256, 4)
{
}
public JitterCacheRng(int cacheSize, int seedSize, int sha3Size) : this(cacheSize, seedSize, sha3Size, 4)
{
}
public JitterCacheRng(int cacheSize, int seedSize, int sha3Size, int sha3Rounds)
{
if (cacheSize == 0)
throw new ArgumentException("Cache Size cannot be zero");
if (seedSize < 256)
throw new ArgumentException("The seed size should be 256 or more bytes.");
if (sha3Size < 64 && sha3Size % 64 != 0)
throw new ArgumentException("The bitWidth of the SHA3 hash algorithm need to be at least 64 bits and a multiple of 64.");
if (sha3Rounds < 4)
throw new ArgumentException("Sha3 rounds of less than 4 might produce some short run repetitive sequences.");
_cacheSize = cacheSize;
_jit = new JitterEx(seedSize);
_cacheBuffer = _jit.GetBuffer();
_cache = new byte[_cacheSize];
_algorithm = new SHA3ModInt(sha3Size, sha3Rounds);
_moveSize = _algorithm.ComputeHash(2.GetBytes()).Length;
FillCache();
}
public bool Protect
{
get;
set;
}
protected override void Dispose(bool disposing)
{
_cache.Fill(0);
_availableCacheBytes = 0;
_algorithm.Dispose();
}
public override void GetBytes(byte[] data)
{
if (data.Length > _cacheSize)
{
_cacheSize = data.Length;
_cache = new byte[_cacheSize];
FillCache();
}
if (_availableCacheBytes == 0 || _availableCacheBytes < data.Length)
{
if (_cacheSize < data.Length)
{
_cacheSize = data.Length;
_cache = new byte[_cacheSize];
}
FillCache();
}
if (_ptr + data.Length > _cacheSize)
FillCache();
if (Protect)
ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon);
Buffer.BlockCopy(_cache, _ptr, data, 0, data.Length);
if (Protect)
ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon);
_ptr += data.Length;
_availableCacheBytes -= data.Length;
}
private void FillCache()
{
var btrd = new Thread(() =>
{
_availableCacheBytes = 0;
_ptr = 0;
var p = 0;
var moveSize = _moveSize;
cacheFills++;
if (cacheFills % ReSecureThreshold == 0)
_cacheBuffer = _jit.GetBuffer();
if (Protect)
ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon);
while (true)
{
var remainingBytesToMove = _cacheSize - _availableCacheBytes;
if (remainingBytesToMove < moveSize)
moveSize = remainingBytesToMove;
if (remainingBytesToMove <= 0)
break;
_cacheBuffer = _algorithm.ComputeHash(_cacheBuffer);
Buffer.BlockCopy(_cacheBuffer, 0, _cache, p, moveSize);
p += moveSize;
_availableCacheBytes += moveSize;
}
if (Protect)
ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon);
}) {Priority = ThreadPriority.Highest};
btrd.Start();
btrd.Join();
}
}
using System; using System.Security.Cryptography; using System.Threading; [Serializable] public class JitterCacheRng : RandomNumberGenerator { private const int ReSecureThreshold = 10; private readonly SHA3ModInt _algorithm; private readonly JitterEx _jit; private readonly int _moveSize; private int _availableCacheBytes; private byte[] _cache; private byte[] _cacheBuffer; private int _cacheSize; private int _ptr; public int cacheFills; public JitterCacheRng() : this(1048576, 256, 256, 4) { } public JitterCacheRng(int cacheSize) : this(cacheSize, 256, 256, 4) { } public JitterCacheRng(int cacheSize, int seedSize) : this(cacheSize, seedSize, 256, 4) { } public JitterCacheRng(int cacheSize, int seedSize, int sha3Size) : this(cacheSize, seedSize, sha3Size, 4) { } public JitterCacheRng(int cacheSize, int seedSize, int sha3Size, int sha3Rounds) { if (cacheSize == 0) throw new ArgumentException("Cache Size cannot be zero"); if (seedSize < 256) throw new ArgumentException("The seed size should be 256 or more bytes."); if (sha3Size < 64 && sha3Size % 64 != 0) throw new ArgumentException("The bitWidth of the SHA3 hash algorithm need to be at least 64 bits and a multiple of 64."); if (sha3Rounds < 4) throw new ArgumentException("Sha3 rounds of less than 4 might produce some short run repetitive sequences."); _cacheSize = cacheSize; _jit = new JitterEx(seedSize); _cacheBuffer = _jit.GetBuffer(); _cache = new byte[_cacheSize]; _algorithm = new SHA3ModInt(sha3Size, sha3Rounds); _moveSize = _algorithm.ComputeHash(2.GetBytes()).Length; FillCache(); } public bool Protect { get; set; } protected override void Dispose(bool disposing) { _cache.Fill(0); _availableCacheBytes = 0; _algorithm.Dispose(); } public override void GetBytes(byte[] data) { if (data.Length > _cacheSize) { _cacheSize = data.Length; _cache = new byte[_cacheSize]; FillCache(); } if (_availableCacheBytes == 0 || _availableCacheBytes < data.Length) { if (_cacheSize < data.Length) { _cacheSize = data.Length; _cache = new byte[_cacheSize]; } FillCache(); } if (_ptr + data.Length > _cacheSize) FillCache(); if (Protect) ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon); Buffer.BlockCopy(_cache, _ptr, data, 0, data.Length); if (Protect) ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon); _ptr += data.Length; _availableCacheBytes -= data.Length; } private void FillCache() { var btrd = new Thread(() => { _availableCacheBytes = 0; _ptr = 0; var p = 0; var moveSize = _moveSize; cacheFills++; if (cacheFills % ReSecureThreshold == 0) _cacheBuffer = _jit.GetBuffer(); if (Protect) ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon); while (true) { var remainingBytesToMove = _cacheSize - _availableCacheBytes; if (remainingBytesToMove < moveSize) moveSize = remainingBytesToMove; if (remainingBytesToMove <= 0) break; _cacheBuffer = _algorithm.ComputeHash(_cacheBuffer); Buffer.BlockCopy(_cacheBuffer, 0, _cache, p, moveSize); p += moveSize; _availableCacheBytes += moveSize; } if (Protect) ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon); }) {Priority = ThreadPriority.Highest}; btrd.Start(); btrd.Join(); } }
using System;
using System.Security.Cryptography;
using System.Threading;
[Serializable]
public class JitterCacheRng : RandomNumberGenerator
{
    private const    int        ReSecureThreshold = 10;
    private readonly SHA3ModInt _algorithm;
    private readonly JitterEx   _jit;
    private readonly int        _moveSize;
    private          int        _availableCacheBytes;
    private          byte[]     _cache;
    private          byte[]     _cacheBuffer;
    private          int        _cacheSize;
    private          int        _ptr;
    public           int        cacheFills;
    public JitterCacheRng() : this(1048576, 256, 256, 4)
    {
    }
    public JitterCacheRng(int cacheSize) : this(cacheSize, 256, 256, 4)
    {
    }
    public JitterCacheRng(int cacheSize, int seedSize) : this(cacheSize, seedSize, 256, 4)
    {
    }
    public JitterCacheRng(int cacheSize, int seedSize, int sha3Size) : this(cacheSize, seedSize, sha3Size, 4)
    {
    }
    public JitterCacheRng(int cacheSize, int seedSize, int sha3Size, int sha3Rounds)
    {
        if (cacheSize == 0)
            throw new ArgumentException("Cache Size cannot be zero");
        if (seedSize < 256)
            throw new ArgumentException("The seed size should be 256 or more bytes.");
        if (sha3Size < 64 && sha3Size % 64 != 0)
            throw new ArgumentException("The bitWidth of the SHA3 hash algorithm need to be at least 64 bits and a multiple of 64.");
        if (sha3Rounds < 4)
            throw new ArgumentException("Sha3 rounds of less than 4 might produce some short run repetitive sequences.");
        _cacheSize   = cacheSize;
        _jit         = new JitterEx(seedSize);
        _cacheBuffer = _jit.GetBuffer();
        _cache       = new byte[_cacheSize];
        _algorithm   = new SHA3ModInt(sha3Size, sha3Rounds);
        _moveSize    = _algorithm.ComputeHash(2.GetBytes()).Length;
        FillCache();
    }
    public bool Protect
    {
        get;
        set;
    }
    protected override void Dispose(bool disposing)
    {
        _cache.Fill(0);
        _availableCacheBytes = 0;
        _algorithm.Dispose();
    }
    public override void GetBytes(byte[] data)
    {
        if (data.Length > _cacheSize)
        {
            _cacheSize = data.Length;
            _cache     = new byte[_cacheSize];
            FillCache();
        }
        if (_availableCacheBytes == 0 || _availableCacheBytes < data.Length)
        {
            if (_cacheSize < data.Length)
            {
                _cacheSize = data.Length;
                _cache     = new byte[_cacheSize];
            }
            FillCache();
        }
        if (_ptr + data.Length > _cacheSize)
            FillCache();
        if (Protect)
            ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon);
        Buffer.BlockCopy(_cache, _ptr, data, 0, data.Length);
        if (Protect)
            ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon);
        _ptr                 += data.Length;
        _availableCacheBytes -= data.Length;
    }
    private void FillCache()
    {
        var btrd = new Thread(() =>
        {
            _availableCacheBytes = 0;
            _ptr                 = 0;
            var p        = 0;
            var moveSize = _moveSize;
            cacheFills++;
            if (cacheFills % ReSecureThreshold == 0)
                _cacheBuffer = _jit.GetBuffer();
            if (Protect)
                ProtectedMemory.Unprotect(_cache, MemoryProtectionScope.SameLogon);
            while (true)
            {
                var remainingBytesToMove = _cacheSize - _availableCacheBytes;
                if (remainingBytesToMove < moveSize)
                    moveSize = remainingBytesToMove;
                if (remainingBytesToMove <= 0)
                    break;
                _cacheBuffer = _algorithm.ComputeHash(_cacheBuffer);
                Buffer.BlockCopy(_cacheBuffer, 0, _cache, p, moveSize);
                p                    += moveSize;
                _availableCacheBytes += moveSize;
            }
            if (Protect)
                ProtectedMemory.Protect(_cache, MemoryProtectionScope.SameLogon);
        }) {Priority = ThreadPriority.Highest};
        btrd.Start();
        btrd.Join();
    }
}

JitterEx.cs

//#define TEST
using System;
using System.Diagnostics;
using System.Management;
using System.Runtime.CompilerServices;
using System.Threading;
[Serializable]
public class JitterEx
{
private const int DesaturationLoopLimit = 500;
private const int UpperCpuLoadLimit = 90;
private const int LowerCpuLoadLimit = 10;
private static bool _scaleSet;
private readonly int _bufferSize;
private readonly object _lock = new object();
private readonly Random _prng;
private byte[] _rngCache;
private int _tscLoopLimitCpu = 10;
private int _tscSampleSizeRam = 18;
public JitterEx(int buffersize, bool randomize = false)
{
_bufferSize = buffersize;
_rngCache = new byte[_bufferSize];
_prng = new Random();
Randomize = randomize;
SetScale();
}
public bool Randomize
{
get;
set;
}
#if TEST
public void TestListF()
{
var rlst = new List<List<(byte[], int)>>();
for (var i = 0; i < TestList.Count; i++)
{
var f = TestList[i];
for (var j = i + 1; j < TestList.Count; j++)
{
var s = TestList[j];
rlst.Add(new BMPartialPatternSearch(3).SearchPartialAll(f, s));
}
}
}
#endif
[MethodImpl(MethodImplOptions.NoOptimization)]
private float GetCpuSpeed()
{
void Loop()
{
var i = 0;
while (true)
i = i + 1 - 1;
}
var cpuCounter = new PerformanceCounter("Processor Information", "% Processor Performance", "_Total");
var cpuValue = cpuCounter.NextValue();
var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
var Speed = 0f;
lock (_lock)
{
loop.Start();
Thread.Sleep(60);
cpuValue = cpuCounter.NextValue();
loop.Abort();
}
foreach (ManagementObject obj in new ManagementObjectSearcher("SELECT *, Name FROM Win32_Processor").Get())
{
var v = Convert.ToSingle(obj["MaxClockSpeed"]);
Speed = v / 1000 * cpuValue / 100;
}
return Speed;
}
/// <summary>
/// This is a fairly arbitrary value which is based on the CPU speed. 4.7 is the speed on which the tests are based.
/// </summary>
private void SetScale()
{
if (_scaleSet)
return;
_scaleSet = true;
const float baseFreq = 4.7f;
var thisFreq = GetCpuSpeed();
var rat = baseFreq / thisFreq;
_tscLoopLimitCpu = (int) Math.Ceiling(_tscLoopLimitCpu * rat);
_tscSampleSizeRam = (int) Math.Ceiling(_tscSampleSizeRam * rat);
}
private void LoadBlock()
{
var DesaturationLoops = 0;
var dump = CpuTotalPc.CPULoad;
do
{
Thread.Sleep(0);
DesaturationLoops++;
} while (DesaturationLoops < DesaturationLoopLimit && ((int) CpuTotalPc.CPULoad > UpperCpuLoadLimit || (int) CpuTotalPc.CPULoad < LowerCpuLoadLimit));
}
[MethodImpl(MethodImplOptions.NoInlining)]
private byte[] GetBufferCpu()
{
void Loop()
{
var x = 0;
for (var i = 0; i < _tscLoopLimitCpu; i++)
x = x + 1 - 1;
}
var jitterBuffer = new byte[_bufferSize];
var ptr = 0;
LoadBlock();
lock (_lock)
{
var start = Rdtsc.TimestampP();
do
{
var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
loop.Start();
loop.Join();
var stop = Rdtsc.TimestampP();
Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
start = stop;
ptr += 4;
} while (ptr < _bufferSize);
return jitterBuffer;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private unsafe byte[] GetBufferRam()
{
void Loop()
{
byte tempByte;
fixed (byte* p1 = _rngCache)
{
var x1 = p1;
for (var j = 0; j < _tscSampleSizeRam; ++j, ++x1)
tempByte = *x1;
}
}
LoadBlock();
var jitterBuffer = new byte[_bufferSize];
lock (_lock)
{
if (_rngCache.Length != _bufferSize)
_rngCache = new byte[_bufferSize];
_prng.NextBytes(_rngCache);
var ptr = 0;
var start = Rdtsc.TimestampP();
while (true)
{
do
{
var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
loop.Start();
loop.Join();
var stop = Rdtsc.TimestampP();
Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
start = stop;
ptr += 4;
if (ptr < _bufferSize)
{
if (_rngCache.Length != _bufferSize)
_rngCache = new byte[_bufferSize];
_prng.NextBytes(_rngCache);
}
} while (ptr < _bufferSize);
return jitterBuffer;
}
}
}
public byte[] GetBuffer()
{
var firstBuffer = GetBufferCpu();
#if TEST
///Weighting add 15%, perfection is not what we are looking for here.
var lim = _bufferSize <= 256 ? _bufferSize / 256.0 * 85.0 : 6.8;
if (ent.Entropy(firstBuffer) < lim)
throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
var secondBuffer = GetBufferRam();
#if TEST
if (ent.Entropy(secondBuffer) < lim)
throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
var finalBuffer = new byte[_bufferSize];
for (var j = 0; j < _bufferSize; ++j)
finalBuffer[j] = (byte) (firstBuffer[j] ^ secondBuffer[j]);
#if TEST
if (ent.Entropy(finalBuffer) < lim)
throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
if (Randomize)
{
var ula = CreateNoiseArrays(finalBuffer);
var rBlock = new byte[ula.Length * 8];
Buffer.BlockCopy(ula, 0, rBlock, 0, ula.Length * 8);
#if TEST
if (_bufferSize >= 256)
{
var loop = new Thread(() =>
{
if (!rBlock.ChiSquaredTest().isRandom)
MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning);
}) {Priority = ThreadPriority.Highest};
loop.Start();
}
TestList.Add(rBlock);
#endif
return rBlock;
}
#if TEST
if (_bufferSize >= 256)
{
var loop = new Thread(() =>
{
if (!finalBuffer.ChiSquaredTest().isRandom)
MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning);
}) {Priority = ThreadPriority.Highest};
loop.Start();
}
TestList.Add(finalBuffer);
#endif
return finalBuffer;
}
private ulong[] ByteArrayToULongArray(byte[] ba, int finalSize)
{
var minSize = ba.Length / 8;
if (finalSize < minSize)
finalSize = minSize;
ba = PadULong(ba);
var result = new ulong[finalSize];
for (var i = 0; i < ba.Length; i += 8)
Buffer.BlockCopy(ba, i, result, i, 8);
return result;
}
private static byte[] PadULong(byte[] ba)
{
var s = ba.Length % 8;
switch (s)
{
case 0:
break;
case 1:
Array.Resize(ref ba, ba.Length + 7);
ba[ba.Length - 1] = 0x80;
ba[ba.Length - 2] = 0x80;
ba[ba.Length - 3] = 0x80;
ba[ba.Length - 4] = 0x80;
ba[ba.Length - 5] = 0x80;
ba[ba.Length - 6] = 0x80;
ba[ba.Length - 7] = 0x80;
break;
case 2:
Array.Resize(ref ba, ba.Length + 6);
ba[ba.Length - 1] = 0x80;
ba[ba.Length - 2] = 0x80;
ba[ba.Length - 3] = 0x80;
ba[ba.Length - 4] = 0x80;
ba[ba.Length - 5] = 0x80;
ba[ba.Length - 6] = 0x80;
break;
case 3:
Array.Resize(ref ba, ba.Length + 5);
ba[ba.Length - 1] = 0x80;
ba[ba.Length - 2] = 0x80;
ba[ba.Length - 3] = 0x80;
ba[ba.Length - 4] = 0x80;
ba[ba.Length - 5] = 0x80;
break;
case 4:
Array.Resize(ref ba, ba.Length + 4);
ba[ba.Length - 1] = 0x80;
ba[ba.Length - 2] = 0x80;
ba[ba.Length - 3] = 0x80;
ba[ba.Length - 4] = 0x80;
break;
case 5:
Array.Resize(ref ba, ba.Length + 3);
ba[ba.Length - 1] = 0x80;
ba[ba.Length - 2] = 0x80;
ba[ba.Length - 3] = 0x80;
break;
case 6:
Array.Resize(ref ba, ba.Length + 2);
ba[ba.Length - 1] = 0x80;
ba[ba.Length - 2] = 0x80;
break;
case 7:
Array.Resize(ref ba, ba.Length + 1);
ba[ba.Length - 1] = 0x80;
break;
}
return ba;
}
private static void Extrude(ulong[] x)
{
var size = x.Length;
for (var i = 0; i < size; i++)
{
ulong n = 0;
var j = 0;
while (j < size)
{
n ^= x[j];
++j;
}
x[i] = (n << 1) | (n >> 56);
}
}
private ulong[] CreateNoiseArrays(byte[] ba)
{
var ula = ByteArrayToULongArray(ba, ba.Length / 8);
Extrude(ula);
return ula;
}
internal class EntropyI
{
private const double NaturalLogOfTwo = 0.69314718055994530941723212145818; //Math.Log(2);
/// <summary>
/// Get the Entropy from 1 to 100% 1 being very ordered data,
/// 100% being very disordered data.
/// </summary>
public double Entropy(byte[] a)
{
var h = new int[256];
var l = a.Length;
for (var i = 0; i < l; ++i)
h[a[i]]++;
var e = 0.0;
for (var i = 0; i < 256; ++i)
{
var v = h[i];
if (v <= 0)
continue;
var r = v / (double) l;
e -= r * (Math.Log(r) / NaturalLogOfTwo);
}
return e / 8.0 * 100.0;
}
}
#if TEST
private EntropyI ent = new EntropyI();
private List<byte[]> TestList = new List<byte[]>();
#endif
}
//#define TEST using System; using System.Diagnostics; using System.Management; using System.Runtime.CompilerServices; using System.Threading; [Serializable] public class JitterEx { private const int DesaturationLoopLimit = 500; private const int UpperCpuLoadLimit = 90; private const int LowerCpuLoadLimit = 10; private static bool _scaleSet; private readonly int _bufferSize; private readonly object _lock = new object(); private readonly Random _prng; private byte[] _rngCache; private int _tscLoopLimitCpu = 10; private int _tscSampleSizeRam = 18; public JitterEx(int buffersize, bool randomize = false) { _bufferSize = buffersize; _rngCache = new byte[_bufferSize]; _prng = new Random(); Randomize = randomize; SetScale(); } public bool Randomize { get; set; } #if TEST public void TestListF() { var rlst = new List<List<(byte[], int)>>(); for (var i = 0; i < TestList.Count; i++) { var f = TestList[i]; for (var j = i + 1; j < TestList.Count; j++) { var s = TestList[j]; rlst.Add(new BMPartialPatternSearch(3).SearchPartialAll(f, s)); } } } #endif [MethodImpl(MethodImplOptions.NoOptimization)] private float GetCpuSpeed() { void Loop() { var i = 0; while (true) i = i + 1 - 1; } var cpuCounter = new PerformanceCounter("Processor Information", "% Processor Performance", "_Total"); var cpuValue = cpuCounter.NextValue(); var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest}; var Speed = 0f; lock (_lock) { loop.Start(); Thread.Sleep(60); cpuValue = cpuCounter.NextValue(); loop.Abort(); } foreach (ManagementObject obj in new ManagementObjectSearcher("SELECT *, Name FROM Win32_Processor").Get()) { var v = Convert.ToSingle(obj["MaxClockSpeed"]); Speed = v / 1000 * cpuValue / 100; } return Speed; } /// <summary> /// This is a fairly arbitrary value which is based on the CPU speed. 4.7 is the speed on which the tests are based. /// </summary> private void SetScale() { if (_scaleSet) return; _scaleSet = true; const float baseFreq = 4.7f; var thisFreq = GetCpuSpeed(); var rat = baseFreq / thisFreq; _tscLoopLimitCpu = (int) Math.Ceiling(_tscLoopLimitCpu * rat); _tscSampleSizeRam = (int) Math.Ceiling(_tscSampleSizeRam * rat); } private void LoadBlock() { var DesaturationLoops = 0; var dump = CpuTotalPc.CPULoad; do { Thread.Sleep(0); DesaturationLoops++; } while (DesaturationLoops < DesaturationLoopLimit && ((int) CpuTotalPc.CPULoad > UpperCpuLoadLimit || (int) CpuTotalPc.CPULoad < LowerCpuLoadLimit)); } [MethodImpl(MethodImplOptions.NoInlining)] private byte[] GetBufferCpu() { void Loop() { var x = 0; for (var i = 0; i < _tscLoopLimitCpu; i++) x = x + 1 - 1; } var jitterBuffer = new byte[_bufferSize]; var ptr = 0; LoadBlock(); lock (_lock) { var start = Rdtsc.TimestampP(); do { var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest}; loop.Start(); loop.Join(); var stop = Rdtsc.TimestampP(); Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4); start = stop; ptr += 4; } while (ptr < _bufferSize); return jitterBuffer; } } [MethodImpl(MethodImplOptions.NoInlining)] private unsafe byte[] GetBufferRam() { void Loop() { byte tempByte; fixed (byte* p1 = _rngCache) { var x1 = p1; for (var j = 0; j < _tscSampleSizeRam; ++j, ++x1) tempByte = *x1; } } LoadBlock(); var jitterBuffer = new byte[_bufferSize]; lock (_lock) { if (_rngCache.Length != _bufferSize) _rngCache = new byte[_bufferSize]; _prng.NextBytes(_rngCache); var ptr = 0; var start = Rdtsc.TimestampP(); while (true) { do { var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest}; loop.Start(); loop.Join(); var stop = Rdtsc.TimestampP(); Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4); start = stop; ptr += 4; if (ptr < _bufferSize) { if (_rngCache.Length != _bufferSize) _rngCache = new byte[_bufferSize]; _prng.NextBytes(_rngCache); } } while (ptr < _bufferSize); return jitterBuffer; } } } public byte[] GetBuffer() { var firstBuffer = GetBufferCpu(); #if TEST ///Weighting add 15%, perfection is not what we are looking for here. var lim = _bufferSize <= 256 ? _bufferSize / 256.0 * 85.0 : 6.8; if (ent.Entropy(firstBuffer) < lim) throw new Exception("Error CPU Jitter Buffer Contains only zeros."); #endif var secondBuffer = GetBufferRam(); #if TEST if (ent.Entropy(secondBuffer) < lim) throw new Exception("Error CPU Jitter Buffer Contains only zeros."); #endif var finalBuffer = new byte[_bufferSize]; for (var j = 0; j < _bufferSize; ++j) finalBuffer[j] = (byte) (firstBuffer[j] ^ secondBuffer[j]); #if TEST if (ent.Entropy(finalBuffer) < lim) throw new Exception("Error CPU Jitter Buffer Contains only zeros."); #endif if (Randomize) { var ula = CreateNoiseArrays(finalBuffer); var rBlock = new byte[ula.Length * 8]; Buffer.BlockCopy(ula, 0, rBlock, 0, ula.Length * 8); #if TEST if (_bufferSize >= 256) { var loop = new Thread(() => { if (!rBlock.ChiSquaredTest().isRandom) MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning); }) {Priority = ThreadPriority.Highest}; loop.Start(); } TestList.Add(rBlock); #endif return rBlock; } #if TEST if (_bufferSize >= 256) { var loop = new Thread(() => { if (!finalBuffer.ChiSquaredTest().isRandom) MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning); }) {Priority = ThreadPriority.Highest}; loop.Start(); } TestList.Add(finalBuffer); #endif return finalBuffer; } private ulong[] ByteArrayToULongArray(byte[] ba, int finalSize) { var minSize = ba.Length / 8; if (finalSize < minSize) finalSize = minSize; ba = PadULong(ba); var result = new ulong[finalSize]; for (var i = 0; i < ba.Length; i += 8) Buffer.BlockCopy(ba, i, result, i, 8); return result; } private static byte[] PadULong(byte[] ba) { var s = ba.Length % 8; switch (s) { case 0: break; case 1: Array.Resize(ref ba, ba.Length + 7); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; ba[ba.Length - 5] = 0x80; ba[ba.Length - 6] = 0x80; ba[ba.Length - 7] = 0x80; break; case 2: Array.Resize(ref ba, ba.Length + 6); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; ba[ba.Length - 5] = 0x80; ba[ba.Length - 6] = 0x80; break; case 3: Array.Resize(ref ba, ba.Length + 5); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; ba[ba.Length - 5] = 0x80; break; case 4: Array.Resize(ref ba, ba.Length + 4); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; ba[ba.Length - 4] = 0x80; break; case 5: Array.Resize(ref ba, ba.Length + 3); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; ba[ba.Length - 3] = 0x80; break; case 6: Array.Resize(ref ba, ba.Length + 2); ba[ba.Length - 1] = 0x80; ba[ba.Length - 2] = 0x80; break; case 7: Array.Resize(ref ba, ba.Length + 1); ba[ba.Length - 1] = 0x80; break; } return ba; } private static void Extrude(ulong[] x) { var size = x.Length; for (var i = 0; i < size; i++) { ulong n = 0; var j = 0; while (j < size) { n ^= x[j]; ++j; } x[i] = (n << 1) | (n >> 56); } } private ulong[] CreateNoiseArrays(byte[] ba) { var ula = ByteArrayToULongArray(ba, ba.Length / 8); Extrude(ula); return ula; } internal class EntropyI { private const double NaturalLogOfTwo = 0.69314718055994530941723212145818; //Math.Log(2); /// <summary> /// Get the Entropy from 1 to 100% 1 being very ordered data, /// 100% being very disordered data. /// </summary> public double Entropy(byte[] a) { var h = new int[256]; var l = a.Length; for (var i = 0; i < l; ++i) h[a[i]]++; var e = 0.0; for (var i = 0; i < 256; ++i) { var v = h[i]; if (v <= 0) continue; var r = v / (double) l; e -= r * (Math.Log(r) / NaturalLogOfTwo); } return e / 8.0 * 100.0; } } #if TEST private EntropyI ent = new EntropyI(); private List<byte[]> TestList = new List<byte[]>(); #endif }
//#define TEST
using System;
using System.Diagnostics;
using System.Management;
using System.Runtime.CompilerServices;
using System.Threading;
[Serializable]
public class JitterEx
{
    private const    int    DesaturationLoopLimit = 500;
    private const    int    UpperCpuLoadLimit     = 90;
    private const    int    LowerCpuLoadLimit     = 10;
    private static   bool   _scaleSet;
    private readonly int    _bufferSize;
    private readonly object _lock = new object();
    private readonly Random _prng;
    private          byte[] _rngCache;
    private          int    _tscLoopLimitCpu  = 10;
    private          int    _tscSampleSizeRam = 18;
    public JitterEx(int buffersize, bool randomize = false)
    {
        _bufferSize = buffersize;
        _rngCache   = new byte[_bufferSize];
        _prng       = new Random();
        Randomize   = randomize;
        SetScale();
    }
    public bool Randomize
    {
        get;
        set;
    }
#if TEST
    public void TestListF()
    {
        var rlst = new List<List<(byte[], int)>>();
        for (var i = 0; i < TestList.Count; i++)
        {
            var f = TestList[i];
            for (var j = i + 1; j < TestList.Count; j++)
            {
                var s = TestList[j];
                rlst.Add(new BMPartialPatternSearch(3).SearchPartialAll(f, s));
            }
        }
    }
#endif
    [MethodImpl(MethodImplOptions.NoOptimization)]
    private float GetCpuSpeed()
    {
        void Loop()
        {
            var i = 0;
            while (true)
                i = i + 1 - 1;
        }
        var cpuCounter = new PerformanceCounter("Processor Information", "% Processor Performance", "_Total");
        var cpuValue   = cpuCounter.NextValue();
        var loop       = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
        var Speed      = 0f;
        lock (_lock)
        {
            loop.Start();
            Thread.Sleep(60);
            cpuValue = cpuCounter.NextValue();
            loop.Abort();
        }
        foreach (ManagementObject obj in new ManagementObjectSearcher("SELECT *, Name FROM Win32_Processor").Get())
        {
            var v = Convert.ToSingle(obj["MaxClockSpeed"]);
            Speed = v / 1000 * cpuValue / 100;
        }
        return Speed;
    }
    /// <summary>
    ///     This is a fairly arbitrary value which is based on the CPU speed. 4.7 is the speed on which the tests are based.
    /// </summary>
    private void SetScale()
    {
        if (_scaleSet)
            return;
        _scaleSet = true;
        const float baseFreq = 4.7f;
        var         thisFreq = GetCpuSpeed();
        var         rat      = baseFreq / thisFreq;
        _tscLoopLimitCpu  = (int) Math.Ceiling(_tscLoopLimitCpu  * rat);
        _tscSampleSizeRam = (int) Math.Ceiling(_tscSampleSizeRam * rat);
    }
    private void LoadBlock()
    {
        var DesaturationLoops = 0;
        var dump              = CpuTotalPc.CPULoad;
        do
        {
            Thread.Sleep(0);
            DesaturationLoops++;
        } while (DesaturationLoops < DesaturationLoopLimit && ((int) CpuTotalPc.CPULoad > UpperCpuLoadLimit || (int) CpuTotalPc.CPULoad < LowerCpuLoadLimit));
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private byte[] GetBufferCpu()
    {
        void Loop()
        {
            var x = 0;
            for (var i = 0; i < _tscLoopLimitCpu; i++)
                x = x + 1 - 1;
        }
        var jitterBuffer = new byte[_bufferSize];
        var ptr          = 0;
        LoadBlock();
        lock (_lock)
        {
            var start = Rdtsc.TimestampP();
            do
            {
                var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
                loop.Start();
                loop.Join();
                var stop = Rdtsc.TimestampP();
                Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
                start =  stop;
                ptr   += 4;
            } while (ptr < _bufferSize);
            return jitterBuffer;
        }
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private unsafe byte[] GetBufferRam()
    {
        void Loop()
        {
            byte tempByte;
            fixed (byte* p1 = _rngCache)
            {
                var x1 = p1;
                for (var j = 0; j < _tscSampleSizeRam; ++j, ++x1)
                    tempByte = *x1;
            }
        }
        LoadBlock();
        var jitterBuffer = new byte[_bufferSize];
        lock (_lock)
        {
            if (_rngCache.Length != _bufferSize)
                _rngCache = new byte[_bufferSize];
            _prng.NextBytes(_rngCache);
            var ptr   = 0;
            var start = Rdtsc.TimestampP();
            while (true)
            {
                do
                {
                    var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
                    loop.Start();
                    loop.Join();
                    var stop = Rdtsc.TimestampP();
                    Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
                    start =  stop;
                    ptr   += 4;
                    if (ptr < _bufferSize)
                    {
                        if (_rngCache.Length != _bufferSize)
                            _rngCache = new byte[_bufferSize];
                        _prng.NextBytes(_rngCache);
                    }
                } while (ptr < _bufferSize);
                return jitterBuffer;
            }
        }
    }
    public byte[] GetBuffer()
    {
        var firstBuffer = GetBufferCpu();
#if TEST
        ///Weighting add 15%, perfection is not what we are looking for here.
        var lim = _bufferSize <= 256 ? _bufferSize / 256.0 * 85.0 : 6.8;
        if (ent.Entropy(firstBuffer) < lim)
            throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
        var secondBuffer = GetBufferRam();
#if TEST
        if (ent.Entropy(secondBuffer) < lim)
            throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
        var finalBuffer = new byte[_bufferSize];
        for (var j = 0; j < _bufferSize; ++j)
            finalBuffer[j] = (byte) (firstBuffer[j] ^ secondBuffer[j]);
#if TEST
        if (ent.Entropy(finalBuffer) < lim)
            throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
        if (Randomize)
        {
            var ula    = CreateNoiseArrays(finalBuffer);
            var rBlock = new byte[ula.Length * 8];
            Buffer.BlockCopy(ula, 0, rBlock, 0, ula.Length * 8);
#if TEST
            if (_bufferSize >= 256)
            {
                var loop = new Thread(() =>
                {
                    if (!rBlock.ChiSquaredTest().isRandom)
                        MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning);
                }) {Priority = ThreadPriority.Highest};
                loop.Start();
            }
            TestList.Add(rBlock);
#endif
            return rBlock;
        }
#if TEST
        if (_bufferSize >= 256)
        {
            var loop = new Thread(() =>
            {
                if (!finalBuffer.ChiSquaredTest().isRandom)
                    MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning);
            }) {Priority = ThreadPriority.Highest};
            loop.Start();
        }
        TestList.Add(finalBuffer);
#endif
        return finalBuffer;
    }
    private ulong[] ByteArrayToULongArray(byte[] ba, int finalSize)
    {
        var minSize = ba.Length / 8;
        if (finalSize < minSize)
            finalSize = minSize;
        ba = PadULong(ba);
        var result = new ulong[finalSize];
        for (var i = 0; i < ba.Length; i += 8)
            Buffer.BlockCopy(ba, i, result, i, 8);
        return result;
    }
    private static byte[] PadULong(byte[] ba)
    {
        var s = ba.Length % 8;
        switch (s)
        {
            case 0:
                break;
            case 1:
                Array.Resize(ref ba, ba.Length + 7);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                ba[ba.Length - 6] = 0x80;
                ba[ba.Length - 7] = 0x80;
                break;
            case 2:
                Array.Resize(ref ba, ba.Length + 6);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                ba[ba.Length - 6] = 0x80;
                break;
            case 3:
                Array.Resize(ref ba, ba.Length + 5);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                break;
            case 4:
                Array.Resize(ref ba, ba.Length + 4);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                break;
            case 5:
                Array.Resize(ref ba, ba.Length + 3);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                break;
            case 6:
                Array.Resize(ref ba, ba.Length + 2);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                break;
            case 7:
                Array.Resize(ref ba, ba.Length + 1);
                ba[ba.Length - 1] = 0x80;
                break;
        }
        return ba;
    }
    private static void Extrude(ulong[] x)
    {
        var size = x.Length;
        for (var i = 0; i < size; i++)
        {
            ulong n = 0;
            var   j = 0;
            while (j < size)
            {
                n ^= x[j];
                ++j;
            }
            x[i] = (n << 1) | (n >> 56);
        }
    }
    private ulong[] CreateNoiseArrays(byte[] ba)
    {
        var ula = ByteArrayToULongArray(ba, ba.Length / 8);
        Extrude(ula);
        return ula;
    }
    internal class EntropyI
    {
        private const double NaturalLogOfTwo = 0.69314718055994530941723212145818; //Math.Log(2);
        /// <summary>
        ///     Get the Entropy from 1 to 100% 1 being very ordered data,
        ///     100% being very disordered data.
        /// </summary>
        public double Entropy(byte[] a)
        {
            var h = new int[256];
            var l = a.Length;
            for (var i = 0; i < l; ++i)
                h[a[i]]++;
            var e = 0.0;
            for (var i = 0; i < 256; ++i)
            {
                var v = h[i];
                if (v <= 0)
                    continue;
                var r = v             / (double) l;
                e -= r * (Math.Log(r) / NaturalLogOfTwo);
            }
            return e / 8.0 * 100.0;
        }
    }
#if TEST
    private EntropyI     ent = new EntropyI();
    private List<byte[]> TestList = new List<byte[]>();
#endif
}