当前位置: 首页 > news >正文

csapp实验一:datalab

一、实验目的

本实验目的是加强学生对位级运算的理解及熟练使用的能力。

二、报告要求

本报告要求学生把实验中实现的所有函数逐一进行分析说明,写出实现的依据,也就是推理过程,可以是一个简单的数学证明,也可以是代码分析,根据实现中你的想法不同而异。

三、函数分析

符号只能使用位运算符 ! ~ & ^ | + << >> ,不能使用 if, else, ?:, while

bitXor函数

函数要求:

函数名bitXor
参数int , int
功能实现x^y

实现分析:

a^b = ~(~(a&~b)&(~(~a&b)))

异或的逻辑是 x ^ y = (x AND ~y) OR (~x AND y)

根据de morgan律:A | B = (A & ~B)

函数实现:

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

getByte函数

函数要求:

函数名getByte
参数int , int
功能实现在word x中提取第n个字节

实现分析:

getByte(x,n) = (x>>(n<<3))&0xff

从一个 32 位整数中取出第 n 个字节(0 表示最低字节)。

  • 每个字节是 8 位,所以要移动 n * 8 位,即 n << 3
  • 再用掩码 0xFF(11111111)保留最后 8 位。

函数实现:

int getByte(int x, int n) {return (x>>(n<<3))&0xff;}

logicalShift函数

函数要求:

函数名logicalShift
参数int , int
功能实现将x向右移n位

实现分析:

在函数中新定义了两个变量y和z,其中:

普通的 >> 是算术右移,会补符号位(即1或0)。
逻辑右移则始终补 0。
解决方法:

  1. 先算术右移 x >> n
  2. 再用掩码清除被符号位填充的部分。

掩码思路:
(1 << 31) 是最高位为 1 的数。
((1 << 31) >> n) << 1 构造出 n 位的 1,再取反即为低 32-n 位为1的掩码。

函数实现:

int logicalShift(int x, int n) {int mark = 0x01 << 31;int y = (x & mark);int z = ~((y>>n)<<0x1);return (x>>n) & z;
}

bitCount函数

函数要求:

函数名bitCount
参数int
功能实现计算输入字节中为1的bit数

实现分析:

  • 原理:一个2bit的二进制数,其所有的组合有00, 01, 10, 11。若要计算这个2bit的数的二进制有多少个1,则可以用这个数减去其二进制第二个位上的数字,得到的便是这个2bit数字的二进制中的1个个数。
  • 核心思想(并行计数 / 分治):
    把 32 位分成很多小块,先在最小粒度上对相邻位成对计数,然后把结果在更大粒度上合并,逐层累加,最终得到总和。这样做避免了循环和条件判断,全部用位运算和加法完成,速度快且合法操作数有限。
  • 掩码(便于分组):
  • mask1 = 0x55555555 = 二进制每 2 位为 01 01 01 ...
    用于把每对位分别取出(位0与位1配对)。
  • mask2 = 0x33333333 = 每 4 位为 0011 0011 ...
    用于把每 4 位当作两组 2 位的和来合并。
  • mask4 = 0x0F0F0F0F = 每 8 位为 00001111 ...
    用于把每 8 位当作两组 4 位的和来合并。

函数实现:

int bitCount(int x) {int m8 = 0x55; int mask1 = m8 | (m8 << 8) | (m8 << 16) | (m8 << 24);int m3 = 0x33;int mask2 = m3 | (m3 << 8) | (m3 << 16) | (m3 << 24);int m0f = 0x0f;int mask4 = m0f | (m0f << 8) | (m0f << 16) | (m0f << 24);x = x + (~(((x >> 1) & mask1)) + 1);x = (x & mask2) + ((x >> 2) & mask2);x = (x + (x >> 4)) & mask4;x = x + (x >> 8);x = x + (x >> 16);return x & 0x3f;
}

conditional函数

函数要求:

函数名conditional
参数int , int , int
功能实现实现x ? y : z

实现分析:

核心思想是:
我们想构造一个掩码(mask),它是全 1 或全 0

  • x ≠ 0 时 → mask = 0xFFFFFFFF
  • x == 0 时 → mask = 0x00000000

制造掩码:
mask = !!x; // 把 x 变成 0 或 1
mask = ~mask + 1; // 扩展成全 0 或全 1

  • !!x:两次逻辑非,确保结果只有 0 或 1
    • 比如:x = 5 → !!x = 1
      x = 0 → !!x = 0
  • ~mask + 1
    • 当 mask = 0 → (~0 + 1) = 0
    • 当 mask = 1 → (~1 + 1) = 0xFFFFFFFF

函数实现:

int conditional(int x, int y, int z) {int mask = (!!x << 31) >> 31;return (mask & y) | (~mask & z);}

tmin函数

函数要求:

函数名tmin
参数void
功能实现返回最小补码

实现分析:

最小的补码就是0x10000000,直接返回

函数实现:

int tmin(void) {return 0x1<<31;}

fitsBits函数

函数要求:

函数名fitsBits
参数int , int
功能实现若x能用n个bit表示则返回1,否则返回0

实现分析:

整体思路:

  • 用 n 位能表示的数,其符号扩展后应与原值相同;
  • 左移丢弃高位再右移回来,看是否变了。

函数实现:

int fitsBits(int x, int n) {int shift = 32 + (~n + 1); // 32 - nreturn !(((x << shift) >> shift) ^ x);}

dividePower2函数

函数要求:

函数名dividePower2
参数int , int
功能实现计算x/(2^n),其中0<=n<=30

实现分析:

正数右移n位即可;
负数需要补偿偏差使结果“向零取整”(而非向下取整)。

函数实现:

int dividePower2(int x, int n) {int sign = x >> 31;int bias = (1 << n) + ~0;  // 2^n - 1int add = sign & bias;return (x + add) >> n;}

negate函数

函数要求:

函数名negate
参数int
功能实现取相反数-x

实现分析:

直接按位取反加1即可

函数实现:

int negate(int x) {return ~x+1;
}

howManyBits函数

函数要求:

函数名howManyBits
参数int
功能实现计算一个整数 x 用补码表示所需的最少二进制位数。返回表示x所要用的最小bit数

实现分析:

x二进制补码最少位数
12011005
298010010101010
-510114
001
-111
0x800000001000...00032

要知道要多少位表示 x,实际上是找:

  • 对于正数:最高的 1 在第几位
  • 对于负数:最高的 0 在第几位(因为负数补码前面是 1)

所以要对数处理:

  • 对正数:不变;
  • 对负数:按位取反,相当于找“最高的 1”。

然后用位级的二分来进行查找最高的1

最终 b16 + b8 + b4 + b2 + b1 + b0 + 1 就是所需的位数。

+1 是因为还要包含符号位

函数实现:

int howManyBits(int x) {int b16, b8, b4, b2, b1, b0;int sign = x >> 31;    /* sign = 0 (x >= 0) or -1 (x < 0) */x = (sign & ~x) | (~sign & x);  /* if x negative, set x = ~x, else keep x */b16 = !!(x >> 16) << 4; /* if top 16 bits nonzero, add 16 */x >>= b16;b8 = !!(x >> 8) << 3;   /* if top 8 bits nonzero, add 8 */x >>= b8;b4 = !!(x >> 4) << 2;   /* if top 4 bits nonzero, add 4 */x >>= b4;b2 = !!(x >> 2) << 1;   /* if top 2 bits nonzero, add 2 */x >>= b2;b1 = !!(x >> 1);        /* if top 1 bit nonzero, add 1 */x >>= b1;b0 = x;return b16 + b8 + b4 + b2 + b1 + b0 + 1;
}

isLessOrEqual函数

函数要求:

函数名isLessOrEqual
参数int , int
功能实现若x<=y则返回1,否则返回0

实现分析:

判断大小转换成看两数之差 y - x >= 0,但是两数异号直接计算可能会溢出

所以我们必须先判断 x 与 y 的符号是否相同

情况1:x 与 y 符号不同

  • 如果 x 是负的,y 是正的 → 一定成立 (x ≤ y)
  • 如果 x 是正的,y 是负的 → 一定不成立 (x ≤ y)

情况2:x 与 y 符号相同

  • 用正常的差值判断:y - x >= 0

函数实现:

int isLessOrEqual(int x, int y) {int sx = x >> 31;          /* sign bit of x: 0 or -1 */int sy = y >> 31;          /* sign bit of y */int diff = sx ^ sy;        /* 1 if signs differ */int sub = y + (~x + 1);    /* y - x */int ssub = sub >> 31;      /* sign of (y - x) *//* If signs differ and x negative, x <= y. Else if signs same, check y-x >= 0 */int res = (diff & sx) | ((!diff) & (!ssub));return !!res;
}

intLog2函数

函数要求:

函数名intLog2
参数int
功能实现计算log2(x)并向下取整

实现分析:

这个问题的实质是找最高位的1在哪一位

二分法查找最高位的方式来实现:

设一个变量 ans = 0,表示当前找到了最高位的下标。

从高位向低位检测是否有 1:

  • 如果 x >> 16 不为 0 → 说明最高位至少在 [16, 31],那么 ans += 16
  • 再检测 x >> 8 不为 0 → ans += 8
  • 再检测 x >> 4 不为 0 → ans += 4
  • 再检测 x >> 2 不为 0 → ans += 2
  • 再检测 x >> 1 不为 0 → ans += 1

ans 就是 ⌊log₂(x)⌋

函数实现:

int intLog2(int x) {int ans = 0;int b16, b8, b4, b2, b1;/* check top 16 bits */b16 = !!(x >> 16) << 4; /* if high 16 bits set, add 16 */ans += b16;x >>= b16;/* check top 8 bits */b8 = !!(x >> 8) << 3;ans += b8;x >>= b8;/* check top 4 bits */b4 = !!(x >> 4) << 2;ans += b4;x >>= b4;/* check top 2 bits */b2 = !!(x >> 2) << 1;ans += b2;x >>= b2;/* check top 1 bit */b1 = !!(x >> 1);ans += b1;return ans;
}

floatAbsVal函数

函数要求:

函数名floatAbsVal
参数unsigned
功能实现返回浮点数f的绝对值
要求可以使用运算符,

实现分析:

  • 取绝对值:
    清除符号位即可(符号位在最高位)。
    uf & 0x7FFFFFFF
  • 检测 NaN:
    当指数全为 1(e = 0xFF000000)且尾数不为 0(f != 0)时,是 NaN。

函数实现:

unsigned floatAbsVal(unsigned uf) {unsigned mask = 0x7FFFFFFF;unsigned abs = uf & mask;if (abs > 0x7F800000)return uf;return abs;
}

floatScale1d2函数

函数要求:

可以使用 integer/unsigned, operations, ||, &&. also if, while

函数名floatScale1d2
参数unsigned
功能实现返回0.5*f

功能:
返回与表达式 0.5 * f位级等价的无符号整数。

  • 输入 uf 是一个单精度浮点数的位模式
  • 输出同样是一个位模式;
  • ufNaN,则返回原值。

实现分析:

  • 若输入为INF和NaN,那么直接返回
  • 若exp>1,保留小数位然后直接把exp-1,阶码也就减少1,达到了*0.5的目的
  • exp<=1,此时若直接把exp-1,那么exp将会小于等于0,实现不了f*0.5;
  • 所以将uf右移1位实现"exp-1"(若exp=1那么将会得exp=0,若exp=0那么exp的值不变)和小数部分的f*0.5。
  • 但是在这里要注意小数的舍入问题,若f的第0位和第1位都是1,那么需要给他加2。

函数实现:

unsigned floatScale1d2(unsigned uf) {int exp = (uf & 0x7fffffff)>>23;int sign = uf & 0x80000000;if((uf&0x7fffffff) >= 0x7f800000) return uf;if(exp > 1)    return (uf&0x807fffff)|(--exp)<<23;if((uf&0x3) == 0x3) uf = uf + 0x2;return ((uf>>1)&0xbfffffff)|sign;
}

floatFloat2Int函数

函数要求:
可以使用 integer/unsigned, operations, ||, &&. also if, while

函数名floatFloat2Int
参数unsigned
功能实现将f转换为int形式

实现分析:

  • 提取符号位 S、指数 E 和尾数 F
  • 计算真实指数 exp = E-127
  • 恢复尾数隐含 1 → M
  • 特殊情况:
    • E=255 → NaN/∞ → 返回 0x80000000
    • exp < 0 → |f|<1 → 返回 0
    • exp > 30 → 超出 int → 返回 0x80000000
  • 根据 exp 调整尾数得到整数部分:
    • exp > 23 → 左移
    • exp ≤ 23 → 右移
  • 根据符号返回正负整数

函数实现:

int floatFloat2Int(unsigned uf) {unsigned sign = uf >> 31;int exp = ((uf >> 23) & 0xFF) - 127;unsigned frac = uf & 0x7FFFFF;unsigned M = frac | 0x800000;unsigned val;if (((uf >> 23) & 0xFF) == 0xFF) return 0x80000000;if (exp < 0) return 0;if (exp > 30)return 0x80000000;if (exp > 23) {val = M << (exp - 23);} else {val = M >> (23 - exp);}return sign ? -val : val;
}
http://www.dtcms.com/a/550594.html

相关文章:

  • 两个不同git仓库,如何合并1个git仓库的提交到另1个仓库?
  • 南通网站建设top公司邮箱怎么申请的
  • 网站建设 数据上传 查询歌曲网站源码
  • Kubernetes 常见问题全解析
  • 网站建设合同有哪些杭州小程序开发
  • C++ 单调队列
  • 湖南省建设工程造价管理总站微网站是官网的手机站
  • 上证50期权的到期日期是什么时候?
  • 网站开发看谁的教程成都企业模板网站开发
  • 【.NET】WinForm中如何调整DataGridView控件的列宽?
  • 用asp.net做网站的书凡科h5制作
  • 请别人做网站会不会被盗枣庄建设局网站
  • 网站优化的意义跨境电商营销推广
  • 如何建网站要什么条件做网站国外网站
  • SAP 实施顾问全景指南
  • CS144 知识笔记一(网络概述)
  • 智慧团建网站没有验证码wordpress 说说功能
  • 嘉兴网站制作推广京东云wordpress
  • PostgreSQL 索引损坏问题排查以及修复
  • 网站建设步骤和流程秦皇岛市属于哪个省
  • 低价自适应网站建设贵阳建站
  • Rust 泛型参数的使用:从类型抽象到编译期优化的深度实践
  • 【Rust编程】深入解析 Rust gRPC 框架:Tonic
  • 建设银行指定网站wordpress站群模板
  • CSP-J教程——第一阶段——第二课:变量与数据类型
  • ie6网站模板西固网站建设平台
  • 网站建设公司大型区域工业互联网平台
  • Linux文件层次结构
  • qRT-PCR 分析
  • python进阶教程1:枚举值和类型标注