]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: use math/bits where appropriate
authorRobert Griesemer <gri@golang.org>
Thu, 16 Feb 2017 23:04:33 +0000 (15:04 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 24 Feb 2017 19:19:02 +0000 (19:19 +0000)
This change adds math/bits as a new dependency of math/big.

- use bits.LeadingZeroes instead of local implementation
  (they are identical, so there's no performance loss here)

- leave other functionality local (ntz, bitLen) since there's
  faster implementations in math/big at the moment

Change-Id: I1218aa8a1df0cc9783583b090a4bb5a8a145c4a2
Reviewed-on: https://go-review.googlesource.com/37141
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/dist/buildtool.go
src/go/build/deps_test.go
src/math/big/arith.go
src/math/big/nat.go
src/math/big/nat_test.go
src/math/big/natconv.go

index 2f8136600f44c2c3c0aa530deb0fe4075f6c8e0e..f547a5af9e0f6be47b3c6fe5e766a4b0c3f046dc 100644 (file)
@@ -68,6 +68,7 @@ var bootstrapDirs = []string{
        "cmd/link/internal/x86",
        "debug/pe",
        "math/big",
+       "math/bits",
 }
 
 // File prefixes that are ignored by go/build anyway, and cause
index e6804e7ef506af838a2e23099166c019f34cdac0..c93c04a2c1bdbf9a47f8fcfc704bda86091d0c66 100644 (file)
@@ -260,7 +260,7 @@ var pkgDeps = map[string][]string{
        "internal/singleflight":     {"sync"},
        "internal/trace":            {"L4", "OS"},
        "internal/pprof/profile":    {"L4", "OS", "compress/gzip", "regexp"},
-       "math/big":                  {"L4"},
+       "math/big":                  {"L4", "math/bits"},
        "mime":                      {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
        "mime/quotedprintable":      {"L4"},
        "net/internal/socktest":     {"L4", "OS", "syscall"},
index 1101451f98edc986a81d16eef8a6f83ba8c15aa5..8cc0fb6497d13bdb5e43220cb2432561689b0cb6 100644 (file)
@@ -8,18 +8,17 @@
 
 package big
 
+import "math/bits"
+
 // A Word represents a single digit of a multi-precision unsigned integer.
 type Word uint
 
 const (
-       // Compute the size _S of a Word in bytes.
-       _m    = ^Word(0)
-       _logS = _m>>8&1 + _m>>16&1 + _m>>32&1
-       _S    = 1 << _logS
+       _S = _W / 8 // word size in bytes
 
-       _W = _S << 3 // word size in bits
-       _B = 1 << _W // digit base
-       _M = _B - 1  // digit mask
+       _W = bits.UintSize // word size in bits
+       _B = 1 << _W       // digit base
+       _M = _B - 1        // digit mask
 
        _W2 = _W / 2   // half word size in bits
        _B2 = 1 << _W2 // half digit base
@@ -78,42 +77,30 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
 }
 
 // Length of x in bits.
-func bitLen_g(x Word) (n int) {
-       for ; x >= 0x8000; x >>= 16 {
-               n += 16
-       }
-       if x >= 0x80 {
-               x >>= 8
-               n += 8
-       }
-       if x >= 0x8 {
-               x >>= 4
-               n += 4
-       }
-       if x >= 0x2 {
-               x >>= 2
-               n += 2
-       }
-       if x >= 0x1 {
-               n++
-       }
-       return
+func bitLen_g(x Word) int {
+       return bits.Len(uint(x))
 }
 
 // log2 computes the integer binary logarithm of x.
 // The result is the integer n for which 2^n <= x < 2^(n+1).
 // If x == 0, the result is -1.
 func log2(x Word) int {
+       // TODO(gri) Replace with call to bits.Len once we have a fast
+       // implementation for the same platforms currently supporting math/big.
        return bitLen(x) - 1
 }
 
 // nlz returns the number of leading zeros in x.
 func nlz(x Word) uint {
+       // TODO(gri) Replace with call to bits.LeadingZeros once we have a fast
+       // implementation for the same platforms currently supporting math/big.
        return uint(_W - bitLen(x))
 }
 
 // nlz64 returns the number of leading zeros in x.
 func nlz64(x uint64) uint {
+       // TODO(gri) Replace with call to bits.LeadingZeros64 once we have a fast
+       // implementation for the same platforms currently supporting math/big.
        switch _W {
        case 32:
                w := x >> 32
index 9b1a626c4cf18acd5d2df494bdc2ca740f13272e..1e6f7ae8a891e267ee9574a7cd699ca5eefa07fb 100644 (file)
@@ -9,6 +9,7 @@
 package big
 
 import (
+       "math/bits"
        "math/rand"
        "sync"
 )
@@ -658,44 +659,6 @@ func (x nat) bitLen() int {
        return 0
 }
 
-const deBruijn32 = 0x077CB531
-
-var deBruijn32Lookup = [...]byte{
-       0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
-       31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
-}
-
-const deBruijn64 = 0x03f79d71b4ca8b09
-
-var deBruijn64Lookup = [...]byte{
-       0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
-       62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
-       63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
-       54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
-}
-
-// 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
-       // left shifting, in this case by k bits. The de Bruijn constant is
-       // such that all six bit, consecutive substrings are distinct.
-       // 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 uint(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
-       case 64:
-               return uint(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
-       default:
-               panic("unknown word size")
-       }
-}
-
 // trailingZeroBits returns the number of consecutive least significant zero
 // bits of x.
 func (x nat) trailingZeroBits() uint {
@@ -707,7 +670,7 @@ func (x nat) trailingZeroBits() uint {
                i++
        }
        // x[i] != 0
-       return i*_W + trailingZeroBits(x[i])
+       return i*_W + uint(bits.TrailingZeros(uint(x[i])))
 }
 
 // z = x << s
index ebb29856549b8ef47a9eb228fa71adfa0f7e7e83..200a247f513aaaf1372d045cdb9273f412a776dc 100644 (file)
@@ -303,36 +303,6 @@ func TestModW(t *testing.T) {
        }
 }
 
-func TestTrailingZeroBits(t *testing.T) {
-       // test 0 case explicitly
-       if n := trailingZeroBits(0); n != 0 {
-               t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
-       }
-
-       x := Word(1)
-       for i := uint(0); i < _W; i++ {
-               n := trailingZeroBits(x)
-               if n != i {
-                       t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
-               }
-               x <<= 1
-       }
-
-       // test 0 case explicitly
-       if n := nat(nil).trailingZeroBits(); n != 0 {
-               t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
-       }
-
-       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.utoa(16), n, i)
-               }
-               y = y.shl(y, 1)
-       }
-}
-
 var montgomeryTests = []struct {
        x, y, m      string
        k0           uint64
index 44547842c1ced2f86a225e17f59a35d5c4bd6f47..25a345ef0e55d1739e63bc431f3d2beb0ec2a123 100644 (file)
@@ -11,6 +11,7 @@ import (
        "fmt"
        "io"
        "math"
+       "math/bits"
        "sync"
 )
 
@@ -262,7 +263,7 @@ func (x nat) itoa(neg bool, base int) []byte {
        // convert power of two and non power of two bases separately
        if b := Word(base); b == b&-b {
                // shift is base b digit size in bits
-               shift := trailingZeroBits(b) // shift > 0 because b >= 2
+               shift := uint(bits.TrailingZeros(uint(b))) // shift > 0 because b >= 2
                mask := Word(1<<shift - 1)
                w := x[0]         // current word
                nbits := uint(_W) // number of unprocessed bits in w