为什么int8的范围是[-128,127]

简介: 为什么int8的范围是[-128,127]

今天这篇文章非常基础。


前几天看到的 go 一道题目,其实和 go 本身并没有多大关系。

func main() {

问 b 的值是多少?如果直接说 128,那可能还需要再去补补,毕竟 int8 的范围在 『-128,127』。


这道题的正确答案是 -128。那么问题来了:


为什么 int8 的范围是 『-128,127』?


答案为什么是 -128?


在开始之前,我们先来个简单介绍。


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


打个比方

var number int8 = 3

我们定义一个 number 的变量,它的类型是 int8,转换成二进制就是 00000011,如果是 -3,那么二进制就是 10000011。这里的 00000011 和 10000011 就是机器数。


因为机器数的第一位是符号位,所以机器数的形式值就不等于真正的数值,比如上面的 10000011 最高位 1 表示负,真正的值是 -3 ,而不是 131 (10000011 二进制转为十进制等于 131)。所以,为了区分,就把带符号位的机器数真正对应的数值称为机器数的真值。


0000 0001 的真值是 +000 0001 = +1

我们接着去了解原码,反码以及补码。


原码


原码就是符号位加上真值的绝对值。比如下面这个


[+1]原 = 0000 0001

原码是最容易理解的。因为第一位是符号位,所以 8 位的二进制原码的取值范围是


[11111 1111,0111 1111] 即 [-127,127]


反码


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


[+1] = [0000 0001]原 = [0000 0001]反

这样的话,如果一个反码表示的是负数,你无法直观的看出它的数值,通常需要转化成原码再进行计算。


补码


正数的补码就是它本身。负数的补码是在其原码的基础上,符号位不变,其余位取反,最后 +1。也就是在反码的基础上 +1。


1668568180442.jpg


同理,补码表示形式也是人脑无法直观看出数值的,也需要转化成原码再计算其数值。


从上面可以看出,原码,反码和补码是完全不同的,只有原码才是被人脑直接识别并用于计算表达方式的。为什么还需要反码和补码?


对于计算机来说,加减乘除已经是基础的运算了,要设计的尽量简单,计算机识别 “符号位” 显然会让计算机的基础电路设计变得复杂。于是想到把符号位也参与到运算中。我们知道,根据运算法则,减去一个数等于加上一个负数。1-1 = 1+(-1) = 0 因此计算机可以只有加法没有减法。


我们先看原码,十进制的表达式:1-1=0


1668568201197.jpg


如果用原码表示,让符号位也参与运算,显然对于减法来说,结果不是正确的。这也就是为何计算机内部不使用原码表示一个数。


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


1668568257896.jpg


可以发现,如果使用反码计算减法,结果的真值的部分是正确的,但是引发了新的问题,虽然在理解上 +0 和 -0 是一样的,但是 0 带符号是没有任何意义的。而且会有 [0000 0000] 和 [1000 0000] 两个编码表示 0。


补码终于要闪亮登场了。


1668568265573.jpg


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


1668568272333.jpg


在用补码运算的结果中,[1000 0000] 补 的值就是 -128。实际上是使用之前的 -0 的补码来表示 -128,所以 -128 并没有原码和反码的表示。这也是为什么 int8 使用原码或者反码表示的范围为 [-127,127]。使用补码,不仅仅修复了 0 的符号以及存在两个编码的问题,而且还能多表示一个最低数。


好了,我们再回到问题的本身。因为 var b int8 = -128 /a 不是常量表达式,因此 untyped 常量 -128 隐式转换为 int 8 类型 (和 a 一样),所以 -128 /a 的结果是 int8 类型,值是 128。超出了 int8 的范围,因为结果不是常量,允许溢出,128 的二进制表达式是 [1000 0000],正好是 -128 的补码,因此答案是 -128。

相关文章
|
10月前
error C2040: ‘n‘ : ‘int [1000]‘ differs in levels of indirection from ‘int ‘
error C2040: ‘n‘ : ‘int [1000]‘ differs in levels of indirection from ‘int ‘
85 0
|
7月前
|
算法 C# C++
for (int i = 0; i < v.size() - 1; i++)
for (int i = 0; i < v.size() - 1; i++)
|
8月前
CF489C Given Length and Sum of Digits
CF489C Given Length and Sum of Digits
|
9月前
|
设计模式 缓存 Java
就因为把int改成Integer,第2天被辞了
一个程序员就因为改了生产环境上的一个方法参数,把int型改成了Integer类型,因为涉及到钱,结果上线之后公司损失惨重,程序员被辞退了。信不信继续往下看。先来看一段代码:
46 0
成功解决np.array(zip(x1, x2)).reshape(len(x1), 2) ValueError: cannot reshape array of size 1 int
成功解决np.array(zip(x1, x2)).reshape(len(x1), 2) ValueError: cannot reshape array of size 1 int
成功解决ValueError: min_samples_split must be an integer greater than 1 or a float in (0.0, 1.0]; got th
成功解决ValueError: min_samples_split must be an integer greater than 1 or a float in (0.0, 1.0]; got th
|
Linux 测试技术 Perl
[20180308]测试ARG_MAX参数.txt
[20180308]测试ARG_MAX参数.txt --//上个星期遇到的问题,提到ARG_MAX 参数,可以通过$ getconf ARG_MAX 获得.链接 --//http://blog.
1475 0
1132. Cut Integer (20) 除零
Cutting an integer means to cut a K digits long integer Z into two integers of (K/2) digits long integers A and B.
1087 0