Data Lab1(深入理解计算机系统)精讲

一.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;
}

当你看到这里到这里,说明这次实验完结撒花!!!

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值