mirror of
https://github.com/golang/go
synced 2024-11-22 02:14:40 -07:00
big: Add bitwise methods for Int
R=gri CC=golang-dev https://golang.org/cl/987041
This commit is contained in:
parent
e6d0a6c9c1
commit
4d1b1574af
142
src/pkg/big/int.go
Normal file → Executable file
142
src/pkg/big/int.go
Normal file → Executable file
@ -408,3 +408,145 @@ func (z *Int) Rsh(x *Int, n uint) *Int {
|
|||||||
z.abs = z.abs.shr(x.abs, n)
|
z.abs = z.abs.shr(x.abs, n)
|
||||||
return z
|
return z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// And sets z = x & y and returns z.
|
||||||
|
func (z *Int) And(x, y *Int) *Int {
|
||||||
|
if x.neg == y.neg {
|
||||||
|
if x.neg {
|
||||||
|
// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
|
||||||
|
x1 := nat{}.sub(x.abs, natOne)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = true
|
||||||
|
z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x & y == x & y
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.and(x.abs, y.abs)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x.neg != y.neg
|
||||||
|
if x.neg {
|
||||||
|
x, y = y, x // & is symmetric
|
||||||
|
}
|
||||||
|
|
||||||
|
// x & (-y) == x & ^(y-1) == x &^ (y-1)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.andNot(x.abs, y1)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AndNot sets z = x &^ y and returns z.
|
||||||
|
func (z *Int) AndNot(x, y *Int) *Int {
|
||||||
|
if x.neg == y.neg {
|
||||||
|
if x.neg {
|
||||||
|
// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
|
||||||
|
x1 := nat{}.sub(x.abs, natOne)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.andNot(y1, x1)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x &^ y == x &^ y
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.andNot(x.abs, y.abs)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.neg {
|
||||||
|
// (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
|
||||||
|
x1 := z.abs.sub(x.abs, natOne)
|
||||||
|
z.neg = true
|
||||||
|
z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
|
||||||
|
y1 := z.abs.add(y.abs, natOne)
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.and(x.abs, y1)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Or sets z = x | y and returns z.
|
||||||
|
func (z *Int) Or(x, y *Int) *Int {
|
||||||
|
if x.neg == y.neg {
|
||||||
|
if x.neg {
|
||||||
|
// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
|
||||||
|
x1 := nat{}.sub(x.abs, natOne)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = true
|
||||||
|
z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x | y == x | y
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.or(x.abs, y.abs)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x.neg != y.neg
|
||||||
|
if x.neg {
|
||||||
|
x, y = y, x // | is symmetric
|
||||||
|
}
|
||||||
|
|
||||||
|
// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = true
|
||||||
|
z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Xor sets z = x ^ y and returns z.
|
||||||
|
func (z *Int) Xor(x, y *Int) *Int {
|
||||||
|
if x.neg == y.neg {
|
||||||
|
if x.neg {
|
||||||
|
// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
|
||||||
|
x1 := nat{}.sub(x.abs, natOne)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.xor(x1, y1)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x ^ y == x ^ y
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.xor(x.abs, y.abs)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// x.neg != y.neg
|
||||||
|
if x.neg {
|
||||||
|
x, y = y, x // | is symmetric
|
||||||
|
}
|
||||||
|
|
||||||
|
// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
|
||||||
|
y1 := z.abs.sub(y.abs, natOne)
|
||||||
|
z.neg = true
|
||||||
|
z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Not sets z = ^x and returns z.
|
||||||
|
func (z *Int) Not(x *Int) *Int {
|
||||||
|
if x.neg {
|
||||||
|
// ^(-x) == ^(^(x-1)) == x-1
|
||||||
|
z.neg = false
|
||||||
|
z.abs = z.abs.sub(x.abs, natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// ^x == -x-1 == -(x+1)
|
||||||
|
z.neg = true
|
||||||
|
z.abs = z.abs.add(x.abs, natOne)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
126
src/pkg/big/int_test.go
Normal file → Executable file
126
src/pkg/big/int_test.go
Normal file → Executable file
@ -709,3 +709,129 @@ func TestInt64(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type bitwiseTest struct {
|
||||||
|
x, y string
|
||||||
|
and, or, xor, andNot string
|
||||||
|
}
|
||||||
|
|
||||||
|
var bitwiseTests = []bitwiseTest{
|
||||||
|
bitwiseTest{"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
|
||||||
|
bitwiseTest{"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
|
||||||
|
bitwiseTest{"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
|
||||||
|
bitwiseTest{"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
|
||||||
|
bitwiseTest{"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
|
||||||
|
bitwiseTest{"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
|
||||||
|
bitwiseTest{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
|
||||||
|
bitwiseTest{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
|
||||||
|
bitwiseTest{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
|
||||||
|
bitwiseTest{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
|
||||||
|
bitwiseTest{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
|
||||||
|
bitwiseTest{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
|
||||||
|
bitwiseTest{
|
||||||
|
"0x1000009dc6e3d9822cba04129bcbe3401",
|
||||||
|
"0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
|
||||||
|
"0x1000001186210100001000009048c2001",
|
||||||
|
"0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
|
||||||
|
"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
|
||||||
|
"0x8c40c2d8822caa04120b8321400",
|
||||||
|
},
|
||||||
|
bitwiseTest{
|
||||||
|
"0x1000009dc6e3d9822cba04129bcbe3401",
|
||||||
|
"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
|
||||||
|
"0x8c40c2d8822caa04120b8321401",
|
||||||
|
"-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
|
||||||
|
"-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
|
||||||
|
"0x1000001186210100001000009048c2000",
|
||||||
|
},
|
||||||
|
bitwiseTest{
|
||||||
|
"-0x1000009dc6e3d9822cba04129bcbe3401",
|
||||||
|
"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
|
||||||
|
"-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
|
||||||
|
"-0x1000001186210100001000009048c2001",
|
||||||
|
"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
|
||||||
|
"0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type bitFun func(z, x, y *Int) *Int
|
||||||
|
|
||||||
|
func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
|
||||||
|
expected := new(Int)
|
||||||
|
expected.SetString(exp, 16)
|
||||||
|
|
||||||
|
out := f(new(Int), x, y)
|
||||||
|
if out.Cmp(expected) != 0 {
|
||||||
|
println("Test failed")
|
||||||
|
t.Errorf("%s: got %s want %s", msg, out, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
|
||||||
|
expected := new(Int)
|
||||||
|
expected.SetString(exp, 16)
|
||||||
|
|
||||||
|
x = f(x, x, y)
|
||||||
|
if x.Cmp(expected) != 0 {
|
||||||
|
println("Test failed")
|
||||||
|
t.Errorf("%s: got %s want %s", msg, x, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestBitwise(t *testing.T) {
|
||||||
|
x := new(Int)
|
||||||
|
y := new(Int)
|
||||||
|
for _, test := range bitwiseTests {
|
||||||
|
x.SetString(test.x, 16)
|
||||||
|
y.SetString(test.y, 16)
|
||||||
|
|
||||||
|
testBitFun(t, "and", (*Int).And, x, y, test.and)
|
||||||
|
testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
|
||||||
|
testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
|
||||||
|
testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
|
||||||
|
testBitFun(t, "or", (*Int).Or, x, y, test.or)
|
||||||
|
testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
|
||||||
|
testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
|
||||||
|
testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type notTest struct {
|
||||||
|
in string
|
||||||
|
out string
|
||||||
|
}
|
||||||
|
|
||||||
|
var notTests = []notTest{
|
||||||
|
notTest{"0", "-1"},
|
||||||
|
notTest{"1", "-2"},
|
||||||
|
notTest{"7", "-8"},
|
||||||
|
notTest{"0", "-1"},
|
||||||
|
notTest{"-81910", "81909"},
|
||||||
|
notTest{
|
||||||
|
"298472983472983471903246121093472394872319615612417471234712061",
|
||||||
|
"-298472983472983471903246121093472394872319615612417471234712062",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNot(t *testing.T) {
|
||||||
|
in := new(Int)
|
||||||
|
out := new(Int)
|
||||||
|
expected := new(Int)
|
||||||
|
for i, test := range notTests {
|
||||||
|
in.SetString(test.in, 10)
|
||||||
|
expected.SetString(test.out, 10)
|
||||||
|
out = out.Not(in)
|
||||||
|
if out.Cmp(expected) != 0 {
|
||||||
|
t.Errorf("#%d: got %s want %s", i, out, expected)
|
||||||
|
}
|
||||||
|
out = out.Not(out)
|
||||||
|
if out.Cmp(in) != 0 {
|
||||||
|
t.Errorf("#%d: got %s want %s", i, out, in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
77
src/pkg/big/nat.go
Normal file → Executable file
77
src/pkg/big/nat.go
Normal file → Executable file
@ -629,7 +629,7 @@ func hexValue(ch byte) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// scanN returns the natural number corresponding to the
|
// scan returns the natural number corresponding to the
|
||||||
// longest possible prefix of s representing a natural number in a
|
// longest possible prefix of s representing a natural number in a
|
||||||
// given conversion base, the actual conversion base used, and the
|
// given conversion base, the actual conversion base used, and the
|
||||||
// prefix length. The syntax of natural numbers follows the syntax
|
// prefix length. The syntax of natural numbers follows the syntax
|
||||||
@ -833,6 +833,81 @@ func (z nat) shiftRightDeprecated(x nat, n uint) nat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (z nat) and(x, y nat) nat {
|
||||||
|
m := len(x)
|
||||||
|
n := len(y)
|
||||||
|
if m > n {
|
||||||
|
m = n
|
||||||
|
}
|
||||||
|
// m <= n
|
||||||
|
|
||||||
|
z = z.make(m)
|
||||||
|
for i := 0; i < m; i++ {
|
||||||
|
z[i] = x[i] & y[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return z.norm()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (z nat) andNot(x, y nat) nat {
|
||||||
|
m := len(x)
|
||||||
|
n := len(y)
|
||||||
|
if n > m {
|
||||||
|
n = m
|
||||||
|
}
|
||||||
|
// m >= n
|
||||||
|
|
||||||
|
z = z.make(m)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
z[i] = x[i] &^ y[i]
|
||||||
|
}
|
||||||
|
copy(z[n:m], x[n:m])
|
||||||
|
|
||||||
|
return z.norm()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (z nat) or(x, y nat) nat {
|
||||||
|
m := len(x)
|
||||||
|
n := len(y)
|
||||||
|
s := x
|
||||||
|
if m < n {
|
||||||
|
n, m = m, n
|
||||||
|
s = y
|
||||||
|
}
|
||||||
|
// n >= m
|
||||||
|
|
||||||
|
z = z.make(n)
|
||||||
|
for i := 0; i < m; i++ {
|
||||||
|
z[i] = x[i] | y[i]
|
||||||
|
}
|
||||||
|
copy(z[m:n], s[m:n])
|
||||||
|
|
||||||
|
return z.norm()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (z nat) xor(x, y nat) nat {
|
||||||
|
m := len(x)
|
||||||
|
n := len(y)
|
||||||
|
s := x
|
||||||
|
if n < m {
|
||||||
|
n, m = m, n
|
||||||
|
s = y
|
||||||
|
}
|
||||||
|
// n >= m
|
||||||
|
|
||||||
|
z = z.make(n)
|
||||||
|
for i := 0; i < m; i++ {
|
||||||
|
z[i] = x[i] ^ y[i]
|
||||||
|
}
|
||||||
|
copy(z[m:n], s[m:n])
|
||||||
|
|
||||||
|
return z.norm()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
|
// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
|
||||||
func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
|
func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 }
|
||||||
|
|
||||||
|
22
src/pkg/big/nat_test.go
Normal file → Executable file
22
src/pkg/big/nat_test.go
Normal file → Executable file
@ -173,37 +173,37 @@ func BenchmarkMul(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type strN struct {
|
type str struct {
|
||||||
x nat
|
x nat
|
||||||
b int
|
b int
|
||||||
s string
|
s string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var tabN = []strN{
|
var tab = []str{
|
||||||
strN{nil, 10, "0"},
|
str{nil, 10, "0"},
|
||||||
strN{nat{1}, 10, "1"},
|
str{nat{1}, 10, "1"},
|
||||||
strN{nat{10}, 10, "10"},
|
str{nat{10}, 10, "10"},
|
||||||
strN{nat{1234567890}, 10, "1234567890"},
|
str{nat{1234567890}, 10, "1234567890"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestString(t *testing.T) {
|
func TestString(t *testing.T) {
|
||||||
for _, a := range tabN {
|
for _, a := range tab {
|
||||||
s := a.x.string(a.b)
|
s := a.x.string(a.b)
|
||||||
if s != a.s {
|
if s != a.s {
|
||||||
t.Errorf("stringN%+v\n\tgot s = %s; want %s", a, s, a.s)
|
t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
|
||||||
}
|
}
|
||||||
|
|
||||||
x, b, n := nat(nil).scan(a.s, a.b)
|
x, b, n := nat(nil).scan(a.s, a.b)
|
||||||
if x.cmp(a.x) != 0 {
|
if x.cmp(a.x) != 0 {
|
||||||
t.Errorf("scanN%+v\n\tgot z = %v; want %v", a, x, a.x)
|
t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
|
||||||
}
|
}
|
||||||
if b != a.b {
|
if b != a.b {
|
||||||
t.Errorf("scanN%+v\n\tgot b = %d; want %d", a, b, a.b)
|
t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b)
|
||||||
}
|
}
|
||||||
if n != len(a.s) {
|
if n != len(a.s) {
|
||||||
t.Errorf("scanN%+v\n\tgot n = %d; want %d", a, n, len(a.s))
|
t.Errorf("scan%+v\n\tgot n = %d; want %d", a, n, len(a.s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user