bits的妙用
本文主要讲解变成过程中可能用到的一些位运算以及位运算符使用的技巧
对于整型的操作
第n位置位
x | (1<<n)
第n位置0
x & ~(1<<n)
翻转第n位
x ^ (1<<n)
获取大于等于此数的最小的2次幂数
unsigned int v; //只有当v是 32 bit才奏效
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
比如:当v是63那么转换之后,v-->64
当v是64,那么转换之后,v不变
获取最大整数
int maxInt = ~(1 << 31);
int maxInt = (1 << 31) - 1;
int maxInt = (1 << -1) - 1;
获取最小整数
int minInt = 1 << 31;
int minInt = 1 << -1;
获取最大的长整型数
long maxLong = ((long)1 << 127) - 1;
乘2
n << 1; // n*2
除2
n >> 1; // n/2
乘2的n次幂
n << m;
除2的n次幂
n >> m;
判断两个数是否相等
此方法比普通的比较速率快35%
(a^b) == 0; // a == b
!(a^b) // 在判断语句中使用
检查是否为奇数
(n & 1) == 1;
交换两个数字
//版本 1
a ^= b;
b ^= a;
a ^= b;
//版本 2
a = a ^ b ^ (b = a)
获取绝对值
//版本 1
x < 0 ? -x : x;
//版本 2
(x ^ (x >> 31)) - (x >> 31);
得到两个数的最大值
b & ((a-b) >> 31) | a & (~(a-b) >> 31);
得到两个数的最小值
a & ((a-b) >> 31) | b & (~(a-b) >> 31);
检查两个数字是否有相同的符号
(x ^ y) >= 0;
反转一个数的符号
i = ~i + 1; // or
i = (i ^ -1) + 1; // i = -i
计算2的n次幂
2 << (n-1);
判断一个数是不是2的次幂
n > 0 && (n & (n - 1)) == 0;
m对2的n次幂取余
m & (n - 1);
计算两个数的平均数
(x + y) >> 1;
((x ^ y) >> 1) + (x & y);
获取n的第m位 (从低到高)
(n >> (m-1)) & 1;
n的第m位置为0 (从低到高)
n & ~(1 << (m-1));
检查x的第n位是否被置位
if (x & (1<<n)) {
// 第n位被置位
} else {
//第n位没有被置位
}
提取最右边的为1的位
x & (-x)
例如:7:
0000 0000 0000 0000 0000 0000 0000 0111
经过运算之后 变为
0000 0000 0000 0000 0000 0000 0000 0001
64:
0000 0000 0000 0000 0000 0000 0100 0000
经过运算之后:
0000 0000 0000 0000 0000 0000 0100 0000
提取最右边的为0的位(类比于上一个)
~x & (x+1)
使最右边的为0的位置为1
x | (x+1)
n + 1
-~n
n - 1
~-n
得到一个数的负数
~n + 1;
(n ^ -1) + 1;
if (x == a) x = b; if (x == b) x = a;
x = a ^ b ^ x;
浮点数
此部分大多数都来源于 fast inverse square root method.
把一个浮点数转化为一个bits数组 (unsigned uint32_t)
#include <stdint.h>
typedef union {float flt; uint32_t bits} lens_t;
uint32_t f2i(float x) {
return ((lens_t) {.flt = x}).bits;
}
把一个bits数组转化为浮点数
float i2f(uint32_t x) {
return ((lens_t) {.bits = x}).flt;
}
Approximate the bit-array of a positive float using frexp
frexp
gives the 2n decomposition of a number, so that man, exp = frexp(x)
means that man 2exp = x and 0.5 <= man < 1.*
man, exp = frexp(x);//or man= frexp(x,&exp);
return (uint32_t)((2 * man + exp + 125) * 0x800000);
------------------------------
double x = 666.400000;
double man = 0;
int exp = 0;
//sprintf(x&(-x),"%d");
//cout << (x&(-x)) << endl;
man= frexp(x,&exp);
printf("frexp(%f,&n)=%f,n=%d\n", x, man, exp)
---------------------------------
运行结果:
frexp(666.400000,&n)=0.650781,n=10
---------------------------------
Caveat: This will have at most 2-16 relative error, since man + 125 clobbers the last 8 bits, saving the first 16 bits of your mantissa.
字符串
转换为小写字母
OR by space => (x | ' ')
Result is always lowercase even if letter is already lowercase
eg. ('a' | ' ') => 'a' ; ('A' | ' ') => 'a'
转换为大写字母
AND by underline => (x & '_')
Result is always uppercase even if letter is already uppercase
eg. ('a' & '_') => 'A' ; ('A' & '_') => 'A'
反转大小写
XOR by space => (x ^ ' ')
eg. ('a' ^ ' ') => 'A' ; ('A' ^ ' ') => 'a'
返回在字母表中的位置
AND by chr(31)/binary('11111')/(hex('1F') => (x & "\x1F")
Result is in 1..26 range, letter case is not important
eg. ('a' & "\x1F") => 1 ; ('B' & "\x1F") => 2
返回在字母表中的位置 (只对大写字母有效):
AND by ? => (x & '?') or XOR by @ => (x ^ '@')
eg. ('C' & '?') => 3 ; ('Z' ^ '@') => 26
返回在字母表中的位置 (只对小写字母有效):
XOR by backtick/chr(96)/binary('1100000')/hex('60') => (x ^ '`')
eg. ('d' ^ '`') => 4 ; ('x' ^ '`') => 25
杂项
从R5G5B5 to R8G8B8 的快速像素转换
R8 = (R5 << 3) | (R5 >> 2)
G8 = (R5 << 3) | (R5 >> 2)
B8 = (R5 << 3) | (R5 >> 2)
Note: 使用其他字母会产生严重错误