洞察纵观鸿蒙next版本,如何凭借FinClip加强小程序的跨平台管理,确保企业在数字化转型中的高效运营和数据安全?
692
2022-09-01
深入浅出:举个例子解读原码、反码与补码(原码反码补码课件)
先来看一道 Go 语言中简单的运算题:
package main import "fmt" func main() {
var a int8 = -128 var b = a / -1 fmt.Println(b)
}
在 Go 语言中,int8
代表
有符号
8 位整数。你觉得输出结果是什么呢?我们在文末再公布答案,在此之前,我们先来回顾一下
有符号整数是什么。
有符号整数
一个数在计算机中的二进制表示称为机器数,这个机器数是带符号的。它的最高位是符号位,0 代表正数,1 代表负数。以 8 位有符号整数为例,0000 0001 代表十进制中的 1,1000 0001 则代表十进制中的 -1。
那么,你可能会问了:这样一来,8 位有符号整数的可表达范围应当是 [1111 1111, 0111 1111],即 [-127, 127],但实际上它的可表达范围却是 [-128, 127],那么 -128 又从何而来呢?想要理解 -128 的来历,我们还要知道原码、反码和补码的概念。
原码、反码和补码
计算机需要使用特定的编码方式存储数据,原码、反码和补码都是一种特定的编码方式。以下示例均以 8 位二进制数举例。
原码
原码
[1]
是「未经更改的码」,指一个
二进制数左边加上符号位
后所得到的码。
当二进制数大于 0 时,符号位为 0
当二进制数小于 0 时,符号位为 1
-127 和 127 的原码表示因此,用这种编码方式表示有符号的 8 位二进制数,它的取值范围是 [1111 1111, 0111 1111],即 [-127, 127]。如果我们使用原码计算 (+1) + (-1) 会得到什么结果呢?
(+1) + (-1) =
0000 0001(原码)
+
1000 0001(原码)
=
1000 0010(原码)
=
(-2)
What? 等于 -2 了?这显然是错误的答案。
反码
为了解决「正负数相加」的问题,人类又发明了
反码
[2]
。反码的表示方式为:
正数的反码等于它的原码
负数的反码则保留其原码符号位,然后对其他位进行取反操作
取反操作:将 0 变为 1,1 变为 0。
原码 -> 反码此时,用反码来计算 (+1) + (-1):
(+1) + (-1) =
0000 0001(反码)
+
1111 1110(反码)
=
1111 1111(反码)
=
(-0)
我们知道,0 的原码是
0000 0000
或
1000 0000,0 的反码就是
0000 0000
或
1111 1111。即在反码中,1111 1111
象征
-0,我们终于求出了正确的结果。
补码
但反码的表示方法中存在着
+0
和
-0
两个零,我们希望只有一个 0,所以
补码
[3]
出现了。补码的表示方式为:
正数的补码是其本身
负数的补码是在它的反码基础上加 1
原码 -> 反码 -> 补码由于 +1 的操作,必将出现进位,如果进位超过长度限制,最高位就会丢失。会发生最高位丢失的数就是 -0 的反码表示 1111 1111,它的补码为 1 0000 0000。由于长度是 8 位,最高位的 1 已经溢出,所以丢弃,-0 的补码就成了 0000 0000,和刚才我们所提到的 +0 完美重合了!用补码来计算 (+1) + (-1):
(+1) + (-1) =
0000 0001(补码)
+
1111 1111(补码)
=
0000 0000(补码)
=
(0)
答案正确!
因此,计算机内部使用补码方式表示负数,因为它让「正数 + 负数」也能使用同一套加法规则,使得所有的加法运算可以使用同一种电路完成。
-128 的由来
上面我们说到如果用补码的方式进行表示,-0
就不存在了,为了让有限的位数尽可能表示更多的数,省下的
1000 0000
就用来表示
-128
了。让我们用补码来计算一下
(-1) + (-127):
(-1) + (-127) =
1000 0001(原码)+
1111 1111(原码)
=
1111 1110(反码)+
1000 0000(反码)
=
1111 1111(补码)+
1000 0001(补码)
=
1 1000 0000(补码)
=
1000 0000(丢弃最高位)
=
(-128)
(-1) + (-127)
的结果正是 -128。但由于
1000 0000
是
-0
的补码,所以
-128
没有与之对应的原码和反码表示。
公布答案
好了,让我们再回头看一下开头的那段代码:
package main import "fmt" func main() {
var a int8 = -128 var b = a / -1 fmt.Println(b)
}
显而易见了:int8
的可表示范围是
[-128, 127],所以可以被赋值为 -128。而
(-128) / (-1) = 128
显然超过了该表示范围,+128 用有符号整数表示需要 9 位,表示为
0 1000 0000,最高位的 0 已经溢出,所以丢弃,导致结果是
1000 0000,即 -128。所以这段代码的输出结果就是 -128 啦~
总结
int8 表示有符号 8 位整数,它的可表示范围是 [-128, 127]
计算机内部使用补码方式表示负数
补码解决了 +0 和 -0 并存的问题,并省下 -0 的表示方法,多表示了一个最低数 -128
补码使得所有整数集都能使用同一套加法规则
如果发生溢出,多出的高位将被截取
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~