知识点

1.计算机底层存储数据使用的是二进制。

2.计算机存储最小单位是bit,即1个二进制位。

3.一个数在计算机的存储形式是二进制数,我们称这些二进制数为机器数,机器数是有符号,在计算机中用机器数的最高位存放符号位,0表示正数,1表示负数。

4.因为带有符号位,所以机器数的形式值不等于其真值,以机器数1000 0111为例,其真正表示的值为-7(最高位1代表负数,不参与运算),而形式值为135。将带符号的机器数的真正表示的值称为机器数的真值。

// 二进制数 1000 0111 // 形式值 的10进制 0*2^7 0*2^6 0*2^5 0*2^4 0*2^3 1* 2^2 1*2^1 1*2^0 = 135 // 真值,1(最高位1表示负数,转10进制时不参数运行)000 0111 - (0*2^6 0*2^5 0*2^4 0*2^3 1* 2^2 1*2^1 1*2^0) = -7

5.计算机在存储一个数字时并不是直接存储该数字对应的二进制数字,而是存储该数字对应二进制数字的补码。

6.原码、反码、补码。

原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。

十进制数

原码

1

0000 0001

-1

1000 0001

- 正数的反码是其原码本身。

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

十进制数

原码

原码

1

0000 0001

0000 0001

-1

1000 0001

1111 1110

- 正数的补码是其原码本身。

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

十进制数

原码

原码

补码

1

0000 0001

0000 0001

0000 0001

-1

1000 0001

1111 1110

1111 1111

7.数据的存储大体流程:

计算机实际只存储补码, 所以原码转换为补码的过程,也可以理解为数据存储到计算机内存中的过程:

计算机中的原码反码和补码的运算:计算机存储原码(1)

在原、反、补码中,正数的表示是一模一样的,而负数的表示是不相同的,所以对于负数的补码来说,我们是不能直接用进制转换将其转换为十进制数值的,因为这样是得不到计算机真正存储的十进制数的,所以应该将其转换为原码后,再将转换得到的原码进行进制转换为十进制数。

为何使用补码

直接使用 “机器数(即原码)” 表示再进行计算不好吗?为啥还要有反码,补码?

因为计算机底层只能进行加法运算。所以在存储数时进行算法处理,运算时直接取出来进行加法运算,运算完结果直接存储,思路清楚简单,并且不让计算机关心符号位,让符号位参与到运算中去。用小学学的知识把减法转成加法就是这样: 1 - 1 = 1 (-1) = 0。

下面通过1-1 = 0 的例子分别看一下存储原码、反码、补码哪个才能得到正确的答案:

1 - 1 = 1 (-1)

1.存储时为原码:

(1的原码)0000 0001 (-1的原码)1000 0001 = (结果原码)1000 0010

1000 0010 转为 机器数的真值为 -2,明显 1-1 = -2是错误的,所以不能使用原码存储。

2.存储为反码:

(1的原码)0000 0001 (-1的原码)1000 0001

(1的反码)0000 0001 (-1的反码)1111 1110 = (结果反码)1111 1111

1111 1111 为反码,需要转为原码 1000 0000,再转10进制才是 机器数的真值 -0。结果看似是正确的,但如果有 0 和 -0 看起来怪怪的,因为0的正负是相同的。而使用[0000 0000]和[1000 0000] 都表示 0 有些浪费,所以才有了补码。

3.存储为补码:

(1的原码)0000 0001 (-1的原码)1000 0001

(1的反码)0000 0001 (-1的反码)1111 1110

(1的补码)0000 0001 (-1的补码)1111 1111 = (结果补码)0000 0000

0000 0000 为补码,需化为原码也为 0000 0000,而以前出现问题的-0则不存在了,那么也不能浪费呀,可以使用-0的补码(1000 0000)来表示 -128 ,正好推算也成立。推算过程如下:

(-1) (-127) = -128

(-1的原码)1000 0001 (-127的原码)1111 1111

(-1的补码)1111 1111 (-127的补码)1000 0001 = (结果补码)1000 0000

所以补码 1000 0000 表示 -128,比较特殊,是人们强制规定的,所以-128并没有原码和反码表示,只要补码是[1000 0000],其十进制数值就为-128。

因为补码多存储一个-128,而且在计算机底层中存储的是补码,所以在计算机中一个8位的二进制数的存储范围是用补码表示的[-128,127],而不是用原码或反码表示的[-127,127]。这也可以解释为什么计算机中一个字节的取值范围是[-128,127]。

整数的范围

本例子以32位系统为例,64位同理。1个int在32位系统上是 4个Byte(字节),4 * 8 = 32bit,即32个二进制位。

原码:0111 1111 1111 1111 1111 1111 1111 1111

反码:0111 1111 1111 1111 1111 1111 1111 1111

补码:0111 1111 1111 1111 1111 1111 1111 1111

根据原码转十进制为:2147483647

原码:1111 1111 1111 1111 1111 1111 1111 1111

反码:1000 0000 0000 0000 0000 0000 0000 0000

补码:1000 0000 0000 0000 0000 0000 0000 0001

根据原码转十进制为:-2147483647

同上面补码的 -0 此处的 -0 补码:1000 0000 0000 0000 0000 0000 0000 0000 可以当做最小的负数 -2147483647 ( -1) = -2147483648

总结:
  1. 掌握原码、反码、补码的意义。
  2. 32位的系统 有符号的 int (整数)的范围为:2147483647 ~ -2147483648

既然学习编程就一定把这些和语言无关的基本知识点弄懂。除了整数存储,浮点数存储也是一个值得研究的知识点。比如你在浏览器的 `开发者工具` -> `Console` 里输入 0.1 0.7 看看结果是多少?为什么会这样呢?后面再好好研究一下。

计算机中的原码反码和补码的运算:计算机存储原码(2)

,