Commit 70ea0ec3 authored by Robert Griesemer's avatar Robert Griesemer

math/big: replace local versions of bitLen, nlz with math/bits versions

Verified that BenchmarkBitLen time went down from 2.25 ns/op to 0.65 ns/op
an a 2.3 GHz Intel Core i7, before removing that benchmark (now covered by
math/bits benchmarks).

Change-Id: I3890bb7d1889e95b9a94bd68f0bdf06f1885adeb
Reviewed-on: https://go-review.googlesource.com/38464
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 536a2257
......@@ -76,42 +76,10 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
return
}
// Length of x in bits.
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.
// Wraps bits.LeadingZeros call for convenience.
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
if w == 0 {
return 32 + nlz(Word(x))
}
return nlz(Word(w))
case 64:
return nlz(Word(x))
}
panic("unreachable")
return uint(bits.LeadingZeros(uint(x)))
}
// q = (u1<<_W + u0 - r)/y
......
......@@ -269,14 +269,3 @@ E7: SUBL $1, BX // i--
MOVL DX, r+32(FP)
RET
// func bitLen(x Word) (n int)
TEXT ·bitLen(SB),NOSPLIT,$0
BSRL x+0(FP), AX
JZ Z1
INCL AX
MOVL AX, n+4(FP)
RET
Z1: MOVL $0, n+4(FP)
RET
......@@ -450,14 +450,3 @@ E7: SUBQ $1, BX // i--
MOVQ DX, r+64(FP)
RET
// func bitLen(x Word) (n int)
TEXT ·bitLen(SB),NOSPLIT,$0
BSRQ x+0(FP), AX
JZ Z1
ADDQ $1, AX
MOVQ AX, n+8(FP)
RET
Z1: MOVQ $0, n+8(FP)
RET
......@@ -38,6 +38,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
TEXT ·divWVW(SB),NOSPLIT,$0
JMP ·divWVW_g(SB)
TEXT ·bitLen(SB),NOSPLIT,$0
JMP ·bitLen_g(SB)
......@@ -292,11 +292,3 @@ TEXT ·mulWW(SB),NOSPLIT,$0
MOVW R4, z1+8(FP)
MOVW R3, z0+12(FP)
RET
// func bitLen(x Word) (n int)
TEXT ·bitLen(SB),NOSPLIT,$0
MOVW x+0(FP), R0
CLZ R0, R0
RSB $32, R0
MOVW R0, n+4(FP)
RET
......@@ -165,13 +165,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
TEXT ·divWVW(SB),NOSPLIT,$0
B ·divWVW_g(SB)
// func bitLen(x Word) (n int)
TEXT ·bitLen(SB),NOSPLIT,$0
MOVD x+0(FP), R0
CLZ R0, R0
MOVD $64, R1
SUB R0, R1, R0
MOVD R0, n+8(FP)
RET
......@@ -18,4 +18,3 @@ func shrVU(z, x []Word, s uint) (c Word)
func mulAddVWW(z, x []Word, y, r Word) (c Word)
func addMulVVW(z, x []Word, y Word) (c Word)
func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
func bitLen(x Word) (n int)
......@@ -49,7 +49,3 @@ func addMulVVW(z, x []Word, y Word) (c Word) {
func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
return divWVW_g(z, xn, x, y)
}
func bitLen(x Word) (n int) {
return bitLen_g(x)
}
......@@ -41,6 +41,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
TEXT ·divWVW(SB),NOSPLIT,$0
JMP ·divWVW_g(SB)
TEXT ·bitLen(SB),NOSPLIT,$0
JMP ·bitLen_g(SB)
......@@ -41,6 +41,3 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
TEXT ·divWVW(SB),NOSPLIT,$0
JMP ·divWVW_g(SB)
TEXT ·bitLen(SB),NOSPLIT,$0
JMP ·bitLen_g(SB)
......@@ -175,12 +175,3 @@ end:
TEXT ·divWVW(SB), NOSPLIT, $0
BR ·divWVW_g(SB)
// func bitLen(x Word) int
TEXT ·bitLen(SB), NOSPLIT, $0
MOVD x+0(FP), R4
CNTLZD R4, R4
MOVD $64, R5
SUB R4, R5
MOVD R5, n+8(FP)
RET
......@@ -1237,13 +1237,3 @@ E7: SUB $1, R7 // i--
MOVD R10, r+64(FP)
RET
// func bitLen(x Word) (n int)
TEXT ·bitLen(SB),NOSPLIT,$0
MOVD x+0(FP), R2
FLOGR R2, R2 // clobbers R3
MOVD $64, R3
SUB R2, R3
MOVD R3, n+8(FP)
RET
......@@ -395,32 +395,3 @@ func BenchmarkAddMulVVW(b *testing.B) {
})
}
}
func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
for i := 0; i <= _W; i++ {
x := Word(1) << uint(i-1) // i == 0 => x == 0
n := f(x)
if n != i {
t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
}
}
}
func TestWordBitLen(t *testing.T) {
testWordBitLen(t, "bitLen", bitLen)
testWordBitLen(t, "bitLen_g", bitLen_g)
}
// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
func BenchmarkBitLen(b *testing.B) {
// Individual bitLen tests. Numbers chosen to examine both sides
// of powers-of-two boundaries.
for _, nbits := range []uint{0, 1, 2, 3, 4, 5, 8, 9, 16, 17, 31} {
testword := Word((uint64(1) << nbits) - 1)
b.Run(fmt.Sprint(nbits), func(b *testing.B) {
for i := 0; i < b.N; i++ {
bitLen(testword)
}
})
}
}
......@@ -14,6 +14,7 @@ package big
import (
"fmt"
"math"
"math/bits"
)
const debugFloat = false // enable for debugging
......@@ -498,8 +499,8 @@ func (z *Float) setBits64(neg bool, x uint64) *Float {
}
// x != 0
z.form = finite
s := nlz64(x)
z.mant = z.mant.setUint64(x << s)
s := bits.LeadingZeros64(x)
z.mant = z.mant.setUint64(x << uint(s))
z.exp = int32(64 - s) // always fits
if z.prec < 64 {
z.round(0)
......
......@@ -8,6 +8,7 @@ import (
"bytes"
"fmt"
"math"
"math/bits"
"strconv"
"testing"
)
......@@ -328,9 +329,9 @@ func TestFloat64Text(t *testing.T) {
// actualPrec returns the number of actually used mantissa bits.
func actualPrec(x float64) uint {
if bits := math.Float64bits(x); x != 0 && bits&(0x7ff<<52) == 0 {
if mant := math.Float64bits(x); x != 0 && mant&(0x7ff<<52) == 0 {
// x is denormalized
return 64 - nlz64(bits&(1<<52-1))
return 64 - uint(bits.LeadingZeros64(mant&(1<<52-1)))
}
return 53
}
......
......@@ -644,7 +644,7 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
// Length of x in bits. x must be normalized.
func (x nat) bitLen() int {
if i := len(x) - 1; i >= 0 {
return i*_W + bitLen(x[i])
return i*_W + bits.Len(uint(x[i]))
}
return 0
}
......
......@@ -8,10 +8,18 @@ import (
"bytes"
"fmt"
"io"
"math/bits"
"strings"
"testing"
)
// 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 {
return bits.Len(uint(x)) - 1
}
func itoa(x nat, base int) []byte {
// special cases
switch {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment