实验一:bitAnd实验
用~、|实现&操作。
int bitAnd(int x, int y)
{
return ~(~x|~y);
}
实验二:getByte实验
取出x
中的n
号字节,将结果return
返回。
int getByte(int x, int n)
{
return (x>>8*n)&0xFF;
}
注意代码当中0xFF也是默认为32位其他位置默认补零,因此&0xFF和&0x00FF效果相同。本实验的操作是一个典型的操作用于取出一个数据的某几位。
实验三:logicalShift实验
将x
逻辑右移n
位(0<=n<=31) ,将结果return
返回。
int logicalShift(int x, int n)
{
return ((unsigned int)x)>>n;
}
在C语言当中的位移操作分为逻辑右移和算数右移,对于无符号数来说所有的右移操作都是逻辑右移,而对于有符号数来说所有的右移操作都是算数右移。因此本实验中,现将x转化为无符号数再进行右移以保证对int x,进行逻辑右移的操作。而对于左移操作来说不分逻辑左移和算数左移,都是进行补零操作。
实验九:negate实验
补充函数negate()
,计算-x
。
int negate(int x)
{
return ~x+1;
}
本实验即计算x的反码,操作就是对于x的每一位都取反再加1。注意要对于补码和反码进行区别对于补码来说,正数的补码是他本身,而负数的补码是他的反码。
实验十:isPositive实验
如果x
大于0
返回1
,否则返回0
。
int isPositive(int x)
{
if (x==0){
return 0;
}
return !(x>>31&1);
}
负数的最高为零,正数的最高位为一,所以只需将x的最高为取出进行判断即可。特别的零分为正零和负零,所以对于零我们需要单独讨论。
实验十一:isLessOrEqual实验
如果x
小于等于y
则返回1
,否则返回0
。
int isLessOrEqual(int x, int y)
{
int t = 1 << 31;
int xp = !(x & t);//若x为负数则xp=0;正数为1;
int yp = !(y & t);//若y为负数则yp=0;正数为1;
int p = x + ~y + 1;//p = x-y
return (!!(((!xp) & yp) | ((p & t) | !p))) & (!(xp & (!yp)));//后一部分解决当x为正数y为负数的时候返回0;开头部分解决当x为负数y为正数的时候返回1;!P排除了x=y的情况
}
对于这个题目的代码,我们还有一个比较好理解的版本。
# include <stdio.h>
int isLessOrEqual(int x, int y)
{
if (x==y){
return 1;
}
if (((x+~y+1)>>31)&1==1){
return 1;
}
else {
return 0;
}
}
int main (){
int re = isLessOrEqual(5,8);
printf ("%d",re);
}
不过这个代码目前存在一些问题,后续可以尝试进行完善。
实验十二:ilog2实验
返回x
求以2
为底的对数的结果(向下取整)。
由于计算机是以二进制的形式进行存储的,因此计算这种题目对于计算机来说十分简单。因为一个int类型的数再计算机内部为2的不同次幂的连加形式。所以只需找出从高位到低位第一个不为零的数即可。我们可以这样进行书写。
int ilog2(int x)
{
if (x<=0){
return 0;
}
else {
for (int i=30;i>=0;i--){
if ((x>>i)&1==1){
return i;
}
}
}
}
实验十四:float_i2f实验
实现由 int
到 float
的类型转换。
unsigned float_i2f(int x)
{
/********* Begin *********/
int i = 1;
int nega = 0;
unsigned temp;
unsigned result;
if (x & 0x80000000) {//判断x是否为负数,如果是负数则执行nega=1,x=-x
nega = 1;
x = ~x + 1;
}
if (x == 0) {//判断x是否为零。
return 0;
}
while ((x & 0x80000000) != 0x80000000) {//当x的首位不为1时则继续执行
++i;
x <<= 1;//每次x左移一位
}//找到x从左到右第一个为1的位数
result = x << 1;//将x再左移一位即丢弃掉x的第一个为1的位。
temp = result;//相当于frac位上的内容
result >>= 9;//再将result右移九位以便填入符号位和exp位
if (nega) {
result |= 0x80000000;//将x的符号还原。
} else {
result &= 0x7FFFFFFF;//保证x的符号为正
}
i = (32 - i) + 127;求出exp
result = (result & 0x807FFFFF) | (i << 23);把exp位上的内容全部置零把exp填入
if ((temp & 0x00000100) == 0x00000100) {//舍入步骤
if (temp & 0x000000FF) {
return result + 1;
} else {
if (result & 1) {
return result + 1;
} else {
return result;
}
}
}
return result;
/********* End *********/
}
注意对于零需要单独讨论。并且要注意在int类型转化为float类型的数据的时候有时需要进行舍入操作。对于这一过程下图给出了形象的转化过程。
可以通过视频来了解这一过程进行的详细操作http://【【CSAPP-深入理解计算机系统】2-1.信息的存储(上)】 https://www.bilibili.com/video/BV1tV411U7N3/?share_source=copy_web
对于舍入操作,对于二进制的舍入,如果舍入到n位,对于n位以后的k位如果>10000....则进一。
如果k位<100000.....则舍去。如果后k位=10000....则对n位进行凑零操作。即如果n位为1则进一,如果n位为0则舍去。