计算机眼中的负数

 

前言

C语言中,变量有许多类型,如short(int)、int、long int、float等等。

这些变量一旦给出什么类型的声明,内存就会分配给它一定长度的空间,以字节(byte)计算,也可用位(bit;比特)计算。

 

例如:short占用2字节,即是16比特;

    int占用的内存一般和计算机cpu单次处理位数有关,也和编译器环境有关,一般64bit计算机的int为64/8=8字节,32位计算机为32bit/8=4字节

 

但它仅仅是分配的内存长度,如果我们做了一些不合法的操作,会引发许多奇妙的事情。

 

由于计算机运算时,里面只有0和1。存储亦是0和1的形式。不出所料的话,计算机会根据给的内存空间大小(如8bit)一路上只能存储00111100或11100010这种形式

 

举个栗子

有一个奇妙的事情,示例如下:

Unsigned short  J  =-1

printf(“%u”,J)

得到65535

我们知道unsigned是无符号整型,它代表后续定义的变量是个正数,Unsigned short变量范围为0-65535(2¹⁶-1)。

signed是有符号整型,会将unsigned这样大小的变量范围分出大约一半给负数

signed类型里面,负数个数一般比正数多一个,比如-128为负数最小的那个,127为正数最大的那个,源于0这个位置分走了正数的位置

unsigned会把所有内存位都纳入计算,而signed会把第一位内存位(0或1)作为区别正或负数的标准。

在上述程序中,我们已知short有16bit,令其变量 j 等于-1 时,计算机会存储为 1111 1111 1111 1111(不论规定为signed还是unsigned)

但是你一旦输出,计算机进行解读“%u”,发现这个格式化输出是unsigned类型,便会直接把第一位也纳入计算,得到2^16-1=65535

 

计算机里的负数

在声明‘有符号(signed)’的整型变量时,以申请一字节(8bit)空间为例,变量取值范围为

              -128到127

即从         0000 0000到1111 1111

但要注意,上述两者之间并非按顺序对应。

 

在‘有符号’的整型变量中,在我们人看来,需要将二进制数第一位视为符号,它不参与计算,这一位中,0代表正数,1代表负数。为负数时,需要我们人加上补码操作,来理解这是多少。

 

众所周知,不论是‘有符号’的还是‘无符号(unsigned)’的,他们的二进制的0111 1111=十进制的2⁶+2⁵+2⁴+2³+2²+2¹=127

 

但127+1又是多少呢。

计算机的内在硬件只会加法,会将0111 1111+1=1000 0000

加法过程 详见《计算机组成原理》算术逻辑单元ALU

内存将所谓127+1 储存为1000 0000(注意,127+1之后不会是128了,反而是-128,因为在‘有符号’的整型变量中数字最大是127

 

但我们人需要知道,如何解读1000 0000,当然不能读成2⁷=128

这时第一位是1,所以它是负数,需要进行补码操作来认清它实际对应多少。

补码时,第一位符号位1略去不算,剩下的逐一取反,末尾一位加一。

即为1000 0000补码操作为 1000 0000 1111 1111  → 11000 0000

 

实际中计算机中它只是存储为1000 0000,因为只有8bit空间储存

 

我们人读取补码的1000 0000 : 11000 0000的含义时

第一个数字为1,即为负数,后续为128,所以这是-128

所以1000 0000   解读为   -128;而不能看做2⁷=128

 

计算机的确将我们的-128储存为了1000 0000,如果输出形式是“有符号整型变量”,那么计算机会毫不留情,按照刚刚的法则输出为-128

而之所以这么储存,是因为它适应计算机只会的加法运算。计算机的数数,是从越来越大的正数突然数到一个最小的负数,然后从负数越数越大,数到正数,就像是一个循环一样,这也是因为储存空间有限原因,所形成的闭环。而我们人可以数数到一个很大的正数,而不必担心这个世界存在不了这么大的一个数。

 

举个栗子

你看:

                -128+1=-127

计算机算为1000 0000+1=1000 0001

 

当作“有符号”类型输出这个时, 1000 0001 需要经过以上类似的补码操作,

1000 0001补码为

1 0111 1111

第一个为1,即为负数,后面为127。 所以这是-127

推广

以此类推。声明‘有符号’整型变量时(8bit为例),计算机是这样数数的:

0

1

 ……

127

-128

-127

…..

-1然后回到零。

即:

0000 0000

0000 0001

……..

0111 1111

1000 0000

1000 0001

…….

1111 1111

这里可以注意一下,-1表示为1111 1111

1111 1111+1=1 0000 0000(9bit)

但是只有一字节(8bit)空间可用,会发生‘溢出’现象,多余的第一位舍去。

变成0000 0000 即为 0

心得

很奇妙吧,补码就是为了迎合计算机硬件加法逻辑,人为创造的,窥见计算机储存内容是什么的工具。

 

posted @ 2022-10-19 17:04  不撞楠乔  阅读(160)  评论(0)    收藏  举报