mirror of
https://github.com/golang/go
synced 2024-11-21 21:34:40 -07:00
big: add Int methods to act on numbered bits.
Speeds up setting individual bits by ~75%, useful when using big.Int as a bit set. R=gri, rsc CC=golang-dev https://golang.org/cl/4538053
This commit is contained in:
parent
8f57f49398
commit
83fd82b349
@ -560,6 +560,42 @@ func (z *Int) Rsh(x *Int, n uint) *Int {
|
||||
}
|
||||
|
||||
|
||||
// Bit returns the value of the i'th bit of z. That is, it
|
||||
// returns (z>>i)&1. The bit index i must be >= 0.
|
||||
func (z *Int) Bit(i int) uint {
|
||||
if i < 0 {
|
||||
panic("negative bit index")
|
||||
}
|
||||
if z.neg {
|
||||
t := nat{}.sub(z.abs, natOne)
|
||||
return t.bit(uint(i)) ^ 1
|
||||
}
|
||||
|
||||
return z.abs.bit(uint(i))
|
||||
}
|
||||
|
||||
|
||||
// SetBit sets the i'th bit of z to bit and returns z.
|
||||
// That is, if bit is 1 SetBit sets z = x | (1 << i);
|
||||
// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
|
||||
// SetBit will panic.
|
||||
func (z *Int) SetBit(x *Int, i int, b uint) *Int {
|
||||
if i < 0 {
|
||||
panic("negative bit index")
|
||||
}
|
||||
if x.neg {
|
||||
t := z.abs.sub(x.abs, natOne)
|
||||
t = t.setBit(t, uint(i), b^1)
|
||||
z.abs = t.add(t, natOne)
|
||||
z.neg = len(z.abs) > 0
|
||||
return z
|
||||
}
|
||||
z.abs = z.abs.setBit(x.abs, uint(i), b)
|
||||
z.neg = false
|
||||
return z
|
||||
}
|
||||
|
||||
|
||||
// And sets z = x & y and returns z.
|
||||
func (z *Int) And(x, y *Int) *Int {
|
||||
if x.neg == y.neg {
|
||||
|
@ -984,6 +984,142 @@ func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
|
||||
}
|
||||
}
|
||||
|
||||
func altBit(x *Int, i int) uint {
|
||||
z := new(Int).Rsh(x, uint(i))
|
||||
z = z.And(z, NewInt(1))
|
||||
if z.Cmp(new(Int)) != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func altSetBit(z *Int, x *Int, i int, b uint) *Int {
|
||||
one := NewInt(1)
|
||||
m := one.Lsh(one, uint(i))
|
||||
switch b {
|
||||
case 1:
|
||||
return z.Or(x, m)
|
||||
case 0:
|
||||
return z.AndNot(x, m)
|
||||
}
|
||||
panic("set bit is not 0 or 1")
|
||||
}
|
||||
|
||||
func testBitset(t *testing.T, x *Int) {
|
||||
n := x.BitLen()
|
||||
z := new(Int).Set(x)
|
||||
z1 := new(Int).Set(x)
|
||||
for i := 0; i < n+10; i++ {
|
||||
old := z.Bit(i)
|
||||
old1 := altBit(z1, i)
|
||||
if old != old1 {
|
||||
t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
|
||||
}
|
||||
z := new(Int).SetBit(z, i, 1)
|
||||
z1 := altSetBit(new(Int), z1, i, 1)
|
||||
if z.Bit(i) == 0 {
|
||||
t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
|
||||
}
|
||||
if z.Cmp(z1) != 0 {
|
||||
t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
|
||||
}
|
||||
z.SetBit(z, i, 0)
|
||||
altSetBit(z1, z1, i, 0)
|
||||
if z.Bit(i) != 0 {
|
||||
t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
|
||||
}
|
||||
if z.Cmp(z1) != 0 {
|
||||
t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
|
||||
}
|
||||
altSetBit(z1, z1, i, old)
|
||||
z.SetBit(z, i, old)
|
||||
if z.Cmp(z1) != 0 {
|
||||
t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
|
||||
}
|
||||
}
|
||||
if z.Cmp(x) != 0 {
|
||||
t.Errorf("bitset: got %s want %s", z, x)
|
||||
}
|
||||
}
|
||||
|
||||
var bitsetTests = []struct {
|
||||
x string
|
||||
i int
|
||||
b uint
|
||||
}{
|
||||
{"0", 0, 0},
|
||||
{"0", 200, 0},
|
||||
{"1", 0, 1},
|
||||
{"1", 1, 0},
|
||||
{"-1", 0, 1},
|
||||
{"-1", 200, 1},
|
||||
{"0x2000000000000000000000000000", 108, 0},
|
||||
{"0x2000000000000000000000000000", 109, 1},
|
||||
{"0x2000000000000000000000000000", 110, 0},
|
||||
{"-0x2000000000000000000000000001", 108, 1},
|
||||
{"-0x2000000000000000000000000001", 109, 0},
|
||||
{"-0x2000000000000000000000000001", 110, 1},
|
||||
}
|
||||
|
||||
func TestBitSet(t *testing.T) {
|
||||
for _, test := range bitwiseTests {
|
||||
x := new(Int)
|
||||
x.SetString(test.x, 0)
|
||||
testBitset(t, x)
|
||||
x = new(Int)
|
||||
x.SetString(test.y, 0)
|
||||
testBitset(t, x)
|
||||
}
|
||||
for i, test := range bitsetTests {
|
||||
x := new(Int)
|
||||
x.SetString(test.x, 0)
|
||||
b := x.Bit(test.i)
|
||||
if b != test.b {
|
||||
|
||||
t.Errorf("#%d want %v got %v", i, test.b, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBitset(b *testing.B) {
|
||||
z := new(Int)
|
||||
z.SetBit(z, 512, 1)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
z.SetBit(z, i&512, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBitsetNeg(b *testing.B) {
|
||||
z := NewInt(-1)
|
||||
z.SetBit(z, 512, 0)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
z.SetBit(z, i&512, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBitsetOrig(b *testing.B) {
|
||||
z := new(Int)
|
||||
altSetBit(z, z, 512, 1)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
altSetBit(z, z, i&512, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBitsetNegOrig(b *testing.B) {
|
||||
z := NewInt(-1)
|
||||
altSetBit(z, z, 512, 0)
|
||||
b.ResetTimer()
|
||||
b.StartTimer()
|
||||
for i := b.N - 1; i >= 0; i-- {
|
||||
altSetBit(z, z, i&512, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitwise(t *testing.T) {
|
||||
x := new(Int)
|
||||
|
@ -773,6 +773,43 @@ func (z nat) shr(x nat, s uint) nat {
|
||||
}
|
||||
|
||||
|
||||
func (z nat) setBit(x nat, i uint, b uint) nat {
|
||||
j := int(i / _W)
|
||||
m := Word(1) << (i % _W)
|
||||
n := len(x)
|
||||
switch b {
|
||||
case 0:
|
||||
z = z.make(n)
|
||||
copy(z, x)
|
||||
if j >= n {
|
||||
// no need to grow
|
||||
return z
|
||||
}
|
||||
z[j] &^= m
|
||||
return z.norm()
|
||||
case 1:
|
||||
if j >= n {
|
||||
n = j + 1
|
||||
}
|
||||
z = z.make(n)
|
||||
copy(z, x)
|
||||
z[j] |= m
|
||||
// no need to normalize
|
||||
return z
|
||||
}
|
||||
panic("set bit is not 0 or 1")
|
||||
}
|
||||
|
||||
|
||||
func (z nat) bit(i uint) uint {
|
||||
j := int(i / _W)
|
||||
if j >= len(z) {
|
||||
return 0
|
||||
}
|
||||
return uint(z[j] >> (i % _W) & 1)
|
||||
}
|
||||
|
||||
|
||||
func (z nat) and(x, y nat) nat {
|
||||
m := len(x)
|
||||
n := len(y)
|
||||
|
Loading…
Reference in New Issue
Block a user