Authored by Kirill Smelkov

xmath += CeilLog2, FloorLog2

CeilLog2(x)	= min i: 2^i >= x
FloorLog2(x)	= max i: 2^i <= x
... ... @@ -34,5 +34,30 @@ func CeilPow2(x uint64) uint64 {
}
}
// CeilLog2 returns minimal i: 2^i >= x
func CeilLog2(x uint64) int {
switch bits.OnesCount64(x) {
case 0:
return 0
case 1:
return bits.Len64(x) - 1
default:
return bits.Len64(x)
}
}
// FloorLog2 returns maximal i: 2^i <= x
//
// x=0 gives -> -1.
func FloorLog2(x uint64) int {
switch bits.OnesCount64(x) {
case 0:
return -1
default:
return bits.Len64(x) - 1
}
}
// XXX if needed: NextPow2 (y > x, such that y = 2^i) is
// 1 << bits.Len64(x)
... ...
... ... @@ -21,38 +21,64 @@ import (
"testing"
)
func TestCeilPow2(t *testing.T) {
testv := []struct {in, out uint64} {
{0, 0},
{1, 1},
{2, 2},
{3, 4},
{4, 4},
{5, 8},
{5, 8},
{6, 8},
{7, 8},
{8, 8},
{9, 16},
{10, 16},
{11, 16},
{12, 16},
{13, 16},
{14, 16},
{15, 16},
{16, 16},
{1<<62 - 1, 1<<62},
{1<<62, 1<<62},
{1<<62+1, 1<<63},
{1<<63 - 1, 1<<63},
{1<<63, 1<<63},
func TestPow2(t *testing.T) {
testv := []struct {x, xcpow2 uint64; xclog2 int} {
{0, 0, 0},
{1, 1, 0},
{2, 2, 1},
{3, 4, 2},
{4, 4, 2},
{5, 8, 3},
{5, 8, 3},
{6, 8, 3},
{7, 8, 3},
{8, 8, 3},
{9, 16, 4},
{10, 16, 4},
{11, 16, 4},
{12, 16, 4},
{13, 16, 4},
{14, 16, 4},
{15, 16, 4},
{16, 16, 4},
{1<<62 - 1, 1<<62, 62},
{1<<62, 1<<62, 62},
{1<<62+1, 1<<63, 63},
{1<<63 - 1, 1<<63, 63},
{1<<63, 1<<63, 63},
}
for _, tt := range testv {
out := CeilPow2(tt.in)
if out != tt.out {
t.Errorf("CeilPow2(%v) -> %v ; want %v", tt.in, out, tt.out)
xcpow2 := CeilPow2(tt.x)
if xcpow2 != tt.xcpow2 {
t.Errorf("CeilPow2(%v) -> %v ; want %v", tt.x, xcpow2, tt.xcpow2)
}
xclog2 := CeilLog2(tt.xcpow2)
if xclog2 != tt.xclog2 {
t.Errorf("CeilLog2(%v) -> %v ; want %v", tt.xcpow2, xclog2, tt.xclog2)
}
}
xclog2 = CeilLog2(tt.x)
if xclog2 != tt.xclog2 {
t.Errorf("CeilLog2(%v) -> %v ; want %v", tt.x, xclog2, tt.xclog2)
}
xflog2 := FloorLog2(tt.xcpow2)
xflog2Ok := tt.xclog2
if tt.x == 0 {
xflog2Ok = -1
}
if xflog2 != xflog2Ok {
t.Errorf("FloorLog2(%v) -> %v ; want %v", tt.xcpow2, xflog2, xflog2Ok)
}
if tt.x != tt.xcpow2 {
xflog2Ok--
}
xflog2 = FloorLog2(tt.x)
if xflog2 != xflog2Ok {
t.Errorf("FloorLog2(%v) -> %v ; want %v", tt.x, xflog2, xflog2Ok)
}
}
}
... ...