有符号数、⽆符号数、浮点数的理解
初学计算机的时候,我们就被告知,计算机只能理解0和1,任何东西都是由0和1编码组成。本⽂针对⼆进制数字是如何组成有意义的数字,涉及到的编码形式进⾏理解,主要集中在三个概念:有符号数、⽆符号数、浮点数。虽然这些知识点在实际⼯作当中真正派上⽤场的机会并不多,但是对于理解计算机是如何联系真实世界,还是很有意义的。本⽂通篇都是围绕⼀个问题进⾏展开:如何对⼗进制数字进⾏编码,转化为计算机能够存储、传输的⼆进制数字?
⼀.原码和补码
⾸先是原码和补码这两个⽐较基础的概念,原码是⼀种⾮常⾃然⼆进制编码形式,和⼗进制⾮常类似。补码是相对来说⽐较抽象的概念,它主要是可以解决原码中同时存在+0和-0两种编码的缺陷。
1.原码
原码:是⼀种计算机中对数字的⼆进制定点表⽰⽅法。原码表⽰法在数值前⾯增加了⼀位符号位(即最⾼位为符号位):正数该位为0,负数该位为1(0有两种表⽰:+0和-0),其余位表⽰数值的⼤⼩。例如,对于⼗进制数字23,它的⼆进制原码为 10111【即2^4 + 2^2 + 2^1 + 2^0=23】。
2.补码
补码:N位数字的补码是相对于2^N, ⼀个原码数字和它的补码数字的和正好是2^N。例如,对于三个bit的数字010, 则它的补码是110, 因为 010+110=1000。它的计算是通过对原码数字取反再加⼀得到的。
补码还有⼀个特点就是从原码到补码和从补码到原码的运算过程是⼀模⼀样的,举例说明:-1 对应原码 1 0000001,除符号位外,进⾏取反加1,得到 1 1111111。再进⾏⼀次,除符号位外取反加1,得到 1 0000001,得到的刚好就是原码。这个特点对实际运算的简化是⾮常有利的。
⼆.⽆符号数和有符号数
⽆符号数就是针对⾮负整数数进⾏编码得到的⼆进制数字,编码的⽅式就是原码⽅式。因此对任意的⾮负整数N, 我们都可以⽤ log2(N)位⼆进制数字进⾏表达。 与⽆符号数相对应,有符号数就是针对⼀切整数进⾏编码得到的⼆进制数字。如何表⽰负号,⼀个很⾃然的⽅法是采⽤最⾼位作为符号位来表达正负。最⾼位为1代表是负数,为0代表是正数。如果⽤⼀个字节8位来存储,则-23就是 10010111 。⼀个字节所能表⽰的范围就是 -127 到 127。
但是这种有符号数的表⽰⽅式会有⼀个很明显的问题:1000000 和 0000000 都表⽰⼗进制0。为了解决这个问题,就是⽤原码来表⽰⾮负整数,补码来表⽰负整数。-23就是 11101001。+0 就是 0000000, 原来的 -0 就是 1000000,把它作为补码形式来理解,所对应的⼗进制数就是 -128。虽然浮点数的基数什么意思
这⾥实际上是溢出了,但是如果不管它溢出的话,对应的8bit的⼆进制数跟⽤补码形式表⽰的 -128是⼀模⼀样的。这种有符号数的表⽰⽅法对实际数学运算的好处是⾮常明显的。下⾯举⼀些实际例⼦来进⾏说明,这两个例⼦为了⽅便说明,都是以⼀个字节来进⾏表⽰,更⼤范围的数字增加字节进⾏存储,表⽰⽅法以此类推。
1. -128+127
-128就是 10000000,127就是 01111111。按照⼆进制进⾏相加,结果是 11111111。【再变回原码,除符号位外取反加1,就是10000001,对应的⼗进制数也就是 -1,这个过程只是为了让我知道 11111111 表⽰的就是 -1,计算机没有必要这样做,对于它来说, -1就是 1111111】。
2. -5+(-6)
-5就是 1 1111011, -6就是 1 1111010。相加的结果是 11110101 【变回原码是10001011,对应 -11】。
三.浮点数
对于实数域来说,还有⼀个对象就是带⼩数位的实数,带⼩数位的实数如何⽤⼆进制进⾏表⽰?这⾥就需要⽤到浮点数的概念了。
浮点数,是属于有理数中某特定⼦集的数的数字表⽰,在计算机中⽤以近似表⽰任意某个实数。具体的说,这个实数由⼀个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表⽰⽅法类似于基数为10的科学计数法。
浮点数的概念与⼗进制的科学计数法有点类似,⼀个⼗进制数1234可以表⽰为 1.234 x 10^3,
它可以分为尾数部分1.234和指数部分10^3 。1.234⽤⼆进制表⽰,⼩数点前数字1⽤⼋位⼆进制来表⽰的话是 00000001,0.234变为⼆进制表⽰的如果是abcd……, 则依然符合 a x 2^(-1) + b x 2^(-2) + c x 2^(-3) + d x 2^(-4) + ……。实际当中采⽤⼿算计算尾部⼆进制的话,⽅法如下: 0.234 x 2 = 0.468, 取整数部分0作为第⼀位;0.468 x 2 = 0.936, 取整数部分0作为第⼆位;0.936 x 2 =
1.872, 取整数部分1作为第三位;0.872 x 2 = 1.744, 取整数部分1作为第四位;0.744 x 2 = 1.488, 0.488 x 2 = 0.976, 0.976 x 2 = 1.952, …… 。合起来就是 0000001.0011101…… , 以⼩数部分后7位来看,变为⼗进制数就是 0.2265。如果想进⼀步精确表⽰0.234,所需要的⼆进制位数就越多。⼤部分时候,⼆进制表⽰⼩数部分都不能得到⼀个准确表⽰。所以,才会说计算机中都是⽤以⼀定精度来近似表达实数的。
按照前⾯的例⼦,1.234表⽰起来就是 0000001.0011101,这还只是个近似表⽰。对于这个⼆进制数,如果直接⽤计算机进⾏存储的话依然有很⼤的问题,⽐较浪费存储空间。解决⽅法就是采⽤浮点
数的表⽰⽅法。
如上图所⽰,浮点数主要是分为三部分:符号位 指数位 尾数部分。这⾥浮动是指⼆进制数⼩数点的移动,移动的准则是保证第⼀位为1,由于第⼀位永远是1,所以可以省略,只剩下位数部分⼩数点后⾯的若⼲位。浮点数主要是有两种形式:单精度32位和双精度64位。
对于⽤32位表⽰的浮点数来说,指数部分左移为正,右移为负【指数部分在这⾥没有符号位】,为了保证⾮负,采⽤⼀个默认的偏移量,8位指数位的原码形式最⼤能表⽰的是-127,指数位的默认偏移量就设置为127。 对于64位表⽰的浮点数来说,指数位为11位,默认的偏移量就是 0x03ff。单精度类型所能表达的⼤致范围就是 2^(-127) 到 2^(128) ,即 -10^(39) 到 10^(39) ; 双精度类型所能表达的⼤致范围就是 2^(-1023) 到 2^(1024) , 即 -10^(308) 到 10^(308)。
参考⽂献
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论