oracle 反码工具,原码、反码与补码 - 派大星呐的个人空间 - OSCHINA - 中文开源技术交流社区...

先来看一道 Go 语言中简单的运算题(虽然是Go,但应该看的懂):

package main

import "fmt"

func main() {

// 相当于平时的 int8 a = -128

var a int8 = -128

var b = a / -1

fmt.Println(b)

}

在 Go 语言中,int8代表有符号8 位整数。你觉得输出结果是什么呢?我们在文末再公布答案,在此之前,我们先来回顾一下有符号整数是什么。

有符号整数

一个数在计算机中的二进制表示称为机器数,这个机器数是带符号的。它的最高位是符号位,0 代表正数,1 代表负数。

以 8 位有符号整数为例,0000 0001代表十进制中的 1,1000 0001则代表十进制中的 -1。

11c9015f74848ecb5393dc89d06883c3.png

那么,你可能会问了:这样一来,8 位有符号整数的可表达范围应当是 [1111 1111,0111 1111],即 [-127, 127],但实际上它的可表达范围却是 [-128, 127],那么 -128 又从何而来呢?

想要理解 -128 的来历,我们还要知道原码、反码和补码的概念。

原码、反码和补码

计算机需要使用特定的编码方式存储数据,原码、反码和补码都是一种特定的编码方式。以下示例均以 8 位二进制数举例。

原码

原码[1]是「未经更改的码」,指一个二进制数左边加上符号位后所得到的码。

当二进制数大于 0 时,符号位为 0

当二进制数小于 0 时,符号位为 1

1a5b059bf973c887e6229a818a78e3fa.png

因此,用这种编码方式表示有符号的 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。

94d6bfc6da36cf5091884478f2f62e98.png

此时,用反码来计算 (+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

5b459f06e6e54fe338a65f50c117eb82.png

由于+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

补码使得所有整数集都能使用同一套加法规则

如果发生溢出,多出的高位将被截取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值