重学Android:从位运算到二进制表示(零)

前言

以下内容针对非科班同学,可以快速掌握位运算和二进制表示等计算机基础运算知识,看过源码的同学都知道,源码中大量运用了位运算知识,如果你对这方面不了解的话,看起来是比较困难的,如果你工作接触到蓝牙数据,串口数据收发等内容,这方面更是你必须了解的。

首先说下我自己,以前非科班出身,这方面内容几乎没了解过,但从实习开始领导直接告诉我让我负责蓝牙(用485通信的运动数据蓝牙模块)传输这方面工作(回头想想工作这几年一共接触到了不下于8种不同的蓝牙模块协议),就开始疯狂恶补这方面内容16进制,位运算,异或校验,校验和,进制转换......,越看越蒙,发现短期内并不能完全理解,于是就边学边开发,不知不觉就突然懂了,就是这么神奇,所以说如果前期看不懂没关系,看到能认识就行,再翻翻笔记理解一下,慢慢就懂了(经验之谈)!

说的有点多,直接开搂!

1. 二进制表达形式

1.1 什么是二进制?

计算机内部是通过二进制(0和1)来存储和处理数据的。每一位(bit)只能取两个值,0或1,而多个二进制位(bit)组合起来可以表示不同的数值。比如,8个二进制位可以表示的数值范围是0000000011111111,即0到255,也代表一个字节。

1.1 高位低位?

我们或许在某些地方听说过,高几位和低几位之说,它们都是对于二进制而言诞生的,比如一个字节 8个bit 00010010 通常把左边的称为高位,右边的称为低位,可以叫高四位0001和低四位0010,这没什么讲的,大家了解就行。

2. 位运算概述

位运算是直接对二进制位进行操作的运算方式,常用于底层开发、性能优化和算法实现中。与普通的算数运算(加法、减法等)不同,位运算操作的是二进制位,速度极快,且适用于很多底层系统和嵌入式开发。常见的位运算包括:位与(&)、位或(|)、位异或(^)、位取非(~)、左移(<<)、右移(>>)以及无符号右移(>>>)。

2.1 位与(&)

位与(&)是一个二元运算符,它对比特位上的两个数字进行操作。当且仅当两个相应的位都是1时,结果才为1,否则为0。

举个栗子:

scss 复制代码
  1101 (13)  
& 1011 (11)  
----------
  1001 (9)

只有第二位和第四位都为1,所以结果是1001,即9。通常使用(&)提取相应位的值,比如获取一个字节的高4位 就 &0xF0,获取低四位就 &0x0F

2.2 位或(|)

位或(|)也是一个二元运算符,它会将两个数字的对应位进行比较,只要其中一个位为1,结果就是1。

举个栗子:

scss 复制代码
  1101 (13)  
| 1011 (11)  
----------
  1111 (15)

只有第二位和第四位都为0时才是0,其它位只要有一个为1,结果就为1。所以结果是1111,即15。这个通常运用是将高位和低位相加得到一个值,比如一个值使用高四位存储数值另一个用低四位存储,那么使用(|)就能等到他俩的累加和。

2.3 位异或(^)

位异或(^)是一个二元运算符,两个位相同则结果为0,不同则结果为1。

举个栗子:

scss 复制代码
  1101 (13)  
^ 1011 (11)  
----------
  0110 (6)

这个的应用一般是计算数据帧的校验(异或校验),确保帧完整。

2.4 位取非(~)

位取非(~)是一个一元运算符,它对每一位进行反转操作,将0变成1,将1变成0。

举个栗子:

scss 复制代码
  ~1101 (13)
  ---------
   0010 (-14)  (假设使用4位表示,反转操作会影响符号位)

位取非对一个数的二进制表示进行反转。在计算机中,取非的结果通常会被解释为负数,因为它的符号位(最高位)发生了变化。

2.5 左移(<<)

左移运算符(<<)是将数字的二进制表示向左移动若干位,左移相当于将数值乘以2的幂。左移时,低位补0。

举个栗子:

scss 复制代码
  00000001 (1)  
<< 2   
-----------
  00000100 (4)

1左移两位后变成了4。每左移一位,相当于将数字乘以2。位运算由于是直接操作位,所以运算极快,现在知道为啥源码中这么常见了吧。

2.6 右移(>>)

右移运算符(>>)是将数字的二进制表示向右移动若干位,右移相当于将数值除以2的幂。右移时,符号位会根据符号来进行扩展。

举个栗子:

scss 复制代码
  11100101 (-27)  
>> 3  
-----------
  11111100 (-4)

-27右移3位后变成了-4。右移时,高位补充符号位(在负数情况下为1)。这时候肯定会有人疑惑包括我在内,就算保留符号位,右移三位也是10001100啊,为什么是11111100,这里就简单记住负数移位后的空缺位将用1填充,正数是0填充,这是因为负数一般用补码表示,马上会介绍。

这里只是个特殊的栗子讲解下,开发中最常用的是正数的右移,对于负数我几乎没碰到过。

2.7 无符号右移(>>>)

无符号右移(>>>)与带符号的右移不同,它不保留符号位,而是补充0到高位。

举个栗子:

scss 复制代码
  11100101 (-27)  
>>> 3   
-----------
  00011100 (28)

-27无符号右移3位后变成了28,因为无符号右移会用0补充符号位。

小结

运算符 符号 描述 示例 结果解释
位与 & 如果对应位都是1,则结果为1;否则为0。 1101 & 1011 1001(13 & 11 = 9)
位或 如果对应位中至少有一个1,则结果为1;否则为0。 1101 丨1011 1111(13 | 11 = 15)
位异或 ^ 如果对应位不同,则结果为1;如果相同,则为0。 1101 ^ 1011 0110(13 ^ 11 = 6)
位取非 ~ 对二进制表示的每一位数字进行取反。 ~1101 0010(假设操作在4位上,~13 = 2)
左移 << 将二进制位左移指定的位数,低位补0。 0011 << 2 1100(3 << 2 = 12)
右移 >> 将二进制位右移指定的位数,高位根据符号位填充。 1110 >> 1 1111(-2 >> 1 = -1,假设操作在4位上)
无符号右移 >>> 将二进制位右移指定的位数,高位补0。 11100101 >>> 3 00011100(-27 >>> 3 = 536870902,假设32位)

3. 原码、反码与补码

在计算机中,负数是通过原码、反码和补码来表示的。这些方法影响着数值的存储方式及运算效率。了解这些概念是理解计算机如何处理负数的关键。

3.1 原码

原码是最简单的表示方法。它的最高位是符号位,0表示正数,1表示负数。其余位表示数字的大小。

举个栗子:

  • +7的原码:00000111
  • -7的原码:10000111

原码的优点是简单易懂,缺点是对于运算来说比较复杂,不方便进行加减运算,特别是当正负数混合时更为麻烦。

3.2 反码

反码同样最高位是符号位,0代表正数,1代表负数。其余位表示数值,与原码不同的是,负数的表示方法不同。负数的反码表示方法:将它的绝对值按位取反

举个栗子:

  • +7的反码:00000111
  • -7的反码:11111000

反码的优点是对于加减运算来说比原码简单,特别是当正负数混合时更简单,但缺点是在进行乘除运算时会出现问题。

3.3 补码

补码是现代计算机最常用的负数表示方法。补码同样最高位是符号位,0代表正数,1代表负数。其余位表示数值,其表示方法不同于原码和反码。补码解决了反码的不足,使得加减法运算变得更加简单高效。负数的补码表示方法:将其绝对值的二进制表示取反,然后加上1

举个栗子:

  • +7的补码:00000111
  • -7的补码:11111001

补码不仅能简化加减法运算,还能避免符号位带来的问题。

小结

类型 描述 正数示例 负数示例 特点
原码 最高位为符号位,0表示正,1表示负,其余位表示数值。 +7: 0000 0111 -7: 1000 0111 简单,但正负数加减法操作复杂
反码 正数的反码与原码相同,负数的反码为其原码除符号位外各位取反。 +7: 0000 0111 -7: 1111 1000 解决了0的表示问题,简化了加减法
补码 正数的补码与原码相同,负数的补码为其反码加1。 +7: 0000 0111 -7: 1111 1001 计算机内部普遍使用,优化了运算效率

4. 最后

希望对你有帮助,一起努力,共同进步!

另外给喜欢记笔记的同学安利一款好用的云笔记软件,对比大部分国内的这个算还不错的,免费好用::wolai

相关推荐
Mr.看海14 分钟前
机器学习鼻祖级算法——使用SVM实现多分类及Python实现
算法·机器学习·支持向量机
SimonKing26 分钟前
Mybatis-Plus的竞争对手来了,试试 MyBatis-Flex
java·后端·程序员
.格子衫.31 分钟前
018数据结构之队列——算法备赛
数据结构·算法
文心快码BaiduComate1 小时前
Comate Zulu实测:不会编程也能做软件?AI程序员现状令人震惊
java·程序员·前端框架
大模型教程1 小时前
告别数据隐私焦虑!用FastGPT免费私有化部署AI个人知识管理系统!
程序员·llm·agent
DyLatte1 小时前
迷失自我与忘记初心
程序员
怎么没有名字注册了啊2 小时前
求一个矩阵中的鞍点
数据结构·算法
Greedy Alg2 小时前
LeetCode 74. 搜索二维矩阵
算法
大模型教程2 小时前
非常适合初学者的大模型应用开发教程,快速掌握 LLM 开发技能
程序员·llm·agent
小猪咪piggy2 小时前
【算法】day7 滑动窗口+二分查找
算法