您的位置:首页 > 编程语言 > Java开发

Java 中的真值、机器数、原码、反码和补码:为什么整形的取值范围 不是对称的,比如 byte的取值范围为 -128到127,而不是-128到128或者-127到127?

2018-01-01 01:53 531 查看
首先,真值、机器数、原码、反码和补码这几个概念并不是Java独有的,而是真个计算机世界中通行的概念。

真值:就是我们日常说的十进制的正数,负数和0,比如-1,-2,-100,0,1,2,1000,100000等等。

机器数:首先,在计算机中使用二进制表示数值,也就是0或者1,其次计算机中有一个数位的概念,比如8位二进制数,16位二进制数,等等。最后,计算机中,第一位二进制数用以表示正负,且规定0为正,即+,1为负,即0为-。这种带有正负符号以及值的组合就是机器数,“机读得懂正负的数字”就是机器数。

然后我们以8位二进制数举例:-1是10000001,-2是10000010,第一个1表示负数的意思,+1为00000001,+2为00000010,第一个0表示正数。

而原码、反码和补码都是机器数的一种。

原码、反码和补码有两层含义的关系,第一层是形式变换的关系,第二层是数学变换的关系,下面我们一一道来。、

第一层是形式变换:

这里再次强调,将机器数需要注意位数的概念,即8位或者16位,或者其他,本文使用8位二进制数。

真值变为原码就是,首位表示正负,0为正,1为负,值的部分变为二进制。正如上文的例子-1是10000001,-2是10000010,第一个1表示负数的意思,+1为00000001,+2为00000010,第一个0表示正数。那么0在原码中是不是有两种表示法呢?是的,+0和-0,即00000000和10000000。对于8位二进制数来说,原码的取值范围是11111111到01111111,其对应的真值取值范围是-127到127,其中0对应+0和-0两个原码。

反码是在原码的基础上拓展出来的一种概念,比如+5和-5的原码数分别为00000101和10000101。正数的反码是其本身,负数的反码是除符号位外其他位取反(0变为1,1变为0),+0按照正数的规则,-0按照负数的规则,那么原码00000000的反码还是00000000,原码10000000的反码是11111111。对于8位二进制数来说,反码的取值范围是11111111到011111111,其对应的真值的取值范围是-127到127,其中0对应+0和-0两个反码。

而且这里需要说到一个模型:正负真值的反码求和为11111111,但是原码没有这个规律。

【+5】真值  【00000101】原   【00000101】反

【-5】真值   【10000101】原     【11111010】反

求和  【0】真值   【10001010】原   【11111111】反   

然后,该补码出场了,正负真值的反码求和是11111111,但是不是0啊,所以规定负数的补码是反码加1,那么正负真值的补码求和就是(1)0000000,最高位会被舍去哦。

而且,+0的补码是00000000,-0的补码也是00000000,这里补码里0只占用了一个标识符,多出了一个10000000,这里补码10000000其实对应真值部分的-128。

总结,正数和+0的原码、反码、补码都是一样的。负数和-0的反码是其原码的符号位外其他位取反(0变为1,1变为0)

第一张图总体看



第二层是数学变换:

这里再次重申一下本文是以8位二进制数来进行的。

之所以强调是8位二进制数,因为这意味着我们所能表示的最高位的数是一定的,因为数值达到一定位置会被自动舍弃,如下的模型:





在这种具有累进关系的模型中(数学中称之为模):

所以就很神奇了,由于8位二进制数的限制,当两个数相加超过128时,进位的操作就会留取剩余的部分。又由于这种累进的关系,我们可以使用正数取代负数,

正如上图-1和127处于同一个位置。所以,补码是这个变换过程之后的二进制表示,而10000000正好是真值-128,这样8位的二进制数在补码的时候可以表示的

真值范围就是-128到127,而Java正好是使用补码表示数字的,所以byte类型是8位,取值范围是-128到127

下图展示了补码通过mod的方式还原为真值的过程,

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 真值 机器码