一.int is AsciiDlgit(int x)
题目描述:
isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters ‘0’ to ‘9’)
Examples: isAsciiDigit(0x35) = 1
isAsciiDigit(0x3a) = 0
isAsciiDigit(0x05) = 0
Legal ops: ! ~ & ^ | + << >>
Max ops: 15
Rating: 3
这道题应该首先考虑x是否在0x30到0x39之间,在不能使用if语句的情况下,应当考虑使用位运算的方法。
对于这个我们考虑,将0x30按位取反再加一之后应该为0x30的相反数,所以我们再加上x。就相当于执行了0x30。同理,对于小于0x39这个条件,我们将x按位取反加一再加上0x39就可以得到0x39-x的值。之后我们让得到的两个数算数右移31bit,符号位填满。+1后只有0,1两种情况。
最后如果符合范围应该是1&1结果仍然为1,其他情况都不等于1,比如1&0为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)
功能:当x的任意奇数位为1时,返回1;其他情况下返回0
题目描述:
anyEvenBit - return 1 if any even-numbered bit in word set to 1
Examples: anyEvenBit(0xA) = 0, anyEvenBit(0xE) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 12
Rating: 2
这个直接看代码就好。
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)
功能:将返回值中的所有位全部置位成x中的第0位的值。
题目描述:
copyLSB - set all bits of result to least significant bit of x
Examples: copyLSB(5) = 0xFFFFFFFF, copyLSB(6) = 0x00000000
Legal ops: ! ~ & ^ | + << >>
Max ops: 5
Rating: 2
使用掩码0x01 获得x的最低位,其他位相当于全是和0进行&运算因此全是0,通过左移到最高,位, 进行算术右移,变为由32个符号位组成的int数据。
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)
功能:返回⼀个掩码,在该掩码中标识了⼆进制数x的所有位中,“1”所在的位权最 小的位。
题目描述:
leastBitPos - return a mask that marks the position of the least significant 1 bit. If x == 0, return 0
Example: leastBitPos(0x60) = 0x20
Legal ops: ! ~ & ^ | + << >>
Max ops: 6
Rating: 2
分析:
一个数的编码中,“1”所在的位权最小的位的低位全为0,即为“…100…0”的形式(记作1
)。按位取反,变为“…011…1”的形式(记作2
),再加1得到“…100…0”的形式(记作3
)。其中形式3
中的“1”的高位与形式2
的对应位相同,即与形式1
(原数)相反。
形式3
即原数的相反数,故可以将参数x
与其相反数按位与,较高位均变为0,只保留了“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)
功能:计算 x / 2^n,并将结果取整
题目描述:
divpwr2 - Compute x/(2^n), for 0 <= n <= 30
Round toward zero
Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
Legal ops: ! ~ & ^ | + << >>
Max ops: 15
Rating: 2
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 divpwr2(int x, int n)
{
int sig = !!(x >> 31);
int msk = (1 << n) + ~0;
int xLowN = msk & x;
return (x >> n) + ((!!xLowN) & sig);
}
六.int bitCount(int x)
功能:计算二进制数x中,对应位值“1”的总位数
核心思想是将一个表示原来数字的01序列==>一个表示1的个数的01序列。
题目描述:
bitCount - returns count of number of 1’s in word
Examples: bitCount(5) = 2, bitCount(7) = 3
Legal ops: ! ~ & ^ | + << >>
Max ops: 40
Rating: 4
查找“1”一共有多少位,首先可能想到按照每一位进行查找,但此时运算符总数会超出上限。所以我们可以把参数x
划分为8部分,用“模版”0001 0001 0001 0001 0001 0001 0001 0001
来比较,并比较4次。
获得模版的方法同Puzzle 2
。
设比较的结果为sum
,比较完成之后可以发现,我们已经把参数x
的8部分中各自“1”的总数存放在了sum
对应的1/8部分中,然后将这8部分进行3次“对折”,即可将8部分各自总数加到一起。
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;
}
当你看到这里到这里,说明这次实验完结撒花!!!