计算机二进制储存

计算机二进制储存

我们都知道,计算机储存数据最终都是转换成二进制数字进行储存,而计算机进行简单的运算时,也是通过二进制下的数字进行计算的,下面我们就探究一下计算机在二进制储存下的计算方式。

首先我们在数学中学习过对一个十进制数字进行除二取余法之后倒序排列获得这个十进制数的二进制数。以(11)_{10}为例:

11除以2等于5,余数为1;5除以2等于2,余数为1;2除以2等于1,余数为0;1除以2等于0,余数为1。最后我们得到了1101,倒序排列就是1011,这就是二进制数的11,即(11)_{10}=(1011)_2

在计算机中,一个整数通常存放在一个整数型变量中,对于java而言,其整数型变量类型有byte, short, int, long四种;对于c++而言,其整型有unsigned int, int, long int(这里声明一点,c++语言中有short, int, long int, long long, long long int等等整型的数据类型,但是这些类型有微妙的关系。这和c语言当时的定义有关,c语言定义整型数据的空间占用根据操作系统的位数,具体大家可以参考其他博客资料或者书籍资料。而c语言标准也有这么一句话:长整型至少和整型一样长,整型至少和短整型一样长。也就是说int可以和short一样长,long可以和int一样长。这里我只列出三个类型,分别占用4Bytes, 4Bytes, 8Bytes)。

计算机储存变量的时候,通常把最左边一位当做符号位,即0表示正数,1表示负数。比如4Bytes的int类型变量储存了十进制的11,那么在内存中它的存在形式是00000000 00000000 00000000 00001011,那么如果它储存的是十进制的-11,那么它的存在形式是10000000 00000000 00000000 00001011,这个数就叫二进制原码。

但是当我们以二进制原码进行计算的时候,就会有出乎意料的问题发生,我把二进制下的11和-11相加(我按照1Byte长度的数字进行演示,这样省略了中间很多的0,看起来很方便),就是00001011 + 10001011 = 10010110 = (-22)_{10},这不正确!!!我们期望的结果是0,但是真正的计算结果是-22,发生了什么?!

这就要引出我们对于反码的概念,我们看到了对二进制原码进行计算会发生出乎预料的结果。所以数学家们很聪明,他们设计了一种二进制编码叫做反码。其规范是这个样子,对于一个正数,其二进制反码和原码相同;对于一个负数,其二进制反码即其二进制原码除了符号位各位取反后的结果。拿13和-15举例:(注明一下,因为我的原稿用的是原,反,补三个字做下标的。但是CSDN的公式不能使用中文作为下标,因此我就取这三个字的拼音首字母作为下标,请各位注意)(13)_{10}=(00001101)_y=(00001101)_f(-15)_{10}=(10001111)_y=(11110000)_f。那么13 + (-15) = (00001101)_f + (11110000)_f = (11111101)_f = (10000010)_y = (-2)_{10}。那么我们再拿15 + (-13)举例:15 + (-13) = (00001111)_f + (11110010)_f = (1\ 00000001)_f这里发生了进位,怎么办?别担心,二进制反码的计算准则是若存在进位,则把进位放到末尾位加上,简单来说就是把多出来的1加给后面的00000001,结果就是(00000010)_f=(+2)_{10}。是不是超级神奇?

但是即便是反码运算,也会存在 (00000000)_f(11111111)_f这两个东西,你可以把它转化成原码看。妈耶!这两个一个是+0一个是-0,而它俩竟然不是一个东西。我学过的数学0就是0,不存在-0这种东西耶?

所以这就引出了下一个东西,它叫做补码。补码的定义和反码很像,对于一个正数,它的二进制补码是它的二进制原码;对于一个负数,它的二进制补码是它的二进制反码再加上1。

还是拿-11举例子:(-11)_{10}=(10001011)_y=(11110100)_f=(11110101)_b。接下来还是拿15+(-13)和13+(-15)进行举例:13 + (-15) = (00001101)_b + (11110001)_b = (11111110)_b = (11111101)_f = (10000010)_y = (-2)_{10}15 + (-13) = (00001111)_b + (11110011)_b = (1\ 00000010)_b。这里要注意了,补码的计算和反码不一样,如果多出了1,那么直接当做越界处理,简单来说就是直接扔掉,保留之后的就好。也就是说,这里的(1\ 00000010)_b = (00000010)_b = (00000010)_y = (+2)_{10}。这样一来补码的计算问题也就解决了,那么接下来就是所谓的+0和-0的问题了,对于(-0)_{10} = (10000000)_y = (11111111)_f = (1\ 00000000)_b,我们不难发现,补码的-0直接越界了,按照我们之前的处理,1被扔掉了,那么又剩下00000000即+0了。我们统一了+0和-0!这很完美!

但是我们还是发现了有一个二进制补码无法被计算到,它就是(10000000)_b。你可以尝试把它转换成二进制原码,你会发现,根本无法转换!这时候我们把(10000000)_b人为定义成(-128)_{10}。为什么这么定义?你可以对它计算一下,你发现,当你计算(-128)+1时,它的结果奇迹般的是(-127)(这个过程我就不写了)。而你计算(-128)+(-1)的时候,它竟然成为了+127!这个过程是这样的:(-128)+(-1)=(10000000)_b+(11111111)_b=(1\ 01111111)_b=(01111111)_b=(+127)_{10}。这就牵扯到储存机制。1byte的数字可以储存从-128~127的数字,这个范围是-2^7~2^7-1。占用4bytes的int整型则可以储存从-2147483648~2147483647也就是-2^{31}~2^{31}-1。上面的7和31就是储存数据的位数。二进制补码就决定了当我们的数字越界的时候,最小的数字继续小下去,就会从最大的那个再小一个轮回;同样最大的数字继续大下去,就会从最小的那个再大一个轮回。

以上就是计算机二进制数据储存的原理。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值