原码、反码、补码与十六进制,八进制

进行算法计算时,常常用到byte类型与十六进制之间的转化,一涉及到负数有时就犯迷糊,先整理记录下来。

1.首先,任何一个数或符号在计算机中,都是以二进制的形式存储的。

一个数在计算机中的二进制表示形式,  叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。

那么,这里的 00000011 和 10000011 就是机器数(但-3在计算中的实际存储中,并不是以10000011的形式存在,详见3)。

因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。

例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

2.下面谈一下十进制、八进制与十六进制。

而现实中我们所熟悉的十进制数,可能是先人还没发明计算机之前的计算方式吧(呵呵,扯远了)。后来有了计算机,单纯的使用二进制表示数,有时人闹反应出我们所熟悉的十进制数比较慢(反之,由十进制在人脑中隐射成二进制亦然),而实际情况中对于3位与8位的二进制经常出现,所以又有了8进制与16进制,而8进制的7正好对应二进制111,如下。

八进制          二进制真值
7                 111
77               111111
777             111111111

十六进制的f对应二进制的1111,转化很方便也很好反应,如下

十六进制            二进制真值
F                      1111     
FF                    11111111
FFF                  111111111111          

 而十进制与二进制却没有这个形式上的直观反应,如十进制中的9对应二进制的1001.99对应二进制的1100011没有什么直观规律可言。

所以在二进制的基础之上又发明了8进制与16进制。

(以上纯属个人臆想,只是为了自己理解方面,不可作为论断来看,权当一个小论述吧)

3.关于原码、补码、反码。

首先,在计算机中,正数是以原码的方式的存储并参与运算的,而负数则是以反码的方式存储并参与运算的。

原码:

原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:

    [+1]原 = 0000 0001
    [-1]原 = 1000 0001

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

[1111 1111 , 0111 1111] 

 即[-127 , 127]

反码:

反码的表示方法是:

正数的反码是其本身

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

    [+1] = [00000001]原 = [00000001]反
    [-1] = [10000001]原 = [11111110]反

补码:

补码的表示方法是:

正数的补码就是其本身

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

4.用补码表示负数的意义:(在此不讨论反码,本人认为反码是因补码而生的,只是一个中间概念)

方便计算运算:(在此仅以计算机的基本运算加减法运算为例)

正数之间的加法运算,可以根据二进制的运算法则直接相加求和。在此不再一一列举验证了,有兴趣的可以自己验证。

但是对于减法运算,我们知道减法运算在数学中,a+b等价于a+(-b),所以居此,二进制的减法可以由此根据加法运算法则加上其负数来进行减法运算。

在此:

若我们采用原码的方式计算,如下:

1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2 

 显然与实际不符。

为了解决原码做减法的问题, 出现了反码:

1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

虽然 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000] 和[1000 0000] 两个编码表示0.

于是补码的出现, 解决了0的符号以及两个编码的问题:

1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

 这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:

(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补

 注意:我们上面说的是用[1000 0000]表示 -128,而不是说-128的补码是[1000 0000](即由[1000 0000]不可根据原码转换成补码逆推出气原码)。-128是没有原码的。

在此,引入补码的意义出来了:

使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].

因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-2^31, 2^31-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

最后:

注意负数在计算中是以补码的形式存储并参与运算的!

参考资料:

http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html

猜你喜欢

转载自gwh-08.iteye.com/blog/1749105
今日推荐