Datalab实验报告
4月4日
文件再次毁坏做的备份,部分题目进行了思路借鉴
实验准备
- 安装Linux虚拟机
- 安装gcc编译器,vim编辑器与Archieve Manager
- 下载tar文件并用tar xvf datalab-handout.tar解压,获得datalab-handout 文件夹
- 用vim命令行操作打开bits.c文件,进行编辑
实验项目、思路分析与成果
整数部分
- bitXor
本题旨在求x,y两个数的位异或。可以采用“取出均为0的位”以及“取出均为1的位”.
Eg:有x=11010011与y=00110100两个数
用u=x&y取出x,y均为1的位,用v=(x)&(y)取出x,y均为0的位。
之后(u)&(v)得出既不全为0也不全为1的位
代码如下:int bitXor(int x, int y) { int u=x&y; int v=(~x)&(~y); return (~u)&(~v); }
- Tmin()
此题旨在求二进制补码表示的最小数
显然其为负数,故符号位为1
而由二进制补码实际值的计算公式:
val=-( 2 i − 1 2^{i-1} 2i−1) a i − 1 a_{i-1} ai−1+ 2 i − 2 2^{i-2} 2i−2 a i − 2 a_{i-2} ai−2+…+2* a 1 a_1 a1+1* a 0 a_0 a0
可知当 a i − 2 a^{i-2} ai−2= a i − 1 a^{i-1} ai−1=…= a 1 a_1 a1= a 0 a_0 a0时,值最小
故可直接用1<<31表示int tmin(void) { return 1<<31; }
- isTmax
此题与第二题相反,是在求给出的数是否为二进制补码表示的最大数0111…1111(31个1)
我们不妨考虑其特殊性质((~(x+1))^x)全为1.可将此作为充分条件考虑。
但还需要排除特殊情况:二进制补码能表示的最小数也会出现这种情况,故使用(!!(x+1))来排除
//本题亦可使用如下代码,但因为不能使用<<,故不使用int isTmax(int x){ v=(~(x+1))^x; return (!v)&(!!(x+1)); }
int isTmax(int x) { int u=(x<<1)+1; int v=~u; return (!v)&(!!(x+1)); }
- allOddBits(int x)
最简单的方法是使用!((x&0xAAAAAAAA)^0xAAAAAAAA),但可使用的最大常数是0xAA,故我们开始着手考虑用0xAA进行构造
考虑到该数有8位,而我们需要32位,故我们采用倍增的方法,以逆向二分对其进行扩展int allOddBits(int x) { int a_8=0xAA; int a_16=(a_8<<8)|a_8; int a_32=(a_16<<16)|a_16; return !((a_32&x)^a_32); }
- negate
按二进制补码中一般的表示形式求相反数即可int negate(int x) { return (~x)+1; }
- isAsciiDigit
本题为一维求范围相关题目,转换为01相关问题为与端点比大小
本题中‘-’不允许使用,故将‘-’改为’(~x)+1’
看相减之后值的最高位,若最高位均为0(均为正数),则满足题意。int isAsciiDigit(int x) { int u=x+((~0x30)+1); int v=0x39+((~x)+1); int a=u>>31; int b=v>>31; return (!a)&(!b); }
- conditional
可以通过对x进行一系列变换得到u,使x非0时u全为1,x为0时u全为0
用我们非常常见的(!!x)取反加一,是否越界来化全1或化全0int conditional(int x, int y, int z) { int u=(~(!!x))+1; return (y&u)|(z&(~u)); }
- isOrLessEqual
要分符号一致和符号不一致两种情况讨论,不然会出现越界的情况
减号不被允许使用,那么在符号不一致时使用取反+1即可
相减完之后判断最高位符号,其会进行符号整数的扩展int isLessOrEqual(int x, int y) { int sig_x=(x>>31)&1; int sig_y=(y>>31)&1; int sit_1=sig_x&(!sig_y); int sit_2=(!sig_x)&(!sig_y); int sit_3=sig_x&sig_y; int v=y+((~x)+1); int w=(!(v>>31))&1; return sit_1|(sit_2&w)|(sit_3&w); }
- LogicNeg
分析0和非0数的不同性质:非0数取反加一和原数做或运算,最高位一定为1;
但0取反加一做或运算为0。
然后我们便可以右移31位,获得按符号扩展的整数,+1即可获得相应结果。int logicalNeg(int x) { int u=(~x)+1; int v=(u|x)>>31; return v+1; }
- HowManyBits
因为原码会比补码用的位数少(因为负数补码表示的最高位是1),所以对于用补码表示的负数,转化为正数形式
然后用二分法判断某一些以2为倍数的数域中是否有1值,若有,则去掉低位只看高位以缩减问题规模,若无,则缩小二分范围,判断能否缩减,直到缩减至问题规模为1int howManyBits(int x) { int sig=x>>31; x=((~sig)&x)|(sig&(~x)); int a_16=(!!(x>>16))<<4; x>>=a_16; int a_8=(!!(x>>8))<<3; x>>=a_8; int a_4=(!!(x>>4))<<2; x>>=a_4; int a_2=(!!(x>>2))<<1; x>>=a_2; int a_1=!!(x>>1); x>>=a_1; return a_16+a_8+a_4+a_2+a_1+x+1; }
浮点数部分
此时需要把所传入数值分为3个部分:sig(符号位),exp(指数位),frac(有效数字位)
-
FloatScale2
本题以无符号整数的二进制形式传入一个浮点数的二进制表示形式
题目要求将该浮点数的数值乘2
先将浮点数分几种情况讨论:- NAN:根据题目要求,返回原数
- 阶码全为0:frac部分左移1位,模拟真实数据记录情况,并不改变exp的相关特点
- 阶码不全为0也不全为1:exp+1(既不是全为0的情况,需要特殊处理;也不会溢出)
unsigned floatScale2(unsigned uf) { unsigned int sig=(uf>>31)&1; unsigned int exp=(uf>>23)&(0xFF); unsigned int frac=uf&0x7FFFFF; if(!(exp^0xFF)) return uf; if(!exp) return (sig<<31)+(exp<<23)+(frac<<1); return (sig<<31)+((exp+1)<<23)+frac; }
-
floatFloat2Int
本题通俗地说就是手动把浮点型数化为整形。
我们分几种情况讨论:- 阶码位全为1:根据题目要求,返回0x80000000
- 阶码全为0:因为值val=frac* 2 − 126 2^{-126} 2−126,整数位必为0,故返回0
- 阶码不全为1也不全为0,则先把最高位的1加上,以frac能表示的最高位数:23位为例,分两种情况讨论:
(1) frca>23:按照浮点数计数方法往左移(exp-23)位
(2)frac<=23:按照浮点数计数方法,往右移(23-exp)位(只能移动正数位)
int floatFloat2Int(unsigned uf) { int sig=(uf>>31)&1; int exp=((uf>>23)&(0xFF))-127; int frac=uf&0x7FFFFF; if(exp>=31) return 0x80000000; if(exp<0) return 0; int val; frac=frac|(1<<23); if(exp>23) val=frac<<(exp-23); else val=frac>>(23-exp); if(sig) val=~val+1; return val; }
-
floatPower2
先判断x的范围。
若x>=128,即出现越界的情况,返回+INF,即0x7f800000
若x<-149,即出现向下溢出至整数位为0的情况(x+127<=-23,向下溢出至无法表示),则返回0
若-149<=x<-126,即按照浮点数的表示方法,在该数所能表示的frac部分最高位添1
若-126<=x<128,则按照浮点数的一般表示形式。用x+127得到原来的阶码exp,然后再左移23位unsigned floatPower2(int x) { int exp=x+127; if(x>=128) return 0x7f800000; if(x<-149) return 0; if(x>=-126) return exp<<23; return 1<<(x+149); }
遇到的问题
- 用命令行打开vim编辑器时,即使用:wq,:wq!,:w均有保存,仍然会不定期恢复到初始状态
原因猜测:命令行中打开的命令存在寄存器(缓存)中,而笔者在电脑上打开了缓存自动清理功能,遂不定期恢复至初始状态。
解决方法:打开vim编辑器图形界面,点击"save"按钮保存。 - 最后一题测评时间过长
解决方法:笔者也没有解决这个问题,只是把测评程序中的10s改成了30s,然后全部通过
以上是本次实验报告的全部内容