▶ 计算 unsigned int v 的以 2 为底的对数,结果放入 unsigned int r 。

 // 方法零
#pragma unroll
for(r=;v; r++, v >>= ); // 方法一
union { unsigned int u[]; double d; } t;
t.u[__FLOAT_WORD_ORDER == LITTLE_ENDIAN] = 0x43300000;
t.u[__FLOAT_WORD_ORDER != LITTLE_ENDIAN] = v;
t.d -= 4503599627370496.0;
r = (t.u[__FLOAT_WORD_ORDER == LITTLE_ENDIAN] >> ) - 0x3FF;
// 我的电脑使用的是小端法存储,即 __FLOAT_WORD_ORDER == LITTLE_ENDIAN // 方法二
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n static const char LogTable256[] =
{
-, , , , , , , , , , , , , , , ,
LT(), LT(), LT(), LT(), LT(), LT(), LT(),
LT(), LT(), LT(), LT(), LT(), LT(), LT(), LT()
};
register unsigned int t, tt;
if (tt = v >> )
r = (t = tt >> ) ? + LogTable256[t] : + LogTable256[tt];
else
r = (t = v >> ) ? + LogTable256[t] : LogTable256[v]; // 等价的初始化 LogTable256 的方法
LogTable256[] = LogTable256[] = ;
for (int i = ; i < ; i++)
LogTable256[i] = + LogTable256[i / ];
LogTable256[] = -; // 额外规定 log(0) = -1,可以不要 // 等价的 r 的计算方法
if (tt = v >> )
r = + LogTable256[tt];
else if (tt = v >> )
r = + LogTable256[tt];
else if (tt = v >> )
r = + LogTable256[tt];
else
r = LogTable256[v]; // 方法三
const unsigned int b[] = { 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000 };
const unsigned int S[] = { , , , , };
register unsigned int r = ;
for (int i = ; i >= ; i--)
{
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
} // 等价的 r 的计算方法
register unsigned int shift;
r = (v > 0xFFFF) << ; v >>= r;
shift = (v > 0xFF) << ; v >>= shift; r |= shift;
shift = (v > 0xF) << ; v >>= shift; r |= shift;
shift = (v > 0x3) << ; v >>= shift; r |= shift;
r |= (v >> ); // 方法四,已知 v 是 2 的整数次幂
static const unsigned int b[] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 };
register unsigned int r = (v & b[]) != ;
#pragma unroll
for (i = ; i > ; i--)
r |= ((v & b[i]) != ) << i; // 方法五
static const int MultiplyDeBruijnBitPosition[] =
{
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , ,
};
v |= v >> ;
v |= v >> ;
v |= v >> ;
v |= v >> ;
v |= v >> ;
r = MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> ]; // 方法六,已知 v 是 2 的整数次幂
static const int MultiplyDeBruijnBitPosition2[] =
{
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , ,
};
r = MultiplyDeBruijnBitPosition2[(uint32_t)(v * 0x077CB531U) >> ];

▶ 计算 unsigned int v 的以 10 为底的对数,结果放入 int r 。

 // 方法一
int t;
static unsigned int const PowersOf10[] = { , , , , , ,, , , };
t = (IntegerLogBase2(v) + ) * >> ;// 使用前面的方法计算以 2 为底的对数
r = t - (v < PowersOf10[t]); // 方法二
r = (v >= ) ? : (v >= ) ? : (v >= ) ? :
(v >= ) ? : (v >= ) ? : (v >= ) ? :
(v >= ) ? : (v >= ) ? : (v >= ) ? : ;

▶ 计算 float v 的以 2 为底的对数,结果放入 int r 。

 // 方法一
r = *(const int *)&v;// 等价于 memcpy(&r, &v, sizeof r);
r = (r >> ) - ; // 稳定性改进,需要用到求 2 为底的对数方法里的 LogTable256
int x = *(const int *)&v;
c = x >> ;
if (c) // 正常浮点
c -= ;
else
{ // 非正常浮点,c = intlog2(x) - 149;
register unsigned int t;
if (t = x >> )
c = LogTable256[t] - ;
else
c = (t = x >> ) ? LogTable256[t] - : LogTable256[x] - ;
}

▶ 计算 float v 的 21/r 次幂的以 2 为底的对数(int r),结果放入 int c。

 // 方法一
c = *(const int *)&v;
c = ((((c - 0x3f800000) >> r) + 0x3f800000) >> ) - ;

▶ 计算 unsigned int v 的二进制表示中右侧连续的 0 的个数

 // 方法零
for (c = ; v > && v & == ; c++, v >>= ); // 方法一
if (v)
{
v = (v ^ (v - )) >> ;
for (c = ; v; c++)
v >>= ;
}
else
c = CHAR_BIT * sizeof(v); // 方法二
c=;
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= ;
if (v & 0x00FF00FF) c -= ;
if (v & 0x0F0F0F0F) c -= ;
if (v & 0x33333333) c -= ;
if (v & 0x55555555) c -= ; // 方法三,注意当 v == 0 时 c = 31
if (v & 0x1)
c = ;
else
{
c = ;
if ((v & 0xffff) == )
{
v >>= ;
c += ;
}
if ((v & 0xff) == )
{
v >>= ;
c += ;
}
if ((v & 0xf) == )
{
v >>= ;
c += ;
}
if ((v & 0x3) == )
{
v >>= ;
c += ;
}
c -= v & 0x1;
} // 方法四
float f = (float)(v & -v);
r = (*(unsigned int *)&f >> ) - 0x7f; // 方法五
static const int Mod37BitPosition[] =
{ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,, , , , };
r = Mod37BitPosition[(-v & v) % ]; // 方法六
static const int MultiplyDeBruijnBitPosition[] =
{ , , , , , , , , , , , , , , , ,, , , , , , , , , , , , , , , };
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> ];

▶ 计算不小于 unsigned int v 的最小的 2 的整数次幂,结果放入 unsigned int r 。

 // 方法一
if (v > )
{
float f = (float)v;
unsigned int const t = 1U << ((*(unsigned int *)&f >> ) - 0x7f);
r = t << (t < v);
}
else
r = ; // 方法二,已知 1 < v < (1 << 25)
float f = (float)(v - );
r = 1U << ((*(unsigned int*)(&f) >> ) - ); // 方法三
v--;
v |= v >> ;
v |= v >> ;
v |= v >> ;
v |= v >> ;
v |= v >> ;
v++;

▶ 将 unsigned short x 和 unsigned short y 的二进制表示交替排列组成 unsigned int z,使得 z 的偶数位是 x,奇数位是 y 。

 // 方法零
#pragma unroll
for (int i = ; i < sizeof(x) * CHAR_BIT; i++)
z |= (x & 1U << i) << i | (y & 1U << i) << (i + ); // 方法一
static const unsigned short MortonTable256[] =
{
0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
}; z = MortonTable256[y >> ] << | MortonTable256[x >> ] << | MortonTable256[y & 0xFF] << | MortonTable256[x & 0xFF]; // 方法二
z = ((x * 0x0101010101010101ULL & 0x8040201008040201ULL) * 0x0102040810204081ULL >> ) & 0x5555|
((y * 0x0101010101010101ULL & 0x8040201008040201ULL) * 0x0102040810204081ULL >> ) & 0xAAAA; // 方法三
static const unsigned int B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF };
static const unsigned int S[] = { , , , };
x = (x | (x << S[])) & B[];
x = (x | (x << S[])) & B[];
x = (x | (x << S[])) & B[];
x = (x | (x << S[])) & B[];
y = (y | (y << S[])) & B[];
y = (y | (y << S[])) & B[];
y = (y | (y << S[])) & B[];
y = (y | (y << S[])) & B[];
z = x | (y << );

▶ 判断 unsigned int v 的二进制表示中是否有某一个字节为 0x00,结果放入 bool f 。

 // 方法零
unsigned char * p = (unsigned char *)&v;
f = *p && *(p + ) && *(p + ) && *(p + ); // 方法一
f = ((v & 0xff) && (v & 0xff00) && (v & 0xff0000) && (v & 0xff000000)); // 方法二,操作数更少
f = ~((((v & 0x7F7F7F7F) + 0x7F7F7F7F) | v) | 0x7F7F7F7F); // 方法三,最高字节为 0x80 是也会输出 true
f = ((v + 0x7efefeff) ^ ~v) & 0x81010100;
if (f)
f = ~((((v & 0x7F7F7F7F) + 0x7F7F7F7F) | v) | 0x7F7F7F7F); // 方法四
f = (((v)-0x01010101UL) & ~(v) & 0x80808080UL);

▶ 判断 unsigned int v 的二进制表示中是否有某一个字节等于 unsigned char n,结果放入 bool f 。

 f = (haszero((x) ^ (~0UL /  * (n))));

▶ 判断 unsigned int v 的二进制表示中是否有某一个字节小于 unsigned char n,结果放入 bool f 。

 // 方法一,要求 x ≥ 0,0 ≤ n ≤ 128
f = (((x)-~0UL / * (n))&~(x)&~0UL / * ); // 顺便计算到底有几个
int count = (((~0UL / * ( + (n)) - ((x)&~0UL / * ))&~(x)&~0UL / * ) / % );

▶ 判断 unsigned int v 的二进制表示中是否有某一个字节大于 unsigned char n,结果放入 bool f 。

 // 方法一,要求 x ≥ 0,0 ≤ n ≤ 127
f = (((x)+~0UL / * ( - (n)) | (x))&~0UL / * ); // 顺便计算到底有几个
int count = (((((x)&~0UL / * ) + ~0UL / * ( - (n)) | (x))&~0UL / * ) / % );

▶ 判断 unsigned int v 的二进制表示中是否有某一个字节大于 unsigned char n,结果放入 bool f 。

 // 方法一,要求 x ≥ 0,0 ≤ m ≤ n ≤ 128,m < 128
f = ((((x)-~0UL / * (n))&~(x)&((x)&~0UL / * ) + ~0UL / * ( - (m)))&~0UL / * ); // 方法二,要求 x ≥ 0,0 ≤ m ≤ n ≤ 128,m < 128
f = ((~0UL / * ( + (n)) - ((x)&~0UL / * )&~(x)&((x)&~0UL / * ) + ~0UL / * ( - (m)))&~0UL / * ); // 顺便计算到底有几个
int count = (hasbetween(x, m, n) / % );

▶ 给定 unsigned int v,计算二进制表示中 v 的词典序后继,且非零位个数与 v 相等的 unsigned int w 。

 // 方法一,使用了 GNU C compiler 的内联函数 __builtin_ctz() 计算尾 0 个数,
// MS compiler 中用 is _BitScanForward(),或使用前面求尾 0 个数的方法
unsigned int t = v | (v - );
w = (t + ) | (((~t & -~t) - ) >> (__builtin_ctz(v) + )); // 方法二,较慢,但不需要求尾 0 个数
unsigned int t = (v | (v - )) + ;
w = t | ((((t & -t) / (v & -v)) >> ) - );

位运算骚操作 Part 2的更多相关文章

  1. 位运算骚操作 Part 1

    ▶ 原文标题<Bit Twiddling Hacks>,地址:https://graphics.stanford.edu/~seander/bithacks.html ▶ 额外参考资料:h ...

  2. 位运算骚操作 Part 3

    ▶ 异或运算 "^" 具有的部分性质: ● 交换律,结合律 ● a ^ b == (!a & b) | (a & !b),a ^ 1 == !a,a ^ 0 == ...

  3. java位运算(操作)的使用

    位操作是程序设计中对位模式按位或二进制数的一元和二元操作. 在许多古老的微处理器上, 位运算比加减运算略快, 通常位运算比乘除法运算要快很多. 在现代架构中, 情况并非如此:位运算的运算速度通常与加法 ...

  4. C 碎片九 预处理&位运算&文件操作

    一.预处理 预处理语句:#开头的语句,在预处理阶段处理预处理语句.包括宏定义.文件包含处理.条件编译 1, 宏定义 1. 不带参数宏定义:#define 标识符  字符串 #define PI 3.1 ...

  5. LeetCode | 289. 生命游戏(原地算法/位运算)

    记录dalao的位运算骚操作 根据百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机. 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细 ...

  6. 位运算之——按位与(&)操作——(快速取模算法)

    学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...

  7. 【Java基础】14、位运算之——按位与(&)操作——(快速取模算法)

    学习redis 字典结构,hash找槽位 求槽位的索引值时,用到了 hash值 & sizemask操作, 其后的scan操作涉及扫描顺序逻辑,对同模的槽位 按一定规则扫描! 其中涉及位运算 ...

  8. 全国计算机等级考试二级教程-C语言程序设计_第15章_位运算

    位运算,不适用于实数,仅仅适用于整数.字符. C语言的位运算只能操作整数.字符,实数是指数方式表示的,不适用于位运算. #define _CRT_SECURE_NO_WARNINGS #include ...

  9. LeetCode解题中位运算的运用

    位运算是我最近才开始重视的东西,因为在LeetCode上面刷题的时候发现很多题目使用位运算会快很多.位运算的使用包含着许多技巧(详细可以参考http://blog.csdn.net/zmazon/ar ...

随机推荐

  1. List<Map<String, Integer>> 同key的value全部累加合并

    public static void main(String[] args){ List<Map<String,Object>> list1 = new ArrayList&l ...

  2. pandas Timestamp的用法

    (Timestamp('2018-08-01 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>) 注意这里面的T ...

  3. Oracle中的三种Join 方式

    基本概念 Nested loop join: Outer table中的每一行与inner table中的相应记录join,类似一个嵌套的循环. Sort merge join: 将两个表排序,然后再 ...

  4. PHP com组件的使用 (环境搭建 以及测试)

    COM 组件在实际当前的软件开发中依然是比较重要,包括对于串口开发的人员,软件插件使用的人员,PHP 已经为我们添加了对于 COM的支持,可以很好的解决我们在开发中可能碰到的一些问题.一下是开发环境的 ...

  5. 序列化效率比拼——谁是最后的赢家avaScriptSerializer方式、DataContract方式、Newtonsoft.Json

    前言:作为开发人员,对象的序列化恐怕难以避免.楼主也是很早以前就接触过序列化,可是理解都不太深刻,对于用哪种方式去做序列化更是随波逐流——项目中原来用的什么方式照着用就好了.可是这么多年自己对于这东西 ...

  6. word如何让单页变横向

    word作为图文排版用户最多的软件之一,其功能的强大自不必说,比如将某一页在版式排版上设置为横排方向.那么,应该如何才能设置为横排的纸张呢?请阅读下文! 工具/原料 Microsoft Office ...

  7. 【转】每天一个linux命令(35):ln 命令

    原文网址:http://www.cnblogs.com/peida/archive/2012/12/11/2812294.html ln是linux中又一个非常重要命令,它的功能是为某一个文件在另外一 ...

  8. Python——递归、二分查找算法

    递归函数 1. 递归 (1)什么是递归:在函数中调用自身函数(2)最大递归深度:默认997/998——是Python从内存角度出发做的限制 n = 0 def story(): global n n+ ...

  9. 简单的爬虫例子——爬取豆瓣Top250的电影的排名、名字、评分、评论数

    爬取思路: url从网页上把代码搞下来bytes decode ---> utf-8 网页内容就是我的待匹配的字符串ret = re.findall(正则,待匹配的字符串), ret 是所有匹配 ...

  10. bzoj2035: [2009国家集训队]数据读取问题

    Description Input Output 可以转为边权为1的最短路:将不修改并读取x个数看作有向边,原先树上的边仍保留且视为双向边(但从根出发的边为单向)表示上次读取的修改 第一种边是点到bf ...