深入理解计算机系统第二章:信息的表示和处理 家庭作业
开工日期: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
{
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;
}