实验题目:填写bits.c文件中尚未完成的各个函数的内容,但是,要求只使用有限数量、规定的操作符。然后通过dlc和btest两个工具来测试代码。 | |
实验目的:本实验为课程实验二,补全bits.c中的15个代码,理解掌握计算机的存储方式和逻辑运算操作。 | |
实验环境:个人电脑、32 位ubuntu18.04环境 | |
实验内容及操作步骤: 第一步,填写bits.c文件中尚未完成的各个函数的内容: 1.函数名称:bitAnd()、实现要求:x&y 合法操作:~ |、最大运算符数:8 【解析】~为位运算,因此得到的&也为位运算,且由德摩根定律,可知: x∩y=~~(x∩y)=~(~x∪~y) 【实现】 2.函数名称:getByte()、实现要求:从x中提取第n个字节 合法操作: ! ~ & ^ | + << >>、最大运算符数: 6 【解析】先利用n<<3得到n*8,通过x右移n*8,去掉最后的n*8位, 则现在x的最后8位即为想要的结果,再与8位全为1的数(即0xFF)相与, 得到提取的结果。 【实现】
3.函数名称:logicalShift()、实现要求:逻辑位移,x逻辑右移n(0~31)位 合法操作: ! ~ & ^ | + << >>、最大运算符数:20 【解析】0x7fffffff对应0111 1111 1111 1111 1111 1111 1111 1111,将其 右移n位再左移1位后,则该数前n位均为0,与x右移n的结果相与即可得到 x逻辑右移n位的结果(注意,由于最大整数不能超过0xFF,所以用1<<31再取 反来完成实现0x7fffffff的功能) 【实现】
4.函数名称:bitCount()、实现要求:返回x中1的个数 合法操作: ! ~ & ^ | + << >>、最大运算符数:40 【解析】由于结果不会超过 32,故可以利用一个 32 位二进制数来记录,将每 次的检测位数设定为 4 位的。初始化 tmp=0x1111,用来依次检测 x>>i 的 0,8, 16,24 位是否为 1。利用 val 累加分别计算 4 个字节上 1 的个数, val 的每 个字节的值为对应x 每个字节上的 1 的个数;最后将得到 val 四个字节的值相 加,即 x 四个字节上 1 的个数的和,保留最低字节的信息,为最后结果。 【实现】
5.函数名称: bang()、实现要求:不使用!来计算!x 合法操作: ~ & ^ | + << >>、最大运算符数: 12 【解析】题目所需要求!0=1,!(0除外其他数)=0;一个数取相反数的规则跟负数 补码规则一样,~x+1,按位取反加 1 即可;一个不为 0 的数原数和相反数相或 的结果符号位必然为 1,为0的原数和相反数相或的结果符号位必然为0;则将符 号位右移31位到最低位取反后与0x01相与则可得到结果。 【实现】
6.函数名称: tmin()、实现要求:求补码编码的最小数 合法操作: ! ~ & ^ | + << >>、最大运算符数:4 【解析】从补码的公式可以看出当最高位为 1,而其余位为 0 的时候,获得最小值。 【实现】
7.函数名称: fitsBits()、实现要求:求给定的一个数是否能用n位补码表示, 如果可以则返回1 合法操作: ! ~ & ^ | + << >>、最大运算符数:15 【解析】一个数的前32-n都为0或1则可以用n位补码表示,则可以假设第n-1 位为符号位,通过先算术左移32-n位再算术右移32-n位后比较与原数是否有差别;如果有差别,与原数亦或后为1,否则为 0,再用逻辑非!,将有差别的返回 0,无差别的返回1; 【实现】
8.函数名称: divpwr2()、实现要求:一个数除以 (2^n),有余数则往靠近0 的方向取舍 合法操作: ! ~ & ^ | + << >>、最大运算符数:15 【解析】分x为负数和非负数两种情况:当x为非负数时,直接将 x右移n位 即可;当x为负数时,如果x移出的位中不全为零,即有余数,则结果为右移n 位后的结果加 1; 【实现】
9.函数名称: negate()、实现要求:取一个数的相反数 合法操作: ! ~ & ^ | + << >>、最大运算符数:5 【解析】求相反数,按位取反加一即可。 【实现】
10.函数名称:isPositive()、实现要求:判断一个数是否为正数,是则返回1 合法操作: ! ~ & ^ | + << >>、最大运算符数:8 【解析】判断一个数是否为正数,看它的符号位即可,但要考虑是否为0,如果 一个数x为 0,则!x =1 ,!!x =0,否则,一个不为 0 的数!x =0 ,!!x =1,则 将符号位与!!x相与即可判断是否为正数。 【实现】 11.函数名称:isLessOrEqual()、实现要求:判断x <= y是否成立,成立返回1 合法操作: ! ~ & ^ | + << >>、最大运算符数:24 【解析】判断是否有 x<=y,有三种可能情况:第一种,x为负数,y为正数, 即x符号位为1,y符号位为0;第二种,x与y同号,通过判断x-y的大小来判 断正负,只需要判断x-y的符号位;第三种,x等于y,即x^y必为全0,此时取 非得1。 【实现】 12.函数名称:ilog2()、实现要求: 求一个数的 log2 的值 合法操作: ! ~ & ^ | + << >>、最大运算符数:90 【解析】求一个数的 log2 的值即为求32位二进制数的最高位1对应l log2 的 值。由x>0,ilog 的结果不会超过 31,则可以用5位二进制来表示。依次折半累 加得出最高位的权,方法如下: 首先判断高16位是否全部为 0,tmp+=2^4*i,x相应右移tmp位; 再判断右移后的高8 位是否全部为 0,tmp+=2^3*i ,x 相应右移 tmp位; 再依次累加得出结果tmp。 【实现】 13.函数名称:float_neg() 实现要求:将32 位int 型数解读为单精度浮点型数据f,返回-f 合法操作: Any integer/unsigned operations incl,||, &&. also if, while 最大运算符数:10 【解析】若这个数为特殊值则返回原数;若为非特殊值,则直接对符号位取反。 使用异或操作符^。对1求异或,等价于对1求反;对 0 求异或,等价于保持原 数;当需要对一组数中一部分求反,一部分保持原数时,就可以使用异或运算。 判断一个浮点数是否为特殊值: 截取其阶码位和小数位与阶码位全为1,小数位 全为0,即与0x7f8fffff 比较,若大于它,则必然为特殊值。截取数据,利用与 运算 &,需要截取的数和1与,需要清零的数和0与,即可保留需要的数据部分 【实现】
14.函数名称:float_i2f()、实现要求:将一个整形数转化为浮点数 合法操作: Any integer/unsigned operations incl. ||, &&. also if, while 最大运算符数:30 【解析】将一个整形数,转化为浮点数,浮点数的符号只取决于第一位,所以 对负数作取绝对值处理之后,所有数都可以按照同一种方法处理;将二进制数左 边的零位全部移出,直到移到“ 1”位为止, 移出的位数 shiftleft 则为 32 位 中前面“ 0”的个数, 因此 32-shiftleft 代表的就是阶码的原码部分, 再加 上 127的移码就可以得到最终的阶码;移完 0 之后得到的 aftershift 这串数, 就是小数部分,所以最后将 aftershift 右移 9位,127+32-shiftleft 左移 23 位,最前面加上符号位,即可得到转移后的数字; 【实现】 15.函数名称: float_twice() 实现要求:将一个32位int型数解读为单精度浮点型数据f,返回2*f 合法操作: Any integer/unsigned operations incl. ||, &&. also if, while 最大运算符数:30 【解析】若这个数为特殊值(阶码位全1)则返回原数;若为非特殊值,如果是 规格化数,则对阶码位作+1运算;如果是非规格化数(阶码全为0),则对小数位 作左移运算。符号位不改变。这里涉及到将一个数据拆解为多个部分(符号位、 阶码位和小数位) ,以及最后将各个部分拼合的运算;对于拆分数据,如果只是 保留需要的部分,其它位清零,那么只要作 &运算取数据即可;如果只留下需要 的部分,其它位剔除,那么要先作右移运算,再作类似 &0xFF 的运算截断数据; 对于拼合数据,如果已经将几部分数据处理为置 1 位互不相干(即除了1 有效位 其它位都为 0),那么直接用或 | 运算接合即可; 【实现】 第二步,利用dlc工具验证代码格式的正确性: 直接/dlc bits.c,代码没有问题,dlc无声返回。 所有最大运算符数均满足实验要求。 第三步,利用btest工具验证代码功能的正确性 1.make btest:
2.查看得分, 所获分数41分,15个程序均满足题目对符号和常数的限制要求,正确性证明成功。 3. 输入"./btest [optional cmd line args]"查看bits.c各个功能的实现情况。 4其他操作: 输入"./btest -h"可以查看其它命令的说明。 输入"./ishow <数字>"可以帮助我们进一步理解int的存储。 输入"./fshow <数字>"可以帮助我们进一步理解float的存储。 收获与体会: 通过本次实验,深刻了解了各种数据类型的在计算机中的存储方式,进一步认识了数据的加减乘除、按位取非及!x的实质,更加灵活运用移位操作,会用移位操作来代替数值大的数据,对int转float的操作更加熟练了,提升了编程能力。 同时,在test.c文件中test_fitsBits函数在return前加一行空指令printf("",TMax_n);解决-2147483648不能用二进制表示的问题。 |