细谈为什么单字节的整数范围是[-128 ~ 127]???

01 计算机如何实现减法?

需要掌握的基础知识

在计算机中,机器数有三种表示方法:

  1. 对于正数: [X]原码=[X]反码=[X]补码
  2. 对于负数: [X]反码=[X]原码数值位取反,符号位不变。[X]补码=[X]反码+1

对于计算机来说,只认识0,1他不知道你给的是负数还是正数,如果你进行下面的运算,结果正确是你运气好【因为CPU的运算器只有加法器】

    0000 0011         2
+   0000 0010        +3
   -------  ------
    0000 0101         5

如果运算左边一个是正数一个是负数,那结果就不一定了。
首先,X-Y 我们可以转换为X+(-Y)运算。

那么负数的二进制如何表示 ?
举例:5就是 0000 0101,-5就是1000 0101

计算式: 8+(-5)?【被减数大于减数】
   0000 1000                8
+  1000 0101               -5
  -------        -------
   1000 1101(-13)         3

可以看到按照正常的加法规则,得到1000 1101,转换为十进制为 -13。显然,这是错误的答案。也就是说,在这种情况下,正常的加法规则不适用于正数与负数的加法,因此必须制定两套运算规则,一套用于正数加正数,还有一套用于正数加负数。从电路上说,就是必须为加法运算做两种电路。

计算机原理中有这么一句话 “计算机内部采用2的补码(Two’s Complement)表示负数。”

什么是2的补码?它是一种数值转换方法,分为两步

第一步,每一个二进制位都取相反值,0变成1,1变成0。比如,0000 0101的相反值就是1111 1010。

第二步,将上一步得到的值加1。1111 1010就变成1111 1011。

所以,0000 0101的2的补码就是1111 1011。也就是说,-5在计算机(8位机)中就是用1111 1011表示。

说了这么多2的补码有什么好处呢?

  • 2的补码就是最方便的方式。它的便利体现在,所有的加法运算可以使用同一种电路完成。

现在再看-5的补码表示法:

     0000 1000        8
   + 1111 1011		 -5(补码形式)
   -------    -------
   1 0000 0011        3 

可以看到,按照正常的加法规则,得到的结果是1 0000 0011 。注意,这是一个9位的二进制数。我们已经假定这是一台8位机,因此最高的第9位是一个溢出位,会被自动舍去。所以,结果就变成了0000 0011,转成十进制正好是3,也就是8 + (-5) 的正确答案。这说明了,2的补码表示法可以将加法运算规则,扩展到整个整数集,从而用一套电路就可以实现全部整数的加法。

计算式: 5+(-8)?【被减数小于减数】
     0000 0101        5
   + 1111 1000		 -8(补码形式)
   -------  -------
     1111 1101        -125 

好家伙翻车了!第二种情况结果不对!!!

再来探讨一下2的补码的本质?
在回答2的补码为什么能正确实现加法运算之前,我们先看看它的本质,也就是那两个步骤的转换方法是怎么来的。

要将正数转成对应的负数,其实只要用0减去这个数就可以了。比如,-5其实就是0-5。

已知5的二进制是0000 0101,-5就可以用下面的式子求出:

  0000  0000
 -0000  0101
---------

因为00000000(被减数)小于0000 0101(减数),所以不够减。请回忆一下小学算术,如果被减数的某一位小于减数,我们怎么办?很简单,问上一位借1就可以了。

所以,0000000也问上一位借了1,也就是说,被减数其实是100000000,算式也就改写成:

10000  0000
-0000  0101
---------
 1111  1011

进一步观察,可以发现100000000 = 11111111 + 1,所以上面的式子可以拆成两个:

 1111 1111
- 0000 0101	
---------
  1111 1010    
  +       1         
  -------
  1111 1011

2的补码的两个转换步骤就是这么来的。

为什么正数加法适用于2的补码?

实际上,我们要证明的是,X-Y或X+(-Y)可以用X加上Y的2的补码完成。

Y的2的补码等于(11111111-Y)+1。所以,X加上Y的2的补码,就等于:

X + (11111111-Y) + 1

我们假定这个算式的结果等于Z,即 Z = X + (11111111-Y) + 1

接下来,分成两种情况讨论。

第一种情况,如果X小于Y,那么Z是一个负数。这时,我们就对Z采用2的补码的逆运算(其实这块就是下面内容负数二进制转换为十进制的步骤),求出它对应的正数绝对值,再在前面加上负号就行了。所以,

Z = -[11111111-(Z-1)] = -[11111111-(X + (11111111-Y) + 1-1)] = X - Y

第二种情况,如果X大于Y,这意味着Z肯定大于11111111,但是我们规定了这是8位机,最高的第9位是溢出位,必须被舍去,这相当于减去100000000。所以,

Z = Z - 100000000 = X + (11111111-Y) + 1 - 100000000 = X - Y

这就证明了,在正常的加法规则下,可以利用2的补码得到正数与负数相加的正确结果。换言之,计算机只要部署加法电路和补码电路,就可以完成所有整数的加法。

有了上面的推导过程再来看看这道题

计算式: 5+(-8)?【被减数小于减数】
 1111 1111
-0000 1000
-------
 1111 0111
+0000 0101
-------
 1111 1100


 1111 1111
-1111 1100
-------
 0000 0011

运算的结果取反得到 1000 0011,显示是-3。是不是很绕那就多看几遍。

结论:采用补码运算,可以将减法转换成加法运算。

02 理解byte的数值范围为什么是[-128 127]? 【面试基础题】

Java中所有的数字均为有符号数,最高位是符号位,因此分为两部分去计算

正数所能表示的整数范围: 0000 0000 ~ 0111 1111 【除了符号位是七个零~七个1】

做法:
将二进制转换为十进制

左边: 0000 0000 结果:0
右边: 0111 1111 结果:127

运算过程:

0 * 2^7+1 * 2^6+1 * 2^5+1 * 2^4+1 * 2^3 + 1 * 2^2+1 * 2^1+1 * 2^0 = 127

所以正数的范围:0 ~ 127

负数所能表示的整数范围: 1000 0000 ~ 1111 1111 【除了符号位是七个零~七个1】

负数二进制转换为十进制需要下面几个步骤:
1000 0000【-128的补码形式】
先减1: 0111 1111 【这里需要向高位借一位】
按位取反: 1000 0000
转换为十进制: 128
添加负号: -128

同理:1111 1111
先减1: 1111 1110
按位取反: 0000 0001
转换为十进制: 1
添加负号: -1

所以负数的范围: -128 ~ -1

结论: 两者取并集得到byte字节的数值范围为[-128 ~ 127]

反过来 如果想知道一个负数(十进制)在计算机中如何表示,可以通过上面过程的逆运算得到负数的二进制。

通过以下资料的学习 ,总结成自己的内容,希望能帮到你。

阮一峰老师的关于2的补码

哔哩哔哩中的视频

猜你喜欢

转载自blog.csdn.net/lirui1212/article/details/114950520