实验目的:
通过此次实验,熟悉整型及浮点数的位表达形式,通过位运算了解常用二进制运算的方法。
实验过程:
通过题目要求通过位运算完成INTEGER - 整数部分:bitXor、tmin、isTmax、allOddBits、negate
、isAsciiDigit、conditional、isLessOrEqual、logicalNeg、howManyBits以及FLOAT - 浮点数部分:floatScale2、floatFloat2Int、floatPower2共13个实验
实验原理:
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 ~(~x&~y)&~(x&y);
}
实验要求: 实现异或操作
应用德摩根率
2.tmin
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return (0x1<<31);
}
实验要求:返回二进制中的最小值
由于采用二进制补码进行操作,只需将0x1左移31位
3.isMax
/*
* 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 !(~(1 << 31) ^ x);
}
实验要求:判断x是否为2进制补码中最大值
先用~(1<<31)将二进制补码中的最大值表示出来,再将x与二进制中最大值进行按位异或,若x是最大值,则!后为1;若x不是最大值,则!后为0.
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) {
int flag = 1<<1;
flag =flag|(flag<<2);
flag =flag|(flag<<4);
flag =flag|(flag<<8);
flag =flag|(flag<<16);
return !((flag&x)^flag);
}
实验要求:二进制下如果所有偶数位都是1则返回1,否则返回0。
先将flag通过取或复制的方式得到 0xAAAAAAAA,之后将flag与x进行&操作,得到的结果奇数位均为0,偶数位数字与x相同;再将结果与flag进行异或,判断x的偶数位是否均为1。
5.negate
* negate - return -x
* Example: negate(1) = -1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 5
* Rating: 2
*/
int negate(int x){
return ~x+1;
}
实验要求:输出相反数
根据二进制补码原理,对x进行取反再加1后即可得到x的相反数。
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) {
//找到关系,42,43不同时为一,前8位为0
return !(((~0xFF)&x)+((0xF0&x)^0x30)+!((12&x)^12)+!((10&x)^10));
return 2;
}
实验要求:判断输入数据是否再0x30~0x39
0x30到0x39之间的数有如下规律:前八位均为零;从低位数第4位和第2位不同时为一;第4位和第3位不同时为一;于是可以进行如上的判断。
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) {
//先判断x的布尔型
x=~(!x)+1;//x==0?0xffffffff:0x00000000
return (y&(~x)|z&x);
}
实验要求:返回x ? y : z,即若x为真,返回y;若x为假,返回z。
因此该实验要首先判断x的布尔型:将x变为!x的相反数;即若x为真,x的值赋为1;若x为假,x的值赋为0;
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) {
int signx = (x >> 31) ; //
int signy = (y >> 31) ;
int signy_x = ((y + ~x + 1) >> 31) ;
return (signx & !signy) | (!(signx ^ signy) & !signy_x);//比较符号位是否相同,
}
实验要求:判断两个操作数是否符合小于等于关系:
首先,比较x和y的符号位是否相同;
signy_x = ((y + ~x + 1) >> 31)表示(y-x)的符号位
若x,y符号为不同,通过(signx & !signy)即可返回正确结果;若x,y符号位相同,则(!(signx ^ signy)为1 ,此时若y大于等于x,则!signy_x也为1;若y小于等于x,则!signy_x为0;综上可以输出正确结果
9.logicalNeg
int logicalNeg(int x) {
return ((x|(~x+1))>>31)+1;//有符号数执行算术右移,无符号数进行逻辑右移
}
实验要求:实现逻辑!操作
先进行x|(~x+1)操作,若x非0,则x|(~x+1)最高位一定为1,算术右移31位后得到ffffffff,再加1为0;若x为0,则x|(~x+1)最高位为0,算术右移31位再加1后为1;
故该操作可以实现!操作
10.howManyBits
实验要求:返回在二进制补码中表示 x 所需的最小位数
int howManyBits(int x) {
int sign = x >> 31;
x = (~sign & x) | (sign & ~x); // (x >= 0) ? x : ~x
int b16 = (!!(x>>16))<<4;
x = x >> b16;//,若查找到了,右移16位,继续查找
int b8 = (!!(x>>8))<<3;
x = x >> b8;
int b4 = (!!(x>>4))<<2;
x = x >> b4;
int b2 = (!!(x>>2))<<1;
x = x >> b2;
int b1 = !!(x>>1);
x = x >> b1;
return (1+b1+b2+b4+b8+b16+x);
}
对于负数,最少位数的二进制表示为一位符号位加上负数取反后的最高位1的位数;对于正数,最少位数的二进制表示为一位符号位加上其最高位1的位数,因此该实验的关键在于判断x中第一个出现1的位置.
先将x取绝对值,采用类似7.conditional中操作,x= (~sign & x) | (sign & ~x).采用二分查找法。对前16为判断,若其中存在1,将x右移16位继续查找,进行迭代操作.
最终返回操作次数之和加1即可.
11.floatScale2
实验要求:对于入参unsgned uf,以float来解释其二进制位,若uf为NaN或INF,直接返回;否则计算uf*2并返回。
unsigned floatScale2(unsigned uf) {
int sign = uf & 0x80000000;
int e = uf & 0x7f800000;
int f = uf & 0x007fffff;
if (e == 0)
return (uf << 1) | sign;
if (e == 0x7f800000)
return uf;
e += 0x00800000;
if (e == 0x7f800000)
return 0x7f800000 | sign;
return sign | e | f; // 拼回去
根据float类型储存规则
分别用sign、e、f取出uf的符号位,指数以及有效数
1.e==0,指数为0,则直接左移1位返回×2后的值;
2.e==0x7f800000,为INF,直接返回uf;
3.将指数×2后判断是否为INF,若为INF,直接返回;若非INF,返回sign|e|f.
12.floatFloat2Int
实验要求:传入一个无符号整数 uf,把它当作单精度浮点数,返回它截断后的整数部分。也就是 (int)uf。如果出现溢出,则返回 0x80000000u
int floatFloat2Int(unsigned uf) {
int sign,e,f;
sign = uf >> 31;
e = ((uf & 0x7f800000)>>23)-127;
f = (uf&0x007fffff)|0x00800000;
if(!(uf&0x7fffffff)) return 0;
if(e > 31) return 0x80000000;
if(e < 0) return 0;
if(e > 23) f <<= (e - 23);
else f >>= (23 - e);
if(!((f >> 31)^sign)) return f;
else if (f>>31) return 0x80000000;
else return ~f + 1;
分别取出sign,e,f. 这里e是实际的指数.f将省略的1也加上
1.如果uf为0,则返回0
2.如果真正的指数>31,则返回溢出值
3.真正如果的指数小于零则返回零,因为0<uf<1
4.考虑真正的指数和23的大小,进行移位
如果符号相同直接返回原值
如果为负(原来为正),返回溢出值
如果为正(原来为负),返回相反数
13.floatPower2
实验要求:计算浮点数2.0^x;若结果太小返回0,太大返回 +INF
unsigned floatPower2(int x) {
int exp = x + 127;
if(exp <= 0) return 0;
if(exp >= 255) return 0x7f800000;
return exp << 23;
}
注记:NAN:not a number//denorm:those numbers very close to zero //INF:infinite
根据float类型编码原理,把x看成真正的指数,exp=x+127;
1.exp<=0,denorm,返回0;
2.exp>=255,INF
3.要返回一个float类型的数,其尾码全为0,因此只需将exp左移23为至指数区即可。
测试数据
实验小结:
作为计科大一学生,没有接触过计算机系统相关知识,初次上手该实验感觉较有趣也富有挑战性,更深层次了解了二进制编码