&运算

位运算的定义:通俗点说,位运算就是对一个整数在计算机中二进制进行操作。
任何一个整数都可以用二进度的方式来表示的,不同类型的整数它的位数的长度也不一样,INT8或者char是由8个2进度
位表示,INT16或者short是由16个2进度位表示,INT32是由32位状态位表示。

位运算在游戏中的应用

往往,在游戏开发中做位运算的时候,我关注的主要是某一位的值是0,还是1,而并不是去关注这个整数的值是多少。
比如:00100010,这个8位的整数从右到左,它的第一位为0,第二位为1,第三位为0,第六位为1。

  1. //检查state的第pos位是否为1  
  2. int bitCheck(int state, int pos)  
  3. {  
  4.     return state & 1<< pos - 1;  
  5. }  
  6.    
  7. //将state的第pos位的值设为1  
  8. int bitAdd(int state, int pos)  
  9. {  
  10.     return state | (1 << (pos - 1));  
  11. }  
  12.    
  13. //将state的第pos位的值设为0  
  14. int bitDel(int state, int pos)  
  15. {  
  16.     return state & (~(1 << (pos - 1)));  
  17. }  
//检查state的第pos位是否为1
int bitCheck(int state, int pos)
{
    return state & 1<< pos - 1;
}

//将state的第pos位的值设为1
int bitAdd(int state, int pos)
{
    return state | (1 << (pos - 1));
}

//将state的第pos位的值设为0
int bitDel(int state, int pos)
{
    return state & (~(1 << (pos - 1)));
}

位运算往往在游戏用来记录一些状态,一个32位的整数,就能记录32种状态,并且只需要一个int就够了。
例子:

假设一个NPC有以下几种状态,行走状态,站立状态,普通攻击状态,技能攻击状态,根据这个NPC的不同状态,客户端需要播放不同的动作。很多同学马上联想到的是用枚举,然后就开始写代码,很快就把程序写好了。这个时候,策划又提了一个新的需求,说攻击的时候可能会产生爆击,爆击的时候普通攻击和技能攻击都需要有不同的表现。
然后这个同学想了想,于是加了一个BOOL来记录这次攻击是否产生爆击,于是很快又把代码写好了。策划又提一个需求,攻击的时候还有命中。于是又加了一个BOOL来记录命中。如果还有BUFF效果,这就坑爹了!
真的是大部分刚招进来的同学都是这么干的,一个模块万多个BOOL,关键很气人的是这些BOOL还用一个INT8的方式一个一个地发往客户端。
解决方案:

用状态位来记录NPC的状态,一个8位的整数即可记录8种状态,16位,32位就可以记录更多的状态

  1. //伪代码  
  2. #define STATE_ATTACK 1 //普通攻击  
  3. #define STATE_SKILL 2 //技能攻击  
  4. #define STATE_DODGE 3  //爆击  
  5. #define STATE_HIT 4  //命中  
  6.    
  7. INT8 state = 0; //默认无任何状态  
  8.    
  9. state = bitAdd(state,STATE_ATTACK); //发起普通攻击  
  10. state = bitAdd(state,STATE_HIT);  //命中目标  
  11. state = bitAdd(state,STATE_DODGE); //产生爆击  
  12.    
  13. if(bitCheck(state,STATE_HIT) == 0) //如果未命中目标  
  14. {  
  15. }  
//伪代码




#define STATE_ATTACK 1 //普通攻击 #define STATE_SKILL 2 //技能攻击 #define STATE_DODGE 3 //爆击 #define STATE_HIT 4 //命中 INT8 state = 0; //默认无任何状态 state = bitAdd(state,STATE_ATTACK); //发起普通攻击 state = bitAdd(state,STATE_HIT); //命中目标 state = bitAdd(state,STATE_DODGE); //产生爆击 if(bitCheck(state,STATE_HIT) == 0) //如果未命中目标 { }

位运算 与 类似枚举 的操作,主要的区别在于位运算可以用一个变量来记录多种状态共同存在的情况。

位运算在游戏开发领域是用到的很多的,比如在游戏中的奖励系统,游戏中有很多种奖励,每日登录,排位赛,竞技场,公会奖励,在线奖励,签到奖励等,策划需要每一种奖励可以领取的时候,客户端在相应的功能按钮都需要光效表现来引起玩家注意,让玩家知道某某奖励现在是可以领取的。

我看到很多开发人员都是客户端把所有系统的数据都拿到了,然后再根据数据的相应情况来决定是否让这个按钮开启光效。其实我们只需要用一个整数,在服务器端算好每一种奖励是否可以被领取,客户端收到这个数据后,根据每一个状态的情况来开启相应的光效,让玩家点击进入相应的系统的时候,才去拿相应的数据。

位运算常用的是状态位、权限位、自定义加密 

&位运算符号的应用

  • 清零 
清零:快速对某一段数据单元的数据清零,即将其全部的二进制位为0。例如整型数a=321对其全部数据清零的操作为a=a&0x0。 (321=0000 0001 0100 0001) &0=0000 0000 0000 0000= 0000 0000 0000 0000
  • 获取一个数据的指定位 
例如获得整型数a=321的低八位数据的操作为a=a&0xFF。(321=0000 0001 0100 0001) & (0xFF = 0000 0000 1111 11111)
= 0000 0000 0100 0001
获得整型数a=321的高八位数据的操作为a=a&0xFF00。(321=0000 0001 0100 0001) & (0XFF00=1111 1111 0000 0000)
= 0000 0001 0000 0000
  • 保留数据区的特定位  
例如获得整型数a=321的第7-8位(从0开始)位的数据操作为: a=a&110000000
(321=0000 0001 0100 0001) & (384=0000 0001 1000 0000)=0000 0001 0000 0000

&lt;think&gt; 首先,用户的问题是关于如何将按位与运算(&amp;)和取模运算(Mod)进行转化。用户提到了引用[1]、[2]、[3]和[4],所以我需要参考这些信息。 回顾引用内容: - 引用[1]:提到按位与(&amp;)的效率高于取模运算%,快了10倍以上,并讨论了它们的关系。 - 引用[2]:讨论了取模运算mod和取余运算rem的区别,特别是在C++中,%是取余,向零取整;而取模向负无穷取整。 - 引用[3]:关于高效模幂运算,处理大指数等问题。 - 引用[4]:是关于角度和弧度的转换,似乎不直接相关。 用户的核心问题是:&quot;如何将&amp;运算和Mod运算进行转化&quot;,意思是转换按位与(&amp;)和取模(Mod)运算。 从引用[1]中,用户提到&quot;取模运算%和按位与&amp;的关系&quot;,并说打开了新世界的大门。这表明在某些特定条件下,它们可能有等价关系。 我的知识库中:按位与(&amp;)是位运算,用于操作整数二进制位;取模(Mod)是求余数的运算。它们本质上是不同的操作,但在某些约束下可以相互转换。 一个常见的情况是:当模数是2的幂时,取模运算可以用按位与来实现。例如: - 对于一个整数n和模数m,其中m是2的幂(如m = 2^k),那么 n mod m 等价于 n &amp; (m - 1)。 为什么? - 因为 m = 2^k,那么二进制表示中,m-1 是低k位全1的数字。 - n &amp; (m-1) 相当于取n的低k位,这正是n mod m的结果,因为模2^k的余数就是低k位。 例如: - n = 13 (binary 1101), m = 8 (2^3) - n mod m = 13 mod 8 = 5 - n &amp; (m-1) = 13 &amp; 7 = 1101 &amp; 0111 = 0101 = 5 所以,在模数是2的幂时,&amp; 可以代替 mod。 相反,如何将&amp;转化为mod?不太直接,因为&amp;是位操作,而mod是数学运算。但在特定上下文中,比如当处理掩码时,可以用mod来解释&amp;的行为。 用户的问题中说&quot;转化方法&quot;,所以我需要提供转换方法。 基于上述,关键点是:当模数是2的幂时,可以使用按位与。 从引用[1]:&quot;取模运算%和按位与&amp;的关系&quot;,并说位运算更快。引用[2]讨论了mod和rem的区别,但我认为在转换时,需要小心整数的表示方式,因为负数处理不同。 在C++中,%是取余,而真正的取模可能有不同行为。但在许多编程语言中,当处理正数时,% 可以被视为mod。对于负数,行为可能不同。 但在位运算上下文中,通常假设非负整数或二进制表示的正数,所以&amp;和mod (当m是2的幂) 可以安全互换。 现在,构建回答: - 回答结构清晰:使用中文。 - 解释关系:当模数是2的幂时,n mod m == n &amp; (m-1)。 - 提供例子。 - 警告:当m不是2的幂时,不能直接转化;负数处理可能不一致。 - 引用相关部分:结尾添加引用标识。 用户要求:&quot;生成相关问题&quot;,所以我需要在回答末尾添加相关问题。 相关问题应该基于主题:&quot;&amp;运算和Mod运算的转化&quot;,可能的主题: 1. 为什么当m是2的幂时这个转化有效? 2. 在其他编程语言中如何处理负数? 3. 实际应用场景,如哈希表实现。 4. 性能比较,如引用[1]提到的效率差异。 引用[3]关于模幂运算和引用[4]关于坐标转化似乎不直接相关,但引用[1]直接相关。 最终回答结构: 1. 引入主题。 2. 解释转化方法。 3. 提供例子。 4. 注意事项。 5. 添加相关问题。 引用标识:在相关段落末尾添加[^1], [^2]等,自然地添加。 &lt;/think&gt; ### 按位与(&amp;)和取模运算(Mod)的转化方法 按位与运算(`&amp;`)和取模运算(`Mod`或`%`)在本质上是不同的操作。按位与是位级别的运算,直接操作二进制位;取模运算是数学运算,计算除法余数。**但在特定条件下,它们可以相互转化&mdash;&mdash;关键在于模数必须是2的幂(例如 2、4、8、16 等)**。以下是详细的转化方法和原理分析。 #### 1. **当模数是2的幂时:用按位与代替取模** - **转化公式**:对于任意整数 \(n\) 和模数 \(m\)(其中 \(m = 2^k\),k 为正整数),满足: \[ n \mod m = n \And (m - 1) \] 这里,\( \And \) 表示按位与运算,\( m - 1 \) 是一个二进制低 k 位全为 1 的掩码。 - **原理**:模数 \( m = 2^k \) 时,余数等于 \( n \) 的低 k 位二进制值。按位与运算 \( n \And (m - 1) \) 直接提取这些低位,效率远高于取模运算(性能提升可达10倍以上)[^1]。 - **示例代码(Python)**: ```python def mod_to_bitwise(n, m): # 检查 m 是否为 2 的幂 if m &lt;= 0 or (m &amp; (m - 1)) != 0: raise ValueError(&quot;m must be a power of 2&quot;) return n &amp; (m - 1) # 测试:n=13, m=8 (2^3) print(mod_to_bitwise(13, 8)) # 输出: 5 (因为 13 % 8 = 5, 13 &amp; 7 = 0b1101 &amp; 0b0111 = 0b0101 = 5) ``` - **优点**:速度快,适用于性能敏感场景(如哈希表桶计算)。 #### 2. **当模数非2的幂时:无法直接转化** - 如果模数 \( m \) 不是 2 的幂(例如 m=3 或 m=10),按位与无法等价替代取模运算。因为按位与只能提取固定低位,而取模运算涉及更复杂的除法逻辑。 - **替代方案**:使用数学公式手动模拟,但效率较低: \[ n \mod m = n - \lfloor n / m \rfloor \times m \] 注意:负数的处理需谨慎(C/C++ 中 `%` 是取余,向零取整;而数学取模向负无穷取整)[^2]。 #### 3. **反向转化:如何将按位与转为取模?** - 按位与运算本身不直接对应取模,但可以通过上下文解释: - **当按位与被用作掩码**:例如 `n &amp; mask`,如果 `mask = 2^k - 1`,则等价于 `n mod (mask + 1)`。 - **示例**:若代码中有 `x = y &amp; 0b1111`(mask=15),则等价于 `x = y mod 16`。 - **通用方法不成立**:按位与是位操作,无法直接转换为任意取模运算。仅在掩码隐含模数关系时才有效。 #### 4. **注意事项** - **负数问题**:按位与假设整数为无符号或非负。若涉及负数,取模结果取决于语言规范(如 C++ 的 `%` 是取余,结果符号与被除数相同)[^2]。 - **效率权衡**:在位运算可用时优先使用 `&amp;`,但需确保模数是2的幂;否则,取模更通用。 - **应用场景**:常见于底层优化,如内存对齐、哈希函数或模幂运算(需处理大指数时)[^3]。 ### 相关问题 1. 为什么按位与运算的效率比取模运算高10倍以上? 2. 在负数情况下,如何正确处理取模和按位与的转化? 3. 取模运算在哈希表实现中有哪些优化应用? 4. 如何高效计算大整数的模幂运算(如引用[3]中的场景)? [^1]: 位运算与取模的效率对比及原理。 [^2]: 取模和取余运算的区别及负数处理。 [^3]: 模幂运算的难点与优化方法。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值