深入理解计算机系统data lab

Data Lab

Wercker Wercker Wercker
Thank for watch

实验梗概:

解决比特难题,整数操作问题和浮点问题
比特难题:

名字 描述 评分
bitAnd(x,y) 使用|和~完成x&y 1
getByte(x,n) 从x得到第n字节的数 2
logicalShift(x,n) 使用算数右移完成逻辑右移 3
bitCount(x) x中有多少个1 4
bang(x) 不用!实现!操作符 4

整数操作问题

名字 描述 评分
tmin() 返回最小补码 1
fitsBits(x,n) x能用n bits表示吗 2
divpwr2(x,n) 计算 x/(2^n) 2
negate(x) 不用负号完成取反 2
isPosition(x) x大于0吗 3
isLessOrEqual(x,y) x小于等于y吗 3
ilog2(x) 计算floor(log2(x)) 4

浮点问题

名字 描述 评分
float_neg(uf) 取反 2
float_i2f(x) 计算(float)x 4
float_twice(uf) 计算x*2.0 4

实验指南

完成实验你只需要修改bits.c.配套有btest,dlc和fshow配件。

在本实验中:
不能使用循环,分支语句。只允许使用顺序语句。
只能使用 ! ˜ & ˆ | + << >>(甚至更少)
只能使用小于256的常数。
只能使用int或unsigned,不能使用float,不能类型转换
在每个函数的注释有更清楚的任务要求

工具介绍

btest

这个工具检查bits.c里函数的正确性。(每次修改完bits.c都要重新make)
./btest 检查你的所有答案是否正确
./btest -f bitAnd 检查bitAnd是否正确。

dlc

./dlc bits.c 检查你使用了非法操作符,或过多的操作符,或循环,分支语句
./dlc -e bits.c 检查你每个函数使用的操作符数量


driver

./driver.pl 算出你的最后得分

解法

bitAnd

要求:使用~|完成 x&y
例:bitAnd(6,5)=4
允许操作 ~ |
操作符限定:8
分值:1


摩根定律的运用

int bitAnd(int x, int y) {
  return ~(~x | ~y);
} 




getByte

要求:从x中提取第n字节
例:bitAnd(0x12345678,1)=0x56
允许操作 ! ~ ^ | + << >>
操作符限定:6
分值:2


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

}




logicalShift

要求:用算数右移实现逻辑右移
例:logicalShift(0x87654321,4)=0x08765432
允许操作 ! ~ ^ & ^ + << >>
操作符限定:20
分值:3


int logicalShift(int x, int n) {
    int xsra = x >> n;
    int mask = ~0<<(32+~n)<<1;
    mask = ~mask;
    return xsra&mask;
}




bitCount

要求:计算x里有多少个1
例:bitAnd(5)=2 bitCount(7)=3
允许操作 ! ~ & ^ | + << >>
操作符限定:40
分值:4


首先将32位数分为8组,对于每四位数,通过三次移位运算统计每组数中1的个数,然后将前16位与后16位相加,将1的个数浓缩在16位中,再以同样的方法将1的个数整理到4位中,得到最后结果。·
类似思路

int bitCount(int x) {
    int i = 0x11 | (0x11 << 8);
    i = i + (i << 16);
    int sum = 0;

    sum += x & i;
    sum += (x >> 1) & i;
    sum += (x >> 2) & i;
    sum += (x >> 3) & i;

    i = 0xff + (0xff << 8);
    sum = (sum >> 16) + (sum & i);

    i = 0x0f + (0x0f << 8);
    sum = ((sum >> 4) & i) + (sum & i);

    i = 0xff;
    sum = (sum & i) + (sum>>8);

    return sum;
}




bang

要求:不用!实现!x
例:bang(3)=0,bang(0)=1
允许操作 ~ & ^ | + << >>
操作符限定:12
分值:4


如果不懂,可以看下面链接,有讲的很详细
思路

int bang(int x) {
        x = (x>>1)|x;
        x = (x>>2)|x;
        x = (x>>4)|x;
        x = (x>>8)|x;
        x = (x>>16)|x;
        return ~(x & 1)+2;
}




tmin

要求:返回最小补码
允许操作 ! ~ & ^ | + << >>
操作符限定:4
分值:1


int tmin(void) {
    return 0x80<<24;
}




fitsBits

要求:n bit能表示x吗
例:bitAnd(5,3)=0 bitCount(-4,3)=1
允许操作 ! ~ & ^ | + << >>
操作符限定:15
分值:2


这题其实考补码符号扩展,将x右移(n+~0)位,即得到了符号位
负数:0xffffffff正数0x0。

int fitsBits(int x, int n) {
    x = x>>(n+~0);   
    return !x | !(x+1); 
}




divpwr2

要求:计算x/(2^n) 0<=n<=30,向0舍入
例:divpwr2(15,1)=7 divpwr2(-33,4)=-2
允许操作 ! ~ & ^ | + << >>
操作符限定:15
分值:2


这题,如果x小于0,要加上偏置。

int divpwr2(int x, int n) {
    int sign = (x>>31);    
    x = x + (sign & ((1<<n)+~0) );         
    return x >> n;
}




negata

要求:取反
例:negata(1)=-1
允许操作 ! ~ & ^ | + << >>
操作符限定:5
分值:2


相信国产的书都是这么教补码的(道理在书上的web sides上。这里给出原理网址所以不赘述了
int negate(int x) {
return ~x + 1;
}



isPositive

要求:x大于0吗
例:isPositive(-1)=0
允许操作 ! ~ & ^ | + << >>
操作符限定:8
分值:3


把情况分为正数,0,负数就好懂了

int isPositive(int x) {
  return !(x>>31) & !!x;
  //or
 //retunrn !(x>>31);
}




isLessOrEqual

要求:y大于等于x吗
例:isLessOrEqual(4,5) = 1.
允许操作 ! ~ & ^ | + << >>
操作符限定:24
分值:3


equal是符号相同。在这个情况下,如果x更大,~y+x是0.。如果y更大。~y+x是1
nequal是符号不同.

int isLessOrEqual(int x, int y) {
    unsigned sign_x = x>>31;  
    unsigned sign_y = y>>31;   
    unsigned equal = !(sign_x ^ sign_y) & ((x+~y)>>31);
    unsigned nequal = sign_x & !sign_y;
    return equal | nequal; 
}




ilog2

要求:计算floor(log2(x))
例:ilog2(16) = 4
允许操作 ! ~ & ^ | + << >>
操作符限定:90
分值:4


这个问题可以转换为x最高位是几
前半段思路
后半段确定最高位是第几位
bit_16确定前16位有没有。如果有。bit_16=16,且x右移16位,
bit_8确定前8位有没有。如果有。bit_8=8,且x右移8位,
bit_4确定前4位有没有。如果有。bit_4=4,且x右移4位,
bit_2确定前2位有没有。如果有。bit_2=2,且x右移2位,
bit_1确定前1位有没有。如果有。bit_1=1,且x右移1位,
最后相加,即可知道最高位是几

int ilog2(int x){
    x|=x>>1;  
    x|=x>>2;  
    x|=x>>4;  
    x|=x>>8;  
    x|=x>>16;  
    x = x^(x>>1);
    int bit_16,bit_8,bit_4,bit_2,bit_1;
    bit_16 = !(!(x>>16))<<4;
    x = x>>bit_16;
    bit_8 = !(!(x>>8))<<3;
    x = x>>bit_8;
    bit_4 = !(!(x>>4))<<2;
    x = x>>bit_4;
    bit_2 = !(!(x>>2))<<1;
    x = x>>bit_2;   
    bit_1 = !(!(x>>1));

    return bit_16+bit_8+bit_4+bit_2+bit_1;
}




float_neg

要求:取反,如果x是NaN,返回x
允许操作 循环,分支等等都能用,除了float类型和强制转换类型
操作符限定:10
分值:2


题目说了,注意NaN,那咱们就注意NaN

unsigned float_neg(unsigned uf){
    unsigned exp = uf>>23 &0xFF;
    unsigned frac = uf & 0x7FFFFF;
    if(exp==0xFF && frac!=0)
        return uf;
    unsigned mask = 1<<31;
    return uf ^ mask;
}




float_i2f

要求:返回(float)x
例:ilog2(16) = 4
允许操作 ! ~ & ^ | + << >>
操作符限定:30
分值:4


首先:要找到该int的最高位数,这样确定位移的大小

当左移时,自然不用考虑舍入的问题。

当右移时,要考虑最大舍入+偶数舍入,这是最需要思考的地方

unsigned float_i2f(int x) {
    if(x==0)
        return 0;
    unsigned sign = !!(x>>31);
    if(x<0)
        x = ~x+1;
    unsigned exp =127;
    unsigned frac =x;
    //find the highest bit 
    unsigned  j;
    for (j = (sizeof(int) << 3) - 1; j >= 0; --j) {
        if ((frac >> j) & 1)
            break;
    }
    if(j<23){
        frac <<=(23-j);
    exp += j;
    }
    else{
        frac>>=(j-23);
        exp +=j;
        unsigned mask = (1 << (j - 23)) - 1;
        if ((x&mask) >(1 << (j - 24))) 
            frac++; //需要舍入到大值
        else if ((x&mask) == 1 << (j - 24) && (frac & 1)) 
            frac++; //舍入到偶数
        if (frac == (1 << 24))
            exp++; //舍入到偶数超过(1<<24) - 1,指数需要再加1
    }
    frac&=0x7FFFFF;
    return (sign<<31) | (exp<<23) | frac;
}




float_twice

要求:返回x*2.0,如果是NaN,返回x
允许操作 ! ~ & ^ | + << >>
操作符限定:30
分值:4


分情况讨论
f 非规格是 小数左移一位即时*2.0

f在最大非规格 用公式推出即可

f在规格数里。将exp+1即时*2

f在规格数里,exp已经到1111 1110.再乘2.0就变为了+∞

f位无穷大或者NaN,直接返回f

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

    if(exp==0 && frac< 0x7FFFFF)
        frac <<=1;
    else if(exp ==0 && frac==0x7FFFFF){
        exp+=1;
        frac = 0x7FFFFE;
    }
    else if(exp==0xFE){
        exp = 0xFF;
        frac=0;
    }
    else if(exp==0xFF)
        return uf;
    else
        exp+=1;
    return (sign<<31) | (exp<<23) | frac;
}

猜你喜欢

转载自blog.csdn.net/weixin_41256413/article/details/80172553
今日推荐