共计 6215 个字符,预计需要花费 16 分钟才能阅读完成。
0 前言
二进制的相干概念是学习数据存储、数据压缩、数据序列化的基石,只有真正搞清楚了二进制,能力逐渐深刻到算法源码,达到了解和复现的目标。
本文将介绍二进制和数据存储的相干概念(包含位、字节、高下位、大小端、原码、反码、补码、进制转换),以及二进制的位运算。
留神:本文解说偏实战,有些定义不够谨严,如需深入研究能够进一步浏览 https://zhuanlan.zhihu.com/p/…
1 基本概念
1.1 位、字节
位(bit):计算机外部存储数据的最小单位。
字节(Byte): 计算机存储容量(数据处理)的根本单位,1byte (字节)= 8 bit(位)。无符整型取值范畴 0~255,有符整型取值范畴 -128~127。
1byte = 8bit = 8 二进制位 = 2 个十六进制位
JAVA 中数据类型的占用内存大小如图所示:
留神,string 其实不属于根本数据类型,为便于比照将其放入字符型。
1.2 高位、低位、符号位
- 高位:指在数据类型限定范畴内靠左的二进制位。
- 低位:指在数据类型限定范畴内靠右的二进制位。
- 符号位:指在数据类型限定范畴内最右边的一个二进制位,符号位为 0 示意负数,1 示意正数。
【举例说明】
十进制数 1 的二进制为:0000 0001(最右边的 0 为符号位,从左往右对应的是高位向低位延长)
十进制数 - 1 的二进制为:1111 1111(最右边的 1 为符号位,从左往右对应的是高位向低位延长)
【扩大】为什么 - 1 的二进制位不是 1000 0001 呢?
详见 https://zhuanlan.zhihu.com/p/…
1.3 大小端
对于一个字节序列,如何解析?到底是从左读还是从右读?正因为有了读写程序的差别,带来了两种不同的模式。
【定义】
- 大端模式(Big-endian),是指数据的高字节位 保留在 内存的低地址中,而数据的低字节位 保留在 内存的高地址中。这样的存储模式有点儿相似于把数据当作字符串程序解决:地址由小向大减少,而数据从高位往低位放。和咱们”从左到右“浏览习惯统一。简言之,高位字节在前,低位字节在后。
- 小端模式(Little-endian),是指数据的高字节位 保留在 内存的高地址中,而数据的低字节位 保留在 内存的低地址中。这种存储模式将地址的高下位和数据位无效地联合起来,高地址局部权值高,低地址局部权值低,和咱们的逻辑办法统一。简言之,低位字节在前,高位字节在后。
比方字节数据 0x1A2B3C4D
内存的低位地址 ———–> 内存的高位地址
大端模式:1A 2B 3C 4D
小端模式:4D 3C 2B 1A
【特点】
- 大端:符号位在所示意的数据内存的第一个字节中,便于疾速判断数据的正负和大小(CPU 做数值运算时从内存中依程序顺次从低位地址到高位地址取数据进行运算,大端就会最先拿到数据的 (高字节的) 符号位)。
- 小端:CPU 做数值运算时从内存中依程序顺次从低位地址到高位地址取数据进行运算,开始只管取值,最初刷新最高位地址的符号位就行,这样的运算形式会更高效一些。
目前咱们常见的 CPU PowerPC、IBM 是大端模式,x86 是小端模式。ARM 既能够工作在大端模式,也能够工作在小端模式,个别 ARM 都默认是小端模式。个别通信协定都采纳的是大端模式。
1.4 原码、反码、补码
暂不深究定义,从利用的角度,能够将原码、反码和补码分割在一起了解,就是计算相反数,即
原码的相反数 = 原码的补码 = 原码的反码(在原码根底上按位取反)+1
【举例说明】
原码 =0000 0001(十进制为 1)
反码 = 原码按位取反 =1111 1110
补码 = 反码 +1=1111 1111(十进制为 -1)=- 原码
若原码为 -1,同样的运算能够失去其补码为 1,因而,对于计算相反数而言,原码和补码是个绝对概念。
通过 java 程序验证:
import org.junit.Test;
public class binaryTest {public void print(int value){System.out.println("value="+value+", 其二进制串为(左侧的 0 省略):"+Integer.toBinaryString(value));
}
@Test
public void test(){
int i=-1;
print(i); // 原码
print(~i); // 反码
print(~i+1); // 补码
}
【扩大】
如何用二进制示意浮点数?为何会有精度损失?
详见 https://cloud.tencent.com/dev…
1.5 进制的示意与转换
JAVA 中的进制示意及转换:
@Test
public void convert(){
// 二进制示意 -- 用 0b
System.out.println(0b101);
// 十六进制示意 -- 用 0x
System.out.println(0x101);
// 二进制转十进制
System.out.println(Integer.valueOf("101",2));
// 十六进制转十进制
System.out.println(Integer.valueOf("a",16));
// 十进制转二进制
System.out.println(Integer.toBinaryString(10));
// 十进制转十六进制
System.out.println(Integer.toHexString(10));
}
运行后果如下:
5
257
5
10
1010
a
2 位运算
2.1 与、或、非、异或
假如 A = 60,B = 13; 它们的二进制格局示意将如下:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
2.2 有符号左移 <<
定义:a<<n,即 a 整体左移 n 位,高位抛弃,低位补零。
特点:每左移一位,相当于该数乘以 2。
留神:当 n =size- 1 时(size 指位数,如 1btye 的 size=8),符号位扭转,数值产生极其变动。
JAVA 代码验证如下:
@Test
public void zuoyi(){
int i=1;
System.out.println("================ 原始数据 ===============");
print(i);
System.out.println("================ 左移 1 位 ===============");
print(i<<1);
System.out.println("================ 左移 31 位 ===============");
print(i<<31);
int j =-1;
System.out.println("================ 原始数据 ===============");
print(j);
System.out.println("================ 左移 1 位 ===============");
print(j<<1);
System.out.println("================ 左移 31 位 ===============");
print(j<<31);
}
运行后果如下:
================ 原始数据 ===============
value=1, 其二进制串为(左侧的 0 省略):1
================ 左移 1 位 ===============
value=2, 其二进制串为(左侧的 0 省略):10
================ 左移 31 位 ===============
value=-2147483648, 其二进制串为(左侧的 0 省略):10000000000000000000000000000000
================ 原始数据 ===============
value=-1, 其二进制串为(左侧的 0 省略):11111111111111111111111111111111
================ 左移 1 位 ===============
value=-2, 其二进制串为(左侧的 0 省略):11111111111111111111111111111110
================ 左移 31 位 ===============
value=-2147483648, 其二进制串为(左侧的 0 省略):10000000000000000000000000000000
2.3 有符号右移 >>
定义:a>>n,即 a 整体右移 n 位,低位抛弃,负数高位补零,正数高位补一。
特点:每右移一位,相当于该数除以 2(向下取整)。
留神:当 n 大于原理论有效位数时,负数的最终后果为 0,正数的最终后果为 -1。
JAVA 代码验证如下:
@Test
public void youyi(){
int i=5;
System.out.println("================ 原始数据 ===============");
print(i);
System.out.println("================ 右移 1 位 ===============");
print(i>>1);
System.out.println("================ 右移 2 位 ===============");
print(i>>2);
System.out.println("================ 右移 3 位 ===============");
print(i>>3);
int j =-5;
System.out.println("================ 原始数据 ===============");
print(j);
System.out.println("================ 右移 1 位 ===============");
print(j>>1);
System.out.println("================ 右移 2 位 ===============");
print(j>>2);
System.out.println("================ 右移 3 位 ===============");
print(j>>3);
}
运行后果如下:
================ 原始数据 ===============
value=5, 其二进制串为(左侧的 0 省略):101
================ 右移 1 位 ===============
value=2, 其二进制串为(左侧的 0 省略):10
================ 右移 2 位 ===============
value=1, 其二进制串为(左侧的 0 省略):1
================ 右移 3 位 ===============
value=0, 其二进制串为(左侧的 0 省略):0
================ 原始数据 ===============
value=-5, 其二进制串为(左侧的 0 省略):11111111111111111111111111111011
================ 右移 1 位 ===============
value=-3, 其二进制串为(左侧的 0 省略):11111111111111111111111111111101
================ 右移 2 位 ===============
value=-2, 其二进制串为(左侧的 0 省略):11111111111111111111111111111110
================ 右移 3 位 ===============
value=-1, 其二进制串为(左侧的 0 省略):11111111111111111111111111111111
2.4 无符号右移 >>>
定义:a>>>n,即 a 整体右移 n 位,低位抛弃,高位负数补零。
特点:若 a 为负数,则 >>> 与 >> 成果一样;若 a 为正数,挪动后均转为负数。
@Test
public void youyi2(){
int i=5;
System.out.println("================ 原始数据 ===============");
print(i);
System.out.println("================ 右移 1 位 ===============");
print(i>>>1);
System.out.println("================ 右移 2 位 ===============");
print(i>>>2);
System.out.println("================ 右移 3 位 ===============");
print(i>>>3);
int j =-5;
System.out.println("================ 原始数据 ===============");
print(j);
System.out.println("================ 右移 1 位 ===============");
print(j>>>1);
System.out.println("================ 右移 2 位 ===============");
print(j>>>2);
System.out.println("================ 右移 3 位 ===============");
print(j>>>3);
}
运行后果如下:
================ 原始数据 ===============
value=5, 其二进制串为(左侧的 0 省略):101
================ 右移 1 位 ===============
value=2, 其二进制串为(左侧的 0 省略):10
================ 右移 2 位 ===============
value=1, 其二进制串为(左侧的 0 省略):1
================ 右移 3 位 ===============
value=0, 其二进制串为(左侧的 0 省略):0
================ 原始数据 ===============
value=-5, 其二进制串为(左侧的 0 省略):11111111111111111111111111111011
================ 右移 1 位 ===============
value=2147483645, 其二进制串为(左侧的 0 省略):1111111111111111111111111111101
================ 右移 2 位 ===============
value=1073741822, 其二进制串为(左侧的 0 省略):111111111111111111111111111110
================ 右移 3 位 ===============
value=536870911, 其二进制串为(左侧的 0 省略):11111111111111111111111111111
参考目录
[1] https://zhuanlan.zhihu.com/p/…
[2] https://zhuanlan.zhihu.com/p/…
[3] https://www.runoob.com/java/j…
[4] https://cloud.tencent.com/dev…
[5] https://zhuanlan.zhihu.com/p/…
[6] https://m.yisu.com/zixun/2158…