datalab

本文详细介绍了使用位操作符如~&amp;^|+<<>>来实现异或、取反、比较、浮点数尺度调整等函数,涵盖了整数和浮点数的位级表示和计算,包括最小补码整数、最大值检测、位模式检查以及浮点数与整数之间的转换等操作。

实验内容

实验要求

实验过程
以下是lab包含的所有文件
在这里插入图片描述
在bit.c文件中编写相关代码实现相关函数
使用btest测试函数实现的正确性

bitXor

/* 
* bitXor - x^y using only ~ and & 
*   Example: bitXor(4, 5) = 1
*   Legal ops: ~ &
*   Max ops: 14
*   Rating: 1
*/
int bitXor(int x, int y) {
       //异或运算
       return ~((~((~(x&y))&x))&(~((~(x&y))&y)));
}

用~ &实现异或操作
异或就是当参与运算的两个二进制数不同时结果才为1,其他情况为0。
在这里插入图片描述
可以用与非门实现异或门

tmin

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
 int tmin(void) {
        return 1<<31;
}

返回最小二进制补码整数,int是4B大小,n+1位整数的补码的范围是 – 2n≤ x ≤ 2n–1,因此本题将1左移31位即可

isTmax(x)

/*
 * isTmax - returns 1 if x is the maximum, two's complement number,
 *     and 0 otherwise 
 *   Legal ops: ! ~ & ^ | +
 *   Max ops: 10
 *   Rating: 1
 */
int isTmax(int x) {
  return (!((~(x+1)) ^ x)) & (!!((x + 1) ^ 0x0));
}

如果是补码的最大值返回1,其余数字返回0
对于int类型,补码的最大值是最高位符号位为0,低31位为1。

allOddBits(x)

/* 
 * allOddBits - return 1 if all odd-numbered bits in word set to 1
 *   where bits are numbered from 0 (least significant) to 31 (most significant)
 *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 2
 */
int allOddBits(int x) {
        int t1 = 0xAA;
        int t2 = t1 | (t1 << 8);
        int mask = t2 | (t2 << 16);
        return  !((x & mask) ^ mask);
}

当x的所有奇数位值是1时返回1。
32位数的所有奇数位都是1时是0xAAAAAAAA,以该值为模板通过与操作过滤出所有的奇数位查看是否满足条件。由于本实验规定最多使用8位整数。因此要用0xAA构造出0xAAAAAAAA。

negate

/* 
 * negate - return -x 
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
        return ~x + 1;
}

补码取反操作规则是按位取反再加1

isAscallDigit

 * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
 *   Example: isAsciiDigit(0x35) = 1.
 *            isAsciiDigit(0x3a) = 0.
 *            isAsciiDigit(0x05) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 3
 */
int isAsciiDigit(int x) {
        //判断高位是否为0
        int high1 = x >> 6;
        int t1 = !!high1;
        //判断头两位是否为11
        int high2 = x >> 4;
        int t2 = !(high2 ^ 3);
        //判断剩余位是否小于1001
        int c = x & 0xF;
        int res = c + ~0xA + 1;
        int t3 = !!(res >> 31);
        return t1 & t2 & t3;
}

当数值x在[0x30,0x39]范围内时返回1否则返回0。
由于只能使用基本运算符,所以从数的特点出发,上下限的二进制数是,0x30 = 110000和0x39 = 111001
根据上下限特点,分为三部分考虑。
1.首先要保证高26位全为0,!!x可以判断x是否为0
2.第五位第六位都为1,使用0x11模板判断即可
3.第四位保证在0000-1001之间,手动模拟补码减法查看符号位即可。

conditional

/* 
 * conditional - same as x ? y : z 
 *   Example: conditional(2,4,5) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 16
 *   Rating: 3
 */
int conditional(int x, int y, int z) {
        int mask = ((!!x) << 31) >> 31;
        return ((~mask) & z) | (mask & y);
}

实现三目运算符。当x = 0时返回z,否则返回y。
!!x用来判断x是否为0,当x为0时,mask = 0xFFFFFFFF,当x非0时,mask = 0x00000000。
这里要注意:! :代表逻辑取反,即:把非0的数值变为0,0变为1;
~ :表示按位取反,即在数值的二进制表示方式上,将0变为1,将1变为0;

isLessOrEqual

/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
		//获取符号位
		int sign_x = (x >> 31) & 1;
		int sign_x = (x >> 31) & 1;
		//如果x>0,y<0,返回0
		int t1 = !((!sign_x) & sign_y);
		//如果x<0,y>0,返回1
		int t2 = sign_x & (!sign_y);
		//如果x,y正负性相同,模拟补码减法。
		int t3 = ((x + (~y) + 1) >> 31) & 1;
		//如果两数相等返回1
		int t4 = !(x ^ y); 
        return t4 || (t1 && (t2 || t3));
}

判断x是否小于等于y。由于负数-正数存在溢出问题,因此首先判断符号位。
如果x<0,y>0,返回1
如果x>0,y<0,返回0
如果x,y正负性相同,模拟补码减法。
如果x,y相等,返回1

这里涉及一个多条件模拟。

logicalNeg

/* 
 * logicalNeg - implement the ! operator, using all of 
 *              the legal operators except !
 *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4 
 */
int logicalNeg(int x) {
        int neg = ~x + 1;
        int sign = (neg | x) >> 31;
        return sign + 1;
}

模拟逻辑取非操作,x=0时返回1,x≠0时返回0。
补码运算中不区分+0,-0,符号位都是0,非0数字取负后符号位为0或1。对于非0数字第二步操作可以得到0xFFFFFFFF,对于0可以得到0x0。最后一步+1可以得到对应的0x0,0x1。

howManyBits

/* howManyBits - return the minimum number of bits required to represent x in
 *             two's complement
 *  Examples: howManyBits(12) = 5
 *            howManyBits(298) = 10
 *            howManyBits(-5) = 4
 *            howManyBits(0)  = 1
 *            howManyBits(-1) = 1
 *            howManyBits(0x80000000) = 32
 *  Legal ops: ! ~ & ^ | + << >>
 *  Max ops: 90
 *  Rating: 4
 */
int howManyBits(int x) {
        //将负数化为整数
        //符号位
        int sign = x >> 31;
        //取正数
        x = (sign & (~x)) | ((~sign) & x);
        int bit_16, bit_8, bit_4, bit_2, bit_1, bit_0;
        //看高16位是否为0以确定低16位是否有效
        bit_16 = (!((!!(x >> 16)) ^ 0x1)) << 4;//如果高16位不为0.则低16位有效
        x >>= bit_16;
        bit_8 = (!((!!(x >> 8)) ^ 0x1)) << 3;
        x >>= bit_8;
        bit_4 = (!((!!(x >> 4)) ^ 0x1)) << 2;
        x >>= bit_4;
        bit_2 = (!((!!(x >> 2)) ^ 0x1)) << 1;
        x >>= bit_2;
        bit_1 = (!((!!(x >> 1)) ^ 0x1));
        x >>= bit_1;
        bit_0 = x;
        int res;
        res = bit_0 + bit_1 + bit_2 + bit_4 + bit_8 + bit_16 + 1;//+符号位
        return res;
}

本题返回x的二进制补码表示最少需要多少位。第一步将负数化成正数来处理。第二步采用二分思想逐步判断。在(!((!!(x >> 16)) ^ 0x1)) << 4; 中,!!(x >> 16)判断当前高16位是否为0,若为0则返回1,否则返回0。根据结果判断是否进行移位操作做进一步的判断。

floatScale2

//float
/* 
 * floatScale2 - Return bit-level equivalent of expression 2*f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representation of
 *   single-precision floating point values.
 *   When argument is NaN, return argument
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned floatScale2(unsigned uf) {
        //符号
        int S = (uf >> 31) & 0x1;
        //阶码
        int E = (uf >> 23) & 0xFF;
        //尾数
        int M = uf & 0x7FFFFF;
        //无穷大
        if(E == 0xFF)
                return uf;
        //0
        if(E == 0 && M == 0)
                return uf;
        //非规格数,修改尾数
        if(E == 0){
                M <<= 1;
                return (S << 31) | M;
        }
        //规格数,修改指数
        E++;
        return (S << 31) | (E << 23) | M;
}

根据 IEEE 754 浮点数格式返回2*uf。
第一步,分别获取符号,阶码,尾数。
第二步,对于无穷大和0直接返回。
第三步,对于非规格化数将尾数左移1位返回,规格化数将指数加1。

floatFlout2Int

/* 
 * floatFloat2Int - Return bit-level equivalent of expression (int) f
 *   for floating point argument f.
 *   Argument is passed as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point value.
 *   Anything out of range (including NaN and infinity) should return
 *   0x80000000u.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
int floatFloat2Int(unsigned uf) {
        //阶码
        int S = (uf >> 31) & 0x1;
        //阶码
        int E = (uf >> 23) & 0xFF;
        //尾数
        int M = uf & 0x7FFFFF;
        //0
        if(E == 0 && M == 0)
                return 0;
        //非规格化数字
        if(E == 0)
                return 0;
        //out of range (including NaN and infinity) 
        if(E == 0xFF)
      			return 1 << 31;
      	//规格化数字
        E -= 127;
        M = M | (1 << 23);
        //考虑表示范围
        //超出int表示范围
        if(E > 31){
                return 1 << 31;
        }else if(E < 0){
                return 0;
        }
        //考虑精度问题
        //大于23尾数都能保留下来
        if(E >= 23){
                M <<= (E - 23);
        }else{
                M >>= (23 - E);
        }
        if(S)
                return ~M + 1;
        return M;

根据IEEE 754 float类型转化为int类型。
第一步,分别获取符号位,阶码,尾数。
第二步,当阶码,尾数都为0时表示0,返回0;当阶码为0时表示非规格小数,返回0。
第三步,当阶码为0xFFFFFFFF时表示无穷大,返回0x80000000。
第四步,处理规格数字,32位偏置值是127,先计算阶码E-127,尾数小数点前隐含1,所以在尾数前补1。
第五步,当E > 31 时超过int的最大表示范围,E < 0时低于int的最小表示范围。
第六步,考虑精度问题,当E >=23时左移,E<23时右移。
第七步,处理符号位,符号位为1时返回负数补码。

floatPower2

/* 
 * floatPower2 - Return bit-level equivalent of the expression 2.0^x
 *   (2.0 raised to the power x) for any 32-bit integer x.
 *
 *   The unsigned value that is returned should have the identical bit
 *   representation as the single-precision floating-point number 2.0^x.
 *   If the result is too small to be represented as a denorm, return
 *   0. If too large, return +INF.
 * 
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while 
 *   Max ops: 30 
 *   Rating: 4
 */
unsigned floatPower2(int x) {
  int INF = 0xFF << 23; 
  int exp = x + 127; 
  if (exp <= 0) return 0;
  if (exp >= 255) return INF;
  return exp << 23;
}

计算2.0的x次方。
当x过大时,返回INF,IEEE 754的INF表示规则为阶码为0xFF。x+127=阶码,阶码的有效范围是1-254,当阶码为0时返回0,阶码为0xFFFFFFFF时返回INF。

实验结果:
在这里插入图片描述
通过阅读
前置知识
实验总结
更加熟悉整数和浮点数的位级表示形式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值