github.com/benz9527/toy-box/algo@v0.0.0-20240221120937-66c0c6bd5abd/bit/bit.go (about) 1 package bit 2 3 import ( 4 "unsafe" 5 ) 6 7 func RoundupPowOf2(target uint64) uint64 { 8 target-- 9 target |= target >> 1 10 target |= target >> 2 11 target |= target >> 4 12 target |= target >> 8 13 target |= target >> 16 14 target |= target >> 32 15 target++ 16 return target 17 } 18 19 // RoundupPowOf2ByLoop rounds up the target to the power of 2. 20 // Plain thinking. 21 func RoundupPowOf2ByLoop(target uint64) uint64 { 22 var result uint64 = 1 23 for result < target { 24 result <<= 1 25 } 26 return result 27 } 28 29 // RoundupPowOf2ByCeil rounds up the target to the power of 2. 30 // Copy from linux kernel kfifo. 31 func RoundupPowOf2ByCeil(target uint64) uint64 { 32 return 1 << CeilPowOf2(target) 33 } 34 35 // CeilPowOf2 get the ceil power of 2 of the target. 36 // Copy from linux kernel kfifo. 37 func CeilPowOf2(target uint64) uint8 { 38 target-- 39 if target == 0 { 40 return 0 41 } 42 var pos uint8 = 64 43 if target&0xffffffff00000000 == 0 { 44 target = target << 32 45 pos -= 32 46 } 47 if target&0xffff000000000000 == 0 { 48 target <<= 16 49 pos -= 16 50 } 51 if target&0xff00000000000000 == 0 { 52 target <<= 8 53 pos -= 8 54 } 55 if target&0xf000000000000000 == 0 { 56 target <<= 4 57 pos -= 4 58 } 59 if target&0xc000000000000000 == 0 { 60 target <<= 2 61 pos -= 2 62 } 63 if target&0x8000000000000000 == 0 { 64 pos -= 1 65 } 66 return pos 67 } 68 69 // IsPowOf2 checks if the target is power of 2. 70 // Copy from linux kernel kfifo. 71 func IsPowOf2(target uint64) bool { 72 return target&(target-1) == 0 73 } 74 75 type Number interface { 76 ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~int8 | ~int16 | ~int32 | ~int64 | ~int 77 } 78 79 // HammingWeight counts the number of 1 bit in a number. 80 type HammingWeight[T Number] func(n T) uint8 81 type BitCount[T Number] HammingWeight[T] 82 83 func convert[T Number](n T) uint64 { 84 var target uint64 85 switch unsafe.Sizeof(n) { 86 case 1: 87 target = uint64(*(*uint8)(unsafe.Pointer(&n))) 88 case 2: 89 target = uint64(*(*uint16)(unsafe.Pointer(&n))) 90 case 4: 91 target = uint64(*(*uint32)(unsafe.Pointer(&n))) 92 case 8: 93 target = *(*uint64)(unsafe.Pointer(&n)) 94 } 95 return target 96 } 97 98 // variable-precision SWAR algorithm 99 100 // HammingWeightBySWAR counts the number of 1 bit by group statistics. 101 // Calculate the number of 1 bit by tree-like structure. 102 // Example: 103 // 0x55555555 = 01010101010101010101010101010101 104 // It will keep the odd bits of the original number 1 and keep the even bits of the original number 1. 105 // Every 2 binary bits represent the number of 1 in the corresponding binary bit of the original number. 106 // 0x33333333 = 00110011001100110011001100110011 107 // It will keep the right two bits of the sum of the previous step and keep the left two bits of the sum of the previous step. 108 // Every 4 binary bits represent the number of 1 in the corresponding binary bit of the original number. 109 // 0x0f0f0f0f = 00001111000011110000111100001111 110 // It will keep the right four bits of the sum of the previous step and keep the left four bits of the sum of the previous step. 111 // Every 8 binary bits represent the number of 1 in the corresponding binary bit of the original number. 112 // 0x00ff00ff = 00000000111111110000000011111111 113 // It will keep the right eight bits of the sum of the previous step and keep the left eight bits of the sum of the previous step. 114 // Every 16 binary bits represent the number of 1 in the corresponding binary bit of the original number. 115 // 0x0000ffff = 00000000000000001111111111111111 116 // It will keep the right sixteen bits of the sum of the previous step and keep the left sixteen bits of the sum of the previous step. 117 // Every 32 binary bits represent the number of 1 in the corresponding binary bit of the original number. 118 func HammingWeightBySWAR[T Number](n T) uint8 { 119 _n := convert[T](n) 120 _n = (_n & 0x5555555555555555) + ((_n >> 1) & 0x5555555555555555) 121 _n = (_n & 0x3333333333333333) + ((_n >> 2) & 0x3333333333333333) 122 _n = (_n & 0x0f0f0f0f0f0f0f0f) + ((_n >> 4) & 0x0f0f0f0f0f0f0f0f) 123 _n = (_n & 0x00ff00ff00ff00ff) + ((_n >> 8) & 0x00ff00ff00ff00ff) 124 _n = (_n & 0x0000ffff0000ffff) + ((_n >> 16) & 0x0000ffff0000ffff) 125 _n = (_n & 0x00000000ffffffff) + ((_n >> 32) & 0x00000000ffffffff) 126 return uint8(_n) 127 } 128 129 // HammingWeightBySWAR2 counts the number of 1 bit by group statistics. 130 // Example: 131 // 7 = (0111)2 132 // step 1: 133 // 0x7 & 0x55555555 = 0x5 134 // 0x7 >> 1 = 0x3, 0x3 & 0x55555555 = 0x1 135 // 0x5 + 0x1 = 0x6 136 // step 2: 137 // 0x6 & 0x33333333 = 0x2 138 // 0x6 >> 2 = 0x1, 0x1 & 0x33333333 = 0x1 139 // 0x2 + 0x1 = 0x3 140 // step 3: 141 // 0x3 & 0x0f0f0f0f = 0x3 142 // 0x3 >> 4 = 0x0, 0x0 & 0x0f0f0f0f = 0x0 143 // 0x3 + 0x0 = 0x3 144 // step 4: 145 // 0x3 * 0x01010101 = 0x03030303 146 // 0x03030303 & 0x3fffffff = 0x03030303 147 // 0x03030303 >> 24 = 0x3 148 func HammingWeightBySWAR2[T Number](n T) uint8 { 149 _n := convert[T](n) 150 _n = (_n & 0x5555555555555555) + ((_n >> 1) & 0x5555555555555555) 151 _n = (_n & 0x3333333333333333) + ((_n >> 2) & 0x3333333333333333) 152 _n = (_n & 0x0f0f0f0f0f0f0f0f) + ((_n >> 4) & 0x0f0f0f0f0f0f0f0f) 153 // 8 bits quick multiply 154 // 0x01010101 = 00000001 00000001 00000001 00000001 155 // = 1 << 24 | 1 << 16 | 1 << 8 | 1 << 0 156 // i * 0x01010101 = i << 24 + i << 16 + i << 8 + i << 0 157 // Merge 158 // (i * 0x01010101)>>24 = (i<<24)>>24 + (i<<16)>>24 + (i<<8)>>24 + (i<<0)>>24 159 // Hamming Weight 160 _n = ((_n * 0x0101010101010101) & ((1 << 64) - 1)) >> 56 161 return uint8(_n) 162 } 163 164 // HammingWeightBySWAR3 counts the number of 1 bit by group statistics. 165 func HammingWeightBySWAR3[T Number](n T) uint8 { 166 _n := convert[T](n) 167 bits := func(num uint8) uint8 { 168 remainder := num&0x5 + (num>>1)&0x5 169 return remainder&0x3 + (remainder>>2)&0x3 170 } 171 res := uint8(0) 172 for i := 0; i < 16; i++ { 173 res += bits(uint8((_n >> (i * 4)) & 0xf)) 174 } 175 return res 176 } 177 178 var ( 179 bitCount = [16]uint8{ 180 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 181 } 182 ) 183 184 func HammingWeightByGroupCount[T Number](n T) uint8 { 185 _n := convert[T](n) 186 res := uint8(0) 187 for i := 0; i < 16; i++ { 188 res += bitCount[uint8((_n>>(i*4))&0xf)] 189 } 190 return res 191 }