]> Cypherpunks repositories - gostls13.git/commitdiff
implemented outstanding bit ops on negative integerts
authorRobert Griesemer <gri@golang.org>
Tue, 21 Jul 2009 20:35:51 +0000 (13:35 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 21 Jul 2009 20:35:51 +0000 (13:35 -0700)
R=rsc
DELTA=195  (146 added, 1 deleted, 48 changed)
OCL=31895
CL=31931

src/pkg/bignum/bignum.go
src/pkg/bignum/bignum_test.go

index 95eab508aa7e4ac52f5cad051b4c85563a4dee2c..91a207dd410a297206c186dd256c2152982b1db1 100755 (executable)
@@ -110,10 +110,10 @@ func dump(x []digit) {
 type Natural []digit;
 
 var (
-       natZero Natural = Natural{};
-       natOne Natural = Natural{1};
-       natTwo Natural = Natural{2};
-       natTen Natural = Natural{10};
+       natZero = Natural{};
+       natOne = Natural{1};
+       natTwo = Natural{2};
+       natTen = Natural{10};
 )
 
 
@@ -588,7 +588,7 @@ func (x Natural) Shr(s uint) Natural {
 }
 
 
-// And returns the ``bitwise and'' x & y for the binary representation of x and y.
+// And returns the ``bitwise and'' x & y for the 2's-complement representation of x and y.
 //
 func (x Natural) And(y Natural) Natural {
        n := len(x);
@@ -614,7 +614,7 @@ func copy(z, x []digit) {
 }
 
 
-// AndNot returns the ``bitwise clear'' x &^ y for the binary representation of x and y.
+// AndNot returns the ``bitwise clear'' x &^ y for the 2's-complement representation of x and y.
 //
 func (x Natural) AndNot(y Natural) Natural {
        n := len(x);
@@ -633,7 +633,7 @@ func (x Natural) AndNot(y Natural) Natural {
 }
 
 
-// Or returns the ``bitwise or'' x | y for the binary representation of x and y.
+// Or returns the ``bitwise or'' x | y for the 2's-complement representation of x and y.
 //
 func (x Natural) Or(y Natural) Natural {
        n := len(x);
@@ -652,7 +652,7 @@ func (x Natural) Or(y Natural) Natural {
 }
 
 
-// Xor returns the ``bitwise exclusive or'' x ^ y for the binary representation of x and y.
+// Xor returns the ``bitwise exclusive or'' x ^ y for the 2's-complement representation of x and y.
 //
 func (x Natural) Xor(y Natural) Natural {
        n := len(x);
@@ -1230,68 +1230,135 @@ func (x *Integer) Shl(s uint) *Integer {
 }
 
 
+// The bitwise operations on integers are defined on the 2's-complement
+// representation of integers. From
+//
+//   -x == ^x + 1  (1)  2's complement representation
+//
+// follows:
+//
+//   -(x) == ^(x) + 1
+//   -(-x) == ^(-x) + 1
+//   x-1 == ^(-x)
+//   ^(x-1) == -x  (2)
+//
+// Using (1) and (2), operations on negative integers of the form -x are
+// converted to operations on negated positive integers of the form ~(x-1).
+
+
 // Shr implements ``shift right'' x >> s. It returns x / 2^s.
-// Implementation restriction: Shl is not yet implemented for negative x.
 //
 func (x *Integer) Shr(s uint) *Integer {
-       if !x.sign {
-               return MakeInt(false, x.mant.Shr(s));
+       if x.sign {
+               // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+               return MakeInt(true, x.mant.Sub(natOne).Shr(s).Add(natOne));
+       }
+       
+       return MakeInt(false, x.mant.Shr(s));
+}
+
+
+// Not returns the ``bitwise not'' ^x for the 2's-complement representation of x.
+func (x *Integer) Not() *Integer {
+       if x.sign {
+               // ^(-x) == ^(^(x-1)) == x-1
+               return MakeInt(false, x.mant.Sub(natOne));
        }
 
-       panic("UNIMPLEMENTED Integer.Shr of negative value");
-       return nil;
+       // ^x == -x-1 == -(x+1)
+       return MakeInt(true, x.mant.Add(natOne));
 }
 
 
-// And returns the ``bitwise and'' x & y for the binary representation of x and y.
-// Implementation restriction: And is not implemented for negative integers.
+// And returns the ``bitwise and'' x & y for the 2's-complement representation of x and y.
 //
 func (x *Integer) And(y *Integer) *Integer {
-       if !x.sign && !y.sign {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+                       return MakeInt(true, x.mant.Sub(natOne).Or(y.mant.Sub(natOne)).Add(natOne));
+               }
+
+               // x & y == x & y
                return MakeInt(false, x.mant.And(y.mant));
        }
 
-       panic("UNIMPLEMENTED Integer.And of negative values");
-       return nil;
+       // x.sign != y.sign
+       if x.sign {
+               x, y = y, x;  // & is symmetric
+       }
+
+       // x & (-y) == x & ^(y-1) == x &^ (y-1)
+       return MakeInt(false, x.mant.AndNot(y.mant.Sub(natOne)));
 }
 
 
-// AndNot returns the ``bitwise clear'' x &^ y for the binary representation of x and y.
-// Implementation restriction: AndNot is not implemented for negative integers.
+// AndNot returns the ``bitwise clear'' x &^ y for the 2's-complement representation of x and y.
 //
 func (x *Integer) AndNot(y *Integer) *Integer {
-       if !x.sign && !y.sign {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+                       return MakeInt(false, y.mant.Sub(natOne).AndNot(x.mant.Sub(natOne)));
+               }
+
+               // x &^ y == x &^ y
                return MakeInt(false, x.mant.AndNot(y.mant));
        }
 
-       panic("UNIMPLEMENTED Integer.AndNot of negative values");
-       return nil;
+       if x.sign {
+               // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+               return MakeInt(true, x.mant.Sub(natOne).Or(y.mant).Add(natOne));
+       }
+
+       // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+       return MakeInt(false, x.mant.And(y.mant.Sub(natOne)));
 }
 
 
-// Or returns the ``bitwise or'' x | y for the binary representation of x and y.
-// Implementation restriction: Or is not implemented for negative integers.
+// Or returns the ``bitwise or'' x | y for the 2's-complement representation of x and y.
 //
 func (x *Integer) Or(y *Integer) *Integer {
-       if !x.sign && !y.sign {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+                       return MakeInt(true, x.mant.Sub(natOne).And(y.mant.Sub(natOne)).Add(natOne));
+               }
+
+               // x | y == x | y
                return MakeInt(false, x.mant.Or(y.mant));
        }
 
-       panic("UNIMPLEMENTED Integer.Or of negative values");
-       return nil;
+       // x.sign != y.sign
+       if x.sign {
+               x, y = y, x;  // | or symmetric
+       }
+
+       // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+       return MakeInt(true, y.mant.Sub(natOne).AndNot(x.mant).Add(natOne));
 }
 
 
-// Xor returns the ``bitwise xor'' x | y for the binary representation of x and y.
-// Implementation restriction: Xor is not implemented for negative integers.
+// Xor returns the ``bitwise xor'' x | y for the 2's-complement representation of x and y.
 //
 func (x *Integer) Xor(y *Integer) *Integer {
-       if !x.sign && !y.sign {
+       if x.sign == y.sign {
+               if x.sign {
+                       // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+                       return MakeInt(false, x.mant.Sub(natOne).Xor(y.mant.Sub(natOne)));
+               }
+
+               // x ^ y == x ^ y
                return MakeInt(false, x.mant.Xor(y.mant));
        }
 
-       panic("UNIMPLEMENTED Integer.Xor of negative values");
-       return nil;
+       // x.sign != y.sign
+       if x.sign {
+               x, y = y, x;  // ^ is symmetric
+       }
+
+       // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+       return MakeInt(true, x.mant.Xor(y.mant.Sub(natOne)).Add(natOne));
 }
 
 
index 376bea1eda048385b6e51028c456e13b22cb362f..d07446bb4698d5c16fcfed1ce52f46f2d7ccae08 100644 (file)
@@ -467,8 +467,9 @@ func TestIntShift(t *testing.T) {
        }
 
        test_msg = "IntShift4R";
-       //int_eq(0, Int(-43).Shr(1), Int(-43 >> 1));
-       //int_eq(1, ip.Neg().Shr(10), ip.Neg().Div(Int(1).Shl(10)));
+       int_eq(0, Int(-43).Shr(1), Int(-43 >> 1));
+       int_eq(0, Int(-1024).Shr(100), Int(-1));
+       int_eq(1, ip.Neg().Shr(10), ip.Neg().Div(Int(1).Shl(10)));
 }
 
 
@@ -507,6 +508,83 @@ func TestNatBitOps(t *testing.T) {
 }
 
 
+func TestIntBitOps1(t *testing.T) {
+       tester = t;
+       test_msg = "IntBitOps1";
+       type T struct { x, y int64 };
+       a := []T {
+               T{ +7, +3 },
+               T{ +7, -3 },
+               T{ -7, +3 },
+               T{ -7, -3 },
+       };
+       for i := uint(0); i < uint(len(a)); i++ {
+               e := &a[i];
+               int_eq(4*i+0, Int(e.x).And(Int(e.y)), Int(e.x & e.y));
+               int_eq(4*i+1, Int(e.x).AndNot(Int(e.y)), Int(e.x &^ e.y));
+               int_eq(4*i+2, Int(e.x).Or(Int(e.y)), Int(e.x | e.y));
+               int_eq(4*i+3, Int(e.x).Xor(Int(e.y)), Int(e.x ^ e.y));
+       }
+}
+
+
+func TestIntBitOps2(t *testing.T) {
+       tester = t;
+
+       test_msg = "IntNot";
+       int_eq(0, Int(-2).Not(), Int( 1));
+       int_eq(0, Int(-1).Not(), Int( 0));
+       int_eq(0, Int( 0).Not(), Int(-1));
+       int_eq(0, Int( 1).Not(), Int(-2));
+       int_eq(0, Int( 2).Not(), Int(-3));
+
+       test_msg = "IntAnd";
+       for x := int64(-15); x < 5; x++ {
+               bx := Int(x);
+               for y := int64(-5); y < 15; y++ {
+                       by := Int(y);
+                       for i := uint(50); i < 70; i++ {  // shift across 64bit boundary
+                               int_eq(i, bx.Shl(i).And(by.Shl(i)), Int(x & y).Shl(i));
+                       }
+               }
+       }
+
+       test_msg = "IntAndNot";
+       for x := int64(-15); x < 5; x++ {
+               bx := Int(x);
+               for y := int64(-5); y < 15; y++ {
+                       by := Int(y);
+                       for i := uint(50); i < 70; i++ {  // shift across 64bit boundary
+                               int_eq(2*i+0, bx.Shl(i).AndNot(by.Shl(i)), Int(x &^ y).Shl(i));
+                               int_eq(2*i+1, bx.Shl(i).And(by.Shl(i).Not()), Int(x &^ y).Shl(i));
+                       }
+               }
+       }
+
+       test_msg = "IntOr";
+       for x := int64(-15); x < 5; x++ {
+               bx := Int(x);
+               for y := int64(-5); y < 15; y++ {
+                       by := Int(y);
+                       for i := uint(50); i < 70; i++ {  // shift across 64bit boundary
+                               int_eq(i, bx.Shl(i).Or(by.Shl(i)), Int(x | y).Shl(i));
+                       }
+               }
+       }
+
+       test_msg = "IntXor";
+       for x := int64(-15); x < 5; x++ {
+               bx := Int(x);
+               for y := int64(-5); y < 15; y++ {
+                       by := Int(y);
+                       for i := uint(50); i < 70; i++ {  // shift across 64bit boundary
+                               int_eq(i, bx.Shl(i).Xor(by.Shl(i)), Int(x ^ y).Shl(i));
+                       }
+               }
+       }
+}
+
+
 func TestNatCmp(t *testing.T) {
        tester = t;
        test_msg = "NatCmp";