uint256: Add bit length support.

This adds support for determining the minimum number of bits required to
represent the current value of a uint256 along with associated tests to
ensure proper functionality.

This is part of a series of commits to fully implement the uint256
package.
This commit is contained in:
Dave Collins 2021-11-06 16:07:41 -05:00
parent 7ba863dff6
commit c0854f6f17
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
2 changed files with 95 additions and 3 deletions

View File

@ -26,11 +26,11 @@ var (
// subtraction, multiplication, squaring, division, negation), bitwise
// operations (lsh, rsh, not, or, and, xor), comparison operations (equals,
// less, greater, cmp), interpreting and producing big and little endian bytes,
// and other convenience methods such as whether or not the value can be
// and other convenience methods such as determining the minimum number of bits
// required to represent the current value and whether or not the value can be
// represented as a uint64 without loss of precision.
//
// Future commits will implement other convenience methods such as determining
// the minimum number of bits required to represent the current value and text
// Future commits will implement other convenience methods such as text
// formatting with base conversion.
type Uint256 struct {
// The uint256 is represented as 4 unsigned 64-bit integers in base 2^64.
@ -1326,3 +1326,18 @@ func (n *Uint256) Xor(n2 *Uint256) *Uint256 {
n.n[3] ^= n2.n[3]
return n
}
// BitLen returns the minimum number of bits required to represent the uint256.
// The result is 0 when the value is 0.
func (n *Uint256) BitLen() uint16 {
if w := n.n[3]; w > 0 {
return uint16(bits.Len64(w)) + 192
}
if w := n.n[2]; w > 0 {
return uint16(bits.Len64(w)) + 128
}
if w := n.n[1]; w > 0 {
return uint16(bits.Len64(w)) + 64
}
return uint16(bits.Len64(n.n[0]))
}

View File

@ -3320,3 +3320,80 @@ func TestUint256XorRandom(t *testing.T) {
}
}
}
// TestUint256BitLen ensures determining the minimum number of bits required to
// represent a uint256 works as expected.
func TestUint256BitLen(t *testing.T) {
t.Parallel()
tests := []struct {
name string // test description
n string // hex encoded value
want uint16 // expected result
}{{
name: "zero",
n: "0",
want: 0,
}, {
name: "one",
n: "1",
want: 1,
}, {
name: "two",
n: "2",
want: 2,
}, {
name: "2^32 - 1",
n: "ffffffff",
want: 32,
}, {
name: "2^32",
n: "100000000",
want: 33,
}, {
name: "2^64 - 2",
n: "fffffffffffffffe",
want: 64,
}, {
name: "2^64 - 1",
n: "ffffffffffffffff",
want: 64,
}, {
name: "2^64",
n: "10000000000000000",
want: 65,
}, {
name: "2^128 - 1",
n: "ffffffffffffffffffffffffffffffff",
want: 128,
}, {
name: "2^128",
n: "100000000000000000000000000000000",
want: 129,
}, {
name: "2^192 - 1",
n: "ffffffffffffffffffffffffffffffffffffffffffffffff",
want: 192,
}, {
name: "2^192",
n: "1000000000000000000000000000000000000000000000000",
want: 193,
}, {
name: "2^255 - 1",
n: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
want: 255,
}, {
name: "2^256 - 1",
n: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
want: 256,
}}
for _, test := range tests {
got := hexToUint256(test.n).BitLen()
if got != test.want {
t.Errorf("%q: wrong result -- got: %v, want: %v", test.name, got,
test.want)
continue
}
}
}