自动测试
使用 dlc 检测代码是否符合题目要求
1
unix> ./dlc bits.c
编译并调用自动测试程序
1
2unix> make
unix> ./btest
题目
bitXor(x, y)
要求:仅使用 ~ 和 & 完成异或运算。
运算:~ &
做法:画出 & 运算符的真值表,配合 ~ 运算符易得。
1 | int bitXor(int x, int y) { |
tmin()
要求:返回二进制补码表示的最小整数。
运算: ! ~ & ^ | + << >>
做法:补码表示的最小整数为
1 | int tmin(void) { |
isTmax(x)
要求:判断 x 是否为补码表示的最大整数。
运算:! ~ & ^ | +
做法:当 x 为最大整数时,补码表示为
然而当 x = -1 时,前述等式也成立,因此需要排除掉这种情况。
1 | int isTmax(int x) { |
allOddBits(x)
要求:判断 x 二进制表示下的奇数位是否全为 1。
运算:! ~ & ^ | + << >>
做法:规则允许使用最大为 0xFF 的整数,因此可使用 & 运算每 8 位合并 x 的所有位,然后使用 ^ 运算判断奇数位是否全为 1。
1 | int allOddBits(int x) { |
negate(x)
要求:计算返回 -x。
运算:! ~ & ^ | + << >>
做法:首先将有符号数转换成无符号数以便于位运算处理。
相互转换的规则是:数值可能会改变,但位模式不变。因此,补码转换为无符号数为:
在
1 | int negate(int x) { |
isAsciiDigit(x)
要求:判断值 x 是否在范围 [0x30, 0x39] 中。
运算: ! ~ & ^ | + << >>
做法:首先前
剩余 4 位划分成 [0, 7] 和 [8, 9] 的两个区间来处理。
第 4 位为 0 时,剩余 3 位可为任意值,表示区间 [0, 7]。
第 4 位为 1 时,8 和 9 的二进制表示分别为 1000 和 1001,即高 3 位必须为 100。
利用掩码表示的思想,x 为 110111(0x37) 的子集或是 111001(0x39) 的子集。
1 | int isAsciiDigit(int x) { |
conditional(x, y, z)
要求:执行三目运算符 x ? y : z:当 x 不为 0 时,返回 y;否则返回 z。
运算:! ~ & ^ | + << >>
做法:核心思想是利用 x 得出位模式等于 -1(全为 1)的值,使用 & 运算和 ~ 运算得到 y 或 z 的位模式,最后使用 | 得到结果。
! 运算将 x 映射到 [0, 1] 区间,使用函数
当
当
1 | int conditional(int x, int y, int z) { |
isLessOrEqual(x, y)
要求:判断 x <= y。
运算:! ~ & ^ | + << >>
做法:将问题转换成判断
当
进一步地,当
注意取符号位是 &1 操作不可省略,因为机器使用了算术右移。
1 | int isLessOrEqual(int x, int y) { |
logicalNeg(x)
要求:计算 !x:当 x = 0 时返回 1;当 x ≠ 0 时返回 0。
运算:~ & ^ | + << >>
做法:当
1 | int logicalNeg(int x) { |
howManyBits(x)
要求:使用二进制补码表示 x 的最少位数。
运算:! ~ & ^ | + << >>
做法:当
首先考虑将负数取反,将问题统一成计算 1
的最高位,利用算术右移即可完成, 即
然后使用二分法计算 1 的最高位:判断高 16 位是否大于 0,若大于 0 说明高 16 位中存在 1,否则 1 在低 16 位中。使用 conditional 函数更新 x(取出高 16 位或低 16 位)。迭代判断 8 位、4 位等等。
1 | int howManyBits(int x) { |
floatScale2(uf)
要求:计算 2 * uf,若 uf 为特殊值值时,直接返回 uf。
运算:Integer/unsigned 相关运算;||,&&,if 和 while 等判断语句。
做法:这道题需要对浮点数表示比较了解,单精度(float)表示包括:1 位符号,8 位阶码,23 位尾数。这里使用 e 表示阶码的无符号数,B 表示阶码的偏置值,f 表示尾数值。
当 e 全 0 时,表示非规格化的值,真实值
。 乘上系数 2 时,阶码是否变动看 2f 是否大于等于 1,即 f 最高位是否为 1。由于阶码在尾数的高位,该情况下位数左移 1 位即可。
当 e 不全 0 也不全 1 时,表示规格化的值,真实值
。 阶码 + 1 即可。
当 e 全 1 时,表示特殊值。
1 | unsigned floatScale2(unsigned uf) { |
floatFloat2Int(uf)
要求:将浮点数 uf 转换成整数。
运算:Integer/unsigned 相关运算;||,&&,if 和 while 等判断语句。
做法:当浮点数是 0 和规格化的值时,才有可能用整数表示,其余部分注意整数表示范围即可。
1 | int floatFloat2Int(unsigned uf) { |
floatPower2(x)
要求:使用浮点数表示 2^x。无法表示时:过小返回 0,过大返回 +INF。
运算:Integer/unsigned 相关运算;||,&&,if 和 while 等判断语句。
做法:
1 | unsigned floatPower2(int x) { |