]> Cypherpunks repositories - gostls13.git/commitdiff
- gcd, exponentiation, population count
authorRobert Griesemer <gri@golang.org>
Fri, 31 Oct 2008 23:58:56 +0000 (16:58 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 31 Oct 2008 23:58:56 +0000 (16:58 -0700)
- more rational numbers stuff
- more tests

R=r
OCL=18295
CL=18295

usr/gri/bignum/bignum.go
usr/gri/bignum/bignum_test.go

index 95be5787942b4969f42e2c2e82610cc11ff8f5a8..08217200485dcf74ae6a10621298ad978ae0c48c 100755 (executable)
@@ -262,6 +262,38 @@ func (x *Natural) Mul(y *Natural) *Natural {
 }
 
 
+func Pop1(x Digit) uint {
+       n := uint(0);
+       for x != 0 {
+               x &= x-1;
+               n++;
+       }
+       return n;
+}
+
+
+func (x *Natural) Pop() uint {
+       n := uint(0);
+       for i := len(x) - 1; i >= 0; i-- {
+               n += Pop1(x[i]);
+       }
+       return n;
+}
+
+
+func (x *Natural) Pow(n uint) *Natural {
+       z := Nat(1);
+       for n > 0 {
+               // z * x^n == x^n0
+               if n&1 == 1 {
+                       z = z.Mul(x);
+               }
+               x, n = x.Mul(x), n/2;
+       }
+       return z;
+}
+
+
 func Shl1(x, c Digit, s uint) (Digit, Digit) {
        assert(s <= LogB);
        return x >> (LogB - s), x << s & M | c
@@ -490,7 +522,7 @@ func (x *Natural) Cmp(y *Natural) int {
 
 func Log1(x Digit) int {
        n := -1;
-       for x != 0 { x >>= 1; n++; }
+       for x != 0 { x = x >> 1; n++; }  // BUG >>= broken for uint64
        return n;
 }
 
@@ -624,6 +656,15 @@ export func Fact(n Digit) *Natural {
 }
 
 
+func (x *Natural) Gcd(y *Natural) *Natural {
+       // Euclidean algorithm.
+       for !y.IsZero() {
+               x, y = y, x.Mod(y);
+       }
+       return x;
+}
+
+
 func HexValue(ch byte) Digit {
        d := Digit(1 << LogH);
        switch {
@@ -650,6 +691,23 @@ export func NatFromString(s string, base Digit) *Natural {
 }
 
 
+// ----------------------------------------------------------------------------
+// Algorithms
+
+export type T interface {
+       IsZero() bool;
+       Mod(y T) bool;
+}
+
+export func Gcd(x, y T) T {
+       // Euclidean algorithm.
+       for !y.IsZero() {
+               x, y = y, x.Mod(y);
+       }
+       return x;
+}
+
+
 // ----------------------------------------------------------------------------
 // Integer numbers
 
@@ -717,6 +775,18 @@ func (x *Integer) Mul(y *Integer) *Integer {
 }
 
 
+func (x *Integer) Quo(y *Integer) *Integer {
+       panic("UNIMPLEMENTED");
+       return nil;
+}
+
+
+func (x *Integer) Rem(y *Integer) *Integer {
+       panic("UNIMPLEMENTED");
+       return nil;
+}
+
+
 func (x *Integer) Div(y *Integer) *Integer {
        panic("UNIMPLEMENTED");
        return nil;
@@ -765,29 +835,36 @@ export type Rational struct {
 }
 
 
-func NewRat(a, b *Integer) *Rational {
-       // TODO normalize the rational
-       return &Rational{a, b};
+func (x *Rational) Normalize() *Rational {
+       f := x.a.mant.Gcd(x.b.mant);
+       x.a.mant = x.a.mant.Div(f);
+       x.b.mant = x.b.mant.Div(f);
+       return x;
+}
+
+
+func Rat(a, b *Integer) *Rational {
+       return (&Rational{a, b}).Normalize();
 }
 
 
 func (x *Rational) Add(y *Rational) *Rational {
-       return NewRat((x.a.Mul(y.b)).Add(x.b.Mul(y.a)), x.b.Mul(y.b));
+       return Rat((x.a.Mul(y.b)).Add(x.b.Mul(y.a)), x.b.Mul(y.b));
 }
 
 
 func (x *Rational) Sub(y *Rational) *Rational {
-       return NewRat((x.a.Mul(y.b)).Sub(x.b.Mul(y.a)), x.b.Mul(y.b));
+       return Rat((x.a.Mul(y.b)).Sub(x.b.Mul(y.a)), x.b.Mul(y.b));
 }
 
 
 func (x *Rational) Mul(y *Rational) *Rational {
-       return NewRat(x.a.Mul(y.a), x.b.Mul(y.b));
+       return Rat(x.a.Mul(y.a), x.b.Mul(y.b));
 }
 
 
 func (x *Rational) Div(y *Rational) *Rational {
-       return NewRat(x.a.Mul(y.b), x.b.Mul(y.a));
+       return Rat(x.a.Mul(y.b), x.b.Mul(y.a));
 }
 
 
index 783273b3475609c3c1896aa4bbf65ac706f445e7..ae81036b0fd997166a89ac07afc7bd41696bcf29 100644 (file)
@@ -129,11 +129,47 @@ func TestMod() {
 }
 
 
+func TestGcd() {
+       test_msg = "TestGcdA";
+       f := Big.Nat(99991);
+       TEST_EQ(0, b.Mul(f).Gcd(c.Mul(f)), Big.MulRange(1, 20).Mul(f));
+}
+
+
+func TestPow() {
+       test_msg = "TestPowA";
+       TEST_EQ(0, Big.Nat(2).Pow(0), Big.Nat(1));
+
+       test_msg = "TestPowB";
+       for i := uint(0); i < 100; i++ {
+               TEST_EQ(i, Big.Nat(2).Pow(i), Big.Nat(1).Shl(i));
+       }
+}
+
+
+func TestPop() {
+       test_msg = "TestPopA";
+       TEST(0, Big.Nat(0).Pop() == 0);
+       TEST(1, Big.Nat(1).Pop() == 1);
+       TEST(2, Big.Nat(10).Pop() == 2);
+       TEST(3, Big.Nat(30).Pop() == 4);
+       TEST(4, Big.Nat(0x1248f).Shl(33).Pop() == 8);
+
+       test_msg = "TestPopB";
+       for i := uint(0); i < 100; i++ {
+               TEST(i, Big.Nat(1).Shl(i).Sub(Big.Nat(1)).Pop() == i);
+       }
+}
+
+
 func main() {
        TestConv();
        TestShift();
        TestMul();
        TestDiv();
        TestMod();
+       TestGcd();
+       TestPow();
+       TestPop();
        print("PASSED\n");
 }