深入理解计算机系统第二章:信息的表示和处理 家庭作业

开工日期:2018年4月11号    完成日期:2018年4月26日     耗时:15日

配置:centOS 7 64位+gcc4.8.5

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.58

int main()
{
    int a=1;
    return *((unsigned char *)&a);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.59

int operator(int x,int y)
{
  return x&0xff | y&(~0xff);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.60

unsigned replace_byte(unsigned x,int i,unsigned char b)
{
  unsigned int offset=0xff;    
  offset=offset<<(i<<3);       //为什么要*8呢,因为编号从0~w/8-1。    
  x=x&~offset;
  x=x | b<<(i<<3);
  return x;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.61

a:

int is_INT_MAX(int x)

{
  return !(x+1);

}

b:

int is_INT_MIN(int x)
{
  return !(~x+1);
  //return is_INT_MAX(x-1);      //solution 2

}

c:

int is_low_byte(int x)
{
  //x=x&0x000000ff;           //solution 1
  //return is_INT_MIN(x-0xff);
  x=x|0xffffff00;
  return is_INT_MAX(x);

}

d:

int is_high_byte(int x)
{
  x=x>>((sizeof(int)-1)<<3);
  return is_low_byte(x);

}

测试单元:

int main()
{
  int x=0;
  int y=0xffffffff;
  int z=0xff123456;
  int p=0x0000000ff;
  printf("%d\n",is_INT_MAX(x));
  printf("%d\n",is_INT_MAX(y));
  printf("%d\n\n",is_INT_MAX(z));
  printf("%d\n",is_INT_MIN(x));
  printf("%d\n",is_INT_MIN(y));
  printf("%d\n\n",is_INT_MIN(z));
  printf("%d\n",is_low_byte(x));
  printf("%d\n",is_low_byte(y));
  printf("%d\n",is_low_byte(z));
  printf("%d\n\n",is_low_byte(p));
  printf("%d\n",is_high_byte(x));
  printf("%d\n",is_high_byte(y));
  printf("%d\n",is_high_byte(z));
  printf("%d\n",is_high_byte(p));
  return 0;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.62

int int_shifts_are_arithmetic()
{
  return ~0==(~0>>1);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=


2.63

unsigned srl(unsigned x,int k)
{
  unsigned xsra = (int) x >> k;
  unsigned sll = ~0<<(sizeof(int)<<3-k);
  sll=~sll;
  return xsra&sll;
}
int sra(int x,int k)
{
  int xsrl = (unsigned) x >> k;
  int sll  = ~0<<(sizeof(int)<<3-k);
  return xsrl+sll;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.64

int any_odd_one(unsigned x)
{
  return !!(x&0x55555555);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.65

int odd_ones(unsigned x)
{
  x^=x>>1;
  x^=x>>2;
  x^=x>>4;
  x^=x>>8;
  x^=x>>16;
  return x&1;

}

blog  这篇blog给出了我的分析

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.66

int leftmost_one(unsigned x)
{
  x|=x>>1;
  x|=x>>2;
  x|=x>>4;
  x|=x>>8;
  x|=x>>16;
  return x^(x>>1);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.67

a:移位超过sizeof(x),UB未定义行为

b:将第10行改为 int beyond_msb = 2<31;

c:不让移31位?那就一次移15位嘛

int int_size_is_32()
{
  int a=1<<15;
  a<<=1;
  int set_msb=a<<15;
  int beyond_msb = (a<<15)<<1;
  return set_msb && !beyond_msb;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.68

int lower_one_mask(int n)
{
    unsigned mask=~0;

    return (int)(mask>>(sizeof(int)*8-n));

    //return (2<<(n-1))-1;          //solution 2

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.69

unsigned rotate_left(unsigned x,int n)
{
  return (x>>(sizeof(int)*8-n)) | (x<<n);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.70

知识点:补码的符号扩展

int fits_bits(int x,int n)
{
  int result=x>>n;
  return result==0 | ~result==0;         //result=0代表符号位为0    ,~result=0代表符号位为1

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.71

A.(word>>(bytenum<<3))&0xFF 结果是unsigned ,但是返回值却要int

B:

typedef unsigned packed_t;

int xbyte(packed_t word,int bytenum)
{
  unsigned result=word<<((3-bytenum)<<3);
  return (int)(result>>24);
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.72

这个题其实就是练习题2.26和旁注函数getpeername的翻版。

A:sizeof()返货size_t是无符号的,在if(maxbytes-sizeof(val)>=0)里,,有符号减去无符号,自动转为无符号的。所以maxbytes-sizeof(val)是一定是正值

B: getpeername做法: 

把maxbytes的类型改为size_t.

练习题2.26做法

把if中的语句改为    if(maxbytes>0 && maxbytes>=sizeof(val))

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.73

int neg_over(int x,int y)
{
  return x<0 && y<0 && (x+y) >=0;
}
int pos_over(int x,int y)
{
 return x>0 && y>0 &&(x+y)<0;
}
int saturating_add(int x,int y)
{
  int negflag= neg_over(x,y) ;
  negflag<<=(sizeof(int)*8-1);
  negflag>>=(sizeof(int)*8-1);
  int posflag=pos_over(x,y) ;
  posflag<<=(sizeof(int)*8-1);
  posflag>>=(sizeof(int)*8-1);
  return (x+y ) & ~(negflag|posflag) | 
  INT_MAX & posflag |
  INT_MIN & negflag;

}

//溢出 书上有讲,这里就不赘述了。

//如果 负溢出,negflag就会返回1, 进过左移31位,变为0X800000000,再算数右移,变为OXFFFFFFFF,

//如果没有负溢出,negflag就是0X00000000

//正溢出同理。

// (x+y)& ~(negflag|posflag) 用来处理没有溢出

//INT_MAX & posflag 用来处理正溢出

//INT_MIN & negflag 用来处理负溢出

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.74

int neg_over(int x,int y)
{
  return x>0 && y<0 && (x-y) <0;
}
int pos_over(int x,int y)
{
 return x<0 && y>0 &&(x-y)>=0;
}
int tsub_ok(int x,int y)
{
  return !(neg_over(x,y) | pos_over(x,y));

}

//X -Y 的溢出条件是:

//  X>0 Y<0 但是X-Y<0  负溢出

// X<0 Y>0 但是 x-y>0 正溢出

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.75

code:

unsigned unsigned_high_prod(unsigned x,unsigned y)

{
  int xw=(int)x>>((sizeof(int)<<3)-1) &y;
  int yw=(int)y>>((sizeof(int)<<3)-1) &x;
  return signed_high_prod(x,y)+xw+yw;

}

signed_high_prod实现

int signed_high_prod(int x,int y)
{
  int64_t result = (int64_t)x*y;
  return result>>(sizeof(int)<<3);

}

该题的正确答案(方便后面检查答案):

unsigned un(unsigned x,unsigned y)
{
  uint64_t result =(uint64_t) x*y;
  return result>>(sizeof(int)<<3);

}

检验函数

int main()
{
  int x=0x12345678;
  int y=0xffffffff;
  printf("%x\n",unsigned_high_prod(x,y));
  printf("%x\n",un(x,y));
}

//为什么写出这段蛋疼的code呢

version1:

unsigned unsigned_high_prod(unsigned x,unsigned y)

{
  return signed_high_prod(x,y)+(x>>31)*y + x*(y>>31);

}//但是不能用乘法啊,宝宝心里苦

version2:

unsigned unsigned_high_prod(unsigned x,unsigned y)

{
  int xw=(int)x>>((sizeof(int)<<3)-1) ;
  int yw=(int)y>>((sizeof(int)<<3)-1) ;
  return signed_high_prod(x,y)+xw&y+yw&x;

}

你会发现,如果用上面的检查代码,是错的。为什么呢? (提醒:用检查代码 , signed_high_prod(x,y)为0xffffffff,xw&y为0,yw&x为0x12345678)

因为编译器在汇编这段程序的时候,+用的不是add,而是and。导致的结果是:

如果是add      0xffffffff+0x12345678 = 0x12345677

如果用的是and  0xffffffff+0x12345678=0x12345678

所以蛋疼的出错了

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.76

#include<stdlib.h>
#include<stdint.h>
#include<memory.h>
void* ccalloc(unsigned memb,unsigned size)
{
 uint64_t asized =(uint64_t)memb*size;
 unsigned asize = (unsigned) asized ;
 if(asize != asized)
   return NULL;
 void* result = malloc(asize);
 memset(result,0,memb);
 return result;
}
int main()
{
  size_t number=0xffffffff;
  int *sta=ccalloc(number,sizeof(int));
  int i=0;
  if(sta !=NULL){
    for(;i!=number;i++)
      printf("%d\n",*(sta+i));
  }
  return 0;
}

//size_t是标准C库中定义的,应为unsigned int,在64位系统中为 long unsigned int

//所以说很蛋疼了,如果你在64位机上,还是把size_t改为unsigned。(书上默认size_t是unsigned)

//这题和前面的XDR库的安全漏洞和练习题2.37是一摸一样的啦

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.77

A : x<<4+x

B : x-x<<3

C:  x<<6-x<<2

D:   x<<7-x<<4

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.78

int divide_power2(int x,int t)
{
  int t1=(1<<t)-1;
  int w= (sizeof(int)<<3)-1;
  int biasing = (x>>w) & t1;
  return (  x+ biasing )>>t;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.79

int divide_power2(int x,int t)
{
  int t1=(1<<t)-1;
  int w= (sizeof(int)<<3)-1;
  int biasing = (x>>w) & t1;
  return (  x+ biasing )>>t;
}
int mul3div4(int x)
{
  x=(x<<2)-x;
  return divide_power2(x,2);

}

//除4直接用7.78编写的函数即可,乘3即时(x<<2)-x  

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.80

int divide_power2(int x,int t)
{
  int t1=(1<<t)-1;
  int w= (sizeof(int)<<3)-1;
  int biasing = (x>>w) & t1;
  return (  x+ biasing )>>t;
}
int threefourths(int x)
{
  int result = divide_power2(x,2);
  int round = x-(result<<2);
  round=(round<<2)-round;
  result=(result<<2)-result;
  return divide_power2(round,2)+result;

}

这题与上面一题的区别是,不会溢出,先乘3再除4会溢出。所以先要除4,再乘3。

但是这有带来了新的问题,就是除4会导致省去的小数过大

如果小数小于0.3333,没问题,在0.333333到0.666666值差一   ,在0.666666到1值差2

所以round就是求余数,余数先乘3再加4是没有问题的(因为余数小于除数,即4).这就是这道题的解法了

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.81

int express1(int k)
{
  return (-1)<<k;

}

int express2(int j,int k)
{
  return ( ((-1)<<j) - ((-1)<<(j+k)) );

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.82

A (x<y) ==(-x>-y)

false     x=TMIN ,y=1   x<y为true      -x>-y为 false

B ((x+y)<<4)+y-x == 17*y+15*x

true 补码的加减乘与顺序无关

C ~x+~y+1 == ~(x+y)

true      ~x+1=-x      ~y+1=-y      所以 ~x+~y+1=-x-1-y-1+1=-x-y-1

              ~(x+y)+1=-(x+y)      ~(x+y) = -(x+y)-1

D (ux-uy)=-(unsigned)(y-x)

false 无符号和有符号的位级表现是一样的,只是用不同的方式解读

E ((x>>2)<<2)<=x

true   ((x>>2)<<2)可能导致最后2个bit为0,也就x可能减小3(无论是正还是负),所以为true

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.83

无穷串  x*2^k -x=Y     x左移K位 -> y.yyyyy    再减去x,变为Y.即前面的表达式

x=Y/(2^k-1)

a 5/7

b 2/5

c 19/63

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.84

unsigned f2u(float x)
{
  return *(unsigned *)&x;
}
int float_le(float x,float y)
{
    unsigned ux =f2u(x);
    unsigned uy=f2u(y);

    unsigned sx = ux>>31;
    unsigned sy = uy>>31;


    return ( (!sx &&!sy) && ux>uy ) || 
      (!sx && sy) ||
    ( (sx && sy) &&  ux<uy );

}

分析:

①x>0 y>0    ux>uy即可。  书81    把正浮点数解释为无符号数时,是按升序排列   

②x>0,y<0     true

③x<0,y>0      false 不用写这种情况

④x<0 y<0     ux<uy即可               把负浮点数解释为无符号数时,是按降序排列

测试函数        

int main()
{
  printf("%d\n",float_le(+0,-0));
  printf("%d\n",float_le(3,0));
  printf("%d\n",float_le(-4,-0));
  printf("%d\n",float_le(-4,4));
  
  return 0;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.85

E=  B2U(e)+1-2^(k-1)

f=B2U(f)/(2^n)

M=1+f

V=M*E

A:    0 100 ...... 01 1100 ......

B:    0 111....... 10  1111.......11

C:   


e=E+bias =2^k-3

所以为0  111.......101 00.....0000

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.86


把n=63,k=15带入即可

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.87


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.88


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.89

A (float)x ==(float) dx

false       float转入int可能会舍入(int过大时)

B dx-dy == (double)(x-y)

false   当x-y溢出时,x-y就不是正确的值了,但是dx,dy有足够的地方

double用52位表示f,float用23位表示f。而int是32位,所以float->int可能会舍入,但double->int正确表达

C (dx+dy)+dz ==dx+(dy+dz)

true 由上所述,double可以表达33位(int+int)

D (dx*dy)*dz == dx*(dy*dz)

false  int*int*int是96位,double可能不能表达

E dx/dx=dz/dz

false dx=0 0/0=NaN

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.90

最小正非规范数 E=1-bias = -127,小数f=2^-32, E*f = 2^-159

最小正规范数 E=1-bias = -127 小数f=1  

最大正规范数E=e-bias = 127 小数f=1

所以Too small return 0.0     x<-159

Denormalized result  [-159,-127)

Normalized result [-126,127)

Too big,return +∞  127<x

float u2f(unsigned x)

{
  return *(float *)&x;
}
float fpw2(int x)
{
  unsigned exp,frac;
  unsigned u;
  
  if(x<-149){     
    exp=0;
    frac=0;
  }
  else if(x<-126){
    exp=0;
    frac=1<<-(x+126);
  }
  else if(x<128){
    exp=x+127;
    frac=0;
  }
  else{
    exp=(unsigned)(~0)>>24;
    frac=0;
  }
  u=exp <<23 | frac;
  return u2f(u);

测试code:

int main()

  printf("%f\n",fpw2(0));
  printf("%f\n",fpw2(100));
  printf("%f\n",fpw2(-1000));
  printf("%f\n",fpw2(10000));  
  printf("%f\n",fpw2(-10000));   
  return 0;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.91

A:0100 0000 0100 1001 0000 1111 1101 1011

B:11. 001 001 001 001 .......

C: 9

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.92

typedef unsigned float_bits;
float u2f(unsigned x)
{
  return *(float *)&x;
}
float_bits float_negate(float_bits f)
{
  unsigned sign = f>>31;
  unsigned exp=(f>>23) &0xff;
  unsigned frac= f &0x7fffff;
  if(exp==0xff && frac!=0)
    sign=sign;
  else
    sign^=1;
  return (sign<<31)|(exp<<23)|frac;

}

测试code:

int main()
{
  unsigned i=0;
  for(;i<0x7f800000;i++){
    if( (-u2f(i)) != u2f(float_negate(i)))
      printf("%d\n",i);
  }
 
  return 0;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.93

#include<stdio.h>
#include<math.h>
typedef unsigned float_bits;
float u2f(unsigned x)
{
  return *(float *)&x;
}
float_bits float_absval(float_bits f)
{
  unsigned sign = f>>31;
  unsigned exp =(f>>23) & 0xff;
  unsigned frac = f &0x7fffff;
  if(exp==0xff && frac!=0)
    return f;
  sign &=0;
  return (sign<<31) | (exp<<23) |frac;

}

测试代码:

float test(float_bits x){
  float fn = u2f(x);
  if(isnan(fn))
    return 0;
  else
    return fn;

}

int main()
{
  unsigned i=0;
  for(;i<0xffffffff;i++){
    float f1 =test( float_absval(i) );
    float f2 = fabsf( test(i) );
    if( f2  != f1 )
      printf("%d\n",i);
  }
  return 0;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.94

f 非规格是  小数左移一位即时*2.0

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

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

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

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

typedef unsigned float_bits;

float u2f(unsigned x)
{
return *(float *)&x;
}
float_bits float_twice(float_bits f)
{
unsigned sign = f >> 31;
unsigned exp = (f >> 23) & 0xff;
unsigned frac = f & 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 )      //+∞NaN  
return f;
else
exp += 1;
return (sign << 31) | (exp << 23) | frac;

}

测试code:

float test(float_bits x) {
float fn = u2f(x);
if (isnan(fn))
return 0;
else
return fn;
}
int main()
{
unsigned i = 0;
for (; i<0xffffffff; i++) {
float f1 = test(i)*2.0;
float f2 = test(float_twice(i));
if (f1 != f2)
printf("%u\n", i);
}
return 0;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.95

比上题难多了,虽然思路一样,但是这题多了偶数舍入,(有了上题的思路,我感觉这题写的好多了)

当frac位数是........011时 舍入为010 即左移一后加一

当frac位数是..........111时,舍入为100,即左移一后加一

当exp大于00000001时,可以直接右移exp达到*0.5不用考虑舍入(因为可以正确表示)

typedef unsigned float_bits;
float u2f(unsigned x)
{
return *(float *)&x;
}
float_bits float_half(float_bits f)
{
unsigned sign = f >> 31;
unsigned exp = (f >> 23) & 0xff;
unsigned frac = f & 0x7fffff;
if (exp == 0xff)    //   &  NaN
return f;
else if (exp == 1) { //round in this
exp = 0;
frac >>= 1;
frac += 0x400000;
if ((f & 3) == 3)
frac += 1;
else if ((f & 7) == 7)
frac += 1;
}
else if (exp == 0 ) {    //fei gui ge round in this
frac >>= 1;
if ((f & 3) == 3)
frac += 1;
else if ((f & 7) == 7)
frac +=1;
}
else
exp -= 1;
return (sign << 31) | (exp << 23) | frac;
}
float test(float_bits x) {
float fn = u2f(x);
if (isnan(fn))
return 0;
else
return fn;

}

测试code:

int main()
{
unsigned i = 8388608;
for (; i<0xffffffff; i++) {
float f1 = test(i)*0.5;
float f2 = test(float_half(i));
if (f1 != f2)
printf("%u\n", i);
}
return 0;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.96

分情况 当exp小于011111111时,都是小于1 所以return 0

当exp小于158时,都是int能正常表达的范围。这里又要分2中情况 左移和右移

当exp大于158时,int都无法正常表达

最后再修改下符号即可

typedef unsigned float_bits;

float u2f(unsigned x)
{
return *(float *)&x;
}
int float_f2i(float_bits f)
{
  unsigned sign = f>>31;
  unsigned exp=(f>>23) &0xff;
  unsigned frac = f & 0x7fffff;
  if(exp <0x7f)    //number is too small
    return 0;
  else if(exp<150){
    exp-=127;
    frac+=0x800000;
    frac>>=(23-exp);
  }
  else if(exp < 158 )
  {
    exp-=127;
    frac+=0x800000;
    frac<<=(exp-23);
  }
  else
    return 0x80000000;
  if (sign == 1)
    return -(int)frac;
  else
    return frac;
}

测试code:
int main()
{
unsigned i = 0;
for (; i<0xffffffff; i++) {
int i1 = (int) u2f(i);
int i2 = float_f2i(i);
if (i1 != i2)
printf("%u\n", i);
}
return 0;

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2.97

这题比上题难多了。

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

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

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

typedef unsigned float_bits;
float u2f(unsigned x)
{
return *(float *)&x;
}
unsigned f2u(float x)
{
return *(unsigned *)&x;
}
float_bits float_i2f(int i)
{
unsigned sign = (unsigned)i >> 31;
if (i == 0)
return 0.0;
else if (i<0)
i = ~(i - 1);
unsigned frac = (unsigned)i;
unsigned  j;
for (j = (sizeof(int) << 3) - 1; j >= 0; --j) {
if ((i >> j) & 1)
break;
}
unsigned  exp = 127 + j;
if (j < 23) {
frac <<= (23 - j);
}
else if (j < 31) {     //don`t forget round
frac = i >> (j - 23);
unsigned mask = (1 << (j - 23)) - 1;
if ((i&mask) >(1 << (j - 24))) 
frac++; //需要舍入到大值
else if ((i&mask) == 1 << (j - 24) && (frac & 1)) 
frac++; //舍入到偶数
if (frac == (1 << 24))
exp++; //舍入到偶数超过(1<<24) - 1,指数需要再加1
}
frac &= 0x7fffff;
return (sign << 31) | (exp << 23) | frac;
}

测试code:
int main()
{
int i = 0;
for (; i<0xffffffff; i++) {
float f1 = (float)(i);
float f2 = u2f(float_i2f(i));
if (f1 != f2)
printf("%d\n", i);
}
return 0;
}

猜你喜欢

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