[CSAPP_lab1] 环境配置与函数实现记录

文章描述了一个名为DATALAB的实验,学生需要用受限的C语言子集实现一系列位操作函数,如位异或、求两s补数最小值、判断最大值等。实验目标是理解C数据类型的位级表示和操作。提供的代码示例展示了如何使用位运算符来实现这些功能。
摘要由CSDN通过智能技术生成

DATA LAB

目录

DATA LAB

注意事项

函数实现

1. bitXOR 

2. tmin

3. isTmax

4. allOddBits 

5. negate

 6. isAsciiDigit

7.conditional

 8. isLessOrEqual

9. logicalNeg

10. howManyBits


注意事项

1.环境配置

在终端命令窗口输入以下三行指令。

> sudo apt-get install build-essential
> sudo apt-get install gcc-multilib
> sudo apt-get install gdb

2.实验说明

       Students implement simple logical, two’s complement, and floating point functions, but using a highly restricted subset of C. For example, they might be asked to compute the absolute value of a number using only bit-level operations and straightline code. This lab helps students understand the bit-level representations of C data types and the bit-level behavior of the operations on data.

3.实验目的

修改bits.c的副本,使其通过btest中的所有测试,而不违反任何编码准则。

4. 实验文件

makefile -生成btest、fshow和show
readme -说明文件
bits.c -你将修改并提交的文件(函数实现的文件)
bits.h -头文件
btest.c -主要的btest程序
btest.h -用于构建btest
decl.c -用于构建btest
tests.c - 用于构建btest
test-header.c - 用于构建btest
dlc* -规则检查编译器二进制(数据实验室编译器)
driver .pl* -使用btest和dlc自动升级位的驱动程序
Driverhdrs.pm -可选的“击败教授”比赛的头文件
fshow.c -用于检查浮点表示的工具
ishow.c -用于检查整数表示的实用程序

附:

  1. 按位右移>> :
    对有符号数都是算数右移(最高位是0补0,最高位是1补1)
    对无符号数都是逻辑右移(最高位补0)
  2. 提取符号的方法:x&1 (格式化该数,得到其符号)

函数实现

1. bitXOR 

/* 
 * bitXor - x^y using only ~ and & 
 *   Example: bitXor(4, 5) = 1
 *   Legal ops: ~ &
 *   Max ops: 14
 *   Rating: 1
 */

用~和&计算x^y

int bitXor(int x, int y) {
   return ~(~(x & ~y) & ~(~x & y));
}
2. tmin

/* 
 * tmin - return minimum two's complement integer 
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */

int tmin(void) {

	return 0x1 << 31;
  // the minimum = 1000...0

}

  int 占4字节32位,求最小值则是得到(0x8000,0000),将0x1左移,右边补零则可以得到。

3. isTmax

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

如果是最大值(0x7fffffff)则返回1,否则都返回0。

int isTmax(int x) {
  // the max 0111...111 
	int i = x + 1; // or int i = ~x
	x = x + i;
    x = ~x; // x = 0
    // if x = max ; i = 10..0; !i = 0
    // if x = oxff..ff; i = 0x0 ; !i = 1
	i = !i;
	x = x + i;
	return !x;
  
}
4. allOddBits 

/* 
 * 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
 */

 判断奇数位是否为1 ,从第0位一直到第31位。

int allOddBits(int x) {
  // oxAA..AA
	int a = 0xAA;
	int i = a + (a << 8);
	i = i + (i << 16);
  // a^a = 0
  // x&i = prevents even bits fron being 1
	return !((x&i) ^ i);
}

   首先构造i=0xAAAAAAAA,然后通过&保留下x的奇数位,再与i异或,如果完全一致则值应为0,最后!(0)得到1。

5. negate

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

int negate(int x) {
	return ~x + 1;
}
 6. isAsciiDigit

/* 
 * 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
 */

判断输入的数字在不在0x30~0x39之间,如果在,返回1,否则返回1.

int isAsciiDigit(int x) {
  // -x = ~x +1 
  // 0x30 =< x =< 0x39
  // x - 0x30>= 0; 0x39 - x>= 0
	int a = x + (~(0x30) + 1);
	int b = 0x39 + (~(x)+1);
	int c = a >> 31; // >=0 c=0, <0 c=-1
	int d = b >> 31;
	return (!c)&(!d);
}
7.conditional

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

实现三目运算符,如果x不为0,输出y;否则输出z

int conditional(int x, int y, int z) {
	x = !!x;
	x = ~x + 1;
	return (x&y) | (~x&z);
}

  只有在x=0x0时,!(x) = 1 ,!!(x)=0。

但是我提交了却出现错误,不是很懂,逻辑上应该没有问题得。

 8. isLessOrEqual

/* 
 * isLessOrEqual - if x <= y  then return 1, else return 0 
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */

判断x是否<=y,如果是的,就返回1,否则返回0;

int isLessOrEqual(int x, int y) {
	int negX = ~x + 1;          //-x
	int a = y + negX;	 //y-x
	int yx = a >> 31 & 1;    //y-x的符号
	int x1 = x >> 31 & 1;	  //x的符号
	int y1 = y >> 31 & 1;	  //y的符号
	int Sign = x1 ^ y1;	//判断x,y的符号是否相同,如果相同,返回0,否则返回1
	return (!Sign & !yx) | (Sign&x1);   
}

 这题要注意得不能之间按上面是否存在0x30与0x39之间得解法计算,因为两者之间得数存在上下界,而这里只有一边有边界,可能发生溢出。

将这里得x小于等于y分成两种情况:

1.) 两者符号相同,并且y-x>=0的符号为正

2.)两者的符号不同,并且x的符号为负,这样y一定大于x

最后用 | 输出结果。

9. 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 
 */

如果是0的话返回0,否则返回1。就是实现!的功能

int logicalNeg(int x) {
	int y = (x | (~x + 1)) >> 31;
    // x!=0 y=-1; x=0,y=0
    return y+1;
}

只有当x=0时,(x|(~x+1))的符号为0,其余均为1。然后经过算术右移,y=0或者-1。

当x=0 -> y = 0 -> return y+1(1)

当x!=0 -> y = -1 -> return y+1(0)

10. 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
 */

(12) = 01100 ; (298) = 256+32+8+2 = 0100001010 

求表示的最小位数,不过不是很懂这个-1用一位表示。

int howManyBits(int x) {
	int b16, b8, b4, b2, b1, b0;
	int sign = x >> 31;
	x = (sign&~x) | (~sign&x);//如果x为正则不变,否则按位取反(这样好找最高位为1的,原来是最高位为0的,这样也将符号位去掉了)


  // 不断缩小范围
	b16 = !!(x >> 16) << 4;//高十六位是否有1
	x = x >> b16;//如果有(至少需要16位),则将原数右移16位
	b8 = !!(x >> 8) << 3;//剩余位高8位是否有1
	x = x >> b8;//如果有(至少需要16+8=24位),则右移8位
	b4 = !!(x >> 4) << 2;//同理
	x = x >> b4;
	b2 = !!(x >> 2) << 1;
	x = x >> b2;
	b1 = !!(x >> 1);
	x = x >> b1;
	b0 = x;
	return b16 + b8 + b4 + b2 + b1 + b0 + 1;//+1表示加上符号位
}

   首先要将判断符号,如果是负数,要按位取反。因为对于正数来说,最小位数是寻找从左往右的第一个1,在前面加上一个符号位0,就是最小位数。而负数如-5,补码的表示可以为10011也可以为110011或者1110011,所以对于负数,最小位数是找到从左往右的第一个0,然后加上一个符号位。为了和正数统一寻找方式,将负数按位取反,这样就和正数一样,最小位数是寻找从左往右的第一个1,在前面加上一个符号位0。

  用一个最大值(0x7fffffff)来解释最少需要多少位数的过程。

 之后再补充浮点数的实验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值