Skip to content

Commit f7aedbc

Browse files
committed
add logical and bit manipulation methods for Int
1 parent 6be89f7 commit f7aedbc

File tree

2 files changed

+335
-0
lines changed

2 files changed

+335
-0
lines changed

int.go

+76
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,82 @@ func (z *Int) Rsh(x *Int, s uint) *Int {
449449
return z
450450
}
451451

452+
// Bit returns the value of the i'th bit of x. That is, it
453+
// returns (x>>i)&1. The bit index i must be >= 0.
454+
func (x *Int) Bit(i int) uint {
455+
x.doinit()
456+
return uint(C.mpz_tstbit(&x.i[0], C.mp_bitcnt_t(i)))
457+
}
458+
459+
// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
460+
// That is, if bit is 1 SetBit sets z = x | (1 << i);
461+
// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
462+
// SetBit will panic.
463+
func (z *Int) SetBit(x *Int, i int, b uint) *Int {
464+
z.doinit()
465+
466+
if i < 0 {
467+
panic("negative bit index")
468+
}
469+
470+
z.Set(x)
471+
switch b {
472+
case 0:
473+
C.mpz_clrbit(&z.i[0], C.mp_bitcnt_t(i))
474+
case 1:
475+
C.mpz_setbit(&z.i[0], C.mp_bitcnt_t(i))
476+
default:
477+
panic("set bit is not 0 or 1")
478+
}
479+
return z
480+
}
481+
482+
// And sets z = x & y and returns z.
483+
func (z *Int) And(x, y *Int) *Int {
484+
z.doinit()
485+
x.doinit()
486+
y.doinit()
487+
C.mpz_and(&z.i[0], &x.i[0], &y.i[0])
488+
return z
489+
}
490+
491+
// AndNot sets z = x &^ y and returns z.
492+
func (z *Int) AndNot(x, y *Int) *Int {
493+
z.doinit()
494+
x.doinit()
495+
y.doinit()
496+
497+
temp := new(Int).Not(y)
498+
defer temp.Clear()
499+
return z.And(x, temp)
500+
}
501+
502+
// Or sets z = x | y and returns z.
503+
func (z *Int) Or(x, y *Int) *Int {
504+
z.doinit()
505+
x.doinit()
506+
y.doinit()
507+
C.mpz_ior(&z.i[0], &x.i[0], &y.i[0])
508+
return z
509+
}
510+
511+
// Xor sets z = x ^ y and returns z.
512+
func (z *Int) Xor(x, y *Int) *Int {
513+
z.doinit()
514+
x.doinit()
515+
y.doinit()
516+
C.mpz_xor(&z.i[0], &x.i[0], &y.i[0])
517+
return z
518+
}
519+
520+
// Not sets z = ^x and returns z.
521+
func (z *Int) Not(x *Int) *Int {
522+
z.doinit()
523+
x.doinit()
524+
C.mpz_com(&z.i[0], &x.i[0])
525+
return z
526+
}
527+
452528
// Exp sets z = x^y % m and returns z. If m != nil, negative exponents are
453529
// allowed if x^-1 mod m exists. If the inverse doesn't exist then a
454530
// division-by-zero run-time panic occurs.

int_test.go

+259
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,265 @@ func TestUint64(t *testing.T) {
877877
}
878878
}
879879

880+
var bitwiseTests = []struct {
881+
x, y string
882+
and, or, xor, andNot string
883+
}{
884+
{"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
885+
{"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
886+
{"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
887+
{"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
888+
{"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
889+
{"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
890+
{"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
891+
{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
892+
{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
893+
{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
894+
{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
895+
{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
896+
{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
897+
{
898+
"0x1000009dc6e3d9822cba04129bcbe3401",
899+
"0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
900+
"0x1000001186210100001000009048c2001",
901+
"0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
902+
"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
903+
"0x8c40c2d8822caa04120b8321400",
904+
},
905+
{
906+
"0x1000009dc6e3d9822cba04129bcbe3401",
907+
"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
908+
"0x8c40c2d8822caa04120b8321401",
909+
"-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
910+
"-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
911+
"0x1000001186210100001000009048c2000",
912+
},
913+
{
914+
"-0x1000009dc6e3d9822cba04129bcbe3401",
915+
"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
916+
"-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
917+
"-0x1000001186210100001000009048c2001",
918+
"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
919+
"0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
920+
},
921+
}
922+
923+
type bitFun func(z, x, y *Int) *Int
924+
925+
func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
926+
expected := new(Int)
927+
expected.SetString(exp, 0)
928+
929+
out := f(new(Int), x, y)
930+
if out.Cmp(expected) != 0 {
931+
t.Errorf("%s: got %s want %s", msg, out, expected)
932+
}
933+
}
934+
935+
func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
936+
self := new(Int)
937+
self.Set(x)
938+
expected := new(Int)
939+
expected.SetString(exp, 0)
940+
941+
self = f(self, self, y)
942+
if self.Cmp(expected) != 0 {
943+
t.Errorf("%s: got %s want %s", msg, self, expected)
944+
}
945+
}
946+
947+
func altBit(x *Int, i int) uint {
948+
z := new(Int).Rsh(x, uint(i))
949+
z = z.And(z, NewInt(1))
950+
if z.Cmp(new(Int)) != 0 {
951+
return 1
952+
}
953+
return 0
954+
}
955+
956+
func altSetBit(z *Int, x *Int, i int, b uint) *Int {
957+
one := NewInt(1)
958+
m := one.Lsh(one, uint(i))
959+
switch b {
960+
case 1:
961+
return z.Or(x, m)
962+
case 0:
963+
return z.AndNot(x, m)
964+
}
965+
panic("set bit is not 0 or 1")
966+
}
967+
968+
func testBitset(t *testing.T, x *Int) {
969+
n := x.BitLen()
970+
z := new(Int).Set(x)
971+
z1 := new(Int).Set(x)
972+
for i := 0; i < n+10; i++ {
973+
old := z.Bit(i)
974+
old1 := altBit(z1, i)
975+
if old != old1 {
976+
t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
977+
}
978+
z := new(Int).SetBit(z, i, 1)
979+
z1 := altSetBit(new(Int), z1, i, 1)
980+
if z.Bit(i) == 0 {
981+
t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
982+
}
983+
if z.Cmp(z1) != 0 {
984+
t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
985+
}
986+
z.SetBit(z, i, 0)
987+
altSetBit(z1, z1, i, 0)
988+
if z.Bit(i) != 0 {
989+
t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
990+
}
991+
if z.Cmp(z1) != 0 {
992+
t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
993+
}
994+
altSetBit(z1, z1, i, old)
995+
z.SetBit(z, i, old)
996+
if z.Cmp(z1) != 0 {
997+
t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
998+
}
999+
}
1000+
if z.Cmp(x) != 0 {
1001+
t.Errorf("bitset: got %s want %s", z, x)
1002+
}
1003+
}
1004+
1005+
var bitsetTests = []struct {
1006+
x string
1007+
i int
1008+
b uint
1009+
}{
1010+
{"0", 0, 0},
1011+
{"0", 200, 0},
1012+
{"1", 0, 1},
1013+
{"1", 1, 0},
1014+
{"-1", 0, 1},
1015+
{"-1", 200, 1},
1016+
{"0x2000000000000000000000000000", 108, 0},
1017+
{"0x2000000000000000000000000000", 109, 1},
1018+
{"0x2000000000000000000000000000", 110, 0},
1019+
{"-0x2000000000000000000000000001", 108, 1},
1020+
{"-0x2000000000000000000000000001", 109, 0},
1021+
{"-0x2000000000000000000000000001", 110, 1},
1022+
}
1023+
1024+
func TestBitSet(t *testing.T) {
1025+
for _, test := range bitwiseTests {
1026+
x := new(Int)
1027+
x.SetString(test.x, 0)
1028+
testBitset(t, x)
1029+
x = new(Int)
1030+
x.SetString(test.y, 0)
1031+
testBitset(t, x)
1032+
}
1033+
for i, test := range bitsetTests {
1034+
x := new(Int)
1035+
x.SetString(test.x, 0)
1036+
b := x.Bit(test.i)
1037+
if b != test.b {
1038+
t.Errorf("#%d got %v want %v", i, b, test.b)
1039+
}
1040+
}
1041+
z := NewInt(1)
1042+
z.SetBit(NewInt(0), 2, 1)
1043+
if z.Cmp(NewInt(4)) != 0 {
1044+
t.Errorf("destination leaked into result; got %s want 4", z)
1045+
}
1046+
}
1047+
1048+
func BenchmarkBitset(b *testing.B) {
1049+
z := new(Int)
1050+
z.SetBit(z, 512, 1)
1051+
b.ResetTimer()
1052+
b.StartTimer()
1053+
for i := b.N - 1; i >= 0; i-- {
1054+
z.SetBit(z, i&512, 1)
1055+
}
1056+
}
1057+
1058+
func BenchmarkBitsetNeg(b *testing.B) {
1059+
z := NewInt(-1)
1060+
z.SetBit(z, 512, 0)
1061+
b.ResetTimer()
1062+
b.StartTimer()
1063+
for i := b.N - 1; i >= 0; i-- {
1064+
z.SetBit(z, i&512, 0)
1065+
}
1066+
}
1067+
1068+
func BenchmarkBitsetOrig(b *testing.B) {
1069+
z := new(Int)
1070+
altSetBit(z, z, 512, 1)
1071+
b.ResetTimer()
1072+
b.StartTimer()
1073+
for i := b.N - 1; i >= 0; i-- {
1074+
altSetBit(z, z, i&512, 1)
1075+
}
1076+
}
1077+
1078+
func BenchmarkBitsetNegOrig(b *testing.B) {
1079+
z := NewInt(-1)
1080+
altSetBit(z, z, 512, 0)
1081+
b.ResetTimer()
1082+
b.StartTimer()
1083+
for i := b.N - 1; i >= 0; i-- {
1084+
altSetBit(z, z, i&512, 0)
1085+
}
1086+
}
1087+
1088+
func TestBitwise(t *testing.T) {
1089+
x := new(Int)
1090+
y := new(Int)
1091+
for _, test := range bitwiseTests {
1092+
x.SetString(test.x, 0)
1093+
y.SetString(test.y, 0)
1094+
1095+
testBitFun(t, "and", (*Int).And, x, y, test.and)
1096+
testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
1097+
testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
1098+
testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
1099+
testBitFun(t, "or", (*Int).Or, x, y, test.or)
1100+
testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
1101+
testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
1102+
testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
1103+
}
1104+
}
1105+
1106+
var notTests = []struct {
1107+
in string
1108+
out string
1109+
}{
1110+
{"0", "-1"},
1111+
{"1", "-2"},
1112+
{"7", "-8"},
1113+
{"0", "-1"},
1114+
{"-81910", "81909"},
1115+
{
1116+
"298472983472983471903246121093472394872319615612417471234712061",
1117+
"-298472983472983471903246121093472394872319615612417471234712062",
1118+
},
1119+
}
1120+
1121+
func TestNot(t *testing.T) {
1122+
in := new(Int)
1123+
out := new(Int)
1124+
expected := new(Int)
1125+
for i, test := range notTests {
1126+
in.SetString(test.in, 10)
1127+
expected.SetString(test.out, 10)
1128+
out = out.Not(in)
1129+
if out.Cmp(expected) != 0 {
1130+
t.Errorf("#%d: got %s want %s", i, out, expected)
1131+
}
1132+
out = out.Not(out)
1133+
if out.Cmp(in) != 0 {
1134+
t.Errorf("#%d: got %s want %s", i, out, in)
1135+
}
1136+
}
1137+
}
1138+
8801139
var modInverseTests = []struct {
8811140
element string
8821141
prime string

0 commit comments

Comments
 (0)