-
实验目的:
1更好地熟悉和掌握计算机中整数和浮点数的二进制编码表示。
2.实验中使用有限类型和数量的运算操作实现一组给定功能的函数,在此过程中加深对数据二进制编码表示的了解
3. 熟悉linux基本操作命令,其中常用工具和程序开发环境
4.完善bits.c的各个函数,实现其功能,并通过.btest的测试
-
实验要求
1. 尽快熟悉linux基本操作命令,还有其中常用工具和程序开发环境
2. 除浮点数函数实现外,只能使用顺序程序结构,禁用if, do, while, for, switch等。
有限操作类型,! ~ & ^ | + << >> 各函数不一样
禁用(!=、==、&&、|| 等组合操作符)
常量值范围 0~255
禁用强制类型转换
禁用整型外的任何其它数据类型
禁用定义和宏
不得使用函数
具体要求可参看bits.c各函数框架的注释
可以使用循环和条件控制;
可以使用整型和无符号整型常量及变量(取值不受[0,255]限制);
不使用任何浮点数据类型、操作及常量。
可以使用int和unsigned两种整型数据
禁用浮点数据类型、struct、union或数组结构。
浮点数函数均使用unsigned型数据表示浮点数据。
float_abs等函数必须能处理全范围的变量值,包括(NaN)和infinity。
- 实验内容及分析
1.题目要求:将32位数的末尾变为0
int pow2plus1(int x)
{
return (1 << x) + 1;//先向右移动一位,再向右移动一位,右移后首位不会对结果影响,再左移则末尾自动补0
}
2. 题目要求:第N(0-3)个字节0变为1,1变为0
int byteNot(int x, int n)
{
int temp=0xFF;
temp=temp<<(n<<3); //此时不清楚到底要对哪个字节进行处理,所以用0xFF(前面全为零),然后对其进行移位,使其全为一的字节对准要处理的字节;n代表的是字节,故移位时要乘8.
return x^temp;//异或运算,与0异或等于本身,与1异或取反。
}
3. 题目要求:比较第n个字节是否相等
int byteXor(int x, int y, int n)
{
int temp=0xFF;//比较第n个字节是否相等,就是把其他位置零,只留这一个字节,处理方法同上一题。
temp=temp<<(n<<3);
x=x&temp;
y=y&temp;//把其他位置零,只留这一个字节
return !!(x^y);//x,y若相同,则进行异或运算后所有位全为0,若不等,则存在1,结果大于零。对结果进行两次逻辑非(逻辑非:若为0则结果为1,若不为0,结果为1),正好得到符合题目要求的返回值。
}
4. 题目要求:实现逻辑与
int logicalAnd(int x, int y)
{
return (!!x)&(!!y);//对每个数进行两次逻辑非,两个数就变成0或1,前面31位均为0,这时按位与运算对于最后一位数操作,得出的结果即为逻辑与的值。
}
5. 题目要求:实现逻辑或
int logicalOr(int x, int y)
{
return (!!x)|(!!y);//同上
}
6. 题目要求:将32位数中的前n为移动至末位
int rotateLeft(int x, int n) {
int a=x<<n;//把除前n位外所有数向前移动n位,相当于低(32-n)位,放到高位,低n位为0。
int b=x>>(32-n);//高n位移动到低n位
int c=~((~0)<<n);//0先取反,即为32个1,向右移动n位,再取反,即为低n位为1,前面全是0,用于把b前(32-n)位置零
b=c&b; //这三步是:取出高n位,放到低n位,其余位为0
return a|b;//a和b合并
}
7. 题目要求:32位数中含有奇数个1返回1,含有偶数个1则返回0
int parityCheck(int x)
{
x=x^(x>>16);
x=x^(x>>8);
x=x^(x>>4);
x=x^(x>>2);
x=x^(x>>1);
return x & 0x1;
}//异或运算相当于不进位的加法,现对其分为等长的两部分,再进行异或运算,对应的位置,如果是两个1,结果为0,1个1,结果为1;再重复此过程,直至最后移动1位。若为偶数个1,在这个过程中,1会两两结合,变为0;奇数个会最后剩下一个1在最低位,与0x1按位与,结果只剩最低位,即为所需结果。
8. 题目要求:2*x后是否溢出
int mul2OK(int x)
{
int s1=(x>>31)&0x1;//取x符号位
int s2=((x<<1)>>31)&0x1;//取结果的符号位
return !!!(s1^s2);//若符号位不同则溢出
}
9. 题目要求:返回x*3/2后的结果
int mult3div2(int x)
{
int a=x;
a=(a<<1)+a;//乘以三
int sign=(a>>31)&0x1;// 取出符号位
int low=a&0x1; //取出最低位
a=a>>1;//除以二
a=a+(sign & low);//默认的舍入方式为向左舍入,这对于正数来说是满足题目的向零舍入的要求,但负数不满足。但如果负数为偶数,即最低位为0,结果为整数,没有舍入,不需处理;为负奇数,则需要加一(原来是向左,现加一实现向零舍入)。即只有负奇数要处理,而其符号位和最低位均是1,做按位与得1,加到结果中。
return a;
}
10. 题目要求:x-y是否溢出
int subOK(int x, int y) {
int result=x+(~y+1);//减去一个数就是加上其补码,补码的求法为取反加一
int a=x^y;//判断两个运算的数是否同号
int b=x^result;//判断结果与被减数是否同号
int c=!((a&b)>>31);//取符号位再取非即为结果
return c;
}//减法判断是否溢出,原理:负数减负数,正数减正数均不可能溢出。只有负数减去正数结果为正,和正数减负数结果为负才溢出。即两个运算的数不同号,结果与被减数不同号,才溢出。
11. 题目要求:取x的绝对值
int absVal(int x)
{
int sign=(x>>31)&0x1; //取符号位
int judge=sign+(~0);//符号位加上全1,即正数的时候为全1,负数时候为全0
x=(x&judge)|(~judge&(~x+1));//用judge的值是否为0实现(x>0) ? x : -x
return x;
}
12. 题目要求:当参数为NaN时,返回参数
unsigned float_abs(unsigned uf)
{
unsigned result=uf & 0x7FFFFFFF;
if(result>0x7F800000)
return uf;
else
return result;
}//先将uf化为无符号数result,判断result是否为NaN(NaN表示的数阶码全为1,且尾数为非0),如果是返回uf,否则返回result
13. 题目要求:返回表达式(int)f的位级等效值(将float转换为int),任何超出范围的内容(包括NaN和infinity)都应返回0x80000000
int float_f2i(unsigned uf) {
unsigned a;
unsigned b;
unsigned c;
a=(uf>>31)&0x1; //提取符号位
b=(uf>>23)&0x000000ff; //提取阶码
c=uf&0x007ffff+0x00800000; //提取尾数,在第24位加1,因为IEEE754标准尾数默认省略1
if(((uf&0x7fffffff)>0x7ff00000)||(b>158)) //NaN或者小数点右移溢出,b减去127之后,大于31,而int最多31位,超过其表示范围
{
return 0x80000000;
}
if(b<127)//阶码小于0,即为小数,int不能表示小数,返回0
{
return 0;
}
if(a==1)//负数
{
if((b-127)>23)//需要向左移位
{
c=~(c<<(b-150))+1;//补码
return c;
}
else if((b-127)<23) //需要向右移位
{
c=~(c>>(150-b))+1;
return c;
}
}
if(a==0)//正数,其余同上
{
if((b-127)>23)
{
c=c<<(b-150);
return c;
}
else if((b-127)<23)
{
c=c>>(150-b);
return c;
}
}
}