java byte表示范围的疑惑

这篇文章来源于上一篇再讨论mysql字段类型选型时对数据类型存储范围的一点总结,但是写着写着对表示范围为什么是-128而不是-127产生了疑惑。因此去查了一些资料,整理下自己的想法。
由于本人非科班出身, 计算机基础奇差无比,只是按照自己的疑惑去尽量的让自己更好的理解,大神请绕道。

来算一笔账
byte类型占用一个字节(byte),一个字节等于8位(bit),。
那么如果我们考虑无符号的话,8位11111111能表示的最大数则为2的8次方-1即255,为什么-1,因为0也是其中一个数。八位二进制可以表示最大范围为0000 0000 ~ 1111 11111,一共256个数,也就是每个位如果都是1,那么最多可以表示2的8次方即256个数,然后0占一位,所以考虑无符号则表示的的最大数字为255 。

但是我们知道数字是存在负数的,如果我们要存负数怎么办?一共就能表示256个数字,都让你正数占去了,负数还怎么表示。因此如果要表示负数,就只能缩小正数的表示范围,给负数让位腾空。那么现在正数和负数的范围怎么去划分呢。

对于计算机二进制而言,最高位0为正数,1为负数,这个时候我们就要让出最高位来表示符号了,那么最终可以表示的正数范围自然就缩小了。整个正数的表示范围则为0000 0000 ~ 0111 1111,那么8位最大的二进制数即01111111,转换为我们常用的十进制即127, 所以1个字节最终可以表示的正数范围为 0 ~ 127。

但是当我们按照上述推导正数范围的思路去推导负数表示范围的时候,出现了问题,这个问题困扰了计算机零基础的我好几天;

摘录一段话以及结论

在计算机内,定点数有3种表示法:原码、反码和补码
[原码]二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
[反码]表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
[补码]表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。

现在计算机采用的是补码法。可以看到补码法需要用到反码

因为按照规则, 我们先不说数学概念,就按照二进制这个表示数的规则,则负数的范围则为11111111 ~ 1000 0000 ,(负数的绝对值越小其实表示的值越大,按从小到大因此将11111111放在了前面)。
按照反码定义, 1000 0000的反码为 1111 1111, 按照补码定义, + 1则八位二进制溢出了,现在我已经不知道该怎么去表示了。0000 0000 ? 按照这种说法的话(其实没想明白,查了结论),可以看出来负数的范围是-127到-0,就算我们说没有-0,但捅破了天, 现在最小的值怎么表示也表示的也只能是-127啊,但是已知的知识是负数的最小范围是-128,根本就推导不出来。

然后再回过头看一下0的问题,由于在数学上+0和-0是没有什么意义的,现在我们来看一下这三种数按照规则对0的表示形式

十进制二进制原码二进制反码二进制补码
+00000 00000000 00000000 0000
-01000 00001111 11110000 0000

从上面可以看出来一个问题,采用反码的话,针对0的正负两种表示会有两种不同的编码,而采用补码的话,则没有这个问题,都是统一的 0000 0000 (上面说的反码 + 1 导致的溢出问题,怎么来表示最后的补码没想明白)。
所以这也一方面的解释了为什么计算机采用补码的形式,但是现在再看看下针对0的原码也出现了两种表示形式, 于是本着0不分正负的原则进行资源合理利用, 00000000用来表示0, 而1000 0000,我们知道对应的正数为128, 由于8位的二进制无法表示到128,因此这个值给了-128,这里有个疑问,是不是给128也可以?按照自己的理解解释一下不能给128的原因, 因为符号位不满足, 现在1000 0000,从符号位看至少是个负数,这样保持了符号位的统一。

那么结合上面再来看一下,由于不需要考虑-0的问题, 那么最大的负数则为 1000 0001,即 -1, 而按照规则推导的最小的负数11111111,则让位给了1000 0000,那么就是 -1 ~ -128。暂时先这么说服自己吧,底子在这呢,没办法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值