十進制整數轉二進制的各種實現和思考

對於十進制轉二進制,我的初步想法是將32位整數每次左移一位,將移出的那位保存到對應的數組裏,最後控制格式,輸出打印。

第一步:  

因爲每次移出的那位都在最高位,爲了獲取它,必須屏蔽其他位,布爾與運算&派上用場了,又考慮是32位整數,temp = digit & (1<<31)便可以判斷最高位是1還是0了。

如果現在立即將它輸出,可能出錯,對於最高位0,這不是問題,可是對於最高位1,二進制結果可能是1000 0000 0000 0000 0000 0000 0000 0000,翻譯成十進制就是一個負數:-2147483648.這不是我想要的,於是我再次右移31位,變成0000 0000 0000 0000 0000 0000 0000 00001.

第二步:

可是沒想到右移運算和最高位有關,對於1000 0000 0000 0000 0000 0000 0000 0000來說,右移31位就變成1111 1111 1111 1111 1111 1111 1111 1111。這又不是我想要的,於是我得將右移結果再屏蔽一次,即: temp = (temp>>31) &1

第三步:

只要十進制不爲0,十進制數左移1位, digit<<=1輸出.這裏結束條件之所以是digit !=0而不是左移32位才結束,是因爲我採用了數組,將其全部32個數據初始化爲0。這樣對於最後一位1右邊的所有0,就不用再判斷了。

源代碼如下:

#include <iostream>
using namespace std;

//十進制轉二進制
void DecToBin(int digit,int bin[])
{
		int i=0;
		while(digit !=0)
		{
			int temp =digit & (1<<31);    //判斷最高位
			temp = (temp>>31)&1;    //將最高位右移到最低位,同時屏蔽擴展位.
			bin[i++]=temp; 
			digit<<=1;   //整數左移一位,最高位自動丟棄,不能保存
		}
}

int main()
{
	int a=-10002;
	int b[32]={0};
	
	cout<<"a= " <<a<<endl;
	DecToBin(a,b);
	cout<<"a=";
	for(int i=0;i<32;i++)
	{
		if(i%4==0)      //每四位二進制一組
		{
			cout<<" ";
		}
			cout<<b[i];	
	}
	cout<<endl;
	getchar();
}
結果出來了,但是網上搜羅了下,其實還有更好的想法,如下: 
#define CHAR_BIT 8 

void bit_print(int a)
{   
    int i;    
    int n = sizeof(int) * CHAR_BIT;  
    int mask = 1 << (n - 1);  
    for(i = 1; i <= n; ++i)
    {       
        putchar(((a & mask) == 0) ? '0' : '1');  //這一步速度上應該更快,不需要每次都移32位      
        a <<= 1;        
        if(i % CHAR_BIT == 0 && i < n)  
              putchar(' ');    
}}

以上代碼沒有采用數組,邏輯上更好理解,而且簡化了第二步的判斷;更爲重要的是它是跨平臺的,對不同機器字長都可以勝任。

此外,在保存輸出的二進制結果的問題上,又提出瞭如何使輸出結果佔用內存最小?於是有人用字符串實現,是我的int[ ]數組內存大小的1/4.實現如下:
int dtob(int d, char *bstr)
{
    if(d<0)
       return -1;
    int mod =0;
    char tmpstr[64];
    bzero(tmpstr,sizeof(tmpstr));
    bzero(bstr,sizeof(bstr));

    int i=0;
    while(d>0)
   {
      mod = d%2;
     d/=2;
     tmpstr[i] = mod+ '0';
     i++;
    }
     unsigned int len = strlen(tmpstr);  
     for(i=0; i<len; i++)   //複製字符串
     {
         bstr[i] = tmpstr[len-i-1];
      }
      return (int) len;
}

不過還是有人感覺上面太羅嗦了,而且爲負數的時候無法工作,於是有如下實現:

void d2b(unsigned int d, char *str)
{
 int nStart = -1, i = 0;
 for (i=0; i<32; i++)
 {
  bool bOne = (0 != (d & (1 << (32 - i - 1))));
  if (bOne && nStart < 0)
  {
   nStart = i;
  }
  str[i - nStart] = bOne ? '1' : '0';
 }
 str[i - nStart] = '\0';
}
看了以上各種實現,還是有很多在實際編程過程中沒有考慮的問題,列舉如下:

1.如果輸入的整數過大怎麼辦?本着一個函數完成一個功能的模塊化原則,要麼輸出錯誤,直接返回,要麼採用動態數組或鏈表進行處理。

2.傳入的數組不是全部爲0,怎麼辦? 對於我寫的程序就有問題,避免的唯一方法就是每次函數調用的時候將其初始化爲0

3.整數在不同的機器上,機器字長是不一樣的.不考慮這一點,會有很大隱患。第二種方法,很好的屏蔽了這個問題,值得借鑑!

4.數據過大還會遇到另外一個問題,那就是參數聲明的是int類型,如果傳入的參數是long int 或者double怎麼辦?數據過大,會造成多餘的位數丟棄!解決的思路應該是將輸入int參數,改爲void*指針比較好,然後在函數內進行強制轉換

5.對於計算機,即使long double這樣的整數,它的位數也是有限的,位數再多點它也會溢出報錯!如此這樣,除了第1種建議中的鏈表處理,還要對輸入的數字個數進行判斷,非法輸入進行屏蔽。解決的思路就是統計輸入字符的個數,將數字轉化爲數字字符,然後作相應處理.

總之,對於我們程序員來說,考慮的越多越詳細,代碼纔會更加健壯!靈活的頭腦加上辛勤的汗水,纔是成功的必由之路。


本人寫的程序附圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章