C语言中的位操作(16)--计算二进制数字尾部连续0的数目
本篇文章介绍计算二进制数字尾部连续0的数目的相关算法,例如:v=(1101000)2,该数尾部连续0的数目=3
方法1:线性时间算法
unsigned int v; // 需要计算的目标整数
int c; // c用来保存计算的结果
if (v)
{
v = (v ^ (v - )) >> ;
for (c = ; v; c++)
{
v >>= ;
}
}
else
{
c = CHAR_BIT * sizeof(v);
}
原理比较简单,下面提供一段C测试代码,根据代码显示的结果不难理解算法:
#include<stdio.h>
#include<math.h>
#include<limits.h> void tranlate(long long n) //十进制转换为二进制
{
int a[];
long long i,L,j;
i=L=;
while(n/){
a[i]=n%;
n/=;
L++,i++;
}
a[i]=;
while(L<){ //设置为显示32位的二进制
a[++i]=;
L++;
}
for(j=L-; j>=; j--){
printf("%d",a[j]);
}
printf("\n");
} int main()
{
unsigned int v;
int c;
v=;
tranlate(v);
tranlate(v-);
tranlate(v^(v-));
if (v)
{
v = (v ^ (v - )) >> ;
for (c = ; v; c++)
{
v >>= ;
}
}
else
{
c = CHAR_BIT * sizeof(v);
} printf("%d\n",c);
getchar();
return ;
}
对于一个随机的二进制数而言,尾部连续为0的数目平均值为1,于是上面这个算法相比下面较快的算法不算很糟
方法2:并行算法
unsigned int v; //32位目标数
unsigned int c = ; // 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 -= ;
这里,我们基本上做了与并行计算log2(N)类似的操作,但是我们首先分隔开最低位,然后将c保存最大值并且逐渐递减,对于N位数操作大致不会超过3*lg(N)+4
原理:
若v=A32……Ai100……0,
执行v&=-signed(v)操作, v=0……0100……0,若v!=0,则v中一定至少含1位非0,c--
然后通过下面的5步分别判断,逐步缩小范围,最后得到的结果保存在c中
方法3:二分查找算法
unsigned int v; //目标32位整数
unsigned int c; //c保存结果
// 注意:假如 0 == v, 则 c = 31.
if (v & 0x1)
{
// 特别地,当v为奇数的时候(假设会发生,有一半的概率)
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;
}
这个算法与前面介绍过的算法类似,但是它计算尾部连续0的个数采用一种跳跃式的二分查找
首先,检测最低的16位是否为0,如果是,将v向右移动16位并且c+=16,这样就成半的减少了v中符合条件的比特位,每一个接着的步骤进行类似的二分操作直到剩下1。
方法4:通过float型转换
unsigned int v; // 目标整数
int r; // r 保存结果
float f = (float)(v & -v); // 将v的最低有效位强制转化为float型
r = (*(uint32_t *)&f >> ) - 0x7f;
方法5:通过模除法与查表
unsigned int v; // 目标整数
int r; // r保存结果
static const int Mod37BitPosition[] = //制作一张关于每一个整数对37取模的余数相对应的位置
{
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , ,
, , ,
};
r = Mod37BitPosition[(-v & v) % ];
原理:
由于二进制数字尾部连续0的数目与该二进制的最低有效位的位置有关,而最低有效位的位置只可能出现在0~31的位置,相应的值为0~32,规定当v=0时,r=32
以上的代码作用是计算给定二进制数字尾部连续0的数目,于是对于二进制数0100,结果为2,以上算法基于以下事实:开始的32位位置相对而言与37互素,于是执行模37得到介于0~36之间唯一的一个数字,这些数字可以用来通过查表匹配连续0的数目
方法6:通过模与查表
unsigned int v;
int r;
static const int MultiplyDeBruijnBitPosition[] =
{
, , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , ,
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> ];
C语言中的位操作(16)--计算二进制数字尾部连续0的数目的更多相关文章
- 04 Storage and Calculation C语言中的存储和计算
文章内容来源于Programming Hub的学习记录,本人整理添加了中文翻译,如有侵权,联系本人删除 Variables C语言中的变量 Let's extend our mainfunction ...
- 关于C语言中结构体大小计算
结构体大小的计算,.网上说法一大堆还都不一样分什么对齐不对齐,偏移量什么的.. 在此稍微举例简单总结下: 对齐原则:每一成员的结束偏移量需对齐为后一成员类型的倍数 补齐原则:最终大小补齐为成员中最大 ...
- C语言中的除法的计算
不用除号,计算除法运算.思路是使用减法运算!思路1:循环采用减法每次减去n,直到做完减法之后结果小于0为止 但是这样次数较大 如求100/3,需要次数为34次. 思路2:循环采用减法每次减去k,K的 ...
- C语言中的位操作(14)--反转比特位
本篇文章主要讲述几种反转比特位的方法: 将一个32位数:abcd efgh 转置为hgfe dcba 1.常规方法 unsigned int v; // 目标待转置数 unsigned int r = ...
- C语言中的位操作(12)--判断一个数字是否包含一个全零字节
本文主要介绍一系列算法,算法主要功能是判断一个数字(二进制)中是否包含全零字节 e.g.1010 1111 0000 0000 1001 1111 0001 1111 即 32位整数:A4A3A2A1 ...
- C语言中结构体大小计算
1.普通结构体 struct student { char sex; char a; char b; int age; char name[100]; }; 该结构体大小为108 解答:1.先算str ...
- C语言中的位操作(15)--确定log10(N)的整数部分
本篇文章介绍一个整数的以10为底的对数的整数部分,即对于整数N,求log10(N)整数部分 方法一 : unsigned int v; //32位非0整数 int r; // r保存结果 int t; ...
- C语言中的未初始化变量的值
C语言中未初始化的变量的值是0么 全局变量 .静态变量初始值为0局部变量,自动变量初始值随机分配 C语言中,定义局部变量时如果未初始化,则值是随机的,为什么? 定义局部变量,其实就是在栈中通过移动栈指 ...
- Java中char转为16进制
Java中char转为16进制 char a = '0'; String hexStr = Integer.toHexString(a); System.out.println(hexStr);
随机推荐
- md5加密--32位16进制小写
public class ttgameMd5 { public final static String MD5(String str) { char hexDigits[] = { // 用来将字节转 ...
- 启动avd Android模拟器缓慢 HAXM自动安装失败
问题1.更新Android sdk镜像,腾讯镜像地址 android-mirror.bugly.qq.com 使用方法如图 问题2.自动更新HAXM失败解决方法 手动下载地址 http://softw ...
- C指针解析 ------ 指针的算术运算
本文是自己学习所做笔记.欢迎转载.但请注明出处:http://blog.csdn.net/jesson20121020 指针是一个特殊的变量,表示一个地址,而地址能够上减去或加上一个整数,从而能够表示 ...
- [效果不错] nginx 高并发参数配置及linux内核参数优化,完整的内核优化设置。PHP-FPM高负载解决办法。
背景:对vps小资源的实践中对,https://justwinit.cn/post/7536/ 的再优化,再实践,再优化,特别是Nginx,PHP,内核: 零)Nginx: error_log /da ...
- nginx反向代理做cache配置
前序:请耐性子看完,前面的这个配置可以达到按后缀名进行缓存,但无法被purge.后面的配置可以被purge.具体实施方案按个人情况而定. 需要第三方的ngx_cache_purge模块:wget ht ...
- laravel学习之路2: jwt集成
"tymon/jwt-auth": "^1.0@dev", 执行 composer update 'providers' => [ .... Tymon\ ...
- Android使用JUnit进行单元测试
前言:为什么要进行单元测试?单元测试能快速是开发者,找到代码中的问题所在,因为是单元测试,所以代码只执行响应的测试单元,执行快解决问题的效率高,同时提高代码的质量. Android中的单元测试可简单分 ...
- Lumen开发:如何向 IoC 容器中添加自己定义的类
版权声明:本文为博主原创文章,未经博主允许不得转载. 先在起始文件bootstrap/app.php加上$app->register(App\Providers\User\UserService ...
- com.netflix.hystrix.contrib.javanica.exception.FallbackDefinitionException: fallback method wasn't found: serviceError([class java.lang.String]) 异常
在使用spring cloud 的 Hystrix 后可能会遇到 如下截图错误: 后台代码如下: 找了好一会经过分析参数方法和原方法参数步一致造成: 修改后代码如下:
- 【BZOJ2724】[Violet 6]蒲公英 分块+二分
[BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n ...