mirror of
https://github.com/golang/go
synced 2024-11-18 13:14:47 -07:00
math/big: more cleanups (msbxx, nlzxx functions)
Change-Id: Ibace718452b6dc029c5af5240117f5fc794c38cf Reviewed-on: https://go-review.googlesource.com/10388 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
0858d8847d
commit
635cd91eb4
@ -107,11 +107,26 @@ func log2(x Word) int {
|
||||
return bitLen(x) - 1
|
||||
}
|
||||
|
||||
// Number of leading zeros in x.
|
||||
func leadingZeros(x Word) uint {
|
||||
// nlz returns the number of leading zeros in x.
|
||||
func nlz(x Word) uint {
|
||||
return uint(_W - bitLen(x))
|
||||
}
|
||||
|
||||
// nlz64 returns the number of leading zeros in x.
|
||||
func nlz64(x uint64) uint {
|
||||
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
|
||||
// Adapted from Warren, Hacker's Delight, p. 152.
|
||||
func divWW_g(u1, u0, v Word) (q, r Word) {
|
||||
@ -119,7 +134,7 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
|
||||
return 1<<_W - 1, 1<<_W - 1
|
||||
}
|
||||
|
||||
s := leadingZeros(v)
|
||||
s := nlz(v)
|
||||
v <<= s
|
||||
|
||||
vn1 := v >> _W2
|
||||
|
@ -525,25 +525,6 @@ func (z *Float) round(sbit uint) {
|
||||
return
|
||||
}
|
||||
|
||||
// nlz returns the number of leading zero bits in x.
|
||||
func nlz(x Word) uint {
|
||||
return _W - uint(bitLen(x))
|
||||
}
|
||||
|
||||
func nlz64(x uint64) uint {
|
||||
// TODO(gri) this can be done more nicely
|
||||
if _W == 32 {
|
||||
if x>>32 == 0 {
|
||||
return 32 + nlz(Word(x))
|
||||
}
|
||||
return nlz(Word(x >> 32))
|
||||
}
|
||||
if _W == 64 {
|
||||
return nlz(Word(x))
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (z *Float) setBits64(neg bool, x uint64) *Float {
|
||||
if z.prec == 0 {
|
||||
z.prec = 64
|
||||
@ -732,25 +713,44 @@ func (z *Float) Copy(x *Float) *Float {
|
||||
return z
|
||||
}
|
||||
|
||||
func high32(x nat) uint32 {
|
||||
// TODO(gri) This can be done more efficiently on 32bit platforms.
|
||||
return uint32(high64(x) >> 32)
|
||||
}
|
||||
|
||||
func high64(x nat) uint64 {
|
||||
i := len(x)
|
||||
if i == 0 {
|
||||
// msb32 returns the 32 most significant bits of x.
|
||||
func msb32(x nat) uint32 {
|
||||
i := len(x) - 1
|
||||
if i < 0 {
|
||||
return 0
|
||||
}
|
||||
// i > 0
|
||||
v := uint64(x[i-1])
|
||||
if _W == 32 {
|
||||
v <<= 32
|
||||
if i > 1 {
|
||||
v |= uint64(x[i-2])
|
||||
if debugFloat && x[i]&(1<<(_W-1)) == 0 {
|
||||
panic("x not normalized")
|
||||
}
|
||||
switch _W {
|
||||
case 32:
|
||||
return uint32(x[i])
|
||||
case 64:
|
||||
return uint32(x[i] >> 32)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// msb64 returns the 64 most significant bits of x.
|
||||
func msb64(x nat) uint64 {
|
||||
i := len(x) - 1
|
||||
if i < 0 {
|
||||
return 0
|
||||
}
|
||||
if debugFloat && x[i]&(1<<(_W-1)) == 0 {
|
||||
panic("x not normalized")
|
||||
}
|
||||
switch _W {
|
||||
case 32:
|
||||
v := uint64(x[i]) << 32
|
||||
if i > 0 {
|
||||
v |= uint64(x[i-1])
|
||||
}
|
||||
return v
|
||||
case 64:
|
||||
return uint64(x[i])
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Uint64 returns the unsigned integer resulting from truncating x
|
||||
@ -776,7 +776,7 @@ func (x *Float) Uint64() (uint64, Accuracy) {
|
||||
// 1 <= x < Inf
|
||||
if x.exp <= 64 {
|
||||
// u = trunc(x) fits into a uint64
|
||||
u := high64(x.mant) >> (64 - uint32(x.exp))
|
||||
u := msb64(x.mant) >> (64 - uint32(x.exp))
|
||||
if x.MinPrec() <= 64 {
|
||||
return u, Exact
|
||||
}
|
||||
@ -821,7 +821,7 @@ func (x *Float) Int64() (int64, Accuracy) {
|
||||
// 1 <= |x| < +Inf
|
||||
if x.exp <= 63 {
|
||||
// i = trunc(x) fits into an int64 (excluding math.MinInt64)
|
||||
i := int64(high64(x.mant) >> (64 - uint32(x.exp)))
|
||||
i := int64(msb64(x.mant) >> (64 - uint32(x.exp)))
|
||||
if x.neg {
|
||||
i = -i
|
||||
}
|
||||
@ -934,11 +934,11 @@ func (x *Float) Float32() (float32, Accuracy) {
|
||||
return 0.0, Below
|
||||
}
|
||||
// bexp = 0
|
||||
mant = high32(r.mant) >> (fbits - r.prec)
|
||||
mant = msb32(r.mant) >> (fbits - r.prec)
|
||||
} else {
|
||||
// normal number: emin <= e <= emax
|
||||
bexp = uint32(e+bias) << mbits
|
||||
mant = high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
mant = msb32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
}
|
||||
|
||||
return math.Float32frombits(sign | bexp | mant), r.acc
|
||||
@ -1041,11 +1041,11 @@ func (x *Float) Float64() (float64, Accuracy) {
|
||||
return 0.0, Below
|
||||
}
|
||||
// bexp = 0
|
||||
mant = high64(r.mant) >> (fbits - r.prec)
|
||||
mant = msb64(r.mant) >> (fbits - r.prec)
|
||||
} else {
|
||||
// normal number: emin <= e <= emax
|
||||
bexp = uint64(e+bias) << mbits
|
||||
mant = high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
mant = msb64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
}
|
||||
|
||||
return math.Float64frombits(sign | bexp | mant), r.acc
|
||||
|
@ -572,7 +572,7 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
|
||||
u.clear() // TODO(gri) no need to clear if we allocated a new u
|
||||
|
||||
// D1.
|
||||
shift := leadingZeros(v[n-1])
|
||||
shift := nlz(v[n-1])
|
||||
if shift > 0 {
|
||||
// do not modify v, it may be used by another goroutine simultaneously
|
||||
v1 := make(nat, n)
|
||||
@ -942,7 +942,7 @@ func (z nat) expNN(x, y, m nat) nat {
|
||||
}
|
||||
|
||||
v := y[len(y)-1] // v > 0 because y is normalized and y > 0
|
||||
shift := leadingZeros(v) + 1
|
||||
shift := nlz(v) + 1
|
||||
v <<= shift
|
||||
var q nat
|
||||
|
||||
|
@ -205,11 +205,11 @@ func BenchmarkMul(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLeadingZeros(t *testing.T) {
|
||||
func TestNLZ(t *testing.T) {
|
||||
var x Word = _B >> 1
|
||||
for i := 0; i <= _W; i++ {
|
||||
if int(leadingZeros(x)) != i {
|
||||
t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
|
||||
if int(nlz(x)) != i {
|
||||
t.Errorf("failed at %x: got %d want %d", x, nlz(x), i)
|
||||
}
|
||||
x >>= 1
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user