]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: added nat.trailingZeroBits, simplified some code
authorRobert Griesemer <gri@golang.org>
Fri, 8 Jun 2012 20:00:49 +0000 (13:00 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 8 Jun 2012 20:00:49 +0000 (13:00 -0700)
Will simplify implementation of binaryGCD.

R=rsc, cswenson
CC=golang-dev
https://golang.org/cl/6299064

src/pkg/math/big/nat.go
src/pkg/math/big/nat_test.go

index eaa6ff0666c7a90d48468ac435d6ada257a85d8b..10026c8b1615cd03da9425a672a5ef95474773be 100644 (file)
@@ -740,7 +740,7 @@ func (x nat) string(charset string) string {
        // convert power of two and non power of two bases separately
        if b == b&-b {
                // shift is base-b digit size in bits
-               shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2
+               shift := trailingZeroBits(b) // shift > 0 because b >= 2
                mask := Word(1)<<shift - 1
                w := x[0]
                nbits := uint(_W) // number of unprocessed bits in w
@@ -993,10 +993,9 @@ var deBruijn64Lookup = []byte{
        54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
 }
 
-// trailingZeroBits returns the number of consecutive zero bits on the right
-// side of the given Word.
-// See Knuth, volume 4, section 7.3.1
-func trailingZeroBits(x Word) int {
+// trailingZeroBits returns the number of consecutive least significant zero
+// bits of x.
+func trailingZeroBits(x Word) uint {
        // x & -x leaves only the right-most bit set in the word. Let k be the
        // index of that bit. Since only a single bit is set, the value is two
        // to the power of k. Multiplying by a power of two is equivalent to
@@ -1005,11 +1004,12 @@ func trailingZeroBits(x Word) int {
        // Therefore, if we have a left shifted version of this constant we can
        // find by how many bits it was shifted by looking at which six bit
        // substring ended up at the top of the word.
+       // (Knuth, volume 4, section 7.3.1)
        switch _W {
        case 32:
-               return int(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
+               return uint(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
        case 64:
-               return int(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
+               return uint(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
        default:
                panic("Unknown word size")
        }
@@ -1017,6 +1017,20 @@ func trailingZeroBits(x Word) int {
        return 0
 }
 
+// trailingZeroBits returns the number of consecutive least significant zero
+// bits of x.
+func (x nat) trailingZeroBits() uint {
+       if len(x) == 0 {
+               return 0
+       }
+       var i uint
+       for x[i] == 0 {
+               i++
+       }
+       // x[i] != 0
+       return i*_W + trailingZeroBits(x[i])
+}
+
 // z = x << s
 func (z nat) shl(x nat, s uint) nat {
        m := len(x)
@@ -1169,29 +1183,6 @@ func (x nat) modW(d Word) (r Word) {
        return divWVW(q, 0, x, d)
 }
 
-// powersOfTwoDecompose finds q and k with x = q * 1<<k and q is odd, or q and k are 0.
-func (x nat) powersOfTwoDecompose() (q nat, k int) {
-       if len(x) == 0 {
-               return x, 0
-       }
-
-       // One of the words must be non-zero by definition,
-       // so this loop will terminate with i < len(x), and
-       // i is the number of 0 words.
-       i := 0
-       for x[i] == 0 {
-               i++
-       }
-       n := trailingZeroBits(x[i]) // x[i] != 0
-
-       q = make(nat, len(x)-i)
-       shrVU(q, x[i:], uint(n))
-
-       q = q.norm()
-       k = i*_W + n
-       return
-}
-
 // random creates a random integer in [0..limit), using the space in z if
 // possible. n is the bit length of limit.
 func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
@@ -1343,8 +1334,9 @@ func (n nat) probablyPrime(reps int) bool {
        }
 
        nm1 := nat(nil).sub(n, natOne)
-       // 1<<k * q = nm1;
-       q, k := nm1.powersOfTwoDecompose()
+       // determine q, k such that nm1 = q << k
+       k := nm1.trailingZeroBits()
+       q := nat(nil).shr(nm1, k)
 
        nm3 := nat(nil).sub(nm1, natTwo)
        rand := rand.New(rand.NewSource(int64(n[0])))
@@ -1360,7 +1352,7 @@ NextRandom:
                if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
                        continue
                }
-               for j := 1; j < k; j++ {
+               for j := uint(1); j < k; j++ {
                        y = y.mul(y, y)
                        quotient, y = quotient.div(y, y, n)
                        if y.cmp(nm1) == 0 {
index 64a8ac07c54f0d6ee478558da1f219cbb8832e89..dee64174a1ebf38774df0facf8463393e465dea5 100644 (file)
@@ -613,14 +613,23 @@ func TestModW(t *testing.T) {
 }
 
 func TestTrailingZeroBits(t *testing.T) {
-       var x Word
-       x--
-       for i := 0; i < _W; i++ {
-               if trailingZeroBits(x) != i {
-                       t.Errorf("Failed at step %d: x: %x got: %d", i, x, trailingZeroBits(x))
+       x := Word(1)
+       for i := uint(0); i <= _W; i++ {
+               n := trailingZeroBits(x)
+               if n != i%_W {
+                       t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
                }
                x <<= 1
        }
+
+       y := nat(nil).set(natOne)
+       for i := uint(0); i <= 3*_W; i++ {
+               n := y.trailingZeroBits()
+               if n != i {
+                       t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.string(lowercaseDigits[0:16]), n, i)
+               }
+               y = y.shl(y, 1)
+       }
 }
 
 var expNNTests = []struct {