Byte 8位的范围为何是-128~127,而不是-127~128
一、计算机该怎么做减法
比如 2-1=1,1-1=0 由于种种原因,加法电路难度和成本已经很高了,当时的计算机理论条件下,再去设计一个减法电路,费力又费钱,前辈们想用加法电路来解决减法运算问题。思路如下,熟悉的可以跳过。
假设当前时针指向8点,而准确时间是5点,调整时间可有以下两种拨法:
一是倒拨3小时:8-3=5
二是顺拨9小时:8+9=12+5=5
可以看出在以模为12的系统中,减3和加9效果是一样的,因此减3运算,可以用加9来代替。
对“模”12而言,3和9互为补数(二者相加等于模)
“模”是计量器产生“溢出”的量。
从上面的事例中,我们可以得出结论,即在有模的计量系统中,减一个数等于加上它的补数(可以看下面的实例)。
这就可以将减法运算转化为加法运算,达到用加法电路来解决减法运算的目的。
例如:
减3和加253是一样的,8-3=8+253=256+5=5(对应的二进制数是[0000 0101])
就是说-3用253来表示,可以得到正确结果。这就是计算机做减法的思路。
二、这种算法的结果永远是正数
新的问题是 3-8=3+(256-8)=3+248=251,
显然3-8=-5。这种小的数字减去大的数字该怎么办?
例如:
3-8=3+(256-8)=3+248=251 (对应的二进制码是[1111 1011])
但是很显然,我们想要的是[1111 1011]=-5。
那我们有两种选择:
1)保留这种处理减法的思路,就让[1111 1011]=-5,然后再找其他的二进制码表示251
2)放弃这种处理减法的思路,确认[1111 1011]=251,并且找其他的二进制码表示-5
不管是哪种选择都必须舍弃一个数字,-5和251不能同时存在,有没有发现byte中没有正128,只有-128?
我们可以算一算,-5到-1是5个数,0算一个数,1到251是251个数,总共就有5+1+251=257个数,这可不行。因为8位二进制码最多只能表示256个数,如果-5和251都要表示,就会有257个数(不要少算了0),超出了表示范围。同理,-1和255 只能选一个,-2和254只能选一个,··· ,-128和128也只能选一个。
最终,为了避免2-3=2+(256-3)=255 = 2^8-1 ,即 255 = [1111 1111] 这样的尴尬。
我们确定将[1111 1111]定义为-1,而不是255,同理,[1111 1110]不再是254,定为-2,第一位为符号位,1为负号。
类推下去,0-128=-128,但是按原先的算法,0-128=0+(256-128)=128[1000 0000],尴尬了,因此128也光荣牺牲了,把[1000 0000]让位给-128,
至此,Java中byte的范围确定为-128~127,而不是-127~128。
三、拓展知识与常见问题
1、字、字节、位
字 word
字节 byte
位 bit
1字节=8位 (1 byte = 8bit),一个字节的字长是8
1字=2字节 (1 word = 2 byte) ,一个字的字长为16
字节通常简写为“B”,而位通常简写为小写“b”,计算机存储器的大小通常用字节来表示。
字长:计算机的每个字所包含的位数称为字长,计算的字长是指它一次可处理的二进制数字的数目。一般地,大型计算机的字长为32-64位,小型计算机为12-32位,而微型计算机为4-16位。字长是衡量计算机性能的一个重要因素。
bps( bits per second ),带宽、网络通讯的传输速率都是以「bps」为单位,例如 56Kbps、100.0Mbps
Bps( Byte per second ),电脑一般都以Bps 显示速度,例如 1Mbps 大约等同 128 KBps
bit,电脑记忆体中最小的单位,在二进位电脑系统中,每一bit 可以代表0 或 1 的数位讯号,正负电极表示
Byte,一个Byte由8 bits 所组成,可代表一个字元(A~Z)、数字(0~9)、或符号(,.?!%&+-*/),是记忆体储存资料的基本单位,每个中文字和中文符号则须要两 Bytes
bit - Byte - KB - MB - GB - TB - PB - EB - ZB - YB - BB
字节 (Byte) = 8位(bit)
1KB ( Kilobyte,千字节) = 1024B
1MB ( Megabyte,兆字节) = 1024KB
1GB ( Gigabyte,吉字节,千兆) = 1024MB
1TB ( Trillionbyte,万亿字节,太字节) = 1024GB
1PB ( Petabyte,千万亿字节,拍字节) = 1024TB
1EB ( Exabyte,百亿亿字节,艾字节) = 1024PB
1ZB (Zettabyte,十万亿亿字节,泽字节) = 1024EB
1YB ( Yottabyte,一亿亿亿字节,尧字节) = 1024ZB
BB ( Brontobyte,千亿亿亿字节) = 1024YB
信息存储量是度量存储器存放程序和数据的数量。
主要度量单位是字节,1个字节(Byte)等于8位(b)二进制。
位(bit,Binary Digits):存放一位二进制数,即0或1,为最小的存储单位,8个二进制位为一个字节单位。
一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。
英文标点占一个字节,中文标点占两个字节。
2、原码、反码、补码的概念是拿来干什么的?
答:现在唯一的问题是,用户输入-5后,计算机怎么得到[1111 1011]并保存。
计算机中的有符号数有三种表示方法,即原码、反码、补码。三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位,三种表示方法各不相同。在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理,用加法来替代减法。
整型数据在内存中的存放,是以补码表示的:
1)正数的补码,和原码相同
2)负数的补码,将该数的绝对值得二进制形式按位取反再加1
-5 = 1000 0101[原] = 1111 1010[反] + 1 = 1111 1011[补] (计算机内存的都是补码)
根据上面的理论,-5的补码就是256-5=251[1111 1011],但问题是我们正在解决减法问题,现在计算机还不会做减法,计算机怎么得到[1111 1011],
于是先辈们发明了一种算法,先得出原码[1000 0101],然后符号位不变,其余位取反(逻辑非),得到反码[1111 1010],再加1,得到了[1111 1011]。就是说,原反补码可以跳过计算直接得出2进制码。
3、计算机为什么不用原码表示负数?
答:
一是原码的作用本来就不是保存负数,也不保存正数,而是便于我们理解二进制。
二是因为原码做减法得到值是错误的。在减法计算中,2-1=[0000 0010]原+[1000 0001]原 = [1000 0011]原=-3,结果是不正确的。编码不仅要能表示数字,还要求运算结果和10进制不矛盾。
3.1 计算机为什么不用反码表示负数?
答:和原码同理,用反码也不能做减法:
2-1=2+(-1)=[0000 0010]原+[1000 0001]原= [0000 0010]反+[1111 1110]反=[0000 0000]反=[0111 1111]原= 127,并不等于正确结果1。(符号位也参与运算)
注:上面计算转二进制中,遵循了:
1)正数的补码,和原码相同
2)负数的补码,将该数的绝对值得二进制形式按位取反再加1
3.2 补码可以做减法吗?
答:可以
2-1=2+(-1)=[0000 0010]原+[1000 0001]原= [0000 0010]反+[1111 1110]反
= [0000 0010]补+[1111 1111]补 = [0000 0001]补 =1。
就是说只有补码可以做减法,所以计算机中采用补码来表示负数。
注:上面计算转二进制中,遵循了:
1)正数的反码与补码,和原码相同
2)负数的补码,将该数的绝对值得二进制形式按位取反再加1
3、8位二进制补码具体对应的10进制是多少?
答:
补码 .... 对应的实际数值
1000 0000 ... -128
1000 0001 ... -127
... ... ...
1111 1110 ... -2
1111 1111 ... -1
0000 0000 ... 0
0000 0001 ... 1
0000 0010 ... 2
... ... ...
0111 1110 ... 126
0111 1111 ... 127
上面的看不明白?没关系,我们来穷举法,找规律
正数,原码跟补码一样
+127, 0111 1111
+126, 0111 1110
+125, 0111 1101
+124, 0111 1100
+123, 0111 1011
+122, 0111 1010
...
下面是负数了,值,原码,符号位不变其它取反,+1
-10, 1000 1010, 1111 0101, 1111 0110
-11, 1000 1011, 1111 0100, 1111 0101
-12, 1000 1100, 1111 0011, 1111 0100
-13, 1000 1101, 1111 0010, 1111 0011
-14, 1000 1110, 1111 0001, 1111 0010
-15, 1000 1111, 1111 0000, 1111 0001
-16, 1001 0000, 1110 1111, 1111 0000
-17, 1001 0001, 1110 1110, 1110 1111
...
-24, 1001 1000, 1110 0111, 1110 1000
...
-99, 1110 0011, 1001 1100, 1110 0100
...
-124, 1111 1100, 1000 0011, 1111 1101
-125, 1111 1101, 1000 0010, 1000 0011
-126, 1111 1110, 1000 0001, 1000 0010
-127, 1111 1111, 1000 0000, 1000 0001
看出点什么了没有? 反码还差一个二进制 1000 0000
-128, 1 1000 0000, 1 1111 1111, 1 1000 0000 (注:最高位溢出,并不存在,符号位总在第一位1)
由此可见,-128的原码和补码,都是 1000 0000
回顾扩展,0 原码 0000 0000,非负数的原码、反码、补码都相同,都是 0000 0000
总结规律,发现很好玩的,如下:
数值 , 补码(计算机真实存储的二进制是补码)
127 , 0111 1111
.....
5 , 0000 0101
4 , 0000 0100
3 , 0000 0011
2 , 0000 0010
1 , 0000 0001
0 , 0000 0000
-128 , 1000 0000
-127 , 1000 0001
-126 , 1000 0010
....
-3 , 1111 1101
-2 , 1111 1110
-1 , 1111 1111
3.1 [1000 0000]补为什么表示-128?( 强烈推荐 )
答:上面已经解释了,这里只做验证推理。
[1000 0000]补不管是什么值,[1000 0000]补 + [0000 0001]补 = [1000 0001]补 是恒成立的
补码的原码,跟求原码的补码是一样的,即如下由补码求原码:
[1000 0000]补 = [1111 1111]反 = [1 1000 0000]原 = [1000 0000]原
同理,[1000 0000]原 来计算其补码:
[1000 0000]原 = [1111 1111]反 = [1 1000 0000]原 = [1000 0000]补
注意:符号位 1000 0000 的1一直不变,在二进制的位置总是第一位,第九位是溢出位,其为数值,舍弃。
所以,[1000 0000]补 = [1000 0000]原 = [1000 0000]补,[1000 0000] 是一个很特殊的编码
一步一步转化:
[1000 0000]补+[0000 0001]反(正数原码、反码、补码,三者都相同)= [1000 0000]反
[1000 0000]补+[0000 0001]反 = [1111 1111]反+[0000 0001]反 = [1 1000 0000]反 = [1000 0000]反
再转化:[1000 0000]补 + [0000 0001]原 = [1111 1111]原
[1000 0000]补 + [0000 0001]原 = [1111 1111]反 + [0000 0001]原 = [1000 0000]原 + [0000 0001]原
再转化:[1000 0000]补 + 1 = -127
很明显:[1000 0000]补 = -128
3.2 为什么是-128~127,而不是-127~128了?
答:如果是-127~128了,你会发现0-128=128
非负数有129个,负数只有127个(-1 ~ -127),补码不对称了。
3.3 网上有说因为-128和128同余,所以-128的补码是128,对吗?
答:首要问题不是-128的补码是多少,而是总共只有256个数,-128和128只能选一个,两个都存在不就是257个数了吗?
4、那教材上说原码中出现正0和负0又是怎么回事?
答:国内教材的狗屁理论。
5. 请问8位、16位、32位、64位CPU都是什么时间问世的?
答:CPU处理器8088是准十六位的、是继8086之后推出的,被IBM-PC机选作CPU
1979年6月1日,INTEL发布了 8位的8088微处理器。
1978年6月8日,INTEL发布其 16位微处理器8086。
1985年10月17日,x86系列CPU Intel 80386发布。80386的广泛应用,将PC从16位时代带入了 32位时代。
2003年才以x86-64和64位PowerPC处理器架构的形式引入到个人电脑领域的主流。
8088、8086 微型计算机的区别
1、CPU结构不同
1)8088只有8条数据信号引线。
2)8086有16条数据信号引线。
2、字节数不同
1)8088片内指令预取缓冲器深度只有4字节。
2)8086片内指令预取缓冲器深度为6字节。
段寄存器
一共有4个段地址寄存器,他们是:
CS (code segment register) 16位代码段寄存器
DS (data segment register) 16位数据段寄存器
SS (stack segment register) 16位堆栈段寄存器
ES (extra segment register ) 16为附加段寄存器
有待研究的问题:
1)-128的原码、反码各是多少?
2)计算机不可能懂-5,那我们点击“-”、“5”这两个键,cpu是否直接接受到了-5的源码了?
负数在计算机中的二进制表示
计算机中的有符号数有三种表示方法,即原码、反码、补码
整型数据在内存中的存放,是以补码表示的:
1)正数的补码,和原码相同。
2)负数的补码,将该数的绝对值得二进制形式按位取反再加1。
1、符号位
C语言规定,把内存的最高位作为符号位,0表示正数,1表示负数。
2、原码、反码、补码
在计算机中,正数的补码与原码相同,负数以其正值的补码形式表示
2.1 原码
一个整数,按照绝对值大小转换成的二进制数,称为原码,例如:6的4字节
00000000 00000000 00000000 00000110 是 6 的原码
2.2 反码
将二进制数按位取反,所得的新二进制数称为原二进制数的反码。
如 00000000 00000000 00000000 00000110 的反码是 11111111 11111111 11111111 11111001
2.3 补码
补码 = 反码 + 1 (仅限负数,正数补码是其本身)
反码加1称为补码。也就是说,要得到一个数的补码,先得到反码,然后反码加上1,所得数称为补码。
所以 -6 在计算机器的表示形式为:
# -6 的正值 6 的二进制: 00000000 00000000 00000000 00000110 # 取反得反码: 11111111 11111111 11111111 11111001 # +1 得补码,即 -6 在计算机中的二进制表示: 11111111 11111111 11111111 11111010
简易理解:若模数为256,则负数 -6 取模后的正数值为 -6+256=250
计算机的内存里,存储的都是整数(正数 + 0 + 负数)的补码
补码原理,负数为什么要用补码表示
1、模(Modulo)
In mathematics, modular arithmetic is a system of arithmetic for integers, where numbers “wrap around” upon reaching a certain value—the modulus (plural moduli).
模是指一个计量系统的计数范围,如时钟(12点、24点)、10进制、2进制、16进制、32进制、太极图等。
计算机也是一个计算器,它也是有一个计量范围,即都存在一个“模”。
如时钟的计量范围是0~11,模 = 12
32位计算机的计量范围是2^32,模 = 2^32
“模”是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数,
例如:
12点的余数有 0、1、2、3、4、5、6、7、8、9、10、11
2进制的余数有 0、1
10进制的余数有 0、1、2、3、4、5、6、7、8、9
2、补数
假设当前时针指向11点,而准确时间是8点,调整时间可有以下两种拨法:
1)倒拨3小时:11-3=8
2)顺拨9小时:11+9=12+8=8
在以模为12的系统中,加9和减3效果是一样的,因此凡是减3运算,都可以用加9来代替。对“模”12而言,9和3互为补数(二者相加等于模)。
所以,得出一个结论,即在有模的计量系统中,减一个数等于加上它的补数,从而实现将减法运算转化为加法运算的目的。
从上面的化减法为加法,以及所谓的溢出等等可以看到,“模”可以说就是一个太极,万事万物,阴阳转化,周而复始,无始无终,循环往复。
3、补码原理 ( 强烈推荐 )
计算机上的补码就是算术里的补数。
设我们有一个 4 位的计算机,则其计量范围即模是 2^4 = 16,所以其能够表示的范围是0~15,现在以计算 5 - 3为例,我们知道在计算机中,加法器实现最简单,所以很多运算最终都要转为加法运算,因此5-3就要转化为加法:
# 按以上理论,减一个数等于加上它的补数,所以 5 - 3 # 等价于 5 + (16 - 3) // 算术运算单元将减法转化为加法 # 用二进制表示则为: 0101 + (10000 - 0011) # 等价于 0101 + ((1 + 1111) - 0011) # 等价于 0101 + (1 + (1111 - 0011)) # 等价于 0101 + (1 + 1100) // 括号内是3(0011)的反码+1,正是补码的定义 # 等价于 0101 + 1101 # 所以从这里可以得到,正数5不变,-3实际用1101表示的,即: -3 = 1101 # 即 `-3` 在计算机中的二进制表示为 `1101`,正是“ -3 的正值 3(`0011`)的补码(`1101`)”。 # 最后一步 0101 + 1101 等于 10010
自己来一遍推演:
1)正数补码
5 = 0101 ,正数补码是其自身,即 5 补码也为 0101
2)负数补码
负数补码 = 负数反码 + 1
-3 = 1011 = 1100[反] + 1 = 1101[补],成功验证了 -3 补码为 `1101`
最后,因为我们假设的计算机是 4 位的,10010的第一位“溢出”了,所以只保存了 4 位,即 0010,而当计算机去读取时这正是我们所期望的 2
叹为观止吧,天才般的设计!感恩 伏羲、莱布尼兹和冯诺依曼!
参考推荐:
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2020-07-17 05:01:30
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!