当前位置:   article > 正文

Csapp整数浮点数操作实验(精讲)

Csapp整数浮点数操作实验(精讲)

a. int conditional(int x, int y, int z)

  • 功能:实现与三目运算符表达式 x ? y : z 具有等价功能的函数
  • 合法的运算符:! ~ & ^ | + << >>
  • 可使用的运算符数:16
  • 难度:4
  • 寻找一种转换,使得当x非0时转变为0xFFFFFFFF,当x为0时不变。
    1. int conditional(int x, int y, int z) {
    2. //x不为0时结果为y,为0时结果为z.
    3. int test1,test2,test3;
    4. test1=(!!x);
    5. test1=(test1<<31)>>31; //获得!!x的值填充32位。
    6. test2=!x;
    7. test2=(test2<<31)>>31; //获得!x的值填充32位。
    8. test3=(test1&y)+(test2&z); //分别和y,z进行与运算即可得出结果。
    9. return test3;
    10. }

 b.int isNonNegative(int x)

  • 功能:当 x > y 时,返回1,否则返回0
  • 合法的运算符:! ~ & ^ | + << >>
  • 可使用的运算符数:24
  • 难度:3

功能:当 x >=0 时,返回1;否则返回0
判断符号位即可

  1. int isNonNegative(int x) {
  2. //判断x的符号位
  3. int test1=x>>31;//为0xFFFFFFFF则要return0,为0x00000000要return1.
  4. test1=!test1; //使用!将其变为0与1.
  5. return test1;
  6. }

c. int isGreater(int x, int y)

  • 功能:当 x > y 时,返回1,否则返回0
  • 合法的运算符:! ~ & ^ | + << >>
  • 可使用的运算符数:24
  • 难度:3

功能:当 x > y 时,返回1,否则返回0
可能有溢出的情况,所以将x和y分为同号和异号两种情况进行考虑
正 - 正 ——不会溢出,返回x-y-1符号位的取反即可(减1是为了排除相等的情况)
正 - 负 —— 函数必须 return 1
负 - 正 —— 函数必须 return 0,可以看到,异号状态返回值为y的符号位。
负 - 负——不会溢出,返回x-y-1符号位的取反即可(同理)

  1. int isGreater(int x, int y) {
  2. //需要判断x与y同号和x与y异号的情况。
  3. int equalval=x^y; //判断x与y相等及符号位是否相同。
  4. int subval=x+(~(y+1)+1); //计算x-y-1;
  5. int result=(((~subval)&(~equalval))+(y&equalval))>>31;//分别计算同号与异号的情况。
  6. //并取符号位。前一个为同号,后一个为异号
  7. result=result&0x01;
  8. return result;
  9. }

d. int absVal(int x)

  • 功能:计算x的绝对值
  • 合法的运算符:! ~ & ^ | + << >>
  • 可使用的运算符数:10
  • 难度:4

功能:计算x的绝对值
同样也是分为x为正和负两种情况考虑
若x为正数,则直接返回x
若x为负数,则返回~x+1

  1. int absVal(int x) {
  2. //x为正则返回x, x为负,则返回~x+1;
  3. int result,signbit;
  4. signbit=x>>31;//获得signbit扩充到32位的01序列,为00...00(x为正数) 或 11...11(x为负数)
  5. result=((~signbit)&x)+(signbit&(~x+1));//利用符号位计算结果。
  6. //若x为正数,则后半段为0,前半段为x
  7. //若x为负数,则前半段为0,后半段为~x+1
  8. return result;
  9. }

e.int isPower2(int x)

  • 功能:判断x是否恰好等于 $2^n$,如果等于则返回1,否则返回0
  • 提示:负数必然不是$2^n$
  • 示例:isPower2(5) = 0, isPower2(8) = 1, isPower2(0) = 0
  • 合法的运算符:! ~ & ^ | + << >>
  • 可使用的运算符数:20
  • 难度:4 

功能:判断x是否恰好等于 2^n,如果等于则返回1,否则返回0
考查2^n的位的性质
若 x为 2^n,则 x&(x-1)=0
假设 x为 2^5, 则 x=100000,x-1=011111。显然 x&(x-1)=0
但还需排除负数(即只有符号位为1的情况)和 0 的干扰
等价于判断 x>0
和上一个isGreater 函数方法类似,需要考虑 x<0时溢出的情况,所以分为x>=0和x<0两种情况。

  1. int isPower2(int x) {
  2. //首先2的幂有x&(x-1)为0的特征,然后只要判断x大于0(和isGreater判断方法一致)
  3. int signbit=(x>>31)&0x01;
  4. int signbit2=((x+~0x00)>>31)&0x01;
  5. int abzero=signbit+(signbit2&(~signbit));//判断是否大于0,大于0为0,否则为1
  6. int nature=x&(x+~0x00); //性质符合为0
  7. int result=abzero+nature;//两者都满足的情况下为0,其他情况都不为0.
  8. return !result;
  9. }

 

这段代码的作用是判断一个整数 x 是否为2的幂。
让我们逐步解释代码:

1.int signbit=(x>>31)&0x01;:这行代码提取了 x 的符号位,如果 x 是非负数,signbit 将为0;如果 x 是负数,signbit 将为1。
2.int signbit2=((x+~0x00)>>31)&0x01;:这行代码将 x 加上 -1(即取反加一),然后提取了结果的符号位,实现了一种获取 x 是否大于0 的方式。
3.int abzero=signbit+(signbit2&(~signbit));:这行代码根据 abzero 的定义判断 x 是否大于0。如果 x 大于0,则 abzero 为0,否则为1。
4.int nature=x&(x+~0x00);:这行代码计算了 x 与 x - 1 的按位与,如果 x 是2的幂,其结果将为0。
5.int result = abzero + nature;:这行代码将 abzero 和 nature 相加,如果 x 同时满足大于0且符合2的幂的性质,则 result 为0,否则不为0。
6.return !result;:最后,函数返回 !result,即如果 x 是2的幂,则返回1(真),否则返回0(假)。

f. unsigned float_neg(unsigned uf)

  • 功能:求浮点数f的相反数
  • 说明:参数uf为浮点数f为在计算机中的二进制编码所对应的无符号数。返回值为浮点数-f在计算机中的二进编码所对应的无符号数。
  • 合法的运算符:全部有符号数和无符号数的运算符、||、&&、if 和 while
  • 注意:如果输入为NaN,则返回值等于uf
  • 可使用的运算符数:10
  • 难度:2

功能:求浮点数f的相反数
说明:参数uf为浮点数f为在计算机中的二进制编码所对应的无符号数。返回值为浮点数f在计算机中的 二进编码所对应的无符号数。
合法的运算符:全部有符号数和无符号数的运算符、||、&&、if 和 while
注意:如果输入为NaN,则返回值等于uf
可使用的运算符数:10
难度:2

如题目要求,分为NaN情况和一般情况
NaN情况 :判断出来后,直接返回 uf 的值
NaN:即阶码位全为1,小数位不全为 0时为NaN
一般情况:根据 IEEE 754 原则,将 float 阶码位 ^ 1, 然后返回。

  1. unsigned float_neg(unsigned uf) {
  2. //分为NAN和规范数两种情况。
  3. unsigned result;
  4. int elsign=uf&0x7fffffff; //排除符号位影响。
  5. int exp=elsign>>23; //获得阶码位
  6. if((!(exp^0xff))&&(elsign^0x7f800000))//前一个判断阶码位是否全为1
  7. //后一个在前一个基础上判断小数字段是否不全为0
  8. return uf;
  9. result=uf^0x80000000;
  10. return result;
  11. }

 g. unsigned float_i2f(int x)

  • 功能:返回浮点数(float)x在计算机中的二进制编码所对应的无符号数
  • 合法的运算符:全部有符号数和无符号数的运算符、||、&&、if 和 while
  • 可使用的运算符数:30
  • 难度:4

功能:返回浮点数(float)x在计算机中的二进制编码所对应的无符号数
即把 x 转换为 浮点数类型对应的无符号数字
就是把(float)x的位表示放在一个无符号变量中返回

根据IEEE 754原则和向偶取整原则一步一步进行实现

IEEE 754 中 float x=(-1)^signbit * 2^(exp-Bias)(1+frac)
例:float f=15213.0 ,其二进制值为0011 1011 0110 1101. 在IEEE 754中
其位表示为:(-1)^0 * (1.1101101101101) * 2^13
exp=13+bias(在float中为127)=1000 1100(二进制)
frac=1101101101101…0(小数去掉1,共23位)
s=0

向偶舍入:(四舍六入五成双)
即规定的位后面>100,则进1
若<100,则舍去
若等于100,若此位为1,则进1;此位为0,则舍去。

  1. unsigned float_i2f(int x) {
  2. //即将x变为float型。按照IEEE和向偶取整的规则即可。
  3. int signbit,highbit,exp,fracbits,flag;
  4. unsigned temp,result;
  5. if(!x)
  6. return x; //由于规范数情况不包含0,所以先处理0情况。
  7. signbit=(x>>31)&0x01;
  8. if(signbit)
  9. x=~x+1; //获得符号位,并将x变为正值。
  10. highbit=0;
  11. temp=x;
  12. while(!(temp&0x80000000))
  13. {
  14. temp<<=1;
  15. highbit++;
  16. } //获得x的最高有效位,即确定fraction的位数。
  17. temp=temp<<1;
  18. exp=127+31-highbit; //根据单精度浮点数规则计算出exp,和fraction位数。
  19. fracbits=31-highbit;
  20. flag=0; //进行向偶舍入
  21. if((temp&0x1ff)>0x100)
  22. flag=1; //出现在规定位置后大于0b100的情况就进1.
  23. if((temp&0x3ff)==0x300)
  24. flag=1; //出现最后一位为1,且下一位为1的情况也进1(向偶取整)
  25. result=(signbit<<31)+(exp<<23)+(temp>>9)+flag;//计算最终结果
  26. return result;
  27. }

至此,完结撒花!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/454241
推荐阅读
相关标签
  

闽ICP备14008679号