前天讲到要刚CSAPP,这一刚就是两天半.CSAPP果然够爽,自带完整的说明文档,评判程序,辅助程序.样例直接百万组走起,管饱!

datalab讲的是整数和浮点数怎么用二进制表示的,考验的是用基本只用位运算来实现一些看似稀松平常的操作.实际体会就是看题五秒钟,脱发两小时.当然做出来的成就感也是爆棚的.

求异或

根据离散数学等值演算写出公式

  1. //1
  2. /*
  3. * bitXor - x^y using only ~ and &
  4. * Example: bitXor(4, 5) = 1
  5. * Legal ops: ~ &
  6. * Max ops: 14
  7. * Rating: 1
  8. */
  9. int bitXor(int x, int y) {
  10. return ~(~x&~y)&~(x&y);
  11. }

求补码可表示的最小数

有且仅有最高位为1的数就是了

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

求补码可表示的最大数

这题开始需要一个技巧:!!x可以把非零数变成1,把0变成0

tmax=0x7FFFFFFF

tmax+1=0x10000000

(tmax+1)+(tmax+1)=0x00000000

C语言形式写作: x=tmin()-1

变形得 x+1=tmin()

a ^ b仅在每一位都相同时为假,则可取反用!(a ^ b)表示仅在每一位都相同时为1

最后额外排除0xFFFFFFFF

  1. //2
  2. /*
  3. * isTmax - returns 1 if x is the maximum, two's complement number,
  4. * and 0 otherwise
  5. * Legal ops: ! ~ & ^ | +
  6. * Max ops: 10
  7. * Rating: 1
  8. */
  9. int isTmax(int x) {
  10. return !((x+1)+(x+1))&!!(x+1);
  11. }

判断所有偶数位是否均为1

令y=1010...1010(二进制),即y==0xAAAAAAAA

运用<<和+来让0XAA重复四次得到该值

当且仅当x的任意偶数位都为1时返回1

即x存在偶数位为0时返回0

即结果为!(~x&0XAAAAAAAA)

  1. /*
  2. * allOddBits - return 1 if all odd-numbered bits in word set to 1
  3. * where bits are numbered from 0 (least significant) to 31 (most significant)
  4. * Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
  5. * Legal ops: ! ~ & ^ | + << >>
  6. * Max ops: 12
  7. * Rating: 2
  8. */
  9. int allOddBits(int x) {
  10. int y=0xAA;
  11. y=(y<<8)+y;
  12. y=(y<<16)+y;
  13. return !(~x&y);
  14. }

求-x

根据公式直接写

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

判断是否为'0'~'9'

!(a^b)在当且仅当a与b任意一位都相同时为1,可以代替==

查表得规律:

00...011100X表示38~39

00...0110XXX表示30~37

故借助于<<分别判断之

  1. //3
  2. /*
  3. * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0' to '9')
  4. * Example: isAsciiDigit(0x35) = 1.
  5. * isAsciiDigit(0x3a) = 0.
  6. * isAsciiDigit(0x05) = 0.
  7. * Legal ops: ! ~ & ^ | + << >>
  8. * Max ops: 15
  9. * Rating: 3
  10. */
  11. int isAsciiDigit(int x) {
  12. return !((x>>1)^0x1C) | !((x>>3)^0x6);
  13. }

实现x?y:z

假设存在操作@,

x=1时有x@y=y

x=0时有x@y=0

联想到&的性质可知

x=111...111(二进制)时x&y=y

x=000...000(二进制)时x&y=0

而111...111(二进制)=0XFFFFFFFF=-1

再根据前面求负数的题,~a+1=-a

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

判断小于等于

直接求y-x在异号的时候会溢出

(x>>31)^(y>>31)判断xy符号位是否不同

sub=y-x=y+~x+1求差值

若同号,y-x<0时返回1

若异号,x<0时返回1

  1. /*
  2. * isLessOrEqual - if x <= y then return 1, else return 0
  3. * Example: isLessOrEqual(4,5) = 1.
  4. * Legal ops: ! ~ & ^ | + << >>
  5. * Max ops: 24
  6. * Rating: 3
  7. */
  8. int isLessOrEqual(int x, int y) {
  9. int sx=x>>31;
  10. int sy=y>>31;
  11. int diff=sx^sy;
  12. int sub=(y+~x+1)>>31;
  13. return ((!diff&!sub)|(diff&sx))&1;
  14. /*
  15. 另一种方法:分x>=0?,y>=0?四种情况讨论
  16. int xb=x>>31;
  17. int xa=~xb;
  18. int yb=y>>31;
  19. int ya=~yb;
  20. return (xa&((ya&!((y+~x+1)>>31))))|(xb&((ya&1)|(yb&!!((~y+x)>>31))));
  21. */
  22. }

另一种思路:分x>=0?,y>=0?四种情况讨论

  1. int isLessOrEqual(int x, int y) {
  2. int xb=x>>31;
  3. int xa=~xb;
  4. int yb=y>>31;
  5. int ya=~yb;
  6. return (xa&((ya&!((y+~x+1)>>31))))|(xb&((ya&1)|(yb&!!((~y+x)>>31))));
  7. }

实现!运算符

关键知识点:当且仅当x==0时,x与-x符号位相同,并且值为0

故判断~(-x|x)的符号位即可

  1. //4
  2. /*
  3. * logicalNeg - implement the ! operator, using all of
  4. * the legal operators except !
  5. * Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
  6. * Legal ops: ~ & ^ | + << >>
  7. * Max ops: 12
  8. * Rating: 4
  9. */
  10. int logicalNeg(int x) {
  11. return (~((~x+1)|x)>>31)&1;
  12. }

另一种思路:我管这叫二分折叠

  1. int logicalNeg(int x) {
  2. int a=(x>>16)|x;
  3. int b=(a>>8)|a;
  4. int c=(b>>4)|b;
  5. int d=(c>>2)|c;
  6. int e=(d>>1)|d;
  7. return (~e)&1;
  8. }

判断位数

看Max ops知难度.

预处理:

把负数转换成它的~,使得正负数可用同一套操作

每个数都有一个符号位,所以计数器初始值为1

之后二分法:

判断高十六位是否为0,是的话把计数器加16,然后截取高十六位作为新的x;

否则节取低十六位作为新的x

判断高八位是否为0,是的话把计数器加8,然后截取高八位作为新的x;

否则节取低八位作为新的x

......

这个不断判断的过程可以借用前面x?y:z的代码,最后做一点点化简,防止超90ops

  1. /* howManyBits - return the minimum number of bits required to represent x in
  2. * two's complement
  3. * Examples: howManyBits(12) = 5
  4. * howManyBits(298) = 10
  5. * howManyBits(-5) = 4
  6. * howManyBits(0) = 1
  7. * howManyBits(-1) = 1
  8. * howManyBits(0x80000000) = 32
  9. * Legal ops: ! ~ & ^ | + << >>
  10. * Max ops: 90
  11. * Rating: 4
  12. */
  13. int howManyBits(int x) {
  14. int ret=0;
  15. int h16,h8,h4,h2,h1;
  16. int sign=(x>>31)&1;
  17. x=((~!!sign+1)&(~x))|(~!sign+1&x);
  18. ret=1;
  19. h16=(x>>16);
  20. ret+=((~!!h16+1)&16);
  21. x=h16|(~!h16+1&((x<<16)>>16));
  22. h8=x>>8;
  23. ret+=((~!!h8+1)&8);
  24. x=h8|(~!h8+1&((x<<8)>>8));
  25. h4=x>>4;
  26. ret+=((~!!h4+1)&4);
  27. x=h4|(~!h4+1&((x<<4)>>4));
  28. h2=x>>2;
  29. ret+=((~!!h2+1)&2);
  30. x=h2|(~!h2+1&((x<<2)>>2));
  31. h1=x>>1;
  32. ret+=((~!!h1+1)&1);
  33. ret+=!!x;
  34. return ret;

进一步化简后:

  1. int howManyBits(int x) {
  2. int b16,b8,b4,b2,b1;
  3. int ret=0;
  4. int sign=(x>>31);
  5. x=(~sign&x)|(sign&~x);
  6. ret=1+!!x;
  7. b16=!!(x>>16)<<4;
  8. x=x>>b16;
  9. b8=!!(x>>8)<<3;
  10. x=x>>b8;
  11. b4=!!(x>>4)<<2;
  12. x=x>>b4;
  13. b2=!!(x>>2)<<1;
  14. x=x>>b2;
  15. b1=!!(x>>1);
  16. return b16+b8+b4+b2+b1+ret;
  17. }

求浮点数f*2

if-else解封了还有啥难得?分类讨论,一个坑点在于无符号数右移的时候是无符号右移

  1. //float
  2. /*
  3. * floatScale2 - Return bit-level equivalent of expression 2*f for
  4. * floating point argument f.
  5. * Both the argument and result are passed as unsigned int's, but
  6. * they are to be interpreted as the bit-level representation of
  7. * single-precision floating point values.
  8. * When argument is NaN, return argument
  9. * Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
  10. * Max ops: 30
  11. * Rating: 4
  12. */
  13. unsigned floatScale2(unsigned uf) {
  14. unsigned e=(uf<<1)>>24;
  15. if(e==0xFF) return uf;
  16. else if(e==0) return (uf<<1)+(uf&0x80000000);
  17. else return uf+(1<<23);
  18. }

float转int

注意了<<和>>都不能超过自身的范围,也不能用负数,否则可能发生不可预期的错误

  1. /*
  2. * floatFloat2Int - Return bit-level equivalent of expression (int) f
  3. * for floating point argument f.
  4. * Argument is passed as unsigned int, but
  5. * it is to be interpreted as the bit-level representation of a
  6. * single-precision floating point value.
  7. * Anything out of range (including NaN and infinity) should return
  8. * 0x80000000u.
  9. * Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
  10. * Max ops: 30
  11. * Rating: 4
  12. */
  13. int floatFloat2Int(unsigned uf) {
  14. unsigned f=((uf<<11)>>11)+(1<<23);
  15. unsigned e=(uf<<1)>>24;
  16. int sign=(uf>>31)&1?-1:1;
  17. int shift=e-127-23;
  18. if(e==0xFF) return 0x80000000;
  19. else if(e==0) return 0;
  20. else{
  21. if(shift<-23) return 0;
  22. else if(shift>10) return 0x80000000;
  23. else if(shift<0) return (f>>(-shift))*sign;
  24. else return (f<<shift)*sign;
  25. }
  26. }

求2.0^x

这题我竟然超时了.原因是我是在移动硬盘上装得linux,而评判程序恰好时运行在本地的,这样子速度就慢了一截,结果就超时了.

  1. /*
  2. * floatPower2 - Return bit-level equivalent of the expression 2.0^x
  3. * (2.0 raised to the power x) for any 32-bit integer x.
  4. *
  5. * The unsigned value that is returned should have the identical bit
  6. * representation as the single-precision floating-point number 2.0^x.
  7. * If the result is too small to be represented as a denorm, return
  8. * 0. If too large, return +INF.
  9. *
  10. * Legal ops: Any integer/unsigned operations incl. ||, &&. Also if, while
  11. * Max ops: 30
  12. * Rating: 4
  13. */
  14. unsigned floatPower2(int x) {
  15. if(x<=-127) return 0;
  16. if(x>=128) return 0x7f800000;
  17. return (127+x)<<23;
  18. }

【CSAPP】Data Lab实验笔记的更多相关文章

  1. 【CSAPP】Shell Lab 实验笔记

    shlab这节是要求写个支持任务(job)功能的简易shell,主要考察了linux信号机制的相关内容.难度上如果熟读了<CSAPP>的"异常控制流"一章,应该是可以不 ...

  2. 【CSAPP】Cache Lab 实验笔记

    cachelab这节先让你实现个高速缓存模拟器,再在此基础上对矩阵转置函数进行优化,降低高速缓存不命中次数.我的感受如上一节,实在是不想研究这些犄角旮旯的优化策略了. 前期准备 我实验的时候用到了va ...

  3. 【CSAPP】Architecture Lab 实验笔记

    archlab属于第四章的内容.这章讲了处理器体系结构,就CPU是怎样构成的.看到时候跃跃欲试,以为最后实验是真要去造个CPU,配套资料也是一如既往的豪华,合计四十多页的参考手册,一大包的源码和测试程 ...

  4. 【CSAPP】Attack Lab实验笔记

    attacklab这节玩的是利用一个字符串进行缓冲区溢出漏洞攻击,就小时候想象中黑客干的事儿. 做题的时候好几次感叹这些人的脑洞,"这都可以攻击?还能这么注入?这还可能借力打力?" ...

  5. 【CSAPP】Bomb Lab实验笔记

    bomblab这节搞的是二进制拆弹,可以通俗理解为利用反汇编知识找出程序的六个解锁密码. 早就听闻BOMBLAB的大名,再加上我一直觉得反汇编是个很艰难的工作,开工前我做好了打BOSS心理准备.实际上 ...

  6. 【CSAPP】Performance Lab 实验笔记

    perflab这节的任务是利用书中知识,来对图像处理中的Rotate和Smooth操作函数进行优化.这次没对上电波,觉得学了一堆屠龙之技.于我个人理解,现在计算机配置比以前高多了,连SWAP分区都几近 ...

  7. ChCore Lab3 用户进程和异常处理 实验笔记

    本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第三篇:用户进程与异常处理.所有章节的笔记可在此处查看:chcore | ...

  8. CS:APP配套实验 Data Lab

    刚刚完成注册博客,想写一篇随笔,方便以后自己回顾.如果恰好也能帮助到你,是我的荣幸. 这次随笔是记载我的计算机系统(CS:APP,Computer Systems:A Programer's Pers ...

  9. SQL*Loader实验笔记【二】

      所有SQL*Loader实验笔记 实验案例总结(1-7):     SQL*Loader实验笔记[一] 实验案例总结(8-13):   SQL*Loader实验笔记[二] 实验案例总结(14-19 ...

随机推荐

  1. SpringAOP 失效解决方案、Spring事务失效

    SpringAOP 失效解决方案 SpringAOP是基于代理来对目标方法进行增强,但是有的时候又会出现"增强无效"的情况,比如在@Transactional下的某类中的方法内调用 ...

  2. JSP和Servlet有哪些相同点和不同点?

    JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达.JSP编译后是"类servlet". Servlet和JSP最主要的不同点在于,Servl ...

  3. ubuntu18.04设置开机自启Django

    设置开机自启: rc-local.server [Unit] Description=/etc/rc.local Compatibility ConditionPathExists=/etc/rc.l ...

  4. Java 中怎么获取一份线程 dump 文件?

    在 Linux 下,你可以通过命令 kill -3 PID (Java 进程的进程 ID)来获取 Java 应用的 dump 文件.在 Windows 下,你可以按下 Ctrl + Break 来获取 ...

  5. Redis 相比 Memcached 有哪些优势?

    1.Memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰 富的数据类 2.Redis 的速度比 Memcached 快很 3.Redis 可以持久化其数据

  6. 学习git(一)

    一.自动化运维 1.网络层(接入层.汇聚层.核心层): 1 LB+HA(L4.L7): 2 服务层(reverse proxy cache.应用层.web层.SOA层.分布式层.DAL): 3 数据层 ...

  7. CEPH-3:cephfs功能详解

    ceph集群cephfs使用详解 一个完整的ceph集群,可以提供块存储.文件系统和对象存储. 本节主要介绍文件系统cephfs功能如何灵活的使用,集群背景: [cephadmin@yq01-aip- ...

  8. css技术之用最高和最宽的限制“max-height和max-width”做图片同比例缩放,达到图片不变形目的,做出批量打印图片功能,页面打印“window.print()”

    一.简介 他们是为流而生的,像width/height这种定死的砖头式布局,min-width/max-width就没有存在的意义 ,min-width/max-width一定是自适应布局或流体布局中 ...

  9. 4.4 ROS节点名称重名

    4.4 ROS节点名称重名 场景:ROS 中创建的节点是有名称的,C++初始化节点时通过API:ros::init(argc,argv,"xxxx");来定义节点名称,在Pytho ...

  10. 《深入理解ES6》笔记——块级作用域绑定(1)

    本章涉及3个知识点,var.let.const,现在让我们了解3个关键字的特性和使用方法. var JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方 ...