• 补码的来源以及为什么byte的最小值是-128


    1、        有符号数和无符号数

    我们的实数分为正数和负数和0三部分

    Byte数据类型一共有8位,如果是无符号数,最大可以表示的数为11111111 = 256 -1 = 255

    无符号数代指不需要符号指明就可以知道它是什么数值大小。如果知道范围是正数和0的话,范围确实是0~255了

    可是我们的byte除了存储正数、0还需要存储负数。因此需要一个位置装载符号位。因此我们留出一个位置装符号位,其他位置存储值。第一个位置为0代表正数,第一个数为1代表负数。也就是我们的原码。然后范围应该是-2^7-1 ~ 2^7-1

    2、        引出补码的概念

    按前面的方式,我们使用原码进行运算

         正数运算:

             00001001

             +

             01111101

       = 10000110 第一位为符号位,所以值为 -6 计算用的是:9+125 = 134 超过了-127~127的范围丢失精度没问题。

         换小一点的数值:

             00001001

             +

             00000101

         =   00001110  9 + 5 = 14  计算结果对应上去了

    如果是减法运算呢?

             00001001

             +

    10000101

             = 10001110 = -14 这个减法当成加它的负数形式得到的有问题。我们除非让加负数的时候特殊处理,并不是做二进制加法运算才行。于是我们想办法。

    我们知道一些现象:

    把某物体左转 90 度,和右转 270 度,在不考虑圈数的条件下,最终的效果是相同的;

    把分针倒拨 20 分钟,和正拨 40 分钟,在不考虑时针的条件下,效果也是相同的

    把数字 87,减去 25,和加上 75,在不考虑百位数的条件下,效果也是相同的;

    我们找它们的规律:

       第一个要求两边组成1个圆

           90+270 = 360

        第二个要求总共60分钟,也是一个圆

            20 + 40 = 60

        第三个要求更难理解一些了,

            62 和162 相等,等于每过100就重置,把它也想象成一个圆,加法走的也是环线

            要求25 + 75 = 100

        这里的100/360/60都是一个周期,我们把它叫做“模”(也可以理解成进制)。然后25 和75 这种就是在该进制中的互补的数。

        数A + 数A的补数 = 进制

        数B – 数A = 数B - (进制 – 数A的补数)

    = 数B + 数A的补数  - 进制

    =数B + 数A的补数  (因为数B和数A在同一进制下,所以-进制可以舍去)

        我们去分析我们这里的问题了。

             如果能找到byte运算的进制,是不是就可以求到对应的补码,将减法变成加法形式呢?

             这个进制应该很好找:

                 数A + 数B = 100000000 也就是到了>100000000的数就会将前面的东西舍去了,值的范围只是 00000000这一块。这里要注意一些东西,也就是这是二进制而不是十进制。

        进行与负数的加法也就是与该数对应绝对值整数的补数做加法,减的过程就是逆旋转的过程。

    于是求负数的补数:

        补数 = 100000000(2进制) - |负数的绝对值|

        如: -5 的补数 = 256 – 5 = 251

        100000000

       -

         000000101

         011111011 (这里直接2进制减法相当于逆时针旋转)

        8位也就是11111011

        实验一次:

             8-5 = 3

             00001000

             +

             11111011

             =

             100000011 舍去逸出的位,得到:00000011 也就是3

    得到补数的过程也就是我们的由原码得到反码的过程,不过符号位要忽略掉计算的时候。然后总结规律得出了一个反码的概念,得到了一个计算式:

        反码 = 原码逐位取反,符号位不变

        补码 = 反码 + 1

    与正数的计算肯定用的不是它的补码而是原来的值,于是再得出结论:

        正数的补码等于它的反码等于它的原码

    由0值引出-128的由来:

        我们都是原码表示的时候,可以发现0的位置可以是2个值:

        00000000 和100000000 分别代表+0 和-0

        但是我们将0都转换为补码形式发现:

        100000000 – 0 = 100000000 。也就是说0的补码只有1种表示形态了,也就是00000000

        那么我们的补码中将就多了1个位置出来,可以存储其他值。我们将10000000 如果是无符号数则为128,所以我们这里就多存储了一个负数-128

    这里需要注意1个东西:

        原码和反码这些都是虚拟存在的,它是在换算补码过程中的产物,所以我们不会去管-128如果换算成原码是不是成-0了,为了解决减法问题和0有两个位置的问题等我们才找到了补码这种存储方式的。

        就是原和反的过程是过度的过程,计算机内计算和存储都是补码。补码的由来是负数在进制内相当于它的补数。正数的补码是它本身(不是补数)。求补码的过程和利用补码求10进制值可以用前人总结出的规律,但是要注意一些特殊值,所以理解根本上的求补是很有必要的。

    这里引出前面讲的另一个误区:

        我们前面理解的二进制形式是带符号的,符号是在二进制之外的东西,包括浮点数的小数点这些。

        其实是有问题的,我们java中的二进制就已经存储了数据的全部信息,包括了整数与分数,包括了符号位。

    这里可以发现一个问题:

        数值的2进制形式表现的是它的补码形态,输出的二进制文件会将前面的0都省略

    参考链接:https://blog.csdn.net/z69183787/article/details/79387207

    https://blog.csdn.net/TSZ0000/article/details/82881888

    https://blog.csdn.net/snowsnowsnow1991/article/details/47445153

  • 相关阅读:
    poj2623
    poj2635
    案例解析丨 Spark Hive 自定义函数应用
    云图说 | 华为云GPU共享型AI容器,让你用得起,用得好,用的放心
    云小课 |选定合适的证书,做“有证”的合规域名
    记一次 node 项目重构改进
    SpringBoot写后端接口,看这一篇就够了!
    如何让知识图谱告诉你“故障根因”
    我敢说,这个版本的斗地主你肯定没玩过?
    5 分钟带你掌握 Makefile 分析
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/10518162.html
Copyright © 2020-2023  润新知