1. 程式人生 > >深入理解計算機系統homework2 2.85 2.93 2.95

深入理解計算機系統homework2 2.85 2.93 2.95

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取絕對值,當成一個正數轉化即可。然後判斷i2的幾次冪,可以通過類似於二分法的方式判斷。即右移16位判斷是否不為0,如果不為0exp+16,然後判斷右移16位後剩餘的位數有幾位,否則右移8位判斷依次類推。然後因為是正數,小數點左邊存在一個隱式的1,所以num=( ~ (1<< exp ) ) & num ;把最高的1去掉,然後把剩餘的數放進frac中,同時要考慮向偶數取整的問題。如果num不足23位,直接移動相應位數,放入frac中,否則截掉多餘的位數,如果最後一位並且捨去一段中的最高也為1
或者捨去的東西超過0.5那麼就給frac+1,判斷一下frac時候有溢位,溢位的話給exp+1,然後取剩餘的23位的值即可。最後就是給exp加上bias偏置值,前提是如果num不為0
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;

}