CSAPP | Lab1-Data Lab 详细解析

题目概览

   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 if the shift amount
     is less than 0 or greater than 31.



Part1:整数

1.BitXor

 * 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 2;
}

思路1(利用小结论):

  • 已知的结论有:x ^ y = (~x & y) | (x & ~y)

  • 但是题目中不能使用|,所以要将|转化为~&,而又有结论x | y = ~ (~x & ~y)

因此综合上面的两点可以写出版本一:

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

思路2(直接推导):

在这里插入图片描述

因此版本2:

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 2;
}

思路:tmin的16进制形式为0x80000000,写出即可

代码如下:

int tmin(void) {
  return 1 << 32;
}

3.isTMax

 * 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) {
    return 2;
}

思路:

  • TMax具有如下性质:(x+1)== ~x(这个称为条件1)

  • 但是对于-1(0xffffffff)也具有上面的性质,因此要加上条件2 — x+1不为0

  • 条件1:(x+1)== ~x可以用legal ops表述为 !((x+1) ^ (~x))

综合上面的条件可得如下代码:

int isTmax(int x) {
    int flag1 = (x + 1) ^ (~x);
    int flag2 = (x + 1);
    return !(flag1 | !flag2);
}

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

int allOddBits(int x) {
  return 2;
}

思路:

较为简单,与0xAAAAAAAA与运算之后得到0xAAAAAAAA即为满足条件

由课后习题2.15可知:x==y可以通过位运算!(x ^y)实现

因此代码如下:

int allOddBits(int x) {
  int oddnumber = (0xAA<<24) + (0xAA<<16) + (0xAA<<8) + 0xAA;
  return !((x & oddnumber) ^ oddnumber);
}

5.Negate

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

int negate(int x) {
  return 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

int isAsciiDigit(int x) {
  return 2;
}

思路:

要满足0x30 <= x <= 0x39可以拆解为以下两个条件:

  1. x的高28位和0x30完全相同,这个可以通过!(x >> 4) ^ 3实现
  2. x的低4位位于0到9之间,换一种说法,取出x的低四位再加6一定不会进位

分析即可得到的最后结果如下:

int isAsciiDigit(int x) {
  int flag1 = (x >> 4) ^ 3;
  int flag2 = ((x & 0xF) + 6) >> 4;
  return !(flag1 | flag2);
}

7.conditional

 * 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 2;
}

思路:

关键在于使用!来化整并且将x=0和x!=0转化为0x00000000和0xFFFFFFFF

  • x=0时,!!x = 0,考虑~(!!x) + 1 = 0x00000000

  • x!=0时,!!x = 1,考虑~(!!x) + 1 = 0xFFFFFFFF

  • 最后分别用x~xyz作与运算即可

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

8.isLessOrEqual

 * 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) {
  return 2;
}

思路:

其实这道题的关键在于因为溢出现象的存在我们没办法只使用符号位来判断y - x的正负,那就有办法啦,可以分类讨论嘛

  1. x y同号

    这时候并不溢出,直接用y + ~x + 1的符号位判断即可

  2. x y异号

    这个时候要满足x <= y一定是x为负而y非负

思路理清了之后就很容易写出下面的代码:

int isLessOrEqual(int x, int y) {
  int signx = (x >> 31) & 1;
  int signy = (y >> 31) & 1;
  int flag1 = signx ^ signy;
  int flag2 = (y + ~x + 1) >> 31;

  return (!flag1 & !flag2) | (flag1 & signx);
}

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 

int logicalNeg(int x) {
  return 2;
}

思路:

x 与 -x做或运算之后符号位仍然为零的只有0

  • x=0((~ x + 1) | x) >> 31得到0x00000000,加1就是1
  • x!=0时由于算术右移((~ x + 1) | x) >> 31得到0xFFFFFFFF,加1溢出就是0

代码如下:

int logicalNeg(int x) {
  return (((~ x + 1) | x) >> 31) + 1;
}

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
int howManyBits(int x) {
  return 2;
}

思路:

没做出来,只能尽量清楚地将思路阐述出来

第一步是统一正负数和0的处理:

  • 当x为正数时需要找到最高位的1,除此之外还需要加上一位0作符号位
  • 当x为0时也适用于上面的做法
  • 当x为负数时,需要找到最高位的0,除此之外还需要加上一位1作符号位,为了统一与非负数的处理,对负数取反即可遵循上面的处理得到同样正确的结果

主要思想是二分法:

step1:处理32位数

先判断高16位是否有1,如果有1则变量b16为16,没有则变量b16为0

右移b16位

  • 如果高16位有1相当于我们处理过低16位了只需处理高16位
  • 如果高16位没1相当于只需要处理低16位

step2:处理16位数

对处理后的x判断高8位是否有1,如果有1则变量b8为8,没有则变量b8为0

右移b8位

  • 如果高8位有1相当于我们处理过低8位了只需处理高8位
  • 如果高8位没1相当于只需要处理低8位

step3:处理8位数

对处理后的x判断高4位是否有1,如果有1则变量b4为4,没有则变量b4为0

右移b4位

  • 如果高4位有1相当于我们处理过低4位了只需处理高4位
  • 如果高4位没1相当于只需要处理低4位

step4:处理4位数

对处理后的x判断高2位是否有1,如果有1则变量b2为2,没有则变量b4为0

右移b2位

  • 如果高2位有1相当于我们处理过低2位了只需处理高2位
  • 如果高2位没1相当于只需要处理低2位

step5:处理2位数

对处理后的x判断高1位是否有1,如果有1则变量b1为1,没有则变量b1为0

右移b1位

  • 如果高1位有1相当于我们处理过低1位了只需处理高1位
  • 如果高1位没1相当于只需要处理低1位

step6:处理1位数

这时x=0or1,直接赋给b0即可

最后得到的结果为b16 + b8 + b4 + b2 + b1 + b0 + 1

int howManyBits(int x) {
  int b16, b8, b4, b2, b1, b0;
  int flag = x >> 31;
  x = (~flag & x) | ((flag & ~x));
  b16 = (!!(x >> 16)) << 4;
  x = x >> b16;
  b8 = (!!(x >> 8)) << 3;
  x = x >> b8;
  b4 = (!!(x >> 4)) << 2;
  x = x >> b4;
  b2 = (!!(x >> 2)) << 1;
  x = x >> b2;
  b1 = (!!(x >> 1)) << 0;
  x = x >> b1;
  b0 = x;
  return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}



Part2:浮点数

1.floatScale2

 * 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) {
  return 2;
}

思路:

32字节的数来表示浮点数的话第一位s,接下来八位表示exp可转化为阶码,最后23位表示小数位可转化为尾数

在这里插入图片描述

因此所有题目第一步先将他们取出来

  • unsigned sign = (uf >> 31) & 0x1;
  • unsigned exp = (uf >> 23) & 0xFF;
  • unsigned frac = uf & 0x7FFFFF;

然后分为三类:

1.非规格化值(exp==0x00)

这个时候乘2只需要让frac往左移动一位即可(当frac最高位为1时可以让浮点数由非规格化值转化到规格化的值)

2.特殊值(exp == 0xFF)

这个返回自己即可

3.规格化值

这个时候乘2只需要让exp+1即可(当exp==0xFD时可以让浮点数由规格化值转化到特殊值)

代码如下:

unsigned floatScale2(unsigned uf) {
  unsigned sign = (uf >> 31) & 0x1;
  unsigned exp =  (uf >> 23) & 0xFF;
  unsigned frac = uf & 0x7FFFFF;
  if (exp == 0xFF) return uf;
  else if (exp == 0x00) frac <<= 1; 
  else exp++;
  return (sign << 31) | (exp << 23) | frac;
}

2.floatFloat2Int

 * 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) {
  return 2;
}

思路:

第一步还是取出s exp frac,并根据偏置计算出阶码和尾数

列出下表:

format(32字节)最小值最大值
非规格化数 2 − 149 2^{-149} 2149 2 − 126 ( 1 − ϵ ) 2^{-126}(1-\epsilon) 2126(1ϵ)
规格化数 2 − 126 2^{-126} 2126 2 127 ( 2 − ϵ ) 2^{127}(2-\epsilon) 2127(2ϵ)

这个题有很多种可能性可以合并,但因为不是太熟练,所以我就严格按照非规格化值、特殊值、规格化值一一分类,这样也是可以通过的

在这里插入图片描述

  1. 非规格化值(exp==0x00)

    此时绝对值小于1,无论正负向0舍入,返回0

  2. 特殊值(exp == 0xff)

    溢出,返回0x80000000u

  3. 规格化值

    先不考虑符号位,最后再转化

    • E < 0此时绝对值小于1,返回0

    • E >= 31,此时超过int能表示的范围,溢出

    • E < 23,M末尾的 (23 - E) 个数被舍入

    • 23 <= E < 31 需要在M的最后加上frac 的末尾添加 (E - 23) 个 0

当x为负数时进行一步从x到~x+1的转化即可

代码如下:

int floatFloat2Int(unsigned uf) {
  unsigned sign = (uf >> 31) & 0x1;
  unsigned bias = (1 << 7) - 1;
  unsigned exp =  (uf >> 23) & 0xFF;
  unsigned frac = uf & 0x7FFFFF;
  int E = exp - bias;
  int M = frac | (1 << 23);
  if (exp == 0) {
    return 0;
  } else if (exp == 0xff) {
    return 0x80000000u;
  } else {
    if (E < 0) return 0;
    else if (E >= 31) return 0x80000000u;
    else if (E < 23) M >>= (23 - E);
    else M <<= (E - 23);
  }
  return (sign ? (~M + 1) : M);
}

3.floatPower2

 * 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) {
  return 2;
}

思路:

format(32字节)最小值最大值
非规格化数 2 − 149 2^{-149} 2149 2 − 126 ( 1 − ϵ ) 2^{-126}(1-\epsilon) 2126(1ϵ)
规格化数 2 − 126 2^{-126} 2126 2 127 ( 2 − ϵ ) 2^{127}(2-\epsilon) 2127(2ϵ)

利用下面的表格很容易分析如下:

  • 当x < -149时超出表示范围,返回0
  • 当x > 127时过大超出表示范围,返回(0xFF) << 23
  • 当-149 <= x < -126时用非规格数表示,1 << (x + 149)
  • 当-126 <= x <= 127时用规格数表示,(x + 127) << 23

可以写出下面的代码:

unsigned floatPower2(int x) {
  if (x < -149) return 0;
  else if (x < -126) return 1 << (x + 149);
  else if (x <= 127) return (x + 127) << 23;
  else return (0xFF) << 23;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python语言介绍

一、python基础语法 1、字面量 在代码中&#xff0c;被写下来的固定的值&#xff08;数据&#xff09;&#xff0c;叫做字面量 "abcd" 1 3.6 字面量类型 2、基础python语句 首先&#xff0c;python语句不需要以分号结尾&#xff0c;而是以每一行作为区分&#x…

Springboot整合Mybatis的详细案例+图解+分析(一)

后台访问流程 请求&#xff1a;用户从页面前端&#xff0c;也就是我们所说的view层进行查询访问&#xff0c;进入到controller层找到对应的接口&#xff0c;接着controller层进行对service层进行业务功能的调用&#xff0c;service要进入dao(mapper)层&#xff0c;dao层调用map…

【C++庖丁解牛】stack的介绍和使用 | queue的介绍和使用 | priority_queue的介绍和使用

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. stack的介绍和使用1.1…

面试算法-68-将有序数组转换为二叉搜索树

题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视…

【QT入门】 Qt槽函数五种常用写法介绍

声明&#xff1a;该专栏为本人学习Qt知识点时候的笔记汇总&#xff0c;希望能给初学的朋友们一点帮助(加油&#xff01;) 往期回顾&#xff1a; 【QT入门】实现一个简单的图片查看软件-CSDN博客 【QT入门】图片查看软件(优化)-CSDN博客 【QT入门】 lambda表达式(函数)详解-CSDN…

一篇文章教会你如何用 Axure 画原型图

原型图对于做出更好的 UI 设计决策非常重要。然而&#xff0c;选择合适的原型工具并不容易。我们需要仔细考虑成本、功能、与其他设计工具的集成、学习曲线、协作功能和用户测试方法&#xff0c;本文将分析 Axure 的原型设计工具。 1、为何使用 Axure 绘制原型图&#xff1f; …

绝了!这个国标证书的含金量怎么又提高了?!

在项目管理领域&#xff0c;很多人只知道PMP证书&#xff0c;但却不知CSPM认证体系同样正在逐步深入该领域&#xff0c;其价值和影响力让人难以忽视。 一、“CSPM”正式成为注册商标 上周&#xff0c;项目管理标准化官方发布推文&#xff0c;祝贺"CSPM"正式成为项目…

MQTT和Modbus的物联网网关协议区别分析

MQTT和Modbus的物联网网关协议区别分析 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;与Modbus是两种广泛应用在物联网环境中的通信协议&#xff0c;它们各自具有独特的优势和适用场景&#xff0c;下面将从多个维度对这两种网关协议进行详细区别分析。 首…

【MySQL】DDL的表操作详解:创建&查询&修改&删除(记得3点加上连接)

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

如何使用Net2FTP+cpolar搭建专属文件共享站点并实现无公网IP远程访问——“cpolar内网穿透”

文章目录 1.前言2. Net2FTP网站搭建2.1. Net2FTP下载和安装2.2. Net2FTP网页测试 3. cpolar内网穿透3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 文件传输可以说是互联网最主要的应用之一&#xff0c;特别是智能设备的大面积使用&#xff0c;无论是个人…

MySQL 索引的10 个核心要点

文章目录 &#x1f349;1. 索引底层采用什么数据结构&#xff1f;为什么不用hash&#x1f349;2. B树与B树区别&#xff1f;为何用B树&#xff1f;&#x1f349;3. 自增主键理解&#xff1f;&#x1f349;4. 为什么自增主键不连续&#x1f349;5. Innodb为什么推荐用自增ID&…

Nebula Graph-02-NebulaGraph高阶配置、用户管理、日志

前言&#xff1a; 在上篇中我们已经成功的部署了Nebula Graph 服务:Nebula Graph-01-Nebula Graph简介和安装以及客户端连接&#xff0c; 现在我们来谈一下Nebula Graph 的各项配置 NebulaGraph高阶配置 文件 在上篇文章中&#xff0c;我们成功的启动了NebulaGraph 服务&am…

【C++】1311. 分跳绳

问题&#xff1a;1311. 分跳绳 类型&#xff1a;基本运算、整数运算 题目描述&#xff1a; 学校新买来 m 根跳绳&#xff0c;每个班分 n 根&#xff0c;最多可以分给几个班的同学&#xff0c;还剩多少根&#xff1f;&#xff08;m≥n&#xff09;。 输入&#xff1a; 两个整…

camunda流程引擎事务管理和乐观锁

本文重点介绍camunda开源流程引擎的事务配置&#xff0c;以及在高并发多线程情况下&#xff0c;可能会发生多个线程尝试对相同流程实例数据进行更改的情况&#xff0c;Camunda如何通过数据库的乐观锁解决这种并发冲突的&#xff0c;并介绍了乐观锁和悲观锁的适用场景、性能影响…

【C语言】数9的个数

编写程序数一下 1到 100 的所有整数中出现多少个数字9 1&#xff0c;首先产生1~100的数字。然猴设法得到数9个数&#xff0c;例如个位&#xff1a;19%109&#xff0c;十位&#xff1a;91/109。 2&#xff0c;每次得到数九的时候&#xff0c;就用一个变量来进行计数。 代码如…

【项目笔记】java微服务:黑马头条(day04)

文章目录 自媒体文章-自动审核1)自媒体文章自动审核流程2)内容安全第三方接口2.1)概述2.2)准备工作2.3)文本内容审核接口2.4)图片审核接口2.5)项目集成 3)app端文章保存接口3.1)表结构说明3.2)分布式id3.3)思路分析3.4)feign接口 4)自媒体文章自动审核功能实现4.1)表结构说明4.…

搭建ELK+minio及配置

什么是ELK ELK是一种基于开源工具的日志管理和数据分析解决方案&#xff0c;它由三个核心组件组成&#xff1a; Elasticsearch&#xff1a;用于存储、搜索和分析大规模数据的分布式搜索引擎。Logstash&#xff1a;用于收集、过滤、转换和发送日志数据的数据处理管道。Kibana&…

mysql虚拟列Generated Column

目录​​​​​​​ 1、Generated Column简介 生成的列定义具有以下语法&#xff1a; 2、实践 2.1 存储格式为json字段增加索引 2.2 手机号后四位 3、虚拟列索引介绍 3.1 虚拟列索引的限制 3.1.1 Virtal Generated Column 4、阿里云数据库环境是否支持 下期扩展&…

通过 Socket 手动实现 HTTP 协议

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

使用Oxygen编辑器的项目来做团队协作

▲ 搜索“大龙谈智能内容”关注公众号▲ 扫码见我视频号上的视频 今天&#xff0c;分享一种在Oxygen中使用项目文件进行团队协作的高效方法。这种方法不仅能帮助我们轻松共享文件和文件夹&#xff0c;还能确保团队成员使用统一的项目级别选项和发布配置&#xff0c;从而提高工…
最新文章