前言:
<<
运算规则:按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
语法格式:
需要移位的数字 << 移位的次数
例如: 3 << 2,则是将数字3左移2位
计算过程:
3 << 2
首先把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011,然后把该数字高位(左侧)的两个零移出,其他的数字都朝左平移2位,最后在低位(右侧)的两个空位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 1100,则转换为十进制是12.数学意义:
在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
>>
运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1.
语法格式:
需要移位的数字 >> 移位的次数
例如11 >> 2,则是将数字11右移2位
计算过程:11的二进制形式为:0000 0000 0000 0000 0000 0000 0000 1011,然后把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。则得到的最终结果是0000 0000 0000 0000 0000 0000 0000 0010.转换为十进制是2.数学意义:右移一位相当于除2,右移n位相当于除以2的n次方。
正常情况:
有若干个状态,我们使用一个数组来保存正在使用的状态,
前期判断逻辑 :
当需要某个状态时,就往数组中添加
中期处理逻辑:
拿到使用中的状态,去做一些骚操作,做完以后,从数组中删除掉该状态
看一段c语言的代码
而下面的实现是,状态使用左移位数来区分,数组采用一个整数来表示,这样代码执行效率高,具体原理请看下面的代码
/*
左移运算:就是乘以2
右移运算:就是除以2取整
*/
for (int i = 0; i <1; i++)
{
//下面是六种状态
//状态会有不同 通过依次左移来表示状态索引的唯一性
int sb1 = 1 << i; //玩手机 1
int sb2 = 1 << i+1; //吃东西 2
int sb3 = 1 << i+2; //踩刹车 4
int sb4 = 1 << i+3; //微笑 8
int sb5 = 1 << i+4; //踩油门 16
int sb6 = 1 << i+5; //打左转向灯 32
//添加状态
//状态之间使用|这个运算符连接
//不要在意这个|运算符的操作结果,而是把它看成状态之间的连接来看
//从p1到p6你可以理解不同的状态在添加,满足交换律,交换律这个非常重要
//从宏观的角度看,我们的每一个状态都是数组的一个item,下面的|操作就好像在往p这个数组中插入元素
//只要不插入相同的元素,那么插入的位置可以随意组合
int p1 = sb1;
int p2 = sb1 | sb2;
int p3 = sb1 | sb2 | sb3;
int p4 = sb1 | sb2 | sb3 | sb4;
int p5 = sb1 | sb2 | sb3 | sb4 |sb5;
int p6 = sb1 | sb2 | sb3 | sb4 | sb5 | sb6;
printf("s----%d---%d---%d---%d---%d\n", sb1, sb2, sb3, sb4, sb5, sb6);
printf("~s----%d---%d---%d---%d---%d\n",~sb1, ~sb2 , ~sb3 , ~sb4 , ~sb5,~sb6);
/*
删除状态 相当于从p这个数组中删除状态
下面的操作会发现下面的等式成立
p5 == p6&~sb6
*/
printf("删除sb6状态退回到p5合集状态---%d----%d-\n", p5, p6&~sb6);
//状态比较
//做&运算 不要在意计算结果,从宏观的角度看
/*
p1&p2:p1含有sb1状态,p2含有sb1和sb2两种状态,所以结果就是(sb1)
p2&p3:p2含有sb1和sb2两种状态,p3含有sb1,sb2,sb3三种状态,所以结果就是(sb1|sb2)
...依次类推
*/
printf("&----%d---%d---%d---%d--%d\n", p1 & p2, p2 & p3, p3 & p4, p4 & p5, p5 & p6);
//做|运算 不要在意计算结果,从宏观的角度看
/*
p1|p2:p1含有sb1状态,p2含有sb1和sb2两种状态,所以结果就是(sb1|sb2)
p2|p3:p2含有sb1和sb2两种状态,p3含有sb1,sb2,sb3三种状态,所以结果就是(sb1|sb2|sb3)
...依次类推
*/
printf("|----%d---%d---%d---%d--%d\n",p1|p2,p2|p3,p3|p4,p4|p5,p5|p6);
/*
总结做上面的状态比较,如果发现比较的两边状态数组,没有一个状态相等,那比较结果就为0
*/
}
/*
下面是一个测试 就是对于一个整数1进行0-99次左移,每一次左移的结果都与整数1左移3位的结果进行&操作
发现必须都是1<<3,其结果才是8,其余都是0
这里的int所占字节数为4,也就是说最大移动31位,还有1位表示正负
所以我们的移动位数不应该超过32位,因为你超过了int所代表的内存就没办法表示你的数据了,它就会去自动的截取
它认为有效的位移数是(n = input%32);
*/
for (int i = 0; i <31; i++)
{
int s1 = 1 << 3;
int s2 = 1 << i;
printf("|&-----%d---%d------%d------%d\n", s1&s2, s1 | s2,i,s2);
}
其实在我们的游戏引擎中就用到了这个写法:
一个节点会有缩放,旋转,平移这三种基本的变换,也会有节点颜色,透明度等状态的变化,我们姑且认为就是这五种状态,游戏都是一帧一帧运行的,所以你频繁改变某一个状态,只会到一帧刷新的时间才会生效,游戏处理每一个节点的变化,就是根据节点的状态来进行的,到了一帧的刷新时间的时候,引擎会去访问根节点,从根节点开始访问整棵树的节点,对每一个节点,拿到他的状态变化,根据每一个变化进行相应的数据调整,而存储这个状态变化的就是一个整数而不是数组