为什么int8的范围是[ |
您所在的位置:网站首页 › int8的取值范围 › 为什么int8的范围是[ |
今天这篇文章非常基础。 前几天看到的 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。 同理,补码表示形式也是人脑无法直观看出数值的,也需要转化成原码再计算其数值。 从上面可以看出,原码,反码和补码是完全不同的,只有原码才是被人脑直接识别并用于计算表达方式的。为什么还需要反码和补码? 对于计算机来说,加减乘除已经是基础的运算了,要设计的尽量简单,计算机识别 “符号位” 显然会让计算机的基础电路设计变得复杂。于是想到把符号位也参与到运算中。我们知道,根据运算法则,减去一个数等于加上一个负数。1-1 = 1+(-1) = 0 因此计算机可以只有加法没有减法。 我们先看原码,十进制的表达式:1-1=0 如果用原码表示,让符号位也参与运算,显然对于减法来说,结果不是正确的。这也就是为何计算机内部不使用原码表示一个数。 接着,为了解决原码做减法的问题,出现了反码: 可以发现,如果使用反码计算减法,结果的真值的部分是正确的,但是引发了新的问题,虽然在理解上 +0 和 -0 是一样的,但是 0 带符号是没有任何意义的。而且会有 [0000 0000] 和 [1000 0000] 两个编码表示 0。 补码终于要闪亮登场了。 这样,0 用 [0000 0000] 表示,之前的 -0 问题就不存在了,而且可以用 [1000,0000] 表示 - 128: 在用补码运算的结果中,[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。 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |