深入理解計算機系統homework2 2.85 2.93 2.95
阿新 • • 發佈:2019-02-01
2.85 最小的正非規格化數 值:2^(-63) * (2^(2-2^15)) = 2^(-16445) 十進位制值: 最小的正規格化數 值:1*2^(2-2^15) = 2^(-16382) 十進位制值: 最大的規格化數: 值:(2-2^(-63))* 2^(2^14) = (2-2^(-63))*2^16384 2.93 【分析】 如果exp上全是1則該數是無窮大或者NaN,只需要異或一下判斷全1即可。 否則如果exp大於0,那麼我們在exp上減去一即可,但是如果exp被減成0了,因為exp不等於0,預設小數點前是1,那麼我們就要把小數點前的1給補回去,然後做整體右移一位。如果exp原來是0,整體右移一位即可。 最後考慮向偶數進位,如果原數f末尾兩位是11,則需要最後結果在尾數上加一。
float_bits float_half(float_bits f) { unsigned exp = f & 0x7F800000;//取出階碼 unsigned sign = f & 0x80000000;//取出符號位 unsigned frac = f & 0x7fffff;// 取出尾數 // 判斷f的最後是否是3考慮向偶數進位 unsigned round = ( ( f >> 1 ) & f) & 1; if (exp ^ 0x7F800000) // f不死NAN 或者 無窮大 { if (exp) { exp = ( (exp >> 0x17) + ~0 ) << 0x17;//階碼減一 if ( ! exp ) frac = frac + (1 << 0x17 ); // 向後退1,正數前面預設為1. } if (!exp) frac = ( frac >> 1 )+ round; } return sign | exp | frac; }
2.95為了放在word中,縮進了一些程式碼【分析】將int轉化成float,首先考慮符號位,然後講i取絕對值,當成一個正數轉化即可。然後判斷i是2的幾次冪,可以通過類似於二分法的方式判斷。即右移16位判斷是否不為0,如果不為0則exp+16,然後判斷右移16位後剩餘的位數有幾位,否則右移8位判斷依次類推。然後因為是正數,小數點左邊存在一個隱式的1,所以num=( ~ (1<< exp ) ) & num ;把最高的1去掉,然後把剩餘的數放進frac中,同時要考慮向偶數取整的問題。如果num不足23位,直接移動相應位數,放入frac中,否則截掉多餘的位數,如果最後一位並且捨去一段中的最高也為1
float_bits float_i2f(int i)
{
unsigned sign = i >>0x1F;
unsigned num = i;
if (sign & 0x1)
num = ~num + 1; // 求絕對值
//printf("%x\n",num);
unsigned temp = num;
unsigned exp = 0;
unsigned frac = 0;
if(num >> 16) {
exp= exp + 0x10; num = num >> 0x10;//printf("%x%x\n",exp,num);
}
if(num>>8) {
exp= exp + 0x8; num = num >> 0x8;//printf("%x %x\n",exp,num);
}
if(num>>4) {
exp= exp + 0x4; num = num >> 0x4;//printf("%x %x\n",exp,num);
}
if(num>>2) {
exp= exp + 0x2; num = num >> 0x2;//printf("%x %x\n",exp,num);
}
if(num>>1) {
exp= exp + 0x1; num = num >> 0x1;//printf("%x %x\n",exp,num);
}
//正數小數點前的1需要去掉(即最高位的1去掉)
num = temp;
num=( ~ (1<< exp ) ) & num ;
//printf("num=%x\n",num);
if (temp >> 23) // 如果num超過了23位
{
unsigned delta = exp - 0x17;
frac = num >> delta;
//printf("%x %x\n",delta,frac);
unsigned round = 0;
int Cond1 = ( ( num & ((1 << delta) -1 ) ) > (1 << (delta-1)) );
int Cond2 = (frac & 0x1) && ( num >> (delta -1) & 0x1);
//printf("cond%d %d\n",Cond1,Cond2);
if( (exp != 0x17) & ( Cond1 | Cond2) )
// exp 不等於23 判斷捨去後是否需要向偶數進位
{
round = 1;
frac = frac + round;
//printf("round-frac%x\n",frac);
if (frac >> 0x17)
{
exp +=1;
frac = frac & 0x7fffff;
}
}
//printf("frac=%x\n",frac);
} else
frac = num << (0x17 - exp ) ;
//printf("exp=%x\n",exp);
if (temp)
exp = exp + 127; // 加上bias偏置值
//printf("%x %x %x %x\n", num , sign,exp,frac);
return ( sign << 0x1F ) | ( exp << 0x17 ) | frac;
}