第二章家庭作业

选题:2.69

分值:三分

作业过程:

以下是rotate_right函数的代码:

unsigned rotate_right(unsigned x, int n)
{int endbit;int i;if(n==0)return x;else{for(i=0;i<n;i++){endbit = x & 0x1;endbit = endbit << (8*sizeof(unsigned)-1);x = x >> 1;x = x | endbit;}}return x;
}

这里用到的原理是,区分n的情况,如果是0则直接返回原值,如果不是0,就按照移位的次数控制循环,每次循环只移位1位。

具体循环的实现,是借助了一个变量为endbit,最后一位,用来保留右移一位后损失掉的那位,再通过移位使这位变成最高位,最后与x移位后的数据进行或运算,这样就完成了循环右移一次的功能;共需循环右移几次,就重复几次这个循环。

完成的代码如下:

#include <stdio.h>unsigned rotate_right(unsigned x, int n);int main()
{int n = 0;unsigned x;int w = sizeof(unsigned)*8;int flag = 0;unsigned result;while(!flag){printf("please input how many bits you want to rotate_right shift:\n");scanf("%d",&n);if (n < 0 || n >= w){printf("Wrong! Please input again!\n");}elseflag = 1;}printf("please input your data:\n0x");scanf("%x",&x);result = rotate_right(x,n);printf("the result is:0x%x\n",result);return 0;
}unsigned rotate_right(unsigned x, int n)
{int endbit;int i;if(n==0)return x;else{for(i=0;i<n;i++){endbit = x & 0x1;endbit = endbit << (8*sizeof(unsigned)-1);x = x >> 1;x = x | endbit;}}return x;
}

实验运行结果如下:

实验中遇到的问题:

这个函数原型的构造并不难,找到思路后困扰我一时的只是是用或还是与,这个很容易就能够解决,更大的问题在我的主函数中输入无论如何都得不到正确的结果,后来发现是因为我的输入是0x12345678,我以为这个可以直接转换为16进制但是不可以,输出也是十进制,所以这导致了我的结果错误百出,后来我通过百度发现了%x的方法,输入输出格式改为这个之后就可以方便的输入输出16进制,并且在输入之前加了提示语0x,就可以得出正确的结果了。

这道题本身难度不算大,我主要还是栽在了自己的粗心上,没有注意输入输出格式,只想当然的去做,吸取了这次教训,以后的作业就不会有那么多冤枉路了。

代码的优化

从每次右移一位,按循环次数控制右移位数,能不能扩展成一步到位移动n位呢?我把代码变成了以下样子:

unsigned rotate_right(unsigned x, int n)
{int endbit;int i;if(n==0)return x;else{endbit = x << (8*sizeof(unsigned)-n);x = x >> n;x = x | endbit;}return x;
}

这样就可以直接移动n位了。

这里还有一个小插曲,关于开始的左移位数是要-n还是-什么,是右移了n位,上面的左移就要减n。

然后我又想,n=0的情况能不能并进去?代码就变成了这样子:

unsigned rotate_right(unsigned x, int n)
{int endbit;endbit = x << (8*sizeof(unsigned)-n);x = x >> n;x = x | endbit;return x;
}

验证是可以的。

endbit作为一个中间值,是不是有点多余?去掉之后变成:

unsigned rotate_right(unsigned x, int n)
{x = (x >> n) | x << (8*sizeof(unsigned)-n);return x;
}

也是可以的,更简洁了。

那么可以干脆直接用return返回:

unsigned rotate_right(unsigned x, int n)
{return (x >> n) | x << (8*sizeof(unsigned)-n);
}

这个一步步简化代码的过程让我做完了之后十分满意,最开始的想法很简单,但是代码实现却很复杂,通过一步步的简化最终使代码变的简洁好看,成就感很大。但是对于我现在的水平,如果直接给我这样的一个代码,阅读起来还是有些费劲的,需要多加练习。

第三章家庭作业

选题:3.63

分值:两分

作业过程:

原来的函数:

int sum_col(int n,int A[E1(n)][E2(n)],int j)
{int i;int result = 0;for(i=0;i<E1(n);i++)result += A[i][j];return result;
}

转化为goto代码的版本:

int sum_col(int n,int A[E1(n)][E2(n)],int j)
{int i=0;int result = 0;if(!(i<E1(n)))goto done;
loop:result += A[i][j];i++;if(i<E1(n))goto loop;
done:return result;
}

在书中给的汇编代码中,逐句分析如下:

    movl    8(%ebp),%edx       ;把ebp+8中的值赋给edx,也就是nleal    (%edx,%edx),%eax   ;eax中的值等于两倍的edx中的值,即2nleal    -1(%eax),%ecx      ;ecx中的值等于eax中的值-1,即2n-1leal    (%eax,%edx),%esi   ;esi中的值等于eax的值加edx的值,即3n,esi存储的是E1(n)的值movl    $0,%eax        ;eax置零,eax存储的是result的值testl   %esi,%esi      ;检查esi中的值是正、负还是0jle     .L3    ;因为初始化i是0,如果esi中的E1(n)≤0的话,就满足!(i<E1(n))跳转到doneleal    0(,%ecx,4),%ebx    ;ebx中的值等于0+4*ecx=4(2n-1)movl    16(%ebp),%eax      ;eax中的值等于ebp+16,即j的地址movl    12(%ebp),%edx      ;edx中的值等于ebp+12,即A[i]的地址leal    (%edx,%eax,4),%ecx ;ecx中的值等于[edx+4*eax]中的值,即A[i][j]movl    $0,%edx        ;edx中的值置零movl    $0,%eax        ;eax中的值置零
.L4                ;相当于loopaddl    (%ecx),%eax    ;eax中的值+=ecx中的地址,即A[i][j]的地址addl    $1,%edx        ;edx中的值加一,可以看出edx存放的是iaddl    %ebx,%ecx      ;ecx中的值加上ebx中的值放到ecx中,即ecx内值为A[i+1][j]cmpl    %esi,%edx      ;比较esi与edx中的值,即比较E1(n)和i的值jl      .L4    ;如果i<E1(n),跳转回.L4,相当于回到loop中的循环
.L3                ;相当于done,结束

所以,由上面的逐句分析可得,esi中存储的是E1(n)的值,E1(n)=3n;
E2(n)储存在ebx中,ebx=4*E2(n),所以E2(n)=2n-1.

总结

这道题锻炼了我对汇编语言的分析过程,知道每一句对应的动作,不同指令的用法,寄存器中的数值的变化等等;同时还练习了for循环是如何在汇编中被实现的,这道题如果直接对着原函数分析不好分析,但是转变为goto形式的代码后就比较直接、一目了然

第四章家庭作业

选题:4.47、4.48两题

分值:两题各一分

作业过程:

4.47题:

leave指令等价于如下代码序列:

rrmovl  %ebp,%esp
popl    %ebp

也就是说它要执行的动作是,将帧指针ebp的内容赋给栈指针esp,然后弹出ebp,栈指针+4,结果是消灭这个栈。

参照pop指令的格式,可以得出如下的过程:

取指阶段   icode:ifun<--M1[PC] = D:0valP <= PC + 1  ;下一条指令地址译码阶段   valB <= R[%ebp]   ;得到ebp的值,这个值就是新的栈指针esp的值执行阶段   valE <= valB + 4   ;栈指针的值+4访存阶段   valM <= M4[valB]   ;读ebp中的值写回阶段   R[%esp] <= valE   ;把更新后的指针赋值给espR[%ebp] <= valM   ;弹出的ebp的值

4.48题

iaddl的指令是集合了irmovl指令和addl指令,先用irmovl指令将一个常数加到寄存器,再用addl把这个值加入目的寄存器。

由题中的图,参考irmovl和addl指令的过程,可以得到如下过程:

取指阶段   icode:ifun = M1[PC] = C:0rA:rB <= M1[PC+1]   ;取出操作数指示符valC <= M4[PC+2]   ;取出一个四字节常数字,即想要加进去的那个常数valP <= PC + 6   ;下一条指令地址译码阶段   valB <= R[rB]   ;读入想要存到的那个寄存器执行阶段   valE <= valB + valC   ;得到目的寄存器中的值和常数值的和SetCC访存阶段  写回阶段   R[rB] <= valE   ;把结果写回到目的寄存器中。

感想

这次的作业难度比较低,主要是复习了对顺序实现的几个步骤里都做了些什么,每一步都代表着什么意义,练习熟练后可以做到举一反三。

第六章家庭作业

分值分配

6.28:20135202(1.5) 20135220(0.5)

6.37:20135202(1) 20135220(3)

6.38:20135202(3) 20135220(1)

6.28 分值1分

(1)所有会在组6中命中的十六进制存储器地址:

由习题6.13的表可知,如要命中组六,需要标记位为91,组为6,也就是说八个CT位的值分别为1001 0001,三个CI的值为110,剩下两位是任意的,取值范围为00,01,10,11,所以所有的情况只有四种:

1 0010 0011 1000 = 0x1238

1 0010 0011 1001 = 0x1239

1 0010 0011 1010 = 0x123A

1 0010 0011 1011 = 0x123B

(2)命中组1的:同上题相同,八个CT值分别为0100 0101,三个CI值分别为001,有四种情况:

0 1000 1010 0100 = 0x08A4

0 1000 1010 0101 = 0x08A5

0 1000 1010 0110 = 0x08A6

0 1000 1010 0111 = 0x08A7

6.37 分值2分

题目

C程序:

int x[2][256];
int i;
int sum=0;for (i=0;i<256;i++){sum += x[0][i] * x[1][i];
}
  • sizeof(int) == 4

  • 数组X从存储器地址0x0开始,按照行优先顺序存储。

  • 每种情况中,高速缓存最开始时都是空的。

  • 唯一的存储器访问是对数组x的条目进行访问,其他所有变量都存储在寄存器中。

A、假设高速缓存是1024字节,直接映射,高速缓存块大小为32字节,不命中率是多少?

直接映射是每组只有一个高速缓存行,块大小为32字节,表示可以存储8个int数值。
数组是按照行优先存储的,计算数组一行的大小为256*4=1024,所以高速缓存只够存数组的一行。
所以x[0]和x[1]的每一个元素(x[0][i]和x[1][i])对应的高速缓存是同一个块。
因此,每次请求都在加载,驱逐,替换。不命中率为100%。

B、高速缓存改为2048字节,不命中率是多少?

缓存足够大,可以存储整个数组
因此只有冷不命中,而块大小为32字节,表示可以存储8个int数值
所以每次都会加载x[0][i]~x[0][i+7]共8个数值到缓存组中,这里就只有x[0][i]是不命中的
所以不命中率为1/8 = 12.5%

C、高速缓存是1024字节,两路组相联,使用LRU替换策略,高速缓存块大小为32字节,不命中率是多少?

两路组相联表示每组有两个高速缓存行,而每行可以存储8个数值
高速缓存只有1024字节,不够存储数组
发生不命中的时候,一个是冷不命中,另一个是缓存中没有,需要加载进去
这时使用的是LRU替换策略,替换最近最少用的,替换的那一行的8个数值已经都用过了,再也不会用到了
所以最后还是相当于只有冷不命中,相当于每8个数据中只有一个是不命中的
所以不命中率为1/8 = 12.5%

D、C中,更大的高速缓存大小会帮助降低不命中率吗?

不会,因为块大小不变时,冷不命中的概率不可能被减小。

E、C中,更大的块大小会帮助降低不命中率吗?

会降低,因为一个块的大小增加,冷不命中的频率就降低。

6.38 分值2分

解:

由题意可知,C=4KB=4096 Bytes,而C = S x E x B,在直接映射高速缓存中E = 1,块大小B=16 Bytes,可得S = 256,一共有256个高速缓存组。

(1)N = 64时:

数组大小为2x64x4=512字节,缓存容量足够大,不用考虑容量不命中。
因为每块是16字节,数组中每个单元为4字节,所以四个一组,一共需要16组,每一组中的行都是满的

sumA步长为1,遵循了行优先顺序,这个里面只有冷不命中,就是四个中有一个不命中,不命中率为0.25

sumB是列优先,步长为N,每一次都会与上一次的映射到同一个块,导致每次都会冲突,所以不命中率为1

sumC中除了四个中有一个冷不命中外,还因为列扫描到i+1时的冲突不命中(每次都会映射到同一组同一块),所以不命中率为0.5

(2)N = 60时:

数组大小为2x60x4=480字节,缓存容量足够大,不用考虑容量不命中。
因为每块是16字节,数组中每个单元为4字节,所以四个一组,一共需要16组,但行中不是满的

sumA同上,只有冷不命中,不命中率为0.25

sumB消除了冲突不命中,不会每次都映射到同一组同一块,所以只有冷不命中,不命中率为0.25

sumC理由同上,只有冷不命中,不命中率为0.25

第十章作业

题目:10.8

编写图10-10中的statcheck程序的一个版本,叫fstatcheck,它从命令行上取得一个描述符数字而不是文件名。

分值:2分

解题过程:

图10-10代码如下:

#include "csapp.h"int main (int argc, char **argv)
{struct stat stat;char *type, *readok;if (argc != 2) {fprintf(stderr, "usage: %s <filename>\n", argv[0]);exit(0);}Stat(argv[1], &stat);//这句是从命令行中读取一个文件名if (S_ISREG(stat.st_mode)) type = "regular";else if (S_ISDIR(stat.st_mode))type = "directory";else type = "other";if ((stat.st_mode & S_IRUSR)) /* Check read access */readok = "yes";elsereadok = "no";printf("type: %s, read: %s\n", type, readok);exit(0);
}

题目要求是从命令行读取的内容从文件名改为描述符数字。那就先找到这个取得文件名的代码,是

Stat(argv[1], &stat);

这一句中argv就是用来去输入的信息的,取出放到stat中。所以只需要更改这一句即可,需要的是一个将字符串转换为整型数的函数,经过查询百度后找到了atoi函数,所以这句话修改为:

fstat(atoi(argv[1]), &stat);

即可。

转载于:https://www.cnblogs.com/20135202yjx/p/4970513.html

20135202闫佳歆——家庭作业汇总相关推荐

  1. 20135202闫佳歆--week 9 期中总结

    期中总结 前半学期的主要学习内容是学习mooc课程<Linux内核分析>以及课本<Linux内核设计与实现>. 所涉及知识点总结如下: 1. Linux内核启动的过程--以Me ...

  2. 20135202闫佳歆-第二章家庭作业-2.69

    第二章家庭作业 选题:2.69 分值:三分 作业过程: 以下是rotate_right函数的代码: unsigned rotate_right(unsigned x, int n) {int endb ...

  3. 20135202闫佳歆--week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程--实验及总结...

    week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程 1.环境搭建: rm menu -rf git clone https://github.com/megnning/menu.gi ...

  4. 20135206于佳心【家庭作业汇总】

    如果不扣分的话,总分:13分,因为最高只能得10分所以是10分 选题:3.63 分值:两分 作业过程: int sum_col(int n,int A[E1(n)][E2(n)],int j) {in ...

  5. 20135310陈巧然家庭作业汇总[3.56 3.67 6.23 6.39.6.40 6.41]

    小组成员:20135305姚歌 20135310陈巧然 选题及解答:http://www.cnblogs.com/20135305yg/p/4986724.html 转载于:https://www.c ...

  6. 信息安全系统设计基础家庭作业

    <深入理解计算机系统>家庭作业 * 8.9 答案: 进程对 是否并发 AB 否 AC 是 AD 是 BC 是 BD 是 CD 是 * 8.10 答案: A. 调用一次,返回两次: fork ...

  7. 一次家庭作业意外搞定40年前的数学猜想,牛津小哥:我只研究了几个礼拜

    晓查 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 只是完成一次普通家庭作业,就把困扰了数学家们几十年的猜想搞出了新花样?! 没错,这是来自牛津大学的Thomas Bloom的亲身经历. 在一 ...

  8. 现任明教教主CCNA Security作业汇总

    现任明教教主CCNA Security第二天作业 我最近花了两个月的时间,为我的所有课程(CCNA Security+CCSP)制作了每一天的配套作 业,并且做了相应的视频讲解.本周我会每天共享一天我 ...

  9. 很多家长学历不高,无法辅导孩子的家庭作业怎么办?

    很多家长学历不高,无法辅导孩子的家庭作业.这种现象过去比较普遍,现在随着国家整体教育水平的提高,家长的学历越来越高,尤其在城市里.这样,家长就具备了知识储备,一些可以胜任对孩子的辅导,他们可以辅导孩子 ...

  10. 【CSAPP】家庭作业2.77~2.97

    文章目录 2.77** 2.78** 2.79** 2.80*** 2.81** 2.82* 2.83** 2.84* 2.85* 2.86* 2.87* 2.88** 2.89* 2.90* 2.9 ...

最新文章

  1. Yii 错误页面处理
  2. 【转】css行高line-height的一些深入理解及应用
  3. 8.3. 测试 opensips
  4. 【报告分享】2020年数字政府新基建发展白皮书.pdf(附下载链接)
  5. c/c++教程 - 2.4.3 this指针作用,链式编程思想,空指针访问成员函数,const修饰成员函数,常函数,常对象
  6. win32项目中使用 skia渲染的一个编译问题
  7. 只因一段代码全公司200多人被捕,爬虫敲响警钟!
  8. 开源集锦(五)开源框架和快速开发工具类
  9. 服务器上面显示横杠,系统开机左上角显示一横杠一直闪没法系统
  10. sid图像数据_遥感影像数据
  11. uniapp 真机调试 click点击事件无效
  12. 苹果iPhone XS Max 贴膜之后面容无法使用
  13. 二叉查找树的创建及遍历
  14. rhino 调用 java_rhino-java中调用javascript
  15. JavaSript正则表达式收藏
  16. 微信开发 url传参数 json 导致 ios 微信分享失败苹果手机sinature签名无效
  17. shell教程(二) 四种工作模式
  18. oracle erp转行,【Oracle ERP实施顾问怎么样】TCT2021年Oracle ERP实施顾问前景怎么样-看准网...
  19. 【Vue学习笔记_03】v-bind动态绑定属性
  20. MBD开发流程指导书---->建模(一)

热门文章

  1. 华为网络工程师认证有了解的吗?
  2. http://www.boobooke.com/bbs/thread-51022-1-1.html
  3. SQLite数据库安装(windows)
  4. U盘引导启动LINUX
  5. Word 电子签名简单制作方法
  6. iTween使用小坑
  7. Unity学习笔记–无限地图
  8. 天正电气lisp是什么文件_电气CAD绘图基础幻灯片
  9. 办公软件是计算机吗,什么是办公软件_IT /计算机_资料
  10. 基于SNN脉冲神经网络的Hebbian学习训练过程matlab仿真