基本知识:
1.
左移运算符: x<<k x向左移动k位
位移运算 从左至右可结合 x<<j<<k等价于(x<<j)<<k
右移运算符: x>>k x向右移动k位
逻辑右移和算术右移。
逻辑右移在左端补k个0;
算术右移是在左端补k个最高有效位:
如果符号为位1,则移入的位均为1;若符号位为0,则移入位均为0.
2.
C语言并没有明确定义应该使用哪种类型的右移。
对于无符号数据(unsigned声明的整形对象),右移必须是逻辑的;
对于有符号数据(默认的声明的整型对象),算术的或者逻辑的右移都可以。
然而实际上,几乎所有的编译器/机器组合都对有符号数据使用算术右移,
且许多程序员也都假设机器会使用这种右移。
问题:
1.移位运算为什么比四则运算快
移位快,只有一次寻址,逻辑运算和写操作,按位与需要两次寻址,一次逻辑运算和一次写。
2. 示例 : a<<-5 在如何表示??
某编译器测试后表示 左移27位。
/***********************************代码*****************************************/
/*********************计算一个二进制数中1的个数*******************/
#include<stdio.h>
#include<stdlib.h>
void Count_1(int n )
{
int count = 0;
while (n>0)
{
if((n&1)==1)
{
count ++;
}
n = n>>1;
}
printf("the count of the number is %d \n",count);
}
/*********************移位操作的基本运算*******************/
//去掉 - del 末位 - last 第一位 -- begin 第k位 - k 取反 -- inverse
//右边 - right 左边 — left
//1.去掉最后一位
int Del_Last(int n)
{
n = n>>1;
return n;
}
//2.在最后一个加0
int Last_Plus_Zero(int n)
{
n = n<<1;
return n;
}
//在最后加一个加1
int Last_Plus_One(int n)
{
n = (n<<1)+1;
return n;
}
//把最后一位变成1
int Last_Change_One(int n)
{
n = n|1;
return n;
}
//把最后一位变成0
int Last_Change_Zero(int n)
{
n = (n|1)-1;
return n;
}
//把最后一位取反
int Last_Inverse(int n)
{
n = n^1;
return n;
}
//把右数第k位变成1
int Right_K_One(int n,int k)
{
n= n|(1<<(k-1));
return n;
}
//把右数第k位变成0
int Right_K_Zero(int n,int k)
{
n = n&~(1<<(k-1));
return n;
}
//把右数第k位取反
int Right_K_Inverse(int n,int k)
{
n = n^(1<<(k-1));
return n;
}
//取末尾三位
int Last_Three(int n)
{
n = n&((1<<n)-1);
return n;
}
//取右边数第k位
int Right_K(int n,int k)
{
n = n>>(k-1)&1;
return n;
}
//把右边连续的1变成0
int Right_One_To_Zero(int n)
{
n = n&(n+1);
return n;
}
//把右边第一个0变成1
int Right_Zero1_To_One(int n)
{
n = n|(n+1);
return n;
}
//flag版 同下
//while(n%2 == 1)
// {
// n = n >> 1;
// flag++;
// }
// n = n ^ 1;
//把右边连续的0变成1
int Right_Zero_To_One(int n)
{
n = n|(n-1);
return n;
}
// int flag= 0;
// while(n%2 == 0)
// {
// n = n >> 1;
// flag++;
// }
// for(int i = 0;i <flag;i++)
// {
// n = n << 1;
// n = n ^ 1;
// }
// return n;
int main()
{
Count_1(105); //二进制中1的个数
char arr[10];
itoa(Del_Last(105), arr, 2);//去掉最后一位
printf("Del_Last --> %s\n",arr);
itoa(Last_Plus_Zero(105), arr, 2);//在最后加一个加0
printf("Last_Plus_Zero--> %s\n",arr);
itoa(Right_K_One(105,4), arr, 2);//把右数第k位变成1
printf("Right_K_One--> %s\n",arr);
itoa(Right_Zero_To_One(105), arr, 2); //把右边连续的0变成1
printf("Right_Zero_To_One--> %s\n",arr);
getchar();
return 0;
}