位运算&进制转换

进制转换:

(1)  十进制与二进制之间的转换 

       十进制转换为二进制,分为整数部分和小数部分 
   整数部分 
     方法:除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数读起,一直到最前面的一个余数。下面举例: 


例:将十进制的168转换为二进制  得出结果 将十进制的168转换为二进制,(10101000)2 
       第一步,将168除以2,商84,余数为0。 
       第二步,将商84除以2,商42余数为0。 
       第三步,将商42除以2,商21余数为0。 
       第四步,将商21除以2,商10余数为1。 
       第五步,将商10除以2,商5余数为0。 
       第六步,将商5除以2,商2余数为1。 
       第七步,将商2除以2,商1余数为0。 
       第八步,将商1除以2,商0余数为1。 
       第九步,读数,因为最后一位是经过多次除以2才得到的,因此它是最高位,读数字从最后的余数向前读,即10101000 

    小数部分 
       方法:乘2取整法,即将小数部分乘以2,然后取整数部分,剩下的小数部分继续乘以2,然后取整数部分,剩下的小数部分又乘以2,一直取到小数部分为零为止。如果永远不能为零,就同十进制数的四舍五入一样,按照要求保留多少位小数时,就根据后面一位是0还是1,取舍,如果是零,舍掉,如果是1,向入一位。换句话说就是0舍1入。读数要从前面的整数读到后面的整数,下面举例: 


例:将0.125换算为二进制 ,得出结果:将0.125换算为二进制(0.001)2 
       第一步,将0.125乘以2,得0.25,则整数部分为0,小数部分为0.25; 
       第二步, 将小数部分0.25乘以2,得0.5,则整数部分为0,小数部分为0.5; 
       第三步, 将小数部分0.5乘以2,得1.0,则整数部分为1,小数部分为0.0; 
       第四步,读数,从第一位读起,读到最后一位,即为0.001。 

 

(2)  二/八/十六进制 转化为十进制

 方法:按权相加法,即,将二/八/十六进制每位上的数乘以位权(2/8/16),然后相加之和即是十进制数。 

 

(3)  二到八进制 或者  八进制转换为二进制

 方法:

      1.   二进制、八进制、十六进制相互转换:先转换成十进制再转换成其他进制;
      2.   二进制、八进制、十六进制相互转换按照其对应关系进行转换(三位二进制数对应一位八进制数,四位二进制数对应一位十六进制数)。

 

 

位运算:

 

 

 

题目一:

    在微软Excel中,用A表示第一列,B表示第二列,...,Z表示26,AA表示27,AB表示28.......;输入用字母表示列的编号,输出其是第几列?

分析: 这可以看做是一个26进制的数字转换为10进制的题目。类比二进制每个位用 0-1表示,此26进制的每个位用A~Z表示。

代码实现:

void chToNum(char *str)
{
	char *tmp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //下标加一就是其数值
	long long num = 0;
	int len_tmp = strlen(tmp);
	int len_str = strlen(str);

	for (int i = 0; i < len_str; i++) //保证目标数据全部转换为大写
	{
		if (str[i] >= 'a' && str[i] <= 'z')
		{
			str[i] -= 32;
		}
	}

	for (int i = 0; i < len_str; ++i)
	{
		for (int j = 0; j < len_tmp; ++j)
		{
			if (str[i] == tmp[j])
			{
				num = num * 26 + j + 1; //数据统计
			}
		}
	}
	printf("%d\n",num);
}

int main()
{            
	char str[27] = { '\0'};
	printf("please input object num(input max is 26 numbers):\n");
	scanf("%s", str);
	chToNum(str);
}

 

题目二:

      二进制中 1的个数。输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。例如9表示为二进制是 1001,则输入9时,函数输出为2,因为1001 中有两个 1。

代码实现1:

int  NumberOf_1(int n) 
{
	int count = 0;
	while (n)
	{
		if (n & 1)
			count++;

		n = n >> 1;
	}
	return count;
}

此实现有bug,如果n为负数,则n做右移时可能会导致n变成 0xFFFFFFFF 而陷入死循环。原则请参照右移时左边补位的规则。

 

代码实现2:

int  NumberOf_1(int n) {
         int count = 0;
         unsigned int flag = 1;
         while(flag)
         {
             if(n & flag)
                 count++;
             
             flag = flag << 1;
         }
         return count;
     }

此实现已经能满足要求了。

 

代码实现 3:

实现2中,当n为32位整数时,则需要循环32次;接下来介绍一种算法:整数中有几个 1 就循环几次。

分析:

如果一个不等于0,那么该整数的二进制表示中至少有一个 1;

(1). 假设这个数的最后一位为 1,那么减去 1,最后一位变成0,而其他位保持不变。

(2). 假设这个数的最后一位为 0,如果该整数的二进制表示中最右边的 1位于第m位,那么减去 1后,第m位由 1变为0,而第m位之后的0都变成1,整数中第m位前的位都不变。

(3). 总结前两点,当我们把一个整数减去 1,都是把最右边的 1变成0;如果它的右边还有0,则右边所有的0变成1,左边的位全保持不变

(4). 接下来我们把一个整数和它减去 1的结果做 与运算,相当于把它最右边的 1变成0,举例说明:当一个整数的二进制为1100时,减去 1的结果为 1011, 做 1100 & 1011 = 1000,所以当我们重复几次上述操作就有多少个 1

代码实现:

int  NumberOf_1(int n) {
         int count = 0;
         while(n)
         {
             ++count;
             n = (n-1) & n;
         }
         return count;
     }

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值