lab1
一. 整型代码的实现与思路
该部分主要描述本次实验中整型代码设计思路
1.1 bitXor的代码与实现思路
- 代码设计如下
/*
* bitXor - 只使用 ~ 和 & 实现 x^y
* 例如: bitXor(4, 5) = 1
* 合法运算符: ~ &
* 最多运算符数量: 14
* 分值: 1
*/
int bitXor(int x, int y)
{
return ~(~(~x & y) & ~(x & ~y));
}
通过公式可以只用**~以及&**运算符完成该函数。
- 参考公式如下
x ⊕ y = x ‾ y + x y ‾ x y ‾ = x ‾ + y ‾ \begin{aligned}x\oplus y=\overline{x}y+x\overline{y}\\ \overline{xy}=\overline{x}+\overline{y}\end{aligned} x⊕y=xy+xyxy=x+y
1.2 tmin的代码与实现思路
- 代码设计如下
/*
* tmin - 返回补码表示的最小值
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 4
* 分值: 1
*/
int tmin(void)
{
return 1 << 31;
}
补码最小值为0x80000000,由于我们只能用到0xFF以下的格式,故将0x01向左移位31个比特位即可的到。
1.3 isTmax的代码与实现思路
- 代码设计如下
/*
* isTmax - 如果 x 是补码表示的最大值,则返回 1
* 合法运算符: ! ~ & ^ | +
* 最多运算符数量: 10
* 分值: 1
*/
int isTmax(int x)
{
return !(~(x + (1 << 31)));
}
补码最大值为0x7FFFFFFF,我们若想该值凑1,可以用该值与0x80000000相加可得到0xFFFFFFFF,该值按位取反并做**!**运算即可返回1,其他情况均可得到0。
1.4 allOddBits的代码与实现思路
- 代码设计如下
/*
* allOddBits - 如果所有奇数位都是 1,则返回 1
* 位的编号是从 0 (最低有效位 LSB) to 31 (最高有效位 MSB)
* 例如: allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 12
* 分值: 2
*/
int allOddBits(int x)
{
int m = (0xAA << 8) + 0xAA;
m = (m << 16) + m;
return !(m ^ (x & m));
}
该函数思路主要需要凑出掩码,用x与掩码或运算来表示奇数位的情况,再与掩码异或运算可得知各个奇数位是否为1,如果不是,那么做**!**判断之后返回0,反之则返回1。
掩码的设计主要通过2次移位运算获得,且第二次移位后需要加上第一次移位后的值。
1.5 negate的代码与实现思路
- 代码设计如下
/*
* negate - 返回 -x
* 例如: negate(1) = -1.
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 5
* 分值: 2
*/
int negate(int x)
{
return ~x + 0x01;
}
该部分取反只需返回x的按位取反加1即可。
1.6 isAsciiDigit的代码与实现思路
- 代码设计如下
/*
* isAsciiDigit - 如果 0x30 <= x <= 0x39 ('0' 和 '9'的 ASCII值)则返回 1
* 例如: isAsciiDigit(0x35) = 1.
* isAsciiDigit(0x3a) = 0.
* isAsciiDigit(0x05) = 0.
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 15
* 分值: 3
*/
int isAsciiDigit(int x)
{
return !(0x03 ^ (x >> 4)) & !!((x + 0x06) & 0x10);
}
return后面的表达式以**&**左右分为两个部分。
第一个部分的工作主要判断x的第一个字节的高四位是否为0011(3),以及第一个字节以外的字节是否全部为0,这一步主要是为了第二部分只考虑第一字节的低四位的情况。
第二个部分我们只需要保证第一字节的低四位是否为0~9,这里我们只需要加上6判断是否溢出即可。这里由于第一部分已经保证第一字节高四位为0011(3),故溢出一位会使高四位变为0100(4),然后通过简单的**&**运算即可获得答案。
1.7 conditional的代码与实现思路
- 代码设计如下
/*
* conditional - 实现条件运算符 x ? y : z
* 例如: conditional(2,4,5) = 4
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 16
* 分值: 3
*/
int conditional(int x, int y, int z)
{
int m = !!x;
m = ~m + 1;
return (m & y) + (~m & z);
}
掩码部分我们希望通过x的值使其为0xFFFFFFFF或者0x00000000,这样我们就能通过简单的**&**运算实现返回值。
对于x只需要两次**!**运算即可得到其条件值是0还是1,之后取负可以得到想要的值。
1.8 isLessOrEqual的代码与实现思路
- 代码设计如下
/*
* isLessOrEqual - 如果 x <= y 返回 1, 否则返回 0
* 例如: isLessOrEqual(4,5) = 1.
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 24
* 分值: 3
*/
int isLessOrEqual(int x, int y)
{
int yMx = (y + (~x + 0x01)) >> 31; // yMx 表 y-x
int s = (x >> 31) ^ (y >> 31); // s 表 x与y是否符号位相同
return (!yMx & !s) | !!(s & (x >> 31));
}
参照注释可以很容易理解并得到yMx以及s两个变量,后面只需确保同号时y-x大于0取反(这里取反主要为了使我们可以忽略等于的情况,并且同号时不会发生溢出现象),以及异号时x小于0,这样便可以判断x是否小于等于y。
1.9 logicalNeg的代码与实现思路
- 代码设计如下
/*
* logicalNeg - 实现逻辑非 ! 运算符, 使用除 ! 之外的其他允许使用的运算符
* 例如: logicalNeg(3) = 0, logicalNeg(0) = 1
* 合法运算符: ~ & ^ | + << >>
* 最多运算符数量: 12
* 分值: 4
*/
int logicalNeg(int x)
{
return ((x | (~x + 0x01)) >> 31) + 0x1;
}
0除外,x与所有**-x做或运算都不会得到0(这里取x的负值而不是按位取反是因为前者对所有数的运算结果都是1),故x与-x**或运算后取符号位加1即可得到想要的值。
1.10 howManyBits的代码与实现思路
- 代码设计如下
/* howManyBits - 返回补码表示 x 所需要的最少位数(复杂题,选做)
* 例如: howManyBits(12) = 5
* howManyBits(298) = 10
* howManyBits(-5) = 4
* howManyBits(0) = 1
* howManyBits(-1) = 1
* howManyBits(0x80000000) = 32
* 合法运算符: ! ~ & ^ | + << >>
* 最多运算符数量: 90
* 分值: 4
*/
int howManyBits(int x)
{
int s = x >> 31;
x = (s & ~x) | (~s & x); // 消除负数,统一为正数
int m16 = (~(!!(x >> 16)) + 0x01) & 0x10;
int m8 = (~(!!(x >> (m16 + 0x08))) + 0x01) & 0x08;
int m4 = (~(!!(x >> (m16 + m8 + 0x04))) + 0x01) & 0x04;
int m2 = (~(!!(x >> (m16 + m8 + m4 + 0x02))) + 0x01) & 0x02;
int m1 = (~(!!(x >> (m16 + m8 + m4 + m2 + 0x01))) + 0x01) & 0x01;
int m0 = (~(!!(x >> (m16 + m8 + m4 + m2))) + 0x01) & 0x01;
return m16 + m8 + m4 + m2 + m1 + m0 + 1;
}
该问题我们主要探究:对于正数最高位为1的位置是第几个,对于负数而言我们需要判断最高位为0的位置为第几个,当我们第二行代码执行完毕后负数被化为正数,故同样需要寻找最高位为1的位置,最后统一加上符号位即可判断x所需要最少位数。
代码中m****表示以多少数开始判断1在左还是右(例如m16表示我们以该数第16位为界限,第一个1在高16位还是低16位,在高16位则返回16,低16位则返回0),紧接着我们下一个m8**判断高或者低16位的高或者低8位1的位置,依次类推,我们将各m相加以及符号位相加可得到答案。(特别注意m0和m1组合主要为了判断最后两位的组合情况,若为00则返回0,01则返回1,10和11均返回2)
二. 浮点型代码的实现与思路
该部分主要描述本次实验中浮点型代码设计思路
2.1 floatScale2的代码与实现思路
- 代码设计如下
/*
* floatScale2 - 为浮点型参数 f 返回与表达式 2*f 等价的位级表示
* 参数和返回值都以 unsigned int 传递, 但是它们将被解释成位级表示的单精度浮点值
* 当参数是 NaN, 返回参数
* 合法运算符: 任何 int/unsigned 支持的运算符包括 || && 还有 if, while
* 最多运算符数量: 30
* 分值: 4
*/
unsigned floatScale2(unsigned uf)
{
int e = (uf & 0x7F800000) >> 23;
int s = uf & (1 << 31);
if (e == 0x00)
return uf << 1 | s;
if (e == 0xFF)
return uf;
if (e++ == 0xFF)
return (0x7F800000 | s);
return (e << 23) | (uf & 0x807FFFFF);
}
该问题主要将溢出与非规格数思考清楚即可。
第一个if主要对非规格数进行返回,此时只需要简单的移位一次并加上符号位即可获得。第二个if主要对溢出进行返回,依据题目返回本身即可。第三个if主要对e做自加判断位移一次是否溢出,若等于0xFF则返回最大值。最后一个return只需要简单的将阶码(已经自加过)拼回去即可。
2.2 floatFloat2Int的代码与实现思路
- 代码设计如下
/*
* floatFloat2Int - 为浮点型参数 f 返回与表达式 (int)f 等价的位级表示 (复杂题,选做)
* 参数和返回值都以 unsigned int 传递, 但是它们将被解释成位级表示的单精度浮点值
* 超出表示范围的(包括 NaN 和 infinity) 应该返回 0x80000000u
* 合法运算符: 任何 int/unsigned 支持的运算符包括 || && 还有 if, while
* 最多运算符数量: 30
* 分值: 4
*/
int floatFloat2Int(unsigned uf)
{
int e = ((uf & 0x7F800000) >> 23) - 0x7F;
int f = ((uf & 0x007FFFFF) | 0x00800000);
if (!(uf & 0x7FFFFFFF) || e < 0)
return 0;
if (e > 31)
return 0x80000000;
if (e > 23)
f = f << (e - 23);
else
f = f >> (23 - e);
if (!(uf >> 31))
return f;
else
return ~f + 1;
return 1;
}
首先取出阶码和尾码的值。第一个if判断是否为0或者非规格数,这两类可以返回0。第二个if判断是否越界,越界则按题目要求返回即可。第三个if判断尾码左移或右移。通过上面的几个if基本包括了所有情况。最后通过判断符号位返回相应值。
2.3 floatFloat2Int的代码与实现思路
- 代码设计如下
/*
* floatPower2 - 为任意的 32位 int x 返回与表达式 2.0^x (2.0 的 x 次幂) 等价的位级表示
* 返回的 unsigned 值应该有和单精度浮点值 2.0^x 一模一样的位级表示
* 如果结果太小无法表示成 denorm 时,则返回 0
* 如果太大,则返回 +INF.
*
* 合法运算符: 任何 int/unsigned 支持的运算符包括 || && 还有 if, while
* 最多运算符数量: 30
* 分值: 4
*/
unsigned floatPower2(int x)
{
int INF = 0xFF << 23;
int e = x + 0x7F;
if (e <= 0)
return 0;
if (e >= 0xFF)
return INF;
return e << 23;
}
首先求得INF并求阶码。两个if只需简单的依照题目要求返回即可,最后将阶码左移返回得到答案。
三. 代码测试部分
该部分主要展示代码测试截图
- 代码测试输出
root@Nava9:~/Linux_lab/lab1# ./btest
Score Rating Errors Function
1 1 0 bitXor
1 1 0 tmin
1 1 0 isTmax
2 2 0 allOddBits
2 2 0 negate
3 3 0 isAsciiDigit
3 3 0 conditional
3 3 0 isLessOrEqual
4 4 0 logicalNeg
4 4 0 howManyBits
4 4 0 floatScale2
4 4 0 floatFloat2Int
4 4 0 floatPower2
Total points: 36/36