数据结构与算法--二进制详解 Python二进制算法详解 史上最详细的二进制讲解 彻底搞懂原码、反码、补码 Python的负数二进制表示形式

原码、反码、补码

机器数 和 真值
  • 机器数:
    一个数在计算机中的二进制表示形式, 叫做这个数的机器数。
    机器数是带符号的,在计算机用一个数的最高位,称为符号位:用来存放符号, 正数为0, 负数为1.
    例如:十进制中的数 +3 ,假设计算机字长为8位,转换成二进制就是:00000011 ;如果是 -3 ,就是 10000011;这里的 00000011 和 10000011 就是机器数(其实就是原码 表示形式)
  • 真值:
    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是 “无符号数” 131(二进制数:10000011 转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值(符号位直接按照0或者1 转换成 “+”“-” 占一个位置);例如:0000 0001的真值 = +000 0001 = +1;1000 0001的真值 = –000 0001 = –1;所以 二进制表示形式:10000011 --> - 000 0011 它的真值为 -3 ;其二进制结果为 131
原码、反码、补码的基础
  • 对于一个数,计算机要使用一定的编码方式进行存储:原码,反码,补码是机器存储一个具体数字的编码方式;既然有三种存储形式,那么计算机会选取哪种通用形式呢?答案是:选取补码,即数值在计算机中是以补码的形式来存储的,下面分步来说明为什么要用补码来存?

  • 原码

(1)原码(true form)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小!比如如果是8位二进制 1 :

[+1]= 0000 0001

[-1]= 1000 0001

(2)因为第一位是符号位,所以8位二进制数的取值范围就是:

[1111 1111 , 0111 1111] 
#换成 数字为:
[-127 , 127]

(3)原码的优缺点:优点是简单直观,大脑最容易理解,例如,我们用8位二进制表示一个数,+11的原码为00001011,-11的原码就是10001011;缺点就是:原码不能直接参加运算,如果运算可能会出错。例如:数学上,1+(-1)=0,而在二进制中:

00000001+10000001=10000010 # 换算成十进制为-2 ;这显然出错了

所以原码的符号位不能直接参与运算,必须和其他位分开,这就增加了硬件的开销和复杂性

  • 反码

正数的反码还是其本身负数的反码是在其原码的基础上,符号位不变,其余各个位取反

[+1] = [00000001]= [00000001][-1] = [10000001]= [11111110]'''
如果一个反码表示的是负数, 除了直观的看到它的最高位是1,它表示是个负数外,
我们无法直观的得出来它的具体数值,通常要将其转换成原码再计算
这里假如直接将负数的二进制反码,按:最高位为符号位“-” 剩下的位数按照二进制来转换的话
'''
11111110 --> -126 显然也不是原来的值 -1
  • 补码

正数的补码还是其本身负数的补码是其反码+1(也即是:在其原码的基础上, 符号位不变, 其余各位取反, 最后+1)

[+1] = [00000001]= [00000001]= [00000001][-1] = [10000001]= [11111110]= [11111111]# 如果一个补码表示的是负数, 除了直观的看到它的最高位是1,它表示是个负数外,
# 我们无法直观的得出来它的具体数值,通常要将其转换成原码再计算
# 这里假如直接将负数的二进制补码,按:最高位为符号位“-” 剩下的位数按照二进制来转换的话
11111111 --> -127 显然也不是原来的值 -1
  • 计算机为什么选用以补码的形式来存储?

(1)计算机只有加法运算,没有设置减法运算!原因是:对于计算机,加减乘数已经是最基础的运算,要设计的尽量简单;计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂!于是人们想出了将符号位也参与运算的方法;我们知道,根据运算法则:减去一个正数等于加上一个负数,即: 1-1 = 1 + (-1) = 0;所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单!
那么计算机要选取哪种码值来做加法运算呢?我们先来一一尝试,并看结果为什么要选择补码!

# 先补充:计算机是如何计算 减法 的,看下面的例子(这里我们假设已经知道是选取补码来运算)
# 求:1-2 的值
# 首先:将1-2 变成 1+(-2),然后分别将1的补码和-2的补码拿来运算
0000 ... 0001 (正数 1补码还是本身)
+
1111 ... 1110-2 的补码)
=
1111 ... 1111 (补码)
# 上面结果一看,不对啊,怎么不是-1啊?不急,有规定,我们先看最高位符号位为1,说明它是个负数
# 如果得到的是负数的话,我们需要将它转换成原码的表示形式,如果是正数(最高位符号位为0)则不需要
# 所以我们接着做:
1111 ... 1111 (补码)
1111 ... 1110 (反码)
1000 ... 0001 (原码)
即结果为-1 

(2)如果选择 原码来 存储:

# 假设要计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [00000001]+ [10000001]= [10000010]= -2 

'''
所以如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的,
这也就是为何计算机内部不使用原码表示一个数
'''

(3)如果选择 用 反码 来存储:

# 同样假设要计算十进制的表达式: 1-1=0
1 - 1 = 1 + (-1) = [0000 0001
二进制图文详解 二进制Binary 2进制 逢二进一的计数规则。 在计算机内部,一切数据都是2进制的!! 2进制的数字 补码 补码本质是一种解决负数问题的算法。 1. 将数据的一半当做负数使用。 2. 补码在内存中是2进制的,显示的时候为10进制。 - Java利用算法支持了补码计算: - Integer.parseInt() - Integer.toString() 3. 补码的缺点: - 不支持超范围计算 - 超范围计算自动溢出 4. 解决补码的缺点:采用更大范围(更多位数)的补码 Java是如何计算 -2-1 的 补码的规律 1. 大值的规律:高位0 剩下全是1 - int类型:一个0,31个1 - long类型:一个0,63个1 2. 小值的规律:高位1 剩下全是0 - int类型:一个1,31个0 - long类型:一个1,63个0 3. 负数高位是1, 正数高位是0 - 高位做为识别正数和负数的标志位:称为符号位 - 注意:符号位不是用来表示正负号的!!! 4. -1 的规律:所有位都是1!! 5. 溢出是有规律的! 是一个周期性计算结果。 - 大值+1 = 小值 6. 补码的对称现象:-n = ~n + 1 案例: int max = Integer.MAX_VALUE; System.out.println(Integer.toBinaryString(max)); int min = Integer.MIN_VALUE; System.out.println(Integer.toBinaryString(min)); long lmax = Long.MAX_VALUE; System.out.println(Long.toBinaryString(lmax)); long lmin = Long.MIN_VALUE; System.out.println(Long.toBinaryString(lmin)); //-1的规律 int n = -1; System.out.println(Integer.toBinaryString(n)); long l = -1L; System.out.println(Long.toBinaryString(l)); //大值+1溢出得到小值 // 推论:Java中的int数字是按照补码圆环排列的 int m = Integer.MAX_VALUE+1; System.out.println(m);//小值 //一个数的溢出测试: n = 345; m = n + Integer.MAX_VALUE+1; System.out.println(m);//负数 m = n + Integer.MAX_VALUE+1+ Integer.MAX_VALUE; System.out.println(m);//344 正数 m = n - (Integer.MAX_VALUE+1+ Integer.MAX_VALUE+1); System.out.println(m);//345 正数 经典面试题1 正数的溢出结果是负数(错误!!!) 经典面试题2 int i = Integer.MAX_VALUE+1; System.out.println( Integer.toBinaryString(i)); 选择运行结果(D): A. 11111111111111111111111111111111 B. 1111111111111111111111111111111 C. 01111111111111111111111111111111 D. 10000000000000000000000000000000 经典面试题3 System.out.println(~-55); 如上代码的运算结果: ( 54 ) System.out.println(~-230); 如上代码的运算结果: ( 229 ) System.out.println(~55); 如上代码的运算结果: ( -56 ) 16进制 16进制是2进制的简写形式 2进制运算 1. ~ 取反运算 2. & 运算(逻辑乘法) 运算规则: 1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0 运算用途: n: 00010100 11010111 01010001 11101010 m: 00000000 00000000 00000000 11111111 n&m-------------------------------------- k 00000000 00000000 00000000 11101010 如上的运算是一个有意义的运算: 意义在于k是数字n的低8位数字!!m是一个分割模板,称为Mask(面具) 案例: int n = 0x14d751ea;//16简写(缩写)的2进制 int m = 0xff;//255 int k = n&m; //输出 n m k 的2进制 3. | 或运算(逻辑加法) 规则: 0 | 0 = 0 1 | 0 = 1 0 | 1 = 1 1 | 1 = 1 用途: n = 00000000 00000000 00000000 10110101 m = 00000000 00000000 11011011 00000000 n|m ------------------------------------ k 00000000 00000000 11011011 10110101 //判断是否读取到文件的末尾: ch1 00000000 00000000 00000000 10110101 ch2 00000000 00000000 00000000 11001111 ch3 11111111 11111111 11111111 11111111 ch4 11111111 11111111 11111111 11111111 ch1|ch2|ch3|ch4 ------------------------- -1 11111111 11111111 11111111 11111111 if(ch1|ch2|ch3|ch4 >> 逻辑右移动运算 将2进制数的每个位向右移动,左侧空白补充0 规则: n: 00010100 11010111 01010001 11101010 m = n>>>1; m: 000010100 11010111 01010001 1110101 m = n>>>8; m: 00000000 00010100 11010111 01010001 案例: int n = 0x14d751ea; int m = n>>>1; //按照2进制输出n 和 m m = n>>>8; //按照2进制输出 m k = (n>>>8)&0xff; //按照2进制输出 k > 思考:将一个int拆分为4个8位数 d1 d2 d3 d4? 5. >> 数学右移位运算 复习:移动小数点计算 一个整数 312331. 将小数点先左移动一次 31233.1 原始数据除以10 将小数点先左移动2次 3123.31 原始数据除以100 如果看做小数点不动,数字向右移动一次,原始数据除以10 ... 2进制数有同样现象:数字向右移动一次,原数据除以2 n = 00000000 00000000 00000000 01010000 m = n>>3; m = 00000000000 00000000 00000000 01010 案例: n = 80;// 0x50 m = n>>3;// n<>` 数学右移位,高位补充规则 - 正数补0 负数补1,结果满足数学规则 - 如果溢出,向小方向取整 2. `>>>` 是逻辑右移位:高位只补充0 提示:如果数学计算 使用 `>>` 6. << 左移位运算 将2进制数位每位向左移动,右侧填充0 拼接int d1 = 00000000 00000000 00000000 11101010 d2 = 00000000 00000000 00000000 01010001 d3 = 00000000 00000000 00000000 11010111 d4 = 00000000 00000000 00000000 00010100 d4<<24 00010100 00000000 00000000 00000000 d3<<16 00000000 11010111 00000000 00000000 d2<> 数学右移位 面试题目: 如何优化 n*8 ? 答案: n<<3 提示: 被乘数一定是 2 的n次幂 如何优化 n%8 ? 答案: n&(8-1) 如何优化 n%4 ? 答案: n&(4-1) 如何优化 n ? 答案: n&(16-1) n%0xf 提示: 除数一定是 2 的n次幂
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值