mirror of
https://github.com/golang/go
synced 2024-09-30 11:18:33 -06:00
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: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
536a2257fb
commit
70ea0ec30f
@ -76,42 +76,10 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
|
|||||||
return
|
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.
|
// nlz returns the number of leading zeros in x.
|
||||||
|
// Wraps bits.LeadingZeros call for convenience.
|
||||||
func nlz(x Word) uint {
|
func nlz(x Word) uint {
|
||||||
// TODO(gri) Replace with call to bits.LeadingZeros once we have a fast
|
return uint(bits.LeadingZeros(uint(x)))
|
||||||
// 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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// q = (u1<<_W + u0 - r)/y
|
// q = (u1<<_W + u0 - r)/y
|
||||||
|
@ -269,14 +269,3 @@ E7: SUBL $1, BX // i--
|
|||||||
|
|
||||||
MOVL DX, r+32(FP)
|
MOVL DX, r+32(FP)
|
||||||
RET
|
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)
|
MOVQ DX, r+64(FP)
|
||||||
RET
|
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
|
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||||
JMP ·divWVW_g(SB)
|
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 R4, z1+8(FP)
|
||||||
MOVW R3, z0+12(FP)
|
MOVW R3, z0+12(FP)
|
||||||
RET
|
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)
|
// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
|
||||||
TEXT ·divWVW(SB),NOSPLIT,$0
|
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||||
B ·divWVW_g(SB)
|
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 mulAddVWW(z, x []Word, y, r Word) (c Word)
|
||||||
func addMulVVW(z, x []Word, y 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 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) {
|
func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
|
||||||
return divWVW_g(z, xn, x, y)
|
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
|
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||||
JMP ·divWVW_g(SB)
|
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
|
TEXT ·divWVW(SB),NOSPLIT,$0
|
||||||
JMP ·divWVW_g(SB)
|
JMP ·divWVW_g(SB)
|
||||||
|
|
||||||
TEXT ·bitLen(SB),NOSPLIT,$0
|
|
||||||
JMP ·bitLen_g(SB)
|
|
||||||
|
@ -175,12 +175,3 @@ end:
|
|||||||
|
|
||||||
TEXT ·divWVW(SB), NOSPLIT, $0
|
TEXT ·divWVW(SB), NOSPLIT, $0
|
||||||
BR ·divWVW_g(SB)
|
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)
|
MOVD R10, r+64(FP)
|
||||||
RET
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/bits"
|
||||||
)
|
)
|
||||||
|
|
||||||
const debugFloat = false // enable for debugging
|
const debugFloat = false // enable for debugging
|
||||||
@ -498,8 +499,8 @@ func (z *Float) setBits64(neg bool, x uint64) *Float {
|
|||||||
}
|
}
|
||||||
// x != 0
|
// x != 0
|
||||||
z.form = finite
|
z.form = finite
|
||||||
s := nlz64(x)
|
s := bits.LeadingZeros64(x)
|
||||||
z.mant = z.mant.setUint64(x << s)
|
z.mant = z.mant.setUint64(x << uint(s))
|
||||||
z.exp = int32(64 - s) // always fits
|
z.exp = int32(64 - s) // always fits
|
||||||
if z.prec < 64 {
|
if z.prec < 64 {
|
||||||
z.round(0)
|
z.round(0)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/bits"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -328,9 +329,9 @@ func TestFloat64Text(t *testing.T) {
|
|||||||
|
|
||||||
// actualPrec returns the number of actually used mantissa bits.
|
// actualPrec returns the number of actually used mantissa bits.
|
||||||
func actualPrec(x float64) uint {
|
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
|
// x is denormalized
|
||||||
return 64 - nlz64(bits&(1<<52-1))
|
return 64 - uint(bits.LeadingZeros64(mant&(1<<52-1)))
|
||||||
}
|
}
|
||||||
return 53
|
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.
|
// Length of x in bits. x must be normalized.
|
||||||
func (x nat) bitLen() int {
|
func (x nat) bitLen() int {
|
||||||
if i := len(x) - 1; i >= 0 {
|
if i := len(x) - 1; i >= 0 {
|
||||||
return i*_W + bitLen(x[i])
|
return i*_W + bits.Len(uint(x[i]))
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,18 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/bits"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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 {
|
func itoa(x nat, base int) []byte {
|
||||||
// special cases
|
// special cases
|
||||||
switch {
|
switch {
|
||||||
|
Loading…
Reference in New Issue
Block a user