diff --git a/MithrilShards.P2P.Benchmark/Benchmarks/Target/Target_Study.cs b/MithrilShards.P2P.Benchmark/Benchmarks/Target/Target_Study.cs index 0088024e..6dbbea86 100644 --- a/MithrilShards.P2P.Benchmark/Benchmarks/Target/Target_Study.cs +++ b/MithrilShards.P2P.Benchmark/Benchmarks/Target/Target_Study.cs @@ -78,31 +78,6 @@ public void Setup() // return new NBitcoin_Target(scalar); //} - //[Benchmark] - //public MS_Target MulScalar_Target() - //{ - // return t1 * scalar; - //} - - //[Benchmark] - //public NBitcoin_Target MulScalar_NBitcoinTarget() - //{ - // return new NBitcoin_Target(nt1.ToBigInteger() * new BigInteger((long)scalar)); - //} - - //[Benchmark] - //public MS_Target DivScalar_Target() - //{ - // return t1 / scalar; - //} - - //[Benchmark] - //public NBitcoin_Target DivScalar_NBitcoinTarget() - //{ - // return new NBitcoin_Target(nt1.ToBigInteger() / new BigInteger((long)scalar)); - //} - - [Benchmark] public uint CalculateNextWorkRequired() { diff --git a/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.Operators.cs b/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.Operators.cs index 3a441a5c..7eda1537 100644 --- a/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.Operators.cs +++ b/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.Operators.cs @@ -32,157 +32,81 @@ public partial class Target : UInt256 return new Target(MemoryMarshal.Cast(result)); } - public static Target operator -(Target item) + private void ShiftLeft(int shiftAmount) { - return new Target - { - part1 = ~item.part1, - part2 = ~item.part2, - part3 = ~item.part3, - part4 = ~item.part4, - }; - } + const int ELEMENTS = EXPECTED_SIZE / sizeof(ulong); + const int SIZE = sizeof(ulong) * 8; - public static Target operator -(Target left, Target right) - { - return left + -right; - } + Span data = MemoryMarshal.CreateSpan(ref Unsafe.As(ref this.part1), ELEMENTS); - public static Target operator <<(Target left, int shiftAmount) - { - ReadOnlySpan leftBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref left.part1), UINT_ELEMENTS_COUNT); + Span result = stackalloc ulong[ELEMENTS]; + result.Clear(); - Span result = stackalloc uint[UINT_ELEMENTS_COUNT]; - result.Fill(0); - - int k = shiftAmount / UINT_BIT_SIZE; - shiftAmount %= UINT_BIT_SIZE; + int k = shiftAmount / SIZE; + shiftAmount %= SIZE; - for (int i = 0; i < UINT_ELEMENTS_COUNT; i++) + for (int i = 0; i < ELEMENTS - k; i++) { - if (i + k + 1 < UINT_ELEMENTS_COUNT && shiftAmount != 0) - result[i + k + 1] |= leftBytes[i] >> (UINT_BIT_SIZE - shiftAmount); + if (i + k + 1 < ELEMENTS && shiftAmount != 0) + { + result[i + k + 1] |= data[i] >> (SIZE - shiftAmount); + } - if (i + k < UINT_ELEMENTS_COUNT) - result[i + k] |= leftBytes[i] << shiftAmount; + result[i + k] |= data[i] << shiftAmount; } - return new Target(MemoryMarshal.Cast(result)); + result.CopyTo(data); } - public static Target operator >>(Target left, int shiftAmount) + private uint GetCompactMantissa(int shiftAmount) { - ReadOnlySpan leftBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref left.part1), UINT_ELEMENTS_COUNT); - - Span result = stackalloc uint[UINT_ELEMENTS_COUNT]; - result.Fill(0); - - int k = shiftAmount / UINT_BIT_SIZE; - shiftAmount %= UINT_BIT_SIZE; + const int ELEMENTS = EXPECTED_SIZE / sizeof(uint); + const int SIZE = sizeof(uint) * 8; - for (int i = 0; i < UINT_ELEMENTS_COUNT; i++) - { - if (i - k - 1 >= 0 && shiftAmount != 0) - result[i - k - 1] |= leftBytes[i] << (UINT_BIT_SIZE - shiftAmount); + ReadOnlySpan leftBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref this.part1), ELEMENTS); - if (i - k >= 0) - result[i - k] |= (leftBytes[i] >> shiftAmount); - } - - return new Target(MemoryMarshal.Cast(result)); - } - - public static Target operator *(Target left, Target right) - { - ReadOnlySpan leftBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref left.part1), UINT_ELEMENTS_COUNT); - ReadOnlySpan rightBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref right.part1), UINT_ELEMENTS_COUNT); + int k = shiftAmount / SIZE; + shiftAmount %= SIZE; - Target result = new Target(); - Span resultSpan = MemoryMarshal.CreateSpan(ref Unsafe.As(ref result.part1), UINT_ELEMENTS_COUNT); + Span result = stackalloc uint[ELEMENTS - k]; + result.Clear(); - for (int j = 0; j < UINT_ELEMENTS_COUNT; j++) + for (int i = k; i < ELEMENTS; i++) { - ulong carry = 0; - for (int i = 0; i + j < UINT_ELEMENTS_COUNT; i++) + if (i - k - 1 >= 0 && shiftAmount != 0) { - ulong n = carry + resultSpan[i + j] + ((ulong)leftBytes[j] * rightBytes[i]); - resultSpan[i + j] = (uint)(n & 0xffffffff); - carry = n >> UINT_BIT_SIZE; + result[i - k - 1] |= leftBytes[i] << (SIZE - shiftAmount); } - } - - return result; - } - public static Target operator *(Target left, uint value) - { - Target result = new Target(); - Span resultSpan = MemoryMarshal.CreateSpan(ref Unsafe.As(ref result.part1), UINT_ELEMENTS_COUNT); - - ReadOnlySpan leftBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref left.part1), UINT_ELEMENTS_COUNT); - ulong carry = 0; - for (int i = 0; i < UINT_ELEMENTS_COUNT; i++) - { - ulong n = carry + ((ulong)value * leftBytes[i]); - resultSpan[i] = (uint)(n & 0xffffffff); - carry = n >> UINT_BIT_SIZE; + result[i - k] |= (leftBytes[i] >> shiftAmount); } - return result; + return result[0]; } - public static Target operator /(Target dividend, Target divisor) + public static Target operator >>(Target left, int shiftAmount) { - int dividendBits = dividend.Bits(); - int divisorBits = divisor.Bits(); - - if (divisorBits == 0) - { - ThrowHelper.ThrowArgumentException("Division by zero"); - } - - // the result is certainly 0. - if (divisorBits > dividendBits) - { - return Zero; - } + ReadOnlySpan leftBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref left.part1), UINT_ELEMENTS_COUNT); - // the quotient. Span result = stackalloc uint[UINT_ELEMENTS_COUNT]; - //result.Fill(0); //allocated data is already zeroed + result.Fill(0); + + int k = shiftAmount / UINT_BIT_SIZE; + shiftAmount %= UINT_BIT_SIZE; - int shiftAmount = dividendBits - divisorBits; - divisor <<= shiftAmount; // shift so that div and num align. - while (shiftAmount >= 0) + for (int i = k; i < UINT_ELEMENTS_COUNT; i++) { - if (dividend >= divisor) + if (i - k - 1 >= 0 && shiftAmount != 0) { - dividend -= divisor; - // set a bit of the result. - result[shiftAmount / UINT_BIT_SIZE] |= (uint)(1 << (shiftAmount & (UINT_BIT_SIZE - 1))); + result[i - k - 1] |= leftBytes[i] << (UINT_BIT_SIZE - shiftAmount); } - divisor >>= 1; // shift back. - shiftAmount--; + result[i - k] |= (leftBytes[i] >> shiftAmount); } return new Target(MemoryMarshal.Cast(result)); } - public static Target operator *(Target left, ulong right) - { - return left * FromRawValue(right); - } - - public static Target operator /(Target left, ulong right) - { - return left / FromRawValue(right); - } - - - - - public void Multiply(uint value) { Span data = MemoryMarshal.CreateSpan(ref Unsafe.As(ref this.part1), UINT_ELEMENTS_COUNT); @@ -194,59 +118,26 @@ public void Multiply(uint value) data[i] = (uint)(n & 0xffffffff); carry = n >> UINT_BIT_SIZE; } + + //this is slower + //BigInteger me = new BigInteger(this.GetBytes()); + //Span data = MemoryMarshal.CreateSpan(ref Unsafe.As(ref this.part1), EXPECTED_SIZE); + //data.Clear(); + //(me * value).TryWriteBytes(data, out _); } - public void Divide(uint value) + public void Divide(uint divisor) { + if (divisor == 0) + { + ThrowHelper.ThrowArgumentException("Division by zero"); + } + BigInteger dividend = new BigInteger(this.GetBytes()); Span data = MemoryMarshal.CreateSpan(ref Unsafe.As(ref this.part1), EXPECTED_SIZE); - data.Fill(0); - (dividend / value).TryWriteBytes(data, out int writeBytes); - - - - //Span divisorData = stackalloc uint[UINT_ELEMENTS_COUNT]; - //divisorData[0] = divisor; - - //Span data = MemoryMarshal.CreateSpan(ref Unsafe.As(ref this.part1), UINT_ELEMENTS_COUNT); - - //ReadOnlySpan divisorBytes = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref div.part1), UINT_ELEMENTS_COUNT); - - //int dividendBits = this.Bits(); - //int divisorBits = div.Bits(); - - //if (divisorBits == 0) - //{ - // ThrowHelper.ThrowArgumentException("Division by zero"); - //} - - //// the result is certainly 0. - //if (divisorBits > dividendBits) - //{ - // data.Fill(0); - // return; - //} - - //// the quotient. - //Span result = stackalloc uint[UINT_ELEMENTS_COUNT]; - - //int shiftAmount = dividendBits - divisorBits; - //divisor <<= shiftAmount; // shift so that div and num align. - //while (shiftAmount >= 0) - //{ - // if (dividend >= divisor) - // { - // dividend -= divisor; - // // set a bit of the result. - // result[shiftAmount / UINT_BIT_SIZE] |= (uint)(1 << (shiftAmount & (UINT_BIT_SIZE - 1))); - // } - - // divisor >>= 1; // shift back. - // shiftAmount--; - //} - - //return new Target(MemoryMarshal.Cast(result)); + data.Clear(); + (dividend / divisor).TryWriteBytes(data, out _); } } } \ No newline at end of file diff --git a/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.cs b/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.cs index 5b9b8736..a16416bc 100644 --- a/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.cs +++ b/src/MithrilShards.Chain.Bitcoin/DataTypes/Target.cs @@ -2,7 +2,6 @@ using System.Buffers.Binary; using System.Diagnostics; using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using MithrilShards.Core.DataTypes; @@ -19,18 +18,17 @@ public partial class Target : UInt256 /// public static Target FromRawValue(ulong value) { - return new Target - { - part1 = value, - //part1 = ((ulong)((uint)value) | (ulong)((uint)value >> 32)) - }; + return new Target { part1 = value }; } - private Target() { } public Target(string hexString) : base(hexString) { } + /// + /// Initializes a new instance of the class from a raw byte array. + /// + /// public Target(ReadOnlySpan input) : base(input) { } /// @@ -52,8 +50,14 @@ public Target(uint compactValue) } else { - Target temp = new Target { part1 = mantissa } << (8 * (exponent - 3)); - temp.GetBytes().CopyTo(data); + //BigInteger n = new BigInteger(mantissa) << (8 * (exponent - 3)); + //n.TryWriteBytes(data, out _); + + //Target temp = new Target { part1 = mantissa } << (8 * (exponent - 3)); + //temp.GetBytes().CopyTo(data); + + this.part1 = mantissa; + this.ShiftLeft(8 * (exponent - 3)); } /// 0x00800000 is the mask to use to obtain the sign, if needed. @@ -110,7 +114,7 @@ public uint ToCompact(bool isNegative = false) } else { - compact = (uint)(this >> 8 * (size - 3)).part1; + compact = this.GetCompactMantissa(8 * (size - 3)); } // The 0x00800000 bit denotes the sign. @@ -135,6 +139,5 @@ public BigInteger ToBigInteger() var value = compact & 0x00FFFFFF; return new BigInteger(value) << (8 * ((int)exp - 3)); } - } }