CSAPP Lab01——Data Lab完成思路

陪你把想念的酸拥抱成温暖

陪你把彷徨写出情节来

未来多漫长再漫长还有期待

陪伴你 一直到 故事给说完

——陪你度过漫长岁月

完整代码见:CSAPP/datalab-handout at main · SnowLegend-star/CSAPP (github.com)

01 bitXor

这道题是用~和&计算x^y

异或是两个二进制数a,b对应的位相同为0,不同为1。既然是aibi 不同才为,且只能用~和&两种位运算符号。考虑对a取反,再和b进行&操作。这样当ai =0,bi =1时可以得到1;但是还得考虑当ai =1,bi =0时也应该得到1,此时考虑的对b取反,再和a进行&操作。综合以上两点,我们可以初步得到式子为“(~a&b)|(a&~b)”,换算后得到“~(~(x & ~y) & ~(~x & y))”。

//1
/* * 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 & y));
}

 

02 tmin

返回最小二进制补整数

Tmin不就是0x8000 0000吗?注意这里可以用到的整数在0~0xAA之间,所以是“1<<31”。

/* * tmin - return minimum two's complement integer *   Legal ops: ! ~ & ^ | + << >>*   Max ops: 4*   Rating: 1*/
int tmin(void) {//正数的补码是它本身,负数的补码是取反加一return 1<<31;}

03 isTmax

如果x是二进制补码的最大值,则返回1,否则返回0

       Tmax=0x7FFF FFFF,从Tmax的特殊性来考虑。如果x=Tmax,则x+1+x可以得到0xFFFF FFFF=Tmin。对于Tmin进行取反,则可以得到0。再对0取!,则可以令函数返回1。除此之外,还要考虑如果x本身就为Tmin,则它也会满足上述运算。所以得用^操作排除这种情况。

/** 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) {//二进制补码的最大值是:最高位0,其它位1int temp=x+1;int temp2=x+temp;//还得考虑x本身就是0xffffffff的情况,即x!=temp2return !(~temp2)&!!(x^temp2);}

04 allOddBits

如果word中所有的奇数位为1,则返回1,否则返回0(位从0~31位)

       这题十分恶心,是第一个卡住我的。开始想得太简单了,以为满足条件的数字只有0xAAAA AAAA这一个。后来发现0xFFAA AAAA这种也可以,这就让我犯了难——对于0xFF这种形式要怎么判断呢?想了很久都没有头绪。跳过这题后面再写的时候灵光一闪,想到只要判断奇数位是1就行,根本就不用考虑偶数位。要做到这一步其实就是把x和0xAAAA AAAA进行&操作,可以提取出x奇数为上所有的1得到数字x2。我们会发现,只要x满足条件,那进行上一步操作后的形式都是统一的0xAAAA AAAA。所以最后判断x2是不是与0xAAAA AAAA一致就行。

/* * 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) {//没搞出来//计算机的右移位运算默认是逻辑还是算数呢?dev c++是逻辑//直接不用考虑偶数位的情况,只考虑奇数位全为1的时候//怎么在dev c上跑x=0x80000000的时候返回0,这时候就返回1了?????int a=0xAA<<8;int b=a+0xAA;     //b=0xAAAAint c=(b<<16)+b;  //这里b<<16得加括号,因为+的优先级大于<<int d=!((c&x)^c); return d;//强行令偶数位全为0再进行比较
}

05 negate

返回-x

       简单的取反加一操作。最开始还在考虑Tmin的特殊性,验算后发现Tmin也符合这个规律。秒了,芜湖

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

06 isAsciiDigit

如果0x30 <= x <= 0x39,返回1,否则返回0

       开始我的思路是挨个判断x的每一位。即x的第5、6位只能为1,再高位只能为0;对于低四位,第4位为1的时候只有第1位可以同时为1,如果第4位为0则后三位无论是什么值都可以。但是挨个判断每一位需要的符号好像会超过限制。

       后来看了别的解法,第一次发现了符号位的大用。基本上这次的lab都没提供“-”这个操作,但是可以利用“+(~x+1)”来实现减法。如果给出x,只要用两个边界值0x30和0x39对x进行减法操作就行。最后通过符号位来判断x与0x30和0x39的大小。这种思路在后面的题目也会用到。

/* * 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) {//判断第四五位都是1、且高位都是0,1-3位值得小于等于9//x做完移位运算后自身值不发生改变的int a=x+~(0x30)+1;int b=0x39+~x+1;int c=a>>31;int d=b>>31;return !c&!d;
}

07 conditional

用位级运算表示三目运算符 x?y:z

       我们要注意到一点,这种返回值在几个数中选一个的势必得用到“|”操作,比如T01要是能用上“|”就会简单许多。由于只要x不为0就返回y,为0才返回z。要返回y,就是考虑当x不为0时让y和0xFFFF FFFF进行&操作。一个全新的操作在我脑中应运而生,那就是“!!x”。只要x不为0,那!!x就会得到1;x为0,那!!x会得到0。而对0或者1进行取反加一就可以得到0或者0xFFFF FFFF。这样我们就得到了想要的全1二进制数。此题结束。

/* * 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) {return y&(~(!!x)+1)|(z&~(~(!!x)+1));
}

08 isLessOrEqual

如果x<=y,则返回1,否则返回0

       这题算是T06的弱化版。T06还得进行两次比大小,这题只用比一次就行了。也是用减法然后进行符号位的判断就可以解决。

/* * 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 a=y+(~x+1);int b=x>>31&1;int c=y>>31&1;return (b&!c)|(!(a>>31)&!(b^c));//得控制后半部分只有同号的时候才能计算 
}

09 logicalNeg

用其余的操作符实现

       这题算是第二题卡了我很久的。想了一个多小时也没头绪——要如何才能做到当x不为0时返回0?假如从x的每一位着手,只要发现有一位不为0就可以判断x不为0,但是这样就要用到for循环了。遂跳过这题。

后来第二天再看的时候灵光一闪。既然对x的每位进行判断有困难,那还是老样子直接考虑数字这个整体。由于题目提供的运算符也不多,所以x的正负性成了可以拿来解题的性质。注意到一点,只要x不为0,那x的相反数符号位就和x的符号位是不同的。从正负性和符号位着手这题就很容易解决了。

/* * 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 x2=~x+1;int sign=(x>>31)^(x2>>31);int min=x>>31;return (~sign)&1&~((x2^x)^min);
}

10 howManyBits

使用补码时最少需要多少比特位

       这题的运算符限制是90,给人一种代码结构肯定十分庞大的感觉,倒是让我一下子不知如何下手。首先考虑的是把数字x和 ​​​​​​​​​​​​​​​​​​​​​ 进行比较,但这样用到的运算符数目必然会超过90。于是又想到了用二分法,但是二分法得结合for循环才好实施吧。最后又想到了一种二分法的变体。即x先和 ​​​​​​​ 比较,若是大于它就对x进行“>>16”的操作,然后再和 ​​​​​​​ 相比;小于它就直接和 ​​​​​​​ 进行比较。在不断的比较和移位操作中应该是可以判断出来的。

但是写其他题已经是花费了许多心力,遂开摆。等什么时候状态好了再来拿下这题。

/* 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 temp=x>>31;       //记录x的正负性int a=~x+1;int b=(1<<16)+a;int c=b>>31;          //用符号位判断2^16和x的大小return 0;
}

11 floatScale2

给定一个无符号数f,我们以浮点数的格式来看待这个数f,返回2*f

       首先得明白浮点数大致有三种类型:规格数,非规格数,无穷大或者NaN。然后提取出f的exp和frac部分。若f不是非规格数,对它进行判断再返回。若是规格数就好办了,直接在exp部分加上1就能返回了。

       值得一提的是,非规格数如果尾数最高位为1时,右移1位会使阶码最低位从0变为1,而这时候恰好就是正确的结果,并不需要额外的处理。这是因为乘2之后完成了进位,刚好规格数在小数点前有一个1,规格数和非规格数从而无缝衔接。

/* * 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 exp=uf & 0x7f800000;int frac=uf & 0x7fffff;if(uf==0x7f800000||uf==0xff800000)return uf; else if(exp==0x7f800000&&frac!=0)return uf;else if(exp==0)return (uf&0x80000000)+(frac<<1);//记得给位运算加括号elsereturn uf + 0x800000;
}

12 floatFloat2Int

给定一个无符号数f,我们以浮点数的格式来看待这个数f,将这个浮点数f转换为整形。

       上来就考虑两个边界,即浮点数太小就返回0;太大就返回0x80000000u。我们知道,浮点数的计算方法是“”,其中E=e-127。故当e<127的时候,这个数整体就<1了。当e>127+30的时候,E>=31,直接达到了32bit能表达的数据上限。其他情况就是套用此式即可。

/* * 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 exp=(uf & 0x7f800000)>>23;int frac=uf & 0x7fffff;if(exp>127+30)//无穷大或者是NaN都返回统一的值return 0x80000000u;else if(exp<127){//非规格化的数,return 0;}if(uf>>31)return -(((frac>>23)+1)<<(exp-0x7F));else return ((frac>>23)+1)<<(exp-0x7F); 
}

 

13 floatPower2

返回2的x次方,返回用无符号数表示的浮点数

当e<-126时,这已经是浮点数能表示的最小值了,所以返回0。当e>127,浮点数表示不出来这种数字,只能返回无穷大了。其他的情况E=x+bias,左移23位即可。

/* * 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) {if(x<-126)return 0;else if(x>127)return (0xFF)<<23;return (x+127)<<23;return 2;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/25426.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

红黑树的介绍与实现

前言 前面我们介绍了AVL树&#xff0c;AVL树是一棵非常自律的树&#xff0c;有着严格的高度可控制&#xff01;但是正它的自律给他带来了另一个问题&#xff0c;即虽然他的查找效率很高&#xff0c;但是插入和删除由于旋转而导致效率没有那么高。我们上一期的结尾说过经常修改…

C语言:双链表

一、什么是双链表&#xff1f; 双链表&#xff0c;顾名思义&#xff0c;是一种每个节点都包含两个链接的链表&#xff1a;一个指向下一个节点&#xff0c;另一个指向前一个节点。这种结构使得双链表在遍历、插入和删除操作上都表现出色。与单链表相比&#xff0c;双链表不仅可以…

【机器学习】【遗传算法】【项目实战】药品分拣的优化策略【附Python源码】

仅供学习、参考使用 一、遗传算法简介 遗传算法&#xff08;Genetic Algorithm, GA&#xff09;是机器学习领域中常见的一类算法&#xff0c;其基本思想可以用下述流程图简要表示&#xff1a; &#xff08;图参考论文&#xff1a;Optimization of Worker Scheduling at Logi…

DVB-S系统发射端Matlab仿真及FPGA实现

DVB标准 Digital Video Broadcasting&#xff08;数字视频广播&#xff09;是一个完整的数字电视解决方案&#xff0c;其中包括DVB-C&#xff08;数字电视有线传输标准&#xff09;&#xff0c; DVB-T&#xff08;数字电视地面传输标准&#xff09;&#xff0c;DVB-S&#xff…

正确理解iOS中的同步锁

在 iOS 开发中&#xff0c;同步锁&#xff08;synchronized lock&#xff09;是一种用于管理多线程访问共享资源的机制&#xff0c;而不是某一种特定类型的锁。它涵盖了多种具体实现和技术&#xff0c;用于确保同一时间只有一个线程能够访问某个共享资源&#xff0c;从而避免数…

探地雷达正演模拟,基于时域有限差分方法,一

声明&#xff1a;本博客中的公式均是在Word中使用AxMath写好后截图使用的&#xff0c;欢迎引用&#xff0c;但请标注来源。 本系列会有四篇博客&#xff1a; 第一篇内容&#xff1a; 1、基础知识掌握 2、Maxwell方法差分求解原理 第二篇内容&#xff1a; 1、基于C的TE波波…

docker——基础知识

简介 一、什么是虚拟化和容器化 ​ 实体计算机叫做物理机&#xff0c;又时也称为寄主机&#xff1b; ​ 虚拟化&#xff1a;将一台计算机虚拟化为多态逻辑计算机&#xff1b; ​ 容器化&#xff1a;一种虚拟化技术&#xff0c;操作系统的虚拟化&#xff1b;将用户空间软件实…

mongodb总概

一、mongodb概述 mongodb是最流行的nosql数据库&#xff0c;由C语言编写。其功能非常丰富&#xff0c;包括: 面向集合文档的存储:适合存储Bson(json的扩展)形式的数据;格式自由&#xff0c;数据格式不固定&#xff0c;生产环境下修改结构都可以不影响程序运行;强大的查询语句…

2 程序的灵魂—算法-2.2 简单算法举例-【例 2.3】

【例 2.3】判定 2000 — 2500 年中的每一年是否闰年&#xff0c;将结果输出。 润年的条件: 1. 能被 4 整除&#xff0c;但不能被 100 整除的年份&#xff1b; 2. 能被 100 整除&#xff0c;又能被 400 整除的年份&#xff1b; 设 y 为被检测的年份&#xff0c;则算法可表示如下…

C语言:定义和使用结构体变量

定义和使用结构体变量 介绍基础用法1.定义结构体2. 声明结构体变量3. 初始化和访问结构体成员4. 使用指针访问结构体成员5. 使用结构体数组 高级用法6. 嵌套结构体7. 匿名结构体8. 结构体和动态内存分配9. 结构体作为函数参数按值传递按引用传递 介绍 在C语言中&#xff0c;结…

Edge怎么关闭快捷键

Edge怎么关闭快捷键 在Edge浏览器中&#xff0c;你可以通过以下步骤关闭快捷键&#xff1a; 打开Edge浏览器&#xff0c;输入&#xff1a;edge://flags 并按下回车键。 在Flags页面中&#xff0c;搜索“快捷键”(Keyboard shortcuts)选项。 将“快捷键”选项的状态设置为“…

dos命令---根据端口查找进程

简介 在日常开发中&#xff0c;常常出现端口被占用的情况&#xff0c;导致程序运行报错&#xff0c;这时可以使用此命令查看哪个进程占用了端口 命令 netstat -ano | findstr 11434返回结果&#xff1a;

【简单介绍下DALL-E2,什么是DALL-E2?】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

10.爬虫---XPath插件安装并解析爬取数据

10.XPath插件安装并解析爬取数据 1.XPath简介2.XPath helper安装3.XPath 常用规则4.实例引入4.1 //匹配所有节点4.2 / 或 // 匹配子节点或子孙节点4.3 ..或 parent::匹配父节点4.4 匹配属性4.5 text()文本获取4.6 属性获取4.7 属性多值匹配 1.XPath简介 XPath是一门在XML文档中…

Matlab|混合策略改进的蝴蝶优化算法

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序主要对蝴蝶算法&#xff08;BOA&#xff09;进行改进&#xff0c;参考文献《基于改进蝴蝶优化算法的冗余机器人逆运动学求解》&#xff0c;有如下改进策略&#xff1a; 改进1&#xff1a;采用反向学习策…

手把手带你做一个自己的网络调试助手(1) - TCP服务器准备

程序设计流程图 TCP 服务器 ui界面搭建 Tcp服务器建立连接 - listen() connect() 1.在构造函数中进行如下初始化: 通过 QNetworkInterface 类的 allAddresses 这一API 获得可用IP地址&#xff08;包括IPv4 和 IPv6&#xff09; 然后通过QHostAddress类的 protocol 这一AP…

使用vite从0开始搭建vue项目

使用Vite从0开始创建vue项目 第一步&#xff1a;创建项目目录 mkdir vue-demo -创建目录 cd vue-demo --进入项目 npm init -y --生成package.json文件 第二步&#xff1a;安装vite、typescript--ts、vue、vitejs/plugin-vue--对单文件组件、热重载、生产优化的支持 pnpm…

“三夏”农忙:EasyCVR/EasyDSS无人机技术助推现代农业走向智能化

随着科技的飞速发展&#xff0c;无人机技术已经逐渐渗透到我们生活的方方面面。其中&#xff0c;无人机在农业领域的应用尤为引人注目。它们不仅提高了农业生产的效率&#xff0c;还为农民带来了更便捷、更智能的种植方式。 无人机在农业应用场景中&#xff0c;通过搭载各种设备…

【数据结构】 -- 堆 (堆排序)(TOP-K问题)

引入 要学习堆&#xff0c;首先要先简单的了解一下二叉树&#xff0c;二叉树是一种常见的树形数据结构&#xff0c;每个节点最多有两个子节点&#xff0c;通常称为左子节点和右子节点。它具有以下特点&#xff1a; 根节点&#xff08;Root&#xff09;&#xff1a;树的顶部节…

电脑回收站清空了怎么恢复回来?分享四个好用数据恢复方法

电脑回收站清空了还能恢复回来吗&#xff1f;在使用电脑过程中&#xff0c;很多小伙伴都不重视电脑的回收站,&#xff0c;有用的没用的文件都往里堆积。等空间不够的时候就去一股脑清空回收站。可有时候会发现自己还需要的文件在回收站里&#xff0c;可回收站已经被清空了……那…