dcrd/math/uint256/uint256_bench_test.go
Dave Collins 3b8efba395
math/uint256: Prepare v1.0.0.
While the original plan was to keep uint256 as a part of the primitives
module, there has been interest in using the uint256 code now and the
primitives module will not be complete and ready for release for quite
some time.

Also, after further discussion, the general preference is for a separate
module that lives at math/uint256 for this code since the primitives
module will ultimately be squarely aimed at Decred-specific things while
math/uint256 is more generally useful, including many projects outside
of Decred as well.

Thus, this moves the new uint256 package from the internal staging area
to math/uint256 where it will serve as a base for a new math/uint256
module release.

Finally, it updates all relevant paths and package README.md
accordingly.
2021-12-09 17:25:56 -06:00

1326 lines
35 KiB
Go

// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package uint256
import (
"fmt"
"math/big"
"math/rand"
"testing"
"time"
)
// These variables are used to help ensure the benchmarks do not elide code.
var (
noElideBool bool
noElideBytes []byte
noElideInt int
noElideUint16 uint16
noElideString string
)
// randBenchVal houses values used throughout the benchmarks that are randomly
// generated with each run to ensure they are not overfitted.
type randBenchVal struct {
buf1 [32]byte
buf2 [32]byte
n1 *Uint256
n2 *Uint256
n2Low64 *Uint256
bigN1 *big.Int
bigN2 *big.Int
bigN2Low64 *big.Int
}
// randBenchVals houses a slice of the aforementioned randomly-generated values
// to be used throughout the benchmarks to ensure they are not overfitted.
var randBenchVals = func() []randBenchVal {
// Use a unique random seed each benchmark instance.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
var zeroArr [32]byte
vals := make([]randBenchVal, 512)
for i := 0; i < len(vals); i++ {
val := &vals[i]
if _, err := rng.Read(val.buf1[:]); err != nil {
panic(fmt.Sprintf("failed to read random: %v", err))
}
for val.buf2 == zeroArr {
if _, err := rng.Read(val.buf2[:]); err != nil {
panic(fmt.Sprintf("failed to read random: %v", err))
}
}
val.n1 = new(Uint256).SetBytes(&val.buf1)
val.n2 = new(Uint256).SetBytes(&val.buf2)
val.n2Low64 = new(Uint256).SetUint64(val.n2.Uint64())
val.bigN1 = new(big.Int).SetBytes(val.buf1[:])
val.bigN2 = new(big.Int).SetBytes(val.buf2[:])
val.bigN2Low64 = new(big.Int).SetUint64(val.n2.Uint64())
}
return vals
}()
// maxUint256Bytes returns the raw bytes for a max value unsigned 256-bit
// big-endian integer used throughout the benchmarks.
func maxUint256Bytes() []byte {
return hexToBytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
}
// BenchmarkUint256SetBytes benchmarks initializing an unsigned 256-bit integer
// from bytes in big endian with the specialized type.
func BenchmarkUint256SetBytes(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.SetBytes(&vals[j].buf1)
}
}
}
// BenchmarkBigIntSetBytes benchmarks initializing an unsigned 256-bit integer
// from bytes in big endian with stdlib big integers.
func BenchmarkBigIntSetBytes(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.SetBytes(vals[j].buf1[:])
}
}
}
// BenchmarkUint256SetBytesLE benchmarks initializing an unsigned 256-bit
// integer from bytes in little endian with the specialized type.
func BenchmarkUint256SetBytesLE(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.SetBytesLE(&vals[j].buf1)
}
}
}
// BenchmarkBigIntSetBytesLE benchmarks initializing an unsigned 256-bit integer
// from bytes in little endian with stdlib big integers.
func BenchmarkBigIntSetBytesLE(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
// The big int API only takes the bytes in big endian, so they need
// to be reversed by the caller. Note that this implementation
// assumes the buffer is already 32 bytes and is not robust against
// other cases, but it's good enough for a reasonable benchmark.
buf := vals[j].buf1[:]
reversed := make([]byte, len(buf))
blen := len(buf)
for i := 0; i < blen/2; i++ {
reversed[i], reversed[blen-1-i] = buf[blen-1-i], buf[i]
}
n.SetBytes(reversed)
}
}
}
// BenchmarkUint256Bytes benchmarks unpacking an unsigned 256-bit integer to
// bytes in big endian with the specialized type.
func BenchmarkUint256Bytes(b *testing.B) {
vals := randBenchVals
var buf [32]byte
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
vals[j].n1.PutBytes(&buf)
}
}
}
// BenchmarkBigIntBytes benchmarks unpacking an unsigned 256-bit integer to
// bytes in big endian with the stdlib big integers.
func BenchmarkBigIntBytes(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
noElideBytes = vals[j].bigN1.Bytes()
}
}
}
// BenchmarkUint256BytesLE benchmarks unpacking an unsigned 256-bit integer to
// bytes in little endian with the specialized type.
func BenchmarkUint256BytesLE(b *testing.B) {
vals := randBenchVals
var buf [32]byte
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
vals[j].n1.PutBytesLE(&buf)
}
}
}
// BenchmarkBigIntBytesLE benchmarks unpacking an unsigned 256-bit integer to
// bytes in little endian with the stdlib big integers.
func BenchmarkBigIntBytesLE(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
// The big int API only provides the bytes in big endian, so they
// need to be reversed by the caller. Note that this implementation
// assumes the buffer is already 32 bytes and is not robust against
// other cases, but it's good enough for a reasonable benchmark.
buf := vals[j].bigN1.Bytes()
blen := len(buf)
for i := 0; i < blen/2; i++ {
buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
}
noElideBytes = buf
}
}
}
// BenchmarkUint256Zero benchmarks zeroing an unsigned 256-bit integer with the
// specialized type.
func BenchmarkUint256Zero(b *testing.B) {
n := new(Uint256).SetByteSlice(maxUint256Bytes())
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
n.Zero()
}
}
// BenchmarkBigIntZero benchmarks zeroing an unsigned 256-bit integer with
// stdlib big integers.
func BenchmarkBigIntZero(b *testing.B) {
n := new(big.Int).SetBytes(maxUint256Bytes())
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
n.SetUint64(0)
}
}
// BenchmarkUint256IsZero benchmarks determining if an unsigned 256-bit integer
// is zero with the specialized type.
func BenchmarkUint256IsZero(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
noElideBool = vals[j].n1.IsZero()
}
}
}
// BenchmarkBigIntIsZero benchmarks determining if an unsigned 256-bit integer
// is zero with stdlib big integers.
func BenchmarkBigIntIsZero(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
noElideBool = vals[j].bigN1.Sign() == 0
}
}
}
// BenchmarkUint256IsOdd benchmarks determining if an unsigned 256-bit integer
// is odd with the specialized type.
func BenchmarkUint256IsOdd(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
noElideBool = vals[j].n1.IsOdd()
}
}
}
// BenchmarkBigIntIsOdd benchmarks determining if an unsigned 256-bit integer is
// odd with stdlib big integers.
func BenchmarkBigIntIsOdd(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
noElideBool = vals[j].bigN1.Bit(0) == 1
}
}
}
// BenchmarkUint256Eq benchmarks determining equality between two unsigned
// 256-bit integers with the specialized type.
func BenchmarkUint256Eq(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideBool = val.n1.Eq(val.n2)
}
}
}
// BenchmarkBigIntEq benchmarks determining equality between two unsigned
// 256-bit integers with stdlib big integers.
func BenchmarkBigIntEq(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideBool = val.bigN1.Cmp(val.bigN2) == 0
}
}
}
// BenchmarkUint256Lt benchmarks determining if one unsigned 256-bit integer is
// less than another with the specialized type.
func BenchmarkUint256Lt(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideBool = val.n1.Lt(val.n2)
}
}
}
// BenchmarkBigIntLt benchmarks determining if one unsigned 256-bit integer is
// less than another with stdlib big integers.
func BenchmarkBigIntLt(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideBool = val.bigN1.Cmp(val.bigN2) < 0
}
}
}
// BenchmarkUint256Gt benchmarks determining if one unsigned 256-bit integer is
// greater than another with the specialized type.
func BenchmarkUint256Gt(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideBool = val.n1.Gt(val.n2)
}
}
}
// BenchmarkBigIntGt benchmarks determining if one unsigned 256-bit integer is
// greater than another with stdlib big integers.
func BenchmarkBigIntGt(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideBool = val.bigN1.Cmp(val.bigN2) > 0
}
}
}
// BenchmarkUint256Cmp benchmarks comparing two unsigned 256-bit integers with
// the specialized type.
func BenchmarkUint256Cmp(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideInt = val.n1.Cmp(val.n2)
}
}
}
// BenchmarkBigIntCmp benchmarks comparing two unsigned 256-bit integers with
// stdlib big integers.
func BenchmarkBigIntCmp(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideInt = val.bigN1.Cmp(val.bigN2)
}
}
}
// BenchmarkUint256CmpUint64 benchmarks comparing an unsigned 256-bit integer
// with an unsigned 64-bit integer with the specialized type.
func BenchmarkUint256CmpUint64(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideInt = val.n1.CmpUint64(val.n2Low64.Uint64())
}
}
}
// BenchmarkBigIntCmp benchmarks comparing an unsigned 256-bit integer with an
// unsigned 64-bit integer with stdlib big integers.
func BenchmarkBigIntCmpUint64(b *testing.B) {
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideInt = val.bigN1.Cmp(val.bigN2Low64)
}
}
}
// BenchmarkUint256Add benchmarks computing the sum of unsigned 256-bit integers
// with the specialized type.
func BenchmarkUint256Add(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Add2(val.n1, val.n2)
}
}
}
// BenchmarkBigIntAdd benchmarks computing the sum of unsigned 256-bit integers
// with stdlib big integers.
func BenchmarkBigIntAdd(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Add(val.bigN1, val.bigN2)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256AddUint64 benchmarks computing the sum of an unsigned 256-bit
// integer and an unsigned 64-bit integer with the specialized type.
func BenchmarkUint256AddUint64(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.AddUint64(val.n2Low64.Uint64())
}
}
}
// BenchmarkBigIntAddUint64 benchmarks computing the sum of an unsigned 256-bit
// integer and an unsigned 64-bit integer with stdlib big integers.
func BenchmarkBigIntAddUint64(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.bigN1) // For fair comparison.
n.Add(n, val.bigN2Low64)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256Sub benchmarks computing the difference of unsigned 256-bit
// integers with the specialized type.
func BenchmarkUint256Sub(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Sub2(val.n1, val.n2)
}
}
}
// BenchmarkBigIntSub benchmarks computing the difference of unsigned 256-bit
// integers with stdlib big integers.
func BenchmarkBigIntSub(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Sub(val.bigN1, val.bigN2)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256SubUint64 benchmarks computing the difference of an unsigned
// 256-bit integer and unsigned 64-bit integer with the specialized type.
func BenchmarkUint256SubUint64(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.SubUint64(val.n2Low64.Uint64())
}
}
}
// BenchmarkBigIntSubUint64 benchmarks computing the difference of an unsigned
// 256-bit integer and unsigned 64-bit integer with stdlib big integers.
func BenchmarkBigIntSubUint64(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.bigN1) // For fair comparison.
n.Sub(n, val.bigN2Low64)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256Mul benchmarks computing the product of unsigned 256-bit
// integers with the specialized type.
func BenchmarkUint256Mul(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Mul2(val.n1, val.n2)
}
}
}
// BenchmarkBigIntMul benchmarks computing the product of unsigned 256-bit
// integers with stdlib big integers.
func BenchmarkBigIntMul(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Mul(val.bigN1, val.bigN2)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256MulUint64 benchmarks computing the product of an unsigned
// 256-bit integer and unsigned 64-bit integer with the specialized type.
func BenchmarkUint256MulUint64(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.MulUint64(val.n2Low64.Uint64())
}
}
}
// BenchmarkBigIntMulUint64 benchmarks computing the product of an unsigned
// 256-bit integer and unsigned 64-bit integer with stdlib big integers.
func BenchmarkBigIntMulUint64(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.bigN1) // For fair comparison.
n.Mul(n, val.bigN2Low64)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256Square benchmarks computing the quotient of unsigned 256-bit
// integers with the specialized type.
func BenchmarkUint256Square(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.SquareVal(val.n1)
}
}
}
// BenchmarkBigIntSquare benchmarks computing the quotient of unsigned 256-bit
// integers with stdlib big integers.
func BenchmarkBigIntSquare(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Mul(val.bigN1, val.bigN1)
n.Mod(n, two256)
}
}
}
// divBenchTest describes tests that are used for the deterministic division
// benchmarks. It is defined separately so the same tests can easily be used in
// comparison benchmarks between the specialized type in this package and stdlib
// big integers.
type divBenchTest struct {
name string // benchmark description
n1 *Uint256 // dividend
n2 *Uint256 // divisor
}
// makeDivBenches returns a slice of tests that consist of deterministic
// unsigned 256-bit integers of various lengths for use in the division
// benchmarks.
func makeDivBenches() []divBenchTest {
return []divBenchTest{{
// (1<<256 - 2) / (1<<256 - 1)
name: "dividend lt divisor",
n1: hexToUint256("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"),
n2: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<256 - 1)
name: "dividend eq divisor",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
}, {
// (1<<64 - 1) / (1<<64 - 255)
name: "1 by 1 near",
n1: hexToUint256("000000000000000000000000000000000000000000000000ffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000000ffffffffffffff01"),
}, {
// (1<<64 - 1) / (1<<2 - 1)
name: "1 by 1 far",
n1: hexToUint256("000000000000000000000000000000000000000000000000ffffffffffffffff"),
n2: hexToUint256("0000000000000000000000000000000000000000000000000000000000000003"),
}, {
// (1<<128 - 1) / (1<<64 - 1)
name: "2 by 1 near",
n1: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000000ffffffffffffffff"),
}, {
// (1<<128 - 1) / (1<<2 - 1)
name: "2 by 1 far",
n1: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"),
n2: hexToUint256("0000000000000000000000000000000000000000000000000000000000000003"),
}, {
// (1<<192 - 1) / (1<<64 - 1)
name: "3 by 1 near",
n1: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000000ffffffffffffffff"),
}, {
// (1<<192 - 1) / (1<<2 - 1)
name: "3 by 1 far",
n1: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("0000000000000000000000000000000000000000000000000000000000000003"),
}, {
// (1<<256 - 1) / (1<<64 - 1)
name: "4 by 1 near",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000000ffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<2 - 1)
name: "4 by 1 far",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("0000000000000000000000000000000000000000000000000000000000000003"),
}, {
// (1<<128 - 1) / (1<<128 - 255)
name: "2 by 2 near",
n1: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"),
n2: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffff01"),
}, {
// (1<<128 - 1) / (1<<65 - 1)
name: "2 by 2 far",
n1: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000001ffffffffffffffff"),
}, {
// (1<<192 - 1) / (1<<128 - 1)
name: "3 by 2 near",
n1: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"),
}, {
// (1<<192 - 1) / (1<<65 - 1)
name: "3 by 2 far",
n1: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000001ffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<128 - 1)
name: "4 by 2 near",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("00000000000000000000000000000000ffffffffffffffffffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<65 - 1)
name: "4 by 2 far",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("000000000000000000000000000000000000000000000001ffffffffffffffff"),
}, {
// (1<<192 - 1) / (1<<192 - 255)
name: "3 by 3 near",
n1: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff01"),
}, {
// (1<<192 - 1) / (1<<129 - 1)
name: "3 by 3 far",
n1: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("00000000000000000000000000000001ffffffffffffffffffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<192 - 1)
name: "4 by 3 near",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<129 - 1)
name: "4 by 3 far",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("00000000000000000000000000000001ffffffffffffffffffffffffffffffff"),
}, {
// (1<<256 - 1) / (1<<256 - 255)
name: "4 by 4 near",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01"),
}, {
// (1<<256 - 1) / (1<<193 - 1)
name: "4 by 4 far",
n1: hexToUint256("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
n2: hexToUint256("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff"),
}}
}
// BenchmarkUint256Div benchmarks computing the quotient of deterministic
// unsigned 256-bit integers of various length with the specialized type.
func BenchmarkUint256Div(b *testing.B) {
benches := makeDivBenches()
for benchIdx := range benches {
bench := benches[benchIdx]
b.Run(bench.name, func(b *testing.B) {
n := new(Uint256)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
n.Div2(bench.n1, bench.n2)
}
})
}
}
// BenchmarkUint256DivRandom benchmarks computing the quotient of random large
// unsigned 256-bit integers with the specialized type.
func BenchmarkUint256DivRandom(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Div2(val.n1, val.n2)
}
}
}
// BenchmarkBigIntDiv benchmarks computing the quotient of deterministic
// unsigned 256-bit integers of various length with stdlib big integers.
func BenchmarkBigIntDiv(b *testing.B) {
benches := makeDivBenches()
for benchIdx := range benches {
bench := benches[benchIdx]
b.Run(bench.name, func(b *testing.B) {
n := new(big.Int)
n1Bytes, n2Bytes := bench.n1.Bytes(), bench.n2.Bytes()
n1 := new(big.Int).SetBytes(n1Bytes[:])
n2 := new(big.Int).SetBytes(n2Bytes[:])
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
n.Div(n1, n2)
}
})
}
}
// BenchmarkBigIntDivRandom benchmarks computing the quotient of random large
// unsigned 256-bit integers with stdlib big integers.
func BenchmarkBigIntDivRandom(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Div(val.bigN1, val.bigN2)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256DivUint64 benchmarks computing the quotient of an unsigned
// 256-bit integer and unsigned 64-bit integer with the specialized type.
func BenchmarkUint256DivUint64(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.DivUint64(val.n2Low64.Uint64())
}
}
}
// BenchmarkBigIntDivUint64 benchmarks computing the quotient of an unsigned
// 256-bit integer and unsigned 64-bit integer with stdlib big integers.
func BenchmarkBigIntDivUint64(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Div(val.bigN1, val.bigN2Low64)
n.Mod(n, two256)
}
}
}
// BenchmarkUint256Negate benchmarks computing the negation modulo 2^256 of an
// unsigned 256-bit integer with the specialized type.
func BenchmarkUint256Negate(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.NegateVal(vals[j].n1)
}
}
}
// BenchmarkBigIntNegate benchmarks computing the negation module 2^256 of an
// unsigned 256-bit integer with stdlib big integers.
func BenchmarkBigIntNegate(b *testing.B) {
n := new(big.Int)
two256 := new(big.Int).Lsh(big.NewInt(1), 256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.Mod(n.Neg(vals[j].bigN1), two256)
}
}
}
// BenchmarkUint256Lsh benchmarks left shifting an unsigned 256-bit integer with
// the specialized type.
func BenchmarkUint256Lsh(b *testing.B) {
for _, bits := range []uint32{0, 1, 64, 128, 192, 255, 256} {
benchName := fmt.Sprintf("bits %d", bits)
b.Run(benchName, func(b *testing.B) {
result := new(Uint256)
max256 := new(Uint256).SetByteSlice(maxUint256Bytes())
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
result.LshVal(max256, bits)
}
})
}
}
// BenchmarkBigIntLsh benchmarks left shifting an unsigned 256-bit integer with
// stdlib big integers.
func BenchmarkBigIntLsh(b *testing.B) {
for _, bits := range []uint{0, 1, 64, 128, 192, 255, 256} {
benchName := fmt.Sprintf("bits %d", bits)
b.Run(benchName, func(b *testing.B) {
result := new(big.Int)
max256 := new(big.Int).SetBytes(maxUint256Bytes())
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
result.Lsh(max256, bits)
}
})
}
}
// BenchmarkUint256Rsh benchmarks right shifting an unsigned 256-bit integer
// with the specialized type.
func BenchmarkUint256Rsh(b *testing.B) {
for _, bits := range []uint32{0, 1, 64, 128, 192, 255, 256} {
benchName := fmt.Sprintf("bits %d", bits)
b.Run(benchName, func(b *testing.B) {
result := new(Uint256)
max256 := new(Uint256).SetByteSlice(maxUint256Bytes())
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
result.RshVal(max256, bits)
}
})
}
}
// BenchmarkBigIntRsh benchmarks right shifting an unsigned 256-bit integer with
// stdlib big integers.
func BenchmarkBigIntRsh(b *testing.B) {
for _, bits := range []uint{0, 1, 64, 128, 192, 255, 256} {
benchName := fmt.Sprintf("bits %d", bits)
b.Run(benchName, func(b *testing.B) {
result := new(big.Int)
max256 := new(big.Int).SetBytes(maxUint256Bytes())
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
result.Rsh(max256, bits)
}
})
}
}
// BenchmarkUint256Not benchmarks computing the bitwise not of an unsigned
// 256-bit integer with the specialized type.
func BenchmarkUint256Not(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.Set(vals[j].n1)
n.Not()
}
}
}
// BenchmarkBigIntNot benchmarks computing the bitwise not of an unsigned
// 256-bit integer with stdlib big integers.
func BenchmarkBigIntNot(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
n.Set(vals[j].bigN1) // For fair comparison.
n.Not(n)
}
}
}
// BenchmarkUint256Or benchmarks computing the bitwise or of unsigned 256-bit
// integers with the specialized type.
func BenchmarkUint256Or(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.Or(val.n2)
}
}
}
// BenchmarkBigIntOr benchmarks computing the bitwise or of unsigned 256-bit
// integers with stdlib big integers.
func BenchmarkBigIntOr(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.bigN1) // For fair comparison.
n.Or(n, val.bigN2)
}
}
}
// BenchmarkUint256And benchmarks computing the bitwise and of unsigned 256-bit
// integers with the specialized type.
func BenchmarkUint256And(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.And(val.n2)
}
}
}
// BenchmarkBigIntAnd benchmarks computing the bitwise and of unsigned 256-bit
// integers with stdlib big integers.
func BenchmarkBigIntAnd(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.bigN1) // For fair comparison.
n.And(n, val.bigN2)
}
}
}
// BenchmarkUint256Xor benchmarks computing the bitwise exclusive or of unsigned
// 256-bit integers with the specialized type.
func BenchmarkUint256Xor(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.n1)
n.Xor(val.n2)
}
}
}
// BenchmarkBigIntXor benchmarks computing the bitwise exclusive or of unsigned
// 256-bit integers with stdlib big integers.
func BenchmarkBigIntXor(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.Set(val.bigN1) // For fair comparison.
n.Xor(n, val.bigN2)
}
}
}
// BenchmarkUint256BitLen benchmarks determining the bit length of an unsigned
// 256-bit integer with the specialized type.
func BenchmarkUint256BitLen(b *testing.B) {
for _, bits := range []uint32{64, 128, 192, 255} {
benchName := fmt.Sprintf("bits %d", bits)
b.Run(benchName, func(b *testing.B) {
n := new(Uint256).SetUint64(1).Lsh(bits)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
noElideUint16 = n.BitLen()
}
})
}
}
// BenchmarkBigIntBitLen benchmarks determining the bit length of an unsigned
// 256-bit integer with stdlib big integers.
func BenchmarkBigIntBitLen(b *testing.B) {
for _, bits := range []uint{64, 128, 192, 255} {
benchName := fmt.Sprintf("bits %d", bits)
b.Run(benchName, func(b *testing.B) {
n := new(big.Int).SetUint64(1)
n.Lsh(n, bits)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
noElideInt = n.BitLen()
}
})
}
}
// BenchmarkUint256Text benchmarks converting an unsigned 256-bit integer to
// various output bases with the specialized type.
func BenchmarkUint256Text(b *testing.B) {
vals := randBenchVals
for _, base := range []OutputBase{2, 8, 10, 16} {
benchName := fmt.Sprintf("base %d", base)
b.Run(benchName, func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideString = val.n1.Text(base)
}
}
})
}
}
// BenchmarkBigIntText benchmarks converting an unsigned 256-bit integer to
// various output bases with stdlib big integers.
func BenchmarkBigIntText(b *testing.B) {
vals := randBenchVals
for _, base := range []int{2, 8, 10, 16} {
benchName := fmt.Sprintf("base %d", base)
b.Run(benchName, func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideString = val.bigN1.Text(base)
}
}
})
}
}
// BenchmarkUint256Format benchmarks formatting an unsigned 256-bit integer to
// various output bases via fmt.Sprintf with the specialized type.
func BenchmarkUint256Format(b *testing.B) {
vals := randBenchVals
for _, base := range []int{2, 8, 10, 16} {
benchName := fmt.Sprintf("base %d", base)
b.Run(benchName, func(b *testing.B) {
var fmtStr string
switch base {
case 2:
fmtStr = "%b"
case 8:
fmtStr = "%o"
case 10:
fmtStr = "%d"
case 16:
fmtStr = "%x"
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideString = fmt.Sprintf(fmtStr, val.n1)
}
}
})
}
}
// BenchmarkBigIntFormat benchmarks formatting an unsigned 256-bit integer to
// various output bases via fmt.Sprintf with stdlib big integers.
func BenchmarkBigIntFormat(b *testing.B) {
vals := randBenchVals
for _, base := range []int{2, 8, 10, 16} {
benchName := fmt.Sprintf("base %d", base)
b.Run(benchName, func(b *testing.B) {
var fmtStr string
switch base {
case 2:
fmtStr = "%b"
case 8:
fmtStr = "%o"
case 10:
fmtStr = "%d"
case 16:
fmtStr = "%x"
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
noElideString = fmt.Sprintf(fmtStr, val.bigN1)
}
}
})
}
}
// BenchmarkUint256PutBig benchmarks converting an unsigned 256-bit integer to a
// stdlib big integer.
func BenchmarkUint256PutBig(b *testing.B) {
n := new(big.Int)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
val.n1.PutBig(n)
}
}
}
// BenchmarkUint256PutBig benchmarks converting a stdlib big integer to an
// unsigned 256-bit integer.
func BenchmarkUint256SetBig(b *testing.B) {
n := new(Uint256)
vals := randBenchVals
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i += len(vals) {
for j := 0; j < len(vals); j++ {
val := &vals[j]
n.SetBig(val.bigN1)
}
}
}