└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # awesome-bits [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome) 2 | 3 | > 🐂🍺位运算技巧一览表 4 | > 5 | > 维护者 - [Keon Kim](https://github.com/keonkim) 6 | > 欢迎[pull requests](https://github.com/keonkim/awesome-bits/pulls) 7 | 8 | 9 | 10 | 11 | ## 整数 12 | **设置第n位(置为1)** 13 | ``` 14 | x | (1<> 1; 29 | v |= v >> 2; 30 | v |= v >> 4; 31 | v |= v >> 8; 32 | v |= v >> 16; 33 | v++; 34 | ``` 35 | **向下取整** 36 | ``` 37 | n >> 0 38 | 39 | 5.7812 >> 0 // 5 40 | 41 | ``` 42 | **取最大int值** 43 | ``` 44 | int maxInt = ~(1 << 31); 45 | int maxInt = (1 << 31) - 1; 46 | int maxInt = (1 << -1) - 1; 47 | int maxInt = -1u >> 1; 48 | ``` 49 | **取最小int值** 50 | ``` 51 | int minInt = 1 << 31; 52 | int minInt = 1 << -1; 53 | ``` 54 | **取最大long值** 55 | ``` 56 | long maxLong = ((long)1 << 127) - 1; 57 | ``` 58 | **乘以2** 59 | ``` 60 | n << 1; // n*2 61 | ``` 62 | **除以2** 63 | ``` 64 | n >> 1; // n/2 65 | ``` 66 | **乘以2的m次幂** 67 | ``` 68 | n << m; 69 | ``` 70 | **除以2的m次幂** 71 | ``` 72 | n >> m; 73 | ``` 74 | **检查相等** 75 | 76 | *在Javascript中快35%* 77 | ``` 78 | (a^b) == 0; // a == b 79 | !(a^b) // use in an if 80 | ``` 81 | **检查奇数** 82 | ``` 83 | (n & 1) == 1; 84 | ``` 85 | **交换两个值** 86 | ``` 87 | //version 1 88 | a ^= b; 89 | b ^= a; 90 | a ^= b; 91 | 92 | //version 2 93 | a = a ^ b ^ (b = a) 94 | ``` 95 | **取绝对值** 96 | ``` 97 | //version 1 98 | x < 0 ? -x : x; 99 | 100 | //version 2 101 | (x ^ (x >> 31)) - (x >> 31); 102 | ``` 103 | **取二者最大值** 104 | ``` 105 | b & ((a-b) >> 31) | a & (~(a-b) >> 31); 106 | ``` 107 | **取二者最小值** 108 | ``` 109 | a & ((a-b) >> 31) | b & (~(a-b) >> 31); 110 | ``` 111 | **检查符号一致性** 112 | ``` 113 | (x ^ y) >= 0; 114 | ``` 115 | **符号取反** 116 | ``` 117 | i = ~i + 1; // or 118 | i = (i ^ -1) + 1; // i = -i 119 | ``` 120 | **计算2n** 121 | ``` 122 | 1 << n; 123 | ``` 124 | **是否为2的幂** 125 | ``` 126 | n > 0 && (n & (n - 1)) == 0; 127 | ``` 128 | **m对2n取模** 129 | ``` 130 | m & ((1 << n) - 1); 131 | ``` 132 | **取平均值** 133 | ``` 134 | (x + y) >> 1; 135 | ((x ^ y) >> 1) + (x & y); 136 | ``` 137 | **取n的第m位(由低到高)** 138 | ``` 139 | (n >> (m-1)) & 1; 140 | ``` 141 | **置n的第m位为0(由低到高)** 142 | ``` 143 | n & ~(1 << (m-1)); 144 | ``` 145 | **检查第n位是否为1** 146 | ``` 147 | if (x & (1<> 1) | ((n & 01010101) << 1) 192 | ``` 193 | **m与n最右侧的相反位** 194 | ``` 195 | (n^m)&-(n^m) // returns 2^x where x is the position of the different bit (0 based) 196 | ``` 197 | **m与n最右侧的相同位** 198 | ``` 199 | ~(n^m)&(n^m)+1 // returns 2^x where x is the position of the common bit (0 based) 200 | ``` 201 | ## 浮点数 202 | 203 | 这些是受[fast inverse square root method](https://en.wikipedia.org/wiki/Fast_inverse_square_root)启发而来的技巧。 204 | 大部分为原创。 205 | 206 | **float转换为bit数组(unsigned uint32_t)** 207 | ```c 208 | #include 209 | typedef union {float flt; uint32_t bits} lens_t; 210 | uint32_t f2i(float x) { 211 | return ((lens_t) {.flt = x}).bits; 212 | } 213 | ``` 214 | *注:使用union进行转换在C++中是未定义行为,改使用`std::memcpy`。* 215 | 216 | **将bit数组转换回float** 217 | ```c 218 | float i2f(uint32_t x) { 219 | return ((lens_t) {.bits = x}).flt; 220 | } 221 | ``` 222 | 223 | **利用`frexp`从*正*浮点数中近似取出bit数组** 224 | 225 | *`frexp`将数值按照2n进行分解,即`man, exp = frexp(x)`表示man * 2exp = x同时0.5 <= man < 1.* 226 | ```c 227 | man, exp = frexp(x); 228 | return (uint32_t)((2 * man + exp + 125) * 0x800000); 229 | ``` 230 | *注:此操作最大产生2-16相对误差,由于man + 125覆盖了最后8位,保留了尾数的前16位。* 231 | 232 | **快速计算平方根倒数** 233 | ```c 234 | return i2f(0x5f3759df - f2i(x) / 2); 235 | ``` 236 | *注:此处使用了`i2f`与`f2i`函数。* 237 | 238 | 见[Wikipedia](https://en.wikipedia.org/wiki/Fast_inverse_square_root#A_worked_example)。 239 | 240 | **借助无穷级数快速计算正数的n次方根** 241 | ```c 242 | float root(float x, int n) { 243 | #DEFINE MAN_MASK 0x7fffff 244 | #DEFINE EXP_MASK 0x7f800000 245 | #DEFINE EXP_BIAS 0x3f800000 246 | uint32_t bits = f2i(x); 247 | uint32_t man = bits & MAN_MASK; 248 | uint32_t exp = (bits & EXP_MASK) - EXP_BIAS; 249 | return i2f((man + man / n) | ((EXP_BIAS + exp / n) & EXP_MASK)); 250 | } 251 | ``` 252 | 253 | 推导见[此处](http://www.phailed.me/2012/08/somewhat-fast-square-root/)。 254 | 255 | **Fast Arbitrary Power** 256 | ```c 257 | return i2f((1 - exp) * (0x3f800000 - 0x5c416) + f2i(x) * exp) 258 | ``` 259 | 260 | *注:`0x5c416`是此方法所给出的偏置值。若带入exp = -0.5,则为快速平方根倒数方法中的常量`0x5f3759df`。* 261 | 262 | 此方法推导见[these set of slides](http://www.bullshitmath.lol/FastRoot.slides.html)。 263 | 264 | **快速几何平均** 265 | 266 | 几何平均数是n个数连乘积的n次方根 267 | 268 | ```c 269 | #include 270 | float geometric_mean(float* list, size_t length) { 271 | // Effectively, find the average of map(f2i, list) 272 | uint32_t accumulator = 0; 273 | for (size_t i = 0; i < length; i++) { 274 | accumulator += f2i(list[i]); 275 | } 276 | return i2f(accumulator / n); 277 | } 278 | ``` 279 | 推导见[此处](https://github.com/leegao/float-hacks#geometric-mean-1)。 280 | 281 | **快速自然对数** 282 | 283 | ```c 284 | #DEFINE EPSILON 1.1920928955078125e-07 285 | #DEFINE LOG2 0.6931471805599453 286 | return (f2i(x) - (0x3f800000 - 0x66774)) * EPSILON * LOG2 287 | ``` 288 | 289 | *注:此方法使用`0x66774`作为偏置值。末尾乘以`ln(2)`是因为此方法其余部分计算的为`log2(x)`。* 290 | 291 | 推导见[此处](https://github.com/leegao/float-hacks#log-1)。 292 | 293 | **快速自然指数** 294 | 295 | ```c 296 | return i2f(0x3f800000 + (uint32_t)(x * (0x800000 + 0x38aa22))) 297 | ``` 298 | 299 | *注:偏置值`0x38aa22`对应为基数的乘法系数。特别地,它对应着2z = e中的`z`* 300 | 301 | 推导见[此处](https://github.com/leegao/float-hacks#exp-1)。 302 | 303 | ## 字符串 304 | 305 | **转换字母为小写** 306 | ``` 307 | 按位或空格字符 => (x | ' ') 308 | 结果恒为小写字母,即使原字符已为小写 309 | 例如:('a' | ' ') => 'a' ; ('A' | ' ') => 'a' 310 | ``` 311 | 312 | **转换字母为大写** 313 | ``` 314 | 按位与下划线字符 => (x & '_') 315 | 结果恒为大写字母,即使原字符已为大写 316 | 例如:('a' & '_') => 'A' ; ('A' & '_') => 'A' 317 | ``` 318 | **字母大小写互换** 319 | ``` 320 | 按位异或空格字符 => (x ^ ' ') 321 | 例如:('a' ^ ' ') => 'A' ; ('A' ^ ' ') => 'a' 322 | ``` 323 | **字母表序号** 324 | ``` 325 | 按位与chr(31)/binary('11111')/(hex('1F') => (x & "\x1F") 326 | 结果在1~26之间,大小写无关 327 | 例如:('a' & "\x1F") => 1 ; ('B' & "\x1F") => 2 328 | ``` 329 | **字母表序号(仅大写)** 330 | ``` 331 | 按位与问号字符 => (x & '?') 或按位异或@字符 => (x ^ '@') 332 | 例如:('C' & '?') => 3 ; ('Z' ^ '@') => 26 333 | ``` 334 | **字母表序号(仅小写)** 335 | ``` 336 | 按位异或反引号字符/chr(96)/binary('1100000')/hex('60') => (x ^ '`') 337 | 例如:('d' ^ '`') => 4 ; ('x' ^ '`') => 24 338 | ``` 339 | 340 | ## 杂项 341 | 342 | **使用位移运算快速转换R5G5B5颜色格式至R8G8B8** 343 | ``` 344 | R8 = (R5 << 3) | (R5 >> 2) 345 | G8 = (R5 << 3) | (R5 >> 2) 346 | B8 = (R5 << 3) | (R5 >> 2) 347 | ``` 348 | 注:使用任何非英文字符会产生错误结果 349 | 350 | ## 相关资源 351 | 352 | * [Bit Twiddling Hacks](https://graphics.stanford.edu/~seander/bithacks.html) 353 | * [Floating Point Hacks](https://github.com/leegao/float-hacks) 354 | * [Hacker's Delight](http://www.hackersdelight.org/) 355 | * [The Bit Twiddler](http://bits.stephan-brumme.com/) 356 | --------------------------------------------------------------------------------