Authored by Kirill Smelkov

### xmath += CeilLog2, FloorLog2

```CeilLog2(x)	= min i: 2^i >= x
FloorLog2(x)	= max i: 2^i <= x```
Showing with 80 additions and 29 deletions
 ... ... @@ -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) } } } ... ...