现在的位置: 首页 > 综合 > 正文

十进制整数转二进制的各种实现和思考

2013年04月17日 ⁄ 综合 ⁄ 共 2302字 ⁄ 字号 评论关闭

对于十进制转二进制,我的初步想法是将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 0000
1.

第二步:

可是没想到右移运算和最高位有关,对于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种建议中的链表处理,还要对输入的数字个数进行判断,非法输入进行屏蔽。解决的思路就是统计输入字符的个数,将数字转化为数字字符,然后作相应处理.

总之,对于我们程序员来说,考虑的越多越详细,代码才会更加健壮!灵活的头脑加上辛勤的汗水,才是成功的必由之路。

本人写的程序附图:

抱歉!评论已关闭.