记录自己的学习过程!
程序内允许使用:
a. 运算符: ! ~ & ^ | + << >>
b. 范围在0 - 255之间的常数
c. 局部变量
程序内禁止以下行为:
a. 声明和使用全局变量
b. 声明和使用定义宏
c. 声明和调用其他的函数
d. 类型的强制转换
e. 使用许可范围之外的运算符
f. 使用控制跳转语句:if else switch do while for
文章目录
int is AsciiDIgit(int x)
- int isAsciiDigit(int x) 主要考虑int型变量溢出情况
功能:当0x30<=x<=0x39时(即字符0-9的ASCII码值)返回1;其他情况下返回0
int isAsciiDigit(int x) {
/*判断X-0x30与0x39-X的符号位的情况,同时也排除了int溢出的影响*/
int test1=x+(~(0x30)+1);
int test2=(~x+1)+0x39;//若溢出,二者的符号位仍是不同的,可排除。
test1=(test1>>31)+1;
test2=(test2>>31)+1;//算数右移31bit,符号位填满。+1后只有0,1两种情况。
return test1&test2;//符号要求情况应该为二者都为1即1&1;其余情况均为0
}
int anyEvenBit(int x)
- int anyEvenBit(int x)
功能:当x的任意偶数位为1时,返回1;其他情况下返回0
没什么难度,主要是要知道这种方法
int anyEvenBit(int x) {
/*对X的每个byte都进行 | 运算,只要有一个even-bit 为1,则&0x55结果不为0。 !!运算后可转换为1 */
int test1=((x>>8)|(x>>16)|(x>>24)|x)&0x55;//even-bit 全为0时, test1=0, 否则不为0.
return !!test1; //将test通过!!运算转化为0或1的结果返回
}
int copyLSB(int x)
- int copyLSB(int x)
功能:将返回值中的所有位全部置位成x中的第0位的值
主要考查掩码的应用
int copyLSB(int x) {
/*使用掩码0x01 获得x的最低位,通过左移到最高为, 进行算术右移,变为由32个符号位组成的int数据*/
int test1=x&1;//获得least-bit;
x=(test1<<31)>>31;//将least-bit变为符号位,再使用算术右移, 补符号位(least-bit);
return x;
}
int leastBitPos(int x)
- int leastBitPos(int x)
功能:返回⼀个掩码,在该掩码中标识了⼆进制数x的所有位中,“1”所在的位权最 小的位
主要考虑(~x+1)和x的位级别关系
若x=01 01 11 00,则~x=10 10 00 11,~x+1=10 10 01 00
可以看到~x+1和x(从右往左看),在第一个‘1’出现之前位都是相同的,而‘1’之后位级别是取反的。
所以可以用(~x+1)&x得到第一个‘1’。
int leastBitPos(int x) {
/*~x在0~目标位为1,在目标位为0. ~x+1后0~目标位保持不变,而其他位为原值的反
故 (~x+1)&x保留了0~目标位,而目标位~31都为0*/
x=(~x+1)&x;
return x;
}
int divpwr2(int x, int n)
- int divpwr2(int x, int n)
功能:计算 x / 2^n,并将结果取整
主要考虑负数的情况
int divpwr2(int x, int n) {
/*对非负数只需要>>n bit; 对于负数,需要加上2^n-1,再>>n bit;所以需要得到一个正数为0,负数为2^n-1的偏移量*/
/*为什么要加2^n-1? 1.因为对于被二整除的负数,没有影响*/
/* 2.对不可被二整除的负数,加它后会进位,即原来得数+1,即相当于向零取整*/
int test1=(0x01<<n)+~0x00;//获得2^n-1
int test2=x>>31; //让符号位占满32bit
test1=test2&test1; //若为负数,则偏移量为2^k-1. 若为正数,则偏移量为0
x=(x+test1)>>n;
return x;
}
int bitCount(int x)
- int bitCount(int x)
功能:计算二进制数x中,对应位值“1”的总位数
核心思想是将一个表示原来数字的01序列==>一个表示1的个数的01序列
int bitCount(int x) {
/*为了统计为1的位数,我们必须把这个32-bit的数值,转化为一个统计1个数的数字*/
int test1=(0x55<<8)|(0x55);
test1=(test1<<16)|(test1);
x=(x&test1)+((x>>1)&test1);//首先将每两位看成一个整体,利用掩码0101...0101计算每两位中1的个数,并存入x的对应位置
//例一个16-bit的数:10 11 00 11 11 00 01 10 -->> 01 10 00 10 10 00 01 01
test1=(0x33<<8)|(0x33);
test1=(test1<<16)|(test1);
x=(x&test1)+((x>>2)&test1);/*再将每四位看成一个整体, 利用掩码0011...0011将每两位的1的个数变为
每四位的1的个数,存入x的对应位置*/
//0110 0010 1000 0101 -->> 0011 0010 0010 0010
test1=(0x0f<<8)|(0x0f);
test1=(test1<<16)|(test1);
x=(x&test1)+((x>>4)&test1);/*再将每八位看成一个整体, 利用掩码0000 1111...0000 1111将每4位的1的个数变为
每8位的1的个数,存入x的对应位置*/
//0011 0010 0010 0010 -->> 0000 0101 0000 0100
test1=(0xff<<16)|(0xff);
x=(x&test1)+((x>>8)&test1);/*再将每16位看成一个整体, 利用掩码 0000 0000 1111 1111 0000 0000 1111 1111将每8位的1的个数变为
每16位的1的个数,存入x的对应位置*/
//0000 0101 0000 0100 -->> 0000 0000 0000 1001 = (9)与原数吻合
test1=(0xff<<8)|(0xff);
x=(x&test1)+((x>>16)&test1);/*再将这32位看成一个整体, 利用掩码 0000 0000 0000 0000 1111 1111 1111 1111将每16位的1的个数变为
每32位的1的个数,存入x的对应位置*/
//此时x的数值就变为了原x中所有1的个数
return x;
}