刚刚完成注册博客,想写一篇随笔,方便以后自己回顾。如果恰好也能帮助到你,是我的荣幸。

这次随笔是记载我的计算机系统(CS:APP,Computer Systems:A Programer's Perspective)课程的一次实验

为了实现这15个函数,参考了(抄袭了- -)网上很多大佬的解答,但是过程中也有了自己的一些体会。

下面分享一下自己的理解,每个函数的实现都附有相应解释,有个别自己还不是很理解就没有写解释,见谅啊。

注:实验环境 ubuntu 12.04

  每次修改bits.c时,都要make btest才能用btest测试函数的正确性

/*
* CS:APP Data Lab
*
*
* bits.c - Source file with your solutions to the Lab.
* This is the file you will hand in to your instructor.
*
* WARNING: Do not include the <stdio.h> header; it confuses the dlc
* compiler. You can still use printf for debugging without including
* <stdio.h>, although you might get a compiler warning. In general,
* it's not good practice to ignore compiler warnings, but in this
* case it's OK.
*/ #if 0
/*
* Instructions to Students:
*
* STEP 1: Read the following instructions carefully.
*/ You will provide your solution to the Data Lab by
editing the collection of functions in this source file. INTEGER CODING RULES: Replace the "return" statement in each function with one
or more lines of C code that implements the function. Your code
must conform to the following style: int Funct(arg1, arg2, ...) {
/* brief description of how your implementation works */
int var1 = Expr1;
...
int varM = ExprM; varJ = ExprJ;
...
varN = ExprN;
return ExprR;
} Each "Expr" is an expression using ONLY the following:
1. Integer constants 0 through 255 (0xFF), inclusive. You are
not allowed to use big constants such as 0xffffffff.
2. Function arguments and local variables (no global variables).
3. Unary integer operations ! ~
4. Binary integer operations & ^ | + << >> Some of the problems restrict the set of allowed operators even further.
Each "Expr" may consist of multiple operators. You are not restricted to
one operator per line. You are expressly forbidden to:
1. Use any control constructs such as if, do, while, for, switch, etc.
2. Define or use any macros.
3. Define any additional functions in this file.
4. Call any functions.
5. Use any other operations, such as &&, ||, -, or ?:
6. Use any form of casting.
7. Use any data type other than int. This implies that you
cannot use arrays, structs, or unions. You may assume that your machine:
1. Uses 2s complement, 32-bit representations of integers.
2. Performs right shifts arithmetically.
3. Has unpredictable behavior when shifting an integer by more
than the word size. EXAMPLES OF ACCEPTABLE CODING STYLE:
/*
* pow2plus1 - returns 2^x + 1, where 0 <= x <= 31
*/
int pow2plus1(int x) {
/* exploit ability of shifts to compute powers of 2 */
return (1 << x) + 1;
} /*
* pow2plus4 - returns 2^x + 4, where 0 <= x <= 31
*/
int pow2plus4(int x) {
/* exploit ability of shifts to compute powers of 2 */
int result = (1 << x);
result += 4;
return result;
} FLOATING POINT CODING RULES For the problems that require you to implent floating-point operations,
the coding rules are less strict. You are allowed to use looping and
conditional control. You are allowed to use both ints and unsigneds.
You can use arbitrary integer and unsigned constants. You are expressly forbidden to:
1. Define or use any macros.
2. Define any additional functions in this file.
3. Call any functions.
4. Use any form of casting.
5. Use any data type other than int or unsigned. This means that you
cannot use arrays, structs, or unions.
6. Use any floating point data types, operations, or constants. NOTES:
1. Use the dlc (data lab checker) compiler (described in the handout) to
check the legality of your solutions.
2. Each function has a maximum number of operators (! ~ & ^ | + << >>)
that you are allowed to use for your implementation of the function.
The max operator count is checked by dlc. Note that '=' is not
counted; you may use as many of these as you want without penalty.
3. Use the btest test harness to check your functions for correctness.
4. Use the BDD checker to formally verify your functions
5. The maximum number of ops for each function is given in the
header comment for each function. If there are any inconsistencies
between the maximum ops in the writeup and in this file, consider
this file the authoritative source. /*
* STEP 2: Modify the following functions according the coding rules.
*
* IMPORTANT. TO AVOID GRADING SURPRISES:
* 1. Use the dlc compiler to check that your solutions conform
* to the coding rules.
* 2. Use the BDD checker to formally verify that your solutions produce
* the correct answers.
*/ #endif
/*
* bitAnd - x&y using only ~ and |
* Example: bitAnd(6, 5) = 4
* Legal ops: ~ |
* Max ops: 8
* Rating: 1
*/
int bitAnd(int x, int y) {
return ~((~x) | (~y));
}
//利用德摩根律 /*
* getByte - Extract byte n from word x
* Bytes numbered from 0 (LSB) to 3 (MSB)
* Examples: getByte(0x12345678,1) = 0x56
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 6
* Rating: 2
*/
int getByte(int x, int n) {
return ((x >> (n << 3)) & 0xFF);
}
//将所要取的字节移到最右端然后其余位通过与运算置0 /*
* logicalShift - shift x to the right by n, using a logical shift
* Can assume that 0 <= n <= 31
* Examples: logicalShift(0x87654321,4) = 0x08765432
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int logicalShift(int x, int n) {
int tmp = 32 + (~n);
return (x >> n) & ((1 << tmp) + (~0) + (1 << tmp));
}
//运用机器的算术右移,然后高位置0和低位保持
//右移n位后原最高位到了第31-n位,31-n表示为31+((~n)+1) = 32+(~n)
//通过与高n位全为0,第32-n位全为1的数实现高位置0和低位保持
//这个数是(1 << ((32+(~n)+1)) - 1
//由于n可能为0,这样左移32位会根据gcc编译规则左移 32 % 32(类型位长) = 0位
//故将该数表示为(1 << (32+(~n)+1)) + (~0) + (1 << (32+(~n)+1)) /*
* bitCount - returns count of number of 1's in word
* Examples: bitCount(5) = 2, bitCount(7) = 3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 40
* Rating: 4
*/
int bitCount(int x) {
//造数
int _tmp1 = 0x55 | (0x55 << 8); //0x00005555
int _tmp2 = 0x33 | (0x33 << 8); //0x00003333
int _tmp3 = 0xf | (0xf <<8); //0x00000f0f
int tmp1 = _tmp1 | (_tmp1 << 16); //0x55555555
int tmp2 = _tmp2 | (_tmp2 << 16); //0x33333333
int tmp3 = _tmp3 | (_tmp3 << 16); //0x0f0f0f0f
int tmp4 = 0xff | (0xff << 16); //0x00ff00ff
int tmp5 = 0xff | (0xff << 8); //0x0000ffff
//求和
int res = 0;
res = (x & tmp1) + ((x >> 1) & tmp1);
res = (res & tmp2) + ((res >> 2) & tmp2);
res = (res & tmp3) + ((res >> 4) & tmp3);
res = (res & tmp4) + ((res >> 8) & tmp4);
res = (res & tmp5) + ((res >> 16) & tmp5);
//返回
return res;
}
//类似递归分治的思想,以统计二进制数x=10中1的个数为例
//方法是将高位移到低位和0x1相与,(x & 0x1) + ((x >> 1) & 0x1)
//造出5个数,0x55555555,0x33333333,0x0f0f0f0f,0x00ff00ff,0x0000ffff
//这五个数写成二进制,分别隔着1,2,4,8,16个0 /*
* bang - Compute !x without using !
* Examples: bang(3) = 0, bang(0) = 1
* Legal ops: ~ & ^ | + << >>
* Max ops: 12
* Rating: 4
*/
int bang(int x) {
return ((~((x | ((~x)+1)) >> 31)) & 0x1);
}
//将一个非零数的补码与其相反数的补码相或,最高位一定是1
//但如果对0进行此操作,最高位还是0 /*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return (0x1 << 31);
}
//最小负整数的二进制补码是1000...0000 /*
* fitsBits - return 1 if x can be represented as an
* n-bit, two's complement integer.
* 1 <= n <= 32
* Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int fitsBits(int x, int n) {
return !(((x >> (n+(~0))) + 1) >> 1);
}
//若n位能表示这个数
//正数的1只能出现在低n-1位,其余位全为0
//负数的0只能出现在低n-1位,其余位全为1
//故将该数右移n-1位后所得结果,正数全为0,负数全为1
//此时再+1后右移1位,可以得到全0
//若n位不能表示这个数,则一定不会有以上结论
//n-1表示为n+(-1),即n+(~0) /*
* divpwr2 - Compute x/(2^n), for 0 <= n <= 30
* Round toward zero
* Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 2
*/
int divpwr2(int x, int n) {
return ( x + (((x >> 31) & 0x1) << n) + (~0) + (!((x >> 31) & 0x1)) ) >> n;
}
//本题是对于标准除法/的实现,全正取下整,有负取上整
//而通过移位实现除以2的幂,都是取下整
//故对于负数要加一个偏移量(1 << n) - 1 (证明在深入理解计算机系统第9版P73)
//因为是负数才要加偏移量,所以式子中的1刚好可以用符号位((x >> 31) & 0x1)表示
//若x > 0,(((x >> 31) & 0x1) << n)的结果为0,会导致多减去了1即(~0)
//巧妙多加一个符号位的逻辑非结果即(!((x >> 31) & 0x1)),负数为0,整数为1,恰好弥补 /*
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x) {
return ((~x) + 1);
}
//对一个数的补码进行按位取反加1就能得到其相反数的补码 /*
* isPositive - return 1 if x > 0, return 0 otherwise
* Example: isPositive(-1) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 3
*/
int isPositive(int x) {
return !( ((x >> 31) & 0x1) | (!(x << 1)) );
}
//正数和零的符号位为0,负数为1
//左移1位后用!,正数的结果一定为0,负数的结果可0可1,零的结果一定是1
//将以上两个结果相或,正数的结果为0,负数一定为1,零的结果一定是1 /*
* 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 xSign = (x >> 31) & 0x1;
int ySign = (y >> 31) & 0x1;
int signDiff = xSign & (!ySign);
int signSame = !(((y + (~x+1)) >> 31) & 0x1) & !(xSign ^ ySign);
return signDiff | signSame;
}
//作差法判断大小
//首先要判断符号位,因为可能存在溢出
//正数符号位为0,负数符号位为1,列出x,y的真值表
//x y z
//0 0 符号相同要进行下一步作差
//0 1 0(表示x > y)
//1 0 1(表示x < y)
//1 1 符号相同要进行下一步作差
//可以看到若用一个表达式(xSign & !(ySign))可以实现只用第三种情况为1,就可以完成符号位的判断
//接下来还要看其他三种情况,通过与上!(xSign ^ ySign)保证两者同号,因为第二种不同号的情况在该表达式下结果为0,与0就置0
//前面取y-x的符号位,为0说明,y >= x,否则y < x,再取逻辑非配合与操作 /*
* ilog2 - return floor(log base 2 of x), where x > 0
* Example: ilog2(16) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int ilog2(int x) {
int res = 0;
res = res + ((!!(x>>(16 + res)))<<4);
res = res + ((!!(x>>(8 + res)))<<3);
res = res + ((!!(x>>(4 + res)))<<2);
res = res + ((!!(x>>(2 + res)))<<1);
res = res + ((!!(x>>(1 + res)))<<0);
return res;
} /*
* float_neg - Return bit-level equivalent of expression -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 representations of
* single-precision floating point values.
* When argument is NaN, return argument.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 10
* Rating: 2
*/
unsigned float_neg(unsigned uf) {
unsigned exp = (uf >> 23) & 0xFF;
unsigned frac = uf & 0x7FFFFF;
unsigned res = uf ^ 0x80000000;
if(exp == 0xFF && frac) {
res = uf;
}
return res;
}
//取exp和frac判断是否为NaN
//异或改变符号位 /*
* float_i2f - Return bit-level equivalent of expression (float) x
* Result is returned as unsigned int, but
* it is to be interpreted as the bit-level representation of a
* single-precision floating point values.
* Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
* Max ops: 30
* Rating: 4
*/
unsigned float_i2f(int x) {
unsigned ans;
int xSignx = x & (1 << 31);
int res = 31;
int ss = 0;
int ff = 0;
int tmp;
if(x == 0) ans = 0;
else{
if(xSignx) x = (~x) + 1;
while(!((1 << res) & x)) {
res--;
}
x = x ^ (1 << res);
if(res < 23) x = x << (23 - res);
else {
tmp = res - 24;
if(tmp >= 0) ss = (x >> tmp) & 1,ff = ((1 << tmp) - 1) & x;
x = (x >> (res-23));
}
x = x | ((res+127) << 23);
if(ff == 0) {
ss = (ss & x);
}
x = x + ss;
x = x | xSignx;
ans = x;
}
return ans;
}
/*
* float_twice - 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 float_twice(unsigned uf) {
unsigned tmp = uf;
unsigned exp = (tmp >> 23) & 0xFF;
unsigned frac = tmp & 0x007fffff;
if(exp == 0x0) { //非规格化数
tmp = (tmp & 0x80000000) | (frac << 1);
}
else if(exp != 0xFF) { //规格化数
tmp += (1 << 23);
if(((tmp >> 23) & 0xFF) == 0xFF) {
tmp = tmp >> 23 << 23;
}
}
return tmp;
}

如果读者看完后有自己独到的实现方式,欢迎一起交流学习。

CS:APP配套实验 Data Lab的更多相关文章

  1. 深入理解计算机系统 (CS:APP) - 高速缓存实验 Cache Lab 解析

    原文地址:https://billc.io/2019/05/csapp-cachelab/ 这个实验是这学期的第四个实验.作为缓存这一章的配套实验,设计得非常精妙.难度上来讲,相比之前的修改现成文件, ...

  2. 深入理解计算机系统 (CS:APP) Lab2 - Bomb Lab 解析

    原文地址:https://billc.io/2019/04/csapp-bomblab/ 写在前面 CS:APP是这学期的一门硬核课程,应该是目前接触到最底层的课程了.学校的教学也是尝试着尽量和CMU ...

  3. 《深入理解计算机系统》实验一 —Data Lab

    本文是CSAPP第二章的配套实验,通过使用有限的运算符来实现正数,负数,浮点数的位级表示.通过完成这13个函数,可以使我们更好的理解计算机中数据的编码方式. 准备工作   首先去官网Lab Assig ...

  4. 图文并茂-超详解 CS:APP: Lab3-Attack(附带栈帧分析)

    CS:APP:Lab3-ATTACK 0. 环境要求 关于环境已经在lab1里配置过了.lab1的连接如下 实验的下载地址如下 说明文档如下 http://csapp.cs.cmu.edu/3e/at ...

  5. 【翻译】【中英对照】【企业库6】动手实验 Hands-On Lab 日志应用程序块索引页

    Logging Application Block Hands-On Lab for Enterprise Library 企业库的日志应用程序块动手实验 This walkthrough shoul ...

  6. [mjpeg @ ...] unable to decode APP fields: Invalid data found when processing input

    通过FFmpeg打开自己笔记本摄像头(HP Wide Vision HD Camera)操作时遇到如下错误: [mjpeg @ 0000029be7cbd000] unable to decode A ...

  7. ArcGIS10从入门到精通系列实验图文教程(附配套实验数据持续更新)

    @ 目录 1. 专栏简介 2. 专栏地址 3. 专栏目录 1. 专栏简介 本教程<ArcGIS从入门到精通系列实验教程>内容包括:ArcGIS平台简介.ArcGIS应用基础.空间数据的采集 ...

  8. 深入理解计算机系统 (CS:APP) 缓冲区漏洞实验 – Buffer Lab 解析

    原文地址:https://billc.io/2019/05/csapp-cachelab/ 写在前面 这是 CSAPP 官网上的第 4 个实验 buflab,也是学校要求的第三个实验.这个实验比上一个 ...

  9. 《CS:APP》二进制炸弹实验(phase_1-3)

    <深入理解计算机系统>第三章的bomb lab,拆弹实验:给出一个linux的可执行文件bomb,执行后文件要求分别进行6次输入,每一次输入错误都会导致炸弹爆炸,程序终止.需要通过反汇编来 ...

随机推荐

  1. EventLoop-浏览器篇2

    最近又碰到了event loop问题,之前研究的实在是浅显(https://www.cnblogs.com/zx0423/p/12641637.html)所以今天主要讲述promise的链式调用,as ...

  2. CF208E Blood Cousins 题解

    一个奇奇怪怪的复杂度很垃圾的线段树合并解法 通过分析可以发现,要找$x$的$k$辈兄弟,只需要找到$x$的$k$辈祖先,然后查找以该祖先为根的子树中和$x$深度相同的节点个数$-1$即可.也就是说,询 ...

  3. 前端Web APIs 二

    day04 - Web APIs 学习目标: 能够说出常用的3-5个键盘事件 能够知道如何获取当前键盘按下的是哪个键 能够知道浏览器的顶级对象window 能够使用window.onload事件 能够 ...

  4. 网站seo整站优化有什么优势

    http://www.wocaoseo.com/thread-314-1-1.html       现在很多企业找网络公司做网站优化,已经不再像以前那样做目标关键词,而是通过整站优化来达到企业营销目的 ...

  5. 注册github时总卡在第一步无法验证的解决办法

    从github官网可以看出问题所在,所以造成这一问题的极大可能就是浏览器的问题. 最简单的方法就是换手机浏览器进行注册

  6. 基于Rust-vmm实现Kubernetes运行时

    随着容器及K8s的广泛使用,越来越多的容器安全与隔离问题被暴露出来,如:容器逃逸.水平攻击.DDos攻击等严重威胁了办公和生产环境的安全与稳定,影响了业务的正常运行.安全容器技术孕育而生,产生了kat ...

  7. composer版本号前面`^`和`~`的区别

    ~1.2.3表示: 1.2.3 <= 版本号 < 1.3.0 ^1.2.3表示: 1.2.3 <= 版本号 < 2.0.0 ~1.2 表示: 1.2.0 <= 版本号 & ...

  8. 5000字 | 24张图带你彻底理解Java中的21种锁

    本篇主要内容如下: 本篇文章已收纳到我的Java在线文档. Github 我的SpringCloud实战项目持续更新中 帮你总结好的锁: 序号 锁名称 应用 1 乐观锁 CAS 2 悲观锁 synch ...

  9. 尝试MatCap类型shader

    听说MatCap能在低端机上做出很漂亮的pbr效果,就尝试了一下. MatCap全称MaterailCapture,里面存的是光照信息,通过法线的xy分量去采样matcap,得到在该方向法线的光照信息 ...

  10. Volatile关键字&&DCL单例模式,volatile 和 synchronized 的区别

    Volatile 英文翻译:易变的.可变的.不稳定的. 一.volatile 定义及用法 多个线程的工作内存彼此独立,互不可见,线程启动的时候,虚拟机为每个内存分配一块工作内存,不仅包含了线程内部定义 ...