Datalab实验(有限运算符和语句下的位运算)

问题1:bitAnd

在这里插入图片描述

通过取反、取或实现取与。
思路:
通过德摩根律,A&B=((A&B))=((A)|(~B))
实现:
在这里插入图片描述

问题2:getByte

在这里插入图片描述

获得字长4个字节数据的某一个字节数据
思路:

将要获得的字节右移到最低字节,再与0xff求与,就能得到最低字节的数据了。
其需要向右移动的位数为8*n,即n<<3。
实现:
在这里插入图片描述

问题3:logicalShift

在这里插入图片描述

实现逻辑右移(高位补0)
思路:
由于在C语言中”>>”表示的是算术右移,高位会补充符号位,为了实现逻辑右移,我们先将数据向右移n位,再将前面的n位置0。
置0的方法是,将0x7fffffff(即~(1<<31))向右移n位(此时有n+1个0),再向左移1位。注意,当n为31时,此时为32个0但是我们想要的是31个0,所以再和1取或就可以了。
实现:
在这里插入图片描述

问题4:bitCount

在这里插入图片描述

要求返回该数据二进制表示下1的个数
思路:
利用掩码和移位操作,自底向上计算1的个数。
①将相邻2位看成一个整体。与掩码[01]按位与,保留低位的1。接着右移一位之后再与掩码[01]按位与,保留高位的1。然后让两个结果相加。
②将相邻4位看成一个整体。与掩码[0011]按位与,保留低二位的1。接着右移二位之后再与掩码[0011]按位与,保留高二位的1。然后让两个结果相加。
③将相邻8位看成一个整体。与掩码[00001111]按位与,保留低四位的1。接着右移四位之后再与掩码[00001111]按位与,保留高四位的1。然后让两个结果相加。
④将相邻16位看成一个整体。与掩码[0000000011111111]按位与,保留低八位的1。接着右移八位之后再与掩码[0000000011111111]按位与,保留高八位的1。然后让两个结果相加。
⑤将相邻32位看成一个整体。与掩码[00000000000000001111111111111111]按位与,保留低16位的1。接着右移16位之后再与掩码[00000000000000001111111111111111]按位与,保留高16位的1。然后让两个结果相加。
举例示意图:(以01001010100000111100000001110001为例)
在这里插入图片描述

实现:
在这里插入图片描述

问题5:Bang

在这里插入图片描述

不用“!”实现取非(逻辑取非)
思路:
由于0和-0是统一用0x00000000表示的,对于一般的数,其和相反数取或结果最高位必为1。所以对于(x|(~x+1))>>31只有在x为0的时候最低位为0,其他情况都为0xffffffff。之后再与0x00000001取与,便实现只保留最低位。再与0x00000001取异或,实现最低位的取反。
实现:
在这里插入图片描述

问题6:tmin

在这里插入图片描述

返回二进制表示下的有符号整数的最小值
思路:
负数符号位为1,后面31位数值越小则绝对值越大。
实现:
在这里插入图片描述

问题7:fitsBits

在这里插入图片描述

如果x能被n位二进制的有符号整数表示那么返回1,否则返回0。
思路:
x从32位转为n位可以看成符号拓展的逆过程,所以如果x<<(32-n)>>(32-n)与原来的x相等则可以用n位二进制补码表示。
实现:
在这里插入图片描述

问题8:divpwr2

在这里插入图片描述

计算x/(2^n),但是要求结果是向0取整。
思路:
正数截断小数部分,相当于变小了,是向0取整。所以对于正数可以直接右移。
但是负数截断小数部分(后n位),虽然也变小了,但是这样不是向0取整。需要将后n位的影响消除掉,所以在右移之前需要加一个偏移量2^n-1(后n位最大的数),这样后面的n位就一定会向前进一位,截断时便可实现向0取整。
因为我们要创造一个flag,其在x为正数时为0,在x为负数时为2^n-1。所以
flag=(x>>31)&((1<<n)+(~0));
实现:
在这里插入图片描述

问题9:negate

在这里插入图片描述

要求计算相反数
思路:
由于在补码中绝对值相同的正数和负数相加等于0。即x+(-x)=2^n,其中x>0
所以-x=2n-x根据补码的定义,2n-x即为-x的补码,所以根据补码的求法(按位取反再加1)即可得到x的相反数。
由于这个变换是对称的,所以当x<0时也可以~x+1.
而0和-0在补码中统一成了0x00000000,取反加一之后舍去进位依然为0x00000000
实现:
在这里插入图片描述

问题10:isPositive

在这里插入图片描述

判断x是否为正数,是则返回1,否则返回0。
思路:
对于非负数,其符号位都为0,所以在算术右移31位后会变成全0,而负数变为全1。
再和0x01取与只保留最低位,和0x01取异或实现取反。但是题目只要求正数返回1,还要把0排除掉,所以要与上一个在x为0时为0,在x为非0时为1的flag。
我们想到0取反以后的符号位仍然是0,但是正数取反后的符号位为1,所以该flag就是x取反右移31位。
实现:
在这里插入图片描述

问题11:isLessOrEqual

在这里插入图片描述

如果x<=y那么返回1,否则返回0。
思路:
如果x、 y符号相同那么可以直接y-x即y+(~x+1),如果结果的符号位为0,那么y>=x,否则y<x。
如果x、y符号不同那么可能会发生溢出,此时如果x符号位为1那么x<y,如果x符号位为0那么x>y。
实现:
在这里插入图片描述

问题12:ilog2

在这里插入图片描述

思路:
因为ilog(x)最大不会超过32=2^5即100000,那么对于一般情况为x4x3x2x1x0,其中x0、x1、x2、x3、x4只能取0或者1,因此我们可以根据二分法依次确定他们。
例如对于x4,我们只需要看1是在高16位还是低16位,如果是在高16位那么x4为1,否则x4为0。之后我们把有1的16位作为低16位,继续二分下去。
实现:
在这里插入图片描述

问题13:float_neg

在这里插入图片描述

返回相反数,如果是NaN的话(阶码全1且尾码不是全0)则直接返回。
思路:
当阶码不是全1或者尾码是全0的时候(即不是NaN)的时候只需要修改第32位符号位,方法是:(1<<31)^uf,否则直接返回。
实现:
在这里插入图片描述

问题14:float_i2f

在这里插入图片描述

强制将一个int类型转型成float,以unsigned的类型返回。
思路:
①符号位就最高位的数值:x&(1<<31)。为方便以后的操作,对x取绝对值操作,并将x为0的情况直接返回。
②阶码需要将原来的数表示成1.XXX*2^X的形式从而确定偏移量,所以要确定从高向低第一个1出现的位置。其中n为偏移量,初始化为31。当找到第一个1,while循环终止。
③对于尾码,需要先将第一个1(缺省)和之前的0移出去。对后面的数进行舍入操作。规则是向偶舍入,建立舍入变量flag,flag为1表示进1,flag为0表示舍去。
最终结果即为符号位+阶码+尾码+flag舍入标志
实现:
在这里插入图片描述

问题15:float_twice

在这里插入图片描述

要求返回浮点数的二倍,对于NaN则直接返回。(此处我认为这里对于+∞和-∞的情况也是直接返回,后来试了一下果然如此,这样说题目就有点不严谨了,毕竟NaN是不包含+∞和-∞的)
思路:
对于规格化值,直接将阶码+1即可。
对于非规格化值,不能直接将阶码+1,因为非规格化值的阶码复原是1-bias,只不过前面缺省的1变成了0,所以对于非规格化值的处理方式是将尾数左移1位,并补上符号位。
实现:

在这里插入图片描述
结果演示:
功能检测:
在这里插入图片描述

代码格式检测:
在这里插入图片描述

参考文章:https://blog.csdn.net/qq_40889820/article/details/88831962
感谢学长,收获颇丰!

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值