Created
March 24, 2020 09:24
-
-
Save mjs3339/d1c2cf41d96ca561c622617407add128 to your computer and use it in GitHub Desktop.
512 Bit Unsigned Integer Structure (C#)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Diagnostics; | |
using System.Globalization; | |
using System.Linq; | |
using System.Numerics; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
[Serializable] | |
[StructLayout(LayoutKind.Sequential, Pack = 1)] | |
[TypeConverter(typeof(Int512Converter))] | |
[DebuggerDisplay("{DDisplay}")] | |
public struct UInt512 : IComparable<UInt512>, IComparable, IEquatable<UInt512>, IConvertible, IFormattable | |
{ | |
private ulong B512; | |
private ulong B448; | |
private ulong B384; | |
private ulong B320; | |
private ulong B256; | |
private ulong B192; | |
private ulong B128; | |
private ulong B64; | |
[DebuggerBrowsable(DebuggerBrowsableState.Never)] | |
private string DDisplay => ToString(); | |
public static UInt512 Zero = new UInt512(0); | |
public static UInt512 Ten = new UInt512(10); | |
public static UInt512 One = new UInt512(1); | |
public static UInt512 MaxValue = GetMaxValue(); | |
public static UInt512 MinValue = GetMinValue(); | |
private static UInt512 GetMaxValue() | |
{ | |
return new UInt512(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue); | |
} | |
private static UInt512 GetMinValue() | |
{ | |
return new UInt512(0, 0, 0, 0, 0, 0, 0, 0); | |
} | |
public UInt512(UInt512 value) | |
{ | |
B512 = value.B512; | |
B448 = value.B448; | |
B384 = value.B384; | |
B320 = value.B320; | |
B256 = value.B256; | |
B192 = value.B192; | |
B128 = value.B128; | |
B64 = value.B64; | |
} | |
public UInt512(string value) | |
{ | |
if (!TryParse(value, out var result)) | |
throw new Exception("TryParse Failed."); | |
B512 = result.B512; | |
B448 = result.B448; | |
B384 = result.B384; | |
B320 = result.B320; | |
B256 = result.B256; | |
B192 = result.B192; | |
B128 = result.B128; | |
B64 = result.B64; | |
} | |
public UInt512(byte value) | |
{ | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = value; | |
} | |
public UInt512(bool value) | |
{ | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = (ulong) (value ? 1 : 0); | |
} | |
public UInt512(char value) | |
{ | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = value; | |
} | |
public UInt512(BigDecimal value) | |
{ | |
var ba = value.UnscaledValue.ToByteArray(); | |
B512 = BitConverter.ToUInt64(ba, 56); | |
B448 = BitConverter.ToUInt64(ba, 48); | |
B384 = BitConverter.ToUInt64(ba, 40); | |
B320 = BitConverter.ToUInt64(ba, 32); | |
B256 = BitConverter.ToUInt64(ba, 24); | |
B192 = BitConverter.ToUInt64(ba, 16); | |
B128 = BitConverter.ToUInt64(ba, 8); | |
B64 = BitConverter.ToUInt64(ba, 0); | |
} | |
public UInt512(decimal value) | |
{ | |
if (value < 0) | |
throw new Exception("Value must be a positive."); | |
var bits = decimal.GetBits(value); | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = (uint) bits[2]; | |
B128 = (uint) bits[1]; | |
B64 = (uint) bits[0]; | |
//if (value < 0) | |
//{ | |
// B512 = ~B512; | |
// B448 = ~B448; | |
// B384 = ~B384; | |
// B320 = ~B320; | |
// B256 = ~B256; | |
// B192 = ~B192; | |
// B128 = ~B128; | |
// B64 = ~B64; | |
//} | |
} | |
public UInt512(double value) : this((decimal) value) | |
{ | |
} | |
public UInt512(float value) : this((decimal) value) | |
{ | |
} | |
public UInt512(short value) | |
{ | |
if (value < 0) | |
throw new Exception("Value must be a positive."); | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = (ulong) value; | |
} | |
public UInt512(int value) | |
{ | |
if (value < 0) | |
throw new Exception("Value must be a positive."); | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = (ulong) value; | |
} | |
public UInt512(long value) | |
{ | |
if (value < 0) | |
throw new Exception("Value must be a positive."); | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = (ulong) value; | |
} | |
public UInt512(UInt128 value) | |
{ | |
if (value < 0) | |
throw new Exception("Value must be a positive."); | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = value.B128; | |
B64 = value.B64; | |
} | |
public UInt512(sbyte value) | |
{ | |
if (value < 0) | |
throw new Exception("Value must be a positive."); | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = (ulong) value; | |
} | |
public UInt512(ushort value) | |
{ | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = value; | |
} | |
public UInt512(uint value) | |
{ | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = value; | |
} | |
public UInt512(ulong value) | |
{ | |
B512 = 0; | |
B448 = 0; | |
B384 = 0; | |
B320 = 0; | |
B256 = 0; | |
B192 = 0; | |
B128 = 0; | |
B64 = value; | |
} | |
public UInt512(BigInteger value) : this(value.ToByteArray()) | |
{ | |
//var aba = UInt512.MaxValue.ToByteArray(); | |
//var bn = new BigInteger(aba.Concat(new byte[] { 0 }).ToArray()); | |
} | |
public UInt512(Guid value) : this(value.ToByteArray()) | |
{ | |
} | |
public UInt512(byte[] value) | |
{ | |
if (value == null) | |
throw new Exception("Value cannot be null."); | |
if (value.Length != 64) | |
Array.Resize(ref value, 64); | |
B512 = BitConverter.ToUInt64(value, 56); | |
B448 = BitConverter.ToUInt64(value, 48); | |
B384 = BitConverter.ToUInt64(value, 40); | |
B320 = BitConverter.ToUInt64(value, 32); | |
B256 = BitConverter.ToUInt64(value, 24); | |
B192 = BitConverter.ToUInt64(value, 16); | |
B128 = BitConverter.ToUInt64(value, 8); | |
B64 = BitConverter.ToUInt64(value, 0); | |
} | |
public UInt512(ulong b512, ulong b448, ulong b384, ulong b320, ulong b256, ulong b192, ulong b128, ulong b64) | |
{ | |
B512 = b512; | |
B448 = b448; | |
B384 = b384; | |
B320 = b320; | |
B256 = b256; | |
B192 = b192; | |
B128 = b128; | |
B64 = b64; | |
} | |
public UInt512(uint[] array) | |
{ | |
if (array == null) | |
throw new Exception("Array cannot be null."); | |
var b512 = new byte[8]; | |
var b448 = new byte[8]; | |
var b384 = new byte[8]; | |
var b320 = new byte[8]; | |
var b256 = new byte[8]; | |
var b192 = new byte[8]; | |
var b128 = new byte[8]; | |
var b64 = new byte[8]; | |
if (array.Length > 0) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[0]), 0, b64, 0, 4); | |
if (array.Length > 1) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[1]), 0, b64, 4, 4); | |
if (array.Length > 2) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[2]), 0, b128, 0, 4); | |
if (array.Length > 3) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[3]), 0, b128, 4, 4); | |
if (array.Length > 4) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[4]), 0, b192, 0, 4); | |
if (array.Length > 5) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[5]), 0, b192, 4, 4); | |
if (array.Length > 6) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[6]), 0, b256, 0, 4); | |
if (array.Length > 7) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[7]), 0, b256, 4, 4); | |
if (array.Length > 8) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[8]), 0, b320, 0, 4); | |
if (array.Length > 9) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[9]), 0, b320, 4, 4); | |
if (array.Length > 10) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[10]), 0, b384, 0, 4); | |
if (array.Length > 11) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[11]), 0, b384, 4, 4); | |
if (array.Length > 12) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[12]), 0, b448, 0, 4); | |
if (array.Length > 13) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[13]), 0, b448, 4, 4); | |
if (array.Length > 14) | |
{ | |
Array.Copy(BitConverter.GetBytes(array[14]), 0, b512, 0, 4); | |
if (array.Length > 15) | |
Array.Copy(BitConverter.GetBytes(array[15]), 0, b512, 4, 4); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
B512 = BitConverter.ToUInt64(b512, 0); | |
B448 = BitConverter.ToUInt64(b448, 0); | |
B384 = BitConverter.ToUInt64(b384, 0); | |
B320 = BitConverter.ToUInt64(b320, 0); | |
B256 = BitConverter.ToUInt64(b256, 0); | |
B192 = BitConverter.ToUInt64(b192, 0); | |
B128 = BitConverter.ToUInt64(b128, 0); | |
B64 = BitConverter.ToUInt64(b64, 0); | |
} | |
public int BitWidth | |
{ | |
get | |
{ | |
UInt512 bitWidth = 1; | |
var v = this; | |
while ((v >>= 1) > 0) | |
bitWidth++; | |
if (bitWidth < 8) | |
bitWidth = 8; | |
while (bitWidth % 8 != 0) | |
bitWidth++; | |
return (int) bitWidth; | |
} | |
} | |
public override int GetHashCode() | |
{ | |
return B64.GetHashCode() ^ B128.GetHashCode() ^ B192.GetHashCode() ^ B256.GetHashCode() ^ B320.GetHashCode() ^ B384.GetHashCode() ^ B448.GetHashCode() ^ B512.GetHashCode(); | |
} | |
public override bool Equals(object obj) | |
{ | |
return base.Equals(obj); | |
} | |
public bool Equals(UInt512 obj) | |
{ | |
return B256 == obj.B256 && B192 == obj.B192 && B128 == obj.B128 && B64 == obj.B64; | |
} | |
public override string ToString() | |
{ | |
return ToString(null, null); | |
} | |
public string ToString(string format) | |
{ | |
return ToString(format, null); | |
} | |
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', min); | |
} | |
if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd') | |
throw new NotSupportedException("Not supported format: " + format); | |
} | |
return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo))); | |
} | |
private string ToHexString(bool caps, int min) | |
{ | |
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) | |
{ | |
var buf = ToByteArray(); | |
var bi = new BigInteger(buf.Concat(new byte[] {0}).ToArray()); | |
return bi.ToString(); | |
} | |
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 (int) 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 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 UInt512 Parse(string value) | |
{ | |
return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); | |
} | |
public static UInt512 Parse(string value, NumberStyles style) | |
{ | |
return Parse(value, style, NumberFormatInfo.CurrentInfo); | |
} | |
public static UInt512 Parse(string value, IFormatProvider provider) | |
{ | |
return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); | |
} | |
public static UInt512 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 UInt512 result) | |
{ | |
return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); | |
} | |
public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out UInt512 result) | |
{ | |
result = Zero; | |
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 TryParseHex(value, out result); | |
return TryParseNum(value, out result); | |
} | |
private static bool TryParseHex(string value, out UInt512 result) | |
{ | |
if (value.Length > 128) | |
throw new OverflowException(); | |
result = Zero; | |
var pos = 0; | |
for (var i = value.Length - 1; i >= 0; i--) | |
{ | |
var ch = value[i]; | |
ulong bch; | |
if (ch >= '0' && ch <= '9') | |
bch = (ulong) (ch - '0'); | |
else if (ch >= 'A' && ch <= 'F') | |
bch = (ulong) (ch - 'A' + 10); | |
else if (ch >= 'a' && ch <= 'f') | |
bch = (ulong) (ch - 'a' + 10); | |
else | |
return false; | |
if (pos < 64) | |
result.B64 |= bch << pos; | |
else if (pos < 128) | |
result.B128 |= bch << pos; | |
else if (pos < 192) | |
result.B192 |= bch << pos; | |
else if (pos < 256) | |
result.B256 |= bch << pos; | |
else if (pos < 320) | |
result.B320 |= bch << pos; | |
else if (pos < 384) | |
result.B384 |= bch << pos; | |
else if (pos < 448) | |
result.B448 |= bch << pos; | |
else if (pos < 512) | |
result.B512 |= bch << pos; | |
pos += 4; | |
} | |
return true; | |
} | |
private static bool TryParseNum(string value, out UInt512 result) | |
{ | |
result = Zero; | |
foreach (var ch in value) | |
{ | |
byte b; | |
if (ch >= '0' && ch <= '9') | |
b = (byte) (ch - '0'); | |
else | |
return false; | |
result = Ten * result; | |
result += b; | |
} | |
return true; | |
} | |
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 (B128 != 0) | |
throw new OverflowException(); | |
return Convert.ToUInt16(B64); | |
} | |
uint IConvertible.ToUInt32(IFormatProvider provider) | |
{ | |
if (B128 != 0) | |
throw new OverflowException(); | |
return Convert.ToUInt32(B64); | |
} | |
ulong IConvertible.ToUInt64(IFormatProvider provider) | |
{ | |
if (B128 != 0) | |
throw new OverflowException(); | |
return B64; | |
} | |
int IComparable.CompareTo(object obj) | |
{ | |
return Compare(this, obj); | |
} | |
public static int Compare(UInt512 left, object right) | |
{ | |
if (right is UInt512) | |
return Compare(left, (UInt512) right); | |
if (right is bool) | |
return Compare(left, new UInt512((bool) right)); | |
if (right is byte) | |
return Compare(left, new UInt512((byte) right)); | |
if (right is char) | |
return Compare(left, new UInt512((char) right)); | |
if (right is decimal) | |
return Compare(left, new UInt512((decimal) right)); | |
if (right is double) | |
return Compare(left, new UInt512((double) right)); | |
if (right is short) | |
return Compare(left, new UInt512((short) right)); | |
if (right is int) | |
return Compare(left, new UInt512((int) right)); | |
if (right is long) | |
return Compare(left, new UInt512((long) right)); | |
if (right is sbyte) | |
return Compare(left, new UInt512((sbyte) right)); | |
if (right is float) | |
return Compare(left, new UInt512((float) right)); | |
if (right is ushort) | |
return Compare(left, new UInt512((ushort) right)); | |
if (right is uint) | |
return Compare(left, new UInt512((uint) right)); | |
if (right is ulong) | |
return Compare(left, new UInt512((ulong) right)); | |
var bytes = right as byte[]; | |
if (bytes != null && bytes.Length != 64) | |
return Compare(left, new UInt512(bytes)); | |
if (right is Guid) | |
return Compare(left, new UInt512((Guid) right)); | |
throw new ArgumentException(); | |
} | |
public static int Compare(UInt512 left, UInt512 right) | |
{ | |
if (left.B512 != right.B512) | |
return left.B512.CompareTo(right.B512); | |
if (left.B448 != right.B448) | |
return left.B448.CompareTo(right.B448); | |
if (left.B384 != right.B384) | |
return left.B384.CompareTo(right.B384); | |
if (left.B320 != right.B320) | |
return left.B320.CompareTo(right.B320); | |
if (left.B256 != right.B256) | |
return left.B256.CompareTo(right.B256); | |
if (left.B192 != right.B192) | |
return left.B192.CompareTo(right.B192); | |
if (left.B128 != right.B128) | |
return left.B128.CompareTo(right.B128); | |
return left.B64.CompareTo(right.B64); | |
} | |
public int CompareTo(UInt512 value) | |
{ | |
return Compare(this, value); | |
} | |
public static implicit operator UInt512(bool value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(byte value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(char value) | |
{ | |
return new UInt512(value); | |
} | |
public static explicit operator UInt512(decimal value) | |
{ | |
return new UInt512(value); | |
} | |
public static explicit operator UInt512(double value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(short value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(int value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(long value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(sbyte value) | |
{ | |
return new UInt512(value); | |
} | |
public static explicit operator UInt512(float value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(ushort value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(uint value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(ulong value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(UInt128 value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(BigInteger value) | |
{ | |
return new UInt512(value); | |
} | |
public static implicit operator UInt512(BigDecimal value) | |
{ | |
return new UInt512(value); | |
} | |
public static explicit operator bool(UInt512 value) | |
{ | |
return (byte) value.B64 != 0; | |
} | |
public static explicit operator byte(UInt512 value) | |
{ | |
return (byte) value.B64; | |
} | |
public static explicit operator char(UInt512 value) | |
{ | |
return (char) (ushort) value.B64; | |
} | |
public static explicit operator decimal(UInt512 value) | |
{ | |
return new decimal((int) (value.B64 & 0xFFFFFFFF), (int) (value.B128 & 0xFFFFFFFF), (int) (value.B192 & 0xFFFFFFFF), false, 0); | |
} | |
public static explicit operator double(UInt512 value) | |
{ | |
var nfi = CultureInfo.InvariantCulture.NumberFormat; | |
if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var d)) | |
throw new OverflowException(); | |
return d; | |
} | |
public static explicit operator float(UInt512 value) | |
{ | |
var nfi = CultureInfo.InvariantCulture.NumberFormat; | |
if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var f)) | |
throw new OverflowException(); | |
return f; | |
} | |
public static explicit operator short(UInt512 value) | |
{ | |
return (short) (int) value.B64; | |
} | |
public static explicit operator int(UInt512 value) | |
{ | |
return (int) value.B64; | |
} | |
public static explicit operator long(UInt512 value) | |
{ | |
return (long) value.B64; | |
} | |
public static explicit operator uint(UInt512 value) | |
{ | |
return (uint) value.B64; | |
} | |
public static explicit operator ushort(UInt512 value) | |
{ | |
return (ushort) value.B64; | |
} | |
public static explicit operator ulong(UInt512 value) | |
{ | |
return value.B64; | |
} | |
public static explicit operator BigInteger(UInt512 value) | |
{ | |
return new BigInteger(value.ToByteArray().Concat(new byte[] {0}).ToArray()); | |
} | |
public static explicit operator UInt128(UInt512 value) | |
{ | |
return new UInt128(value.B128, value.B64); | |
} | |
public static bool operator >(UInt512 left, UInt512 right) | |
{ | |
return Compare(left, right) > 0; | |
} | |
public static bool operator <(UInt512 left, UInt512 right) | |
{ | |
return Compare(left, right) < 0; | |
} | |
public static bool operator >=(UInt512 left, UInt512 right) | |
{ | |
return Compare(left, right) >= 0; | |
} | |
public static bool operator <=(UInt512 left, UInt512 right) | |
{ | |
return Compare(left, right) <= 0; | |
} | |
public static bool operator !=(UInt512 left, UInt512 right) | |
{ | |
return Compare(left, right) != 0; | |
} | |
public static bool operator ==(UInt512 left, UInt512 right) | |
{ | |
return Compare(left, right) == 0; | |
} | |
public static UInt512 operator +(UInt512 value) | |
{ | |
return value; | |
} | |
public static UInt512 operator ~(UInt512 value) | |
{ | |
return -(value + One); | |
} | |
public static UInt512 operator -(UInt512 value) | |
{ | |
return Negate(value); | |
} | |
public static UInt512 operator ++(UInt512 value) | |
{ | |
return value + 1; | |
} | |
public static UInt512 operator --(UInt512 value) | |
{ | |
return value - 1; | |
} | |
public static UInt512 Negate(UInt512 value) | |
{ | |
return new UInt512(~value.B512, ~value.B448, ~value.B384, ~value.B320, ~value.B256, ~value.B192, ~value.B128, ~value.B64) + 1; | |
} | |
public static UInt512 operator +(UInt512 left, UInt512 right) | |
{ | |
left.B512 += right.B512; | |
left.B448 += right.B448; | |
if (left.B448 < right.B448) | |
left.B512++; | |
left.B384 += right.B384; | |
if (left.B384 < right.B384) | |
{ | |
left.B448++; | |
if (left.B448 < left.B448 - 1) | |
left.B512++; | |
} | |
left.B320 += right.B320; | |
if (left.B320 < right.B320) | |
{ | |
left.B384++; | |
if (left.B384 < left.B384 - 1) | |
{ | |
left.B448++; | |
if (left.B448 < left.B448 - 1) | |
left.B512++; | |
} | |
} | |
left.B256 += right.B256; | |
if (left.B256 < right.B256) | |
{ | |
left.B320++; | |
if (left.B320 < left.B320 - 1) | |
{ | |
left.B384++; | |
if (left.B384 < left.B384 - 1) | |
{ | |
left.B448++; | |
if (left.B448 < left.B448 - 1) | |
left.B512++; | |
} | |
} | |
} | |
left.B192 += right.B192; | |
if (left.B192 < right.B192) | |
{ | |
left.B256++; | |
if (left.B256 < left.B256 - 1) | |
{ | |
left.B320++; | |
if (left.B320 < left.B320 - 1) | |
{ | |
left.B384++; | |
if (left.B384 < left.B384 - 1) | |
{ | |
left.B448++; | |
if (left.B448 < left.B448 - 1) | |
left.B512++; | |
} | |
} | |
} | |
} | |
left.B128 += right.B128; | |
if (left.B128 < right.B128) | |
{ | |
left.B192++; | |
if (left.B192 < left.B192 - 1) | |
{ | |
left.B256++; | |
if (left.B256 < left.B256 - 1) | |
{ | |
left.B320++; | |
if (left.B320 < left.B320 - 1) | |
{ | |
left.B384++; | |
if (left.B384 < left.B384 - 1) | |
{ | |
left.B448++; | |
if (left.B448 < left.B448 - 1) | |
left.B512++; | |
} | |
} | |
} | |
} | |
} | |
left.B64 += right.B64; | |
if (left.B64 < right.B64) | |
{ | |
left.B128++; | |
if (left.B128 < left.B128 - 1) | |
{ | |
left.B192++; | |
if (left.B192 < left.B192 - 1) | |
{ | |
left.B256++; | |
if (left.B256 < left.B256 - 1) | |
{ | |
left.B320++; | |
if (left.B320 < left.B320 - 1) | |
{ | |
left.B384++; | |
if (left.B384 < left.B384 - 1) | |
{ | |
left.B448++; | |
if (left.B448 < left.B448 - 1) | |
left.B512++; | |
} | |
} | |
} | |
} | |
} | |
} | |
return left; | |
} | |
public static UInt512 operator -(UInt512 left, UInt512 right) | |
{ | |
return left + -right; | |
} | |
public static UInt512 Add(UInt512 left, UInt512 right) | |
{ | |
return left + right; | |
} | |
public static UInt512 Subtract(UInt512 left, UInt512 right) | |
{ | |
return left - right; | |
} | |
public static UInt512 Divide(UInt512 dividend, UInt512 divisor) | |
{ | |
return DivRem(dividend, divisor, out var integer); | |
} | |
public static UInt512 DivRem(UInt512 dividend, UInt512 divisor, out UInt512 remainder) | |
{ | |
if (divisor == 0) | |
throw new DivideByZeroException(); | |
DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out var quotient, out var rem); | |
remainder = new UInt512(rem); | |
return new UInt512(quotient); | |
} | |
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 (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[0]; | |
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 UInt512 Remainder(UInt512 dividend, UInt512 divisor) | |
{ | |
DivRem(dividend, divisor, out var remainder); | |
return remainder; | |
} | |
public static UInt512 Max(UInt512 left, UInt512 right) | |
{ | |
return left.CompareTo(right) < 0 ? right : left; | |
} | |
public static UInt512 Min(UInt512 left, UInt512 right) | |
{ | |
return left.CompareTo(right) <= 0 ? left : right; | |
} | |
public static int GetBitWidth(UInt512 n) | |
{ | |
UInt512 bitWidth = 1; | |
var v = n; | |
while ((v >>= 1) > 0) | |
bitWidth++; | |
if (bitWidth < 8) | |
bitWidth = 8; | |
while (bitWidth % 8 != 0) | |
bitWidth++; | |
return (int) bitWidth; | |
} | |
public static UInt512 operator %(UInt512 dividend, UInt512 divisor) | |
{ | |
return Remainder(dividend, divisor); | |
} | |
public static UInt512 operator /(UInt512 dividend, UInt512 divisor) | |
{ | |
return Divide(dividend, divisor); | |
} | |
public ulong[] ToUIn64Array() | |
{ | |
return new[] {B64, B128, B192, B256, B320, B384, B448, B512}; | |
} | |
public uint[] ToUIn32Array() | |
{ | |
var uia = new uint[16]; | |
var ula = ToUIn64Array(); | |
Buffer.BlockCopy(ula, 0, uia, 0, 64); | |
return uia; | |
} | |
public byte[] ToByteArray() | |
{ | |
var ba = new byte[64]; | |
var ula = ToUIn64Array(); | |
Buffer.BlockCopy(ula, 0, ba, 0, 64); | |
return ba; | |
} | |
public static UInt512 Multiply(UInt512 left, UInt512 right) | |
{ | |
var xInts = left.ToUIn32Array(); | |
var yInts = right.ToUIn32Array(); | |
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; | |
} | |
} | |
return new UInt512(mulInts); | |
} | |
public static UInt512 operator *(UInt512 left, UInt512 right) | |
{ | |
return Multiply(left, right); | |
} | |
public static UInt512 operator >>(UInt512 value, int shift) | |
{ | |
var values = value.ToUIn64Array(); | |
var valueLength = sizeof(ulong) * 8; | |
var length = values.Length; | |
shift = shift % (length * valueLength); | |
var shiftOffset = shift / valueLength; | |
var bshift = shift % valueLength; | |
var shifted = new ulong[length]; | |
for (var i = 0; i < length; i++) | |
{ | |
var ishift = i - shiftOffset; | |
if (ishift < 0) | |
continue; | |
shifted[ishift] |= values[i] >> bshift; | |
if (bshift > 0 && i + 1 < length) | |
shifted[ishift] |= values[i + 1] << (valueLength - bshift); | |
} | |
return new UInt512(shifted[7], shifted[6], shifted[5], shifted[4], shifted[3], shifted[2], shifted[1], shifted[0]); | |
} | |
public static UInt512 operator <<(UInt512 value, int shift) | |
{ | |
var values = value.ToUIn64Array(); | |
var valueLength = sizeof(ulong) * 8; | |
var length = values.Length; | |
shift %= length * valueLength; | |
var shiftOffset = shift / valueLength; | |
var bshift = shift % valueLength; | |
var shifted = new ulong[length]; | |
for (var i = 0; i < length; i++) | |
{ | |
var ishift = i + shiftOffset; | |
if (ishift >= length) | |
continue; | |
shifted[ishift] |= values[i] << bshift; | |
if (bshift > 0 && i - 1 >= 0) | |
shifted[ishift] |= values[i - 1] >> (valueLength - bshift); | |
} | |
return new UInt512(shifted[7], shifted[6], shifted[5], shifted[4], shifted[3], shifted[2], shifted[1], shifted[0]); | |
} | |
public static UInt512 operator |(UInt512 left, UInt512 right) | |
{ | |
if (left == 0) | |
return right; | |
if (right == 0) | |
return left; | |
var x = left.ToUIn32Array(); | |
var y = right.ToUIn32Array(); | |
var z = new uint[Math.Max(x.Length, y.Length)]; | |
for (var i = 0; i < z.Length; i++) | |
{ | |
var xu = i < x.Length ? x[i] : 0u; | |
var yu = i < y.Length ? y[i] : 0u; | |
z[i] = xu | yu; | |
} | |
return new UInt512(z); | |
} | |
public static UInt512 operator ^(UInt512 left, UInt512 right) | |
{ | |
var x = left.ToUIn32Array(); | |
var y = right.ToUIn32Array(); | |
var z = new uint[Math.Max(x.Length, y.Length)]; | |
for (var i = 0; i < z.Length; i++) | |
{ | |
var xu = i < x.Length ? x[i] : 0u; | |
var yu = i < y.Length ? y[i] : 0u; | |
z[i] = xu ^ yu; | |
} | |
return new UInt512(z); | |
} | |
public static UInt512 operator &(UInt512 left, UInt512 right) | |
{ | |
if (left == 0 || right == 0) | |
return Zero; | |
var x = left.ToUIn32Array(); | |
var y = right.ToUIn32Array(); | |
var z = new uint[Math.Max(x.Length, y.Length)]; | |
for (var i = 0; i < z.Length; i++) | |
{ | |
var xu = i < x.Length ? x[i] : 0u; | |
var yu = i < y.Length ? y[i] : 0u; | |
z[i] = xu & yu; | |
} | |
return new UInt512(z); | |
} | |
public static void GetPrimeMultipliers(UInt512 pq, out UInt512 p, out UInt512 q) | |
{ | |
p = PollardRho(pq); | |
q = pq / p; | |
if (p > q) | |
{ | |
var t = p; | |
p = q; | |
q = t; | |
} | |
} | |
public static UInt512 PollardRho(UInt512 number) | |
{ | |
var func = new Func<UInt512, UInt512, UInt512>((param, mod) => (param * param + 1) % mod); | |
UInt512 x = 2, y = 2, z; | |
do | |
{ | |
x = func(x, number); | |
y = func(func(y, number), number); | |
z = GCD(x > y ? x - y : y - x, number); | |
} while (z <= 1); | |
return z; | |
} | |
public static UInt512 GCD(UInt512 a, UInt512 b) | |
{ | |
while (true) | |
{ | |
if (b == 0) | |
return a; | |
var a1 = a; | |
a = b; | |
b = a1 % b; | |
} | |
} | |
private class Int512Converter : 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 UInt512(); | |
} | |
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment