iOS 进制、位运算符

171 阅读7分钟

一、进制

  • 十六进制(0x):0、1、2、3、4、5、6、7、8、9、a、b、c、d、e、f。
  • 八进制(0o): 0、1、2、3、4、5、6、7
  • 二进制(0b): 0、1
let a = 0x1 // 1
let b = 0x10 // 16
let c = 0o1 // 1
let d = 0o10 // 8
let e = 0b1 // 1
let f = 0b10 // 2
let g = 1 // 1
let h = 10 // 10

二进制

1、什么是二进制

二进制(binary),发现者莱布尼茨,是在数学和数字电路中以2为基数的记数系统,是以2为基数代表系统的二进位制。这一系统中,通常用两个不同的符号0(代表零)和1(代表一)来表示 [1] 。数字电子电路中,逻辑门的实现直接应用了二进制,现代的计算机和依赖计算机的设备里都使用二进制。每个数字称为一个比特(Bit,Binary digit的缩写)

2、计算机为什么采用二级制

首先,二进位计数制仅用两个数码。0和1,所以,任何具有二个不同稳定状态的元件都可用来表示数的某一位。而在实际上具有两种明显稳定状态的元件很多。例如,氖灯的“亮”和“熄” ;开关的“开” 和 “关”;电压的“高” 和“低”、“正”和 “负”;纸带上的“有孔”和“无孔”;电路中的“有信号” 和 “无信号”; 磁性材料的南极和北极等等,不胜枚举。 利用这些截然不同的状态来代表数字,是很容易实现的。不仅如此,更重要的是两种截然不同的状态不单有量上的差别,而且是有质上的不同。这样就能大大提高机器的抗干扰能力,提高可靠性。而要找出一个能表示多于二种状态而且简单可靠的器件,就困难得多了 [8] 。

其次,二进位计数制的四则运算规则十分简单。而且四则运算最后都可归结为加法运算和移位,这样,电子计算机中的运算器线路也变得十分简单了。不仅如此,线路简化了,速度也就可以提高。这也是十进位计数制所不能相比的 [8] 。

第三,在电子计算机中采用二进制表示数可以节省设备。可 以从理论上证明,用三进位制最省设备,其次就是二进位制。但由于二进位制有包括三进位制在内的其他进位制所没有的优点,所以大多数电子计算机还是采用二进制。此外,由于二进制中只用二个符号 “ 0” 和“1”,因而可用布尔代数来分析和综合机器中的逻辑线路。 这为设计电子计算机线路提供了一个很有用的工具[8] 。

由于计算机的硬件决定,任何存储于计算机中的数据,其本质都是以二进制码存储。

根据冯·诺依曼提出的经典计算机体系结构框架,一台计算机由运算器、控制器、存储器、输入和输出设备组成。其中运算器只有加法运算器,没有减法运算器(据说一开始是有的,后来由于减法运算器硬件开销太大,被废了)。

所以计算机中没办法直接做减法的,它的减法是通过加法实现的。现实世界中所有的减法也可以当成加法的,减去一个数可以看作加上这个数的相反数,但前提是要先有负数的概念,这就是为什么不得不引入一个符号位。符号位在内存中存放的最左边一位,如果该位位0,则说明该数为正;若为1,则说明该数为负。

而且从硬件的角度上看,只有正数加负数才算减法,正数与正数相加,负数与负数相加,其实都可以通过加法器直接相加。

原码、反码、补码的产生过程就是为了解决计算机做减法和引入符号位的问题。

原码、反码、补码

数值在计算机中是以补码的方式存储的,在探求为何计算机要使用补码之前, 让我们先了解原码, 反码和补码的概念。

对于一个数, 计算机要使用一定的编码方式进行存储。 原码, 反码, 补码是计算机存储一个具体数字的编码方式。

一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。比如,十进制中的数 +2 ,计算机字长为8位,转换成二进制就是[00000010]。如果是 -2 ,就是 [10000010] 。因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 [10000010],其最高位1代表负,其真正数值是 -2 而不是形式值130([10000010]转换成十进制等于130)。所以将带符号位的机器数对应的真正数值称为机器数的真值。

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。

反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。

补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)

1、原码

原码:是最简单的机器数表示法,用最高位表示符号位,其他位存放该数的二进制的绝对值。

以带符号位的四位二进制数为例:1010,最高位为1表示这是一个负数,其它三位010,即02^2+121+0*20=2,所以1010表示十进制数-2。

image.png

0001+0010=00111+2=3;
0000+1000=1000,+0+(-0)=-0;
0001+1001=10101+(-1)=-2
2、反码

原码最大的问题就在于一个数加上它的相反数不等于0,于是反码的设计思想就是冲着解决这一点,既然一个负数是一个正数的相反数,那干脆用一个正数按位取反来表示负数。

反码:正数的反码还是等于原码;负数的反码就是它的原码除符号位外,按位取反。

以带符号位的四位二进制数为例:3是正数,反码与原码相同,则可以表示为0011;-3的原码是1011,符号位保持不变,低三位按位取反,所以-3的反码为1100。

image.png

3、补码

补码:正数的补码等于它的原码;负数的补码等于反码+1

image.png

位运算符

逻辑运算符都是将值转成二进制后,二进制每一位进行处理。

按位移运算符 <<>>

// << 左移位,移动几位在后面加几个零。
let a = 0b101 << 1 // 0b1010 = 10
// >> 右移位,移动几位删除后面几位。
let b = 0b101 >> 1 // 0b10 = 2

按位与运算符 &

// 0b101 和 0b111相同位置只要有一个为1,则结果为1,否则为0。
let a = 0b101 & 0b111 // a = 7(0b111)

按位或运算符 |

// 0b101 和 0b111相同位置只要有一个为1,则结果为1,否则为0。
let a = 0b101 & 0b111 // a = 7(0b111)

按位取反运算符 ~

// 0b101每一位上1变为0,0变为1。
let a = ~0b101 // a = 2(0b010)

按位异或运算符 ^

// 0b101 和 0b111相同位置只要值不相等,则结果为1,否则为0。
let a = 0b101 & 0b111 // a = 2(0b010)