#编程基础#计算机怎么存储负数

计算机中是用二进制来存储数据的。例如用八位二进制来表示数字,便是从00000000到11111111分别与十进制的0到255一一对应。按着这样的思路,二进制无非就是比十进制长一点,要表示更大的数,只要用更多的位就可以了。但这只是第一步,还有一个棘手的问题等着解决——怎么表示负数?

一、有符号数

日常书写中,负数其实就是正数前面加了一个负号。同样,将二进制数的第一位规定为符号位,用0代表正数,1代表负数,就能够表示负数了。这样八位二进制数中就分成了第一位符号位和后七位数值位。11111111就等于“-1111111”,而01111111就是“+1111111”。从00000000到11111111就表示了十进制下从-127到127的所有数字。这种带有符号位的数字称为有符号数,区别于没有符号位只能表示正数的无符号数。这很符合我们的阅读习惯,也没有对原本的存储规则有太大改动,不失为是一种简单优雅的方案。

二、新的问题

顺着这个方案继续拓展,很快又会碰到一个问题。尝试计算一下“1-2=?”,也就是“1+(-2)=?”。转为带符号位的八位二进制数,得到00000001+10000010=10000011。10000011对应的值是-3。也就是“1-1=-3”。这显然不对,因为把符号位也一起代入运算了,而符号位是额外人为规定的,本身并不符合算术运算的规则。因此还要为符号位单独制定一套运算规则。但运算结果的符号不仅与参与运算数字的符号有关,也与他们各自的绝对值有关。这样一来符号位的运算就变得很复杂。

三、反码

为了简化符号位的运算,需要对原有方案做一点修改。规定对负数的每一数值位都取反,正数不变。例如原本-2是表示为10000010,首位符号保持不变,剩下的0变成1,1变成0,得到11111101。11111101就称为-2的反码,而10000001就是-2的原码。而对于正数则不做取反操作,1还是用00000001表示。用反码来计算“1-2=?”,即00000001+11111101=11111110。要知道11111110代表什么数字,首先看符号位,是1,代表负数;再将数值位取反,得到原码10000001,也就是-1。“1-2=-1”,正确。这样只要用反码,符号位也可以直接代入运算了。虽然反码不方便阅读,但用户本来就不需要阅读计算机内部的数据,最后输出成十进制就可以了;但计算机内部的计算就大大简化了,只使用加法和正数就实现了减法和负数运算。

四、又一个问题

如果计算“1-1=?”呢?00000001+11111110=11111111。取反得到原码10000000,也就是-0。-0就是0,但这样一来,0这个数就有了两种表示方式。日常书写时不会写-0,但计算机内部的0和-0却是真实同时存在的。同时因为0的重复记录,八位二进制共256个位置却只表示了-127到127一共255个数,浪费了一个位置。

五、补码

于是在反码方案上继续修改。规定负数用补码表示,补码=反码+1。以-2为例,原码10000010,反码11111101,补码11111110。这时再来计算“1-1=?”,00000001+11111111=(1)00000000。由于只有八位二进制数,进位产生的最高位1会被舍弃,最终结果就是00000000,也就是0。现在-0消失了,空出来的位置呢?尝试计算“-127-1=?”,10000001+11111111=(1)10000000。因为补码=反码+1,发现10000000这个补码不存在对应的反码,自然也没有原码,这个就是-0被去掉后多出的位置。但根据“-127-1=-128”的等式,把10000000规定为-128的补码。

到此问题就全部解决了。按照最后补码的方案,八位二进制有符号数的表示范围就是-128到127共256个数。n位二进制有符号数的表示范围是-2^(n-1)到2^(n-1)-1共2^n个数。

你可能感兴趣的:(#编程基础#计算机怎么存储负数)