zoukankan      html  css  js  c++  java
  • 二进制的补码

    今天在学习C Primer Plus(第五版)中文版.pdf的时候遇到这么个问题,先上代码:

    #include <stdio.h>
    #define PAGES 336
    #define WORDS 65618
    int main(void)
    {
            short num = PAGES;
            short mnum = -PAGES;
    
            printf("num as short and unsigned short:%hd %hu
    ",num,num);
            printf("-num as short and unsigned short:%hd %hu
    ",mnum,mnum);
            printf("num as int and char:%d %c
    ",num,num);
            printf("WORDS as int,short,and char:%d %hd %c
    ",WORDS,WORDS,WORDS);return 0;
    }

    结果:

    num as short and unsigned short:336 336
    -num as short and unsigned short:-336 65200
    num as int and char:336 P
    WORDS as int,short,and char:65618 82 R

    请看我标红的部分,其实我蛮想不明白的,为什么-336的无符号整数是65200呢?书上说是2的补码(书中描述):数字0到32767代表它们本身,而数字32768到65535则代表负数,65535代表-1,65534代表-2,依次类推,因此-336由65536-336,也即65200来表示;本宝宝表示真心没看懂啥意思,然后就在网上各种找二进制的补码是啥意思,下面咱们就来看看什么是二进制的补码

    我试验的计算及环境假设是8位的,那接下来我就拿计算机是8位作基础来讲解:

    一、负数在计算机中如何表示

      之前我写了一篇博客,里面是计算c语言整数类型的取值范围的额,二进制中区分正负数的方法是看二进制的最高位是0还是1,1为负数,0为正数

      比如:127的二进制是01111111,而-127的二进制是 10000001(011111111 - 先取反,再加1 ->10000000+1 = 10000001),从这里可以看出127的最高位是0,而-127的最高位是1

    二、什么是二进制补码

      取一个数的二进制补码需要两步:

      1>.每个二进制位都取相反的值,也就是二进制位是1的,补码就是0,二进制位是0的,补码就是1

      2>.再把取反的二进制数转换成十进制,加上1,最后的结果就是这个数的补码的十进制数

      举例:取-127的二进制补码(8位机)

        二进制数:01111111

        补码:10000000

        结果:补码 10000000 + 1 = 10000001(129)

        也就是说-127在计算机(8位机)中10000001(写到这里,我突然有点明白C Primer Plus书中描述的啥意思:0-127代表它本身,128-255代表负数,那-127就等于256-127=129

      那可能很多人会说:为什么是这样啊?虽然知道怎么计算了,但是不知道为什么是这么计算的,那么接下来就来说说二进制补码的原理

    三、二进制补码的原理

      那大家都知道负数怎么来的,比如:A-B,那A比B小,结果就会是负数,这就有很多情况了,咱不讨论,就比如给你一个负数,那么最直接的你肯定会想到一个表达式了,比如给你个-127,那表达式就是0-127的来的,那我们把他转换成二进制来运算一下:

      预想结果:-127

      十进制表达式:0-127

      二进制表达式:00000000(0) - 01111111(127)

      以前小学数学当被减数大于减数的时候都要向上借一位来减的,那么接下来就是借位(

      重点:这里计算的时候二进制的位数是有规定的,比如-127,它是1111111 由7个1的二进制,那同学就用7个0的二进制去减,结果借一位变成了10000000(128)-1111111(127) = 1,然后在加1等于2,结果-127的补码就是00000010(2),这样可是错的,一定要遵守一个标准,那就是当前计算机是多少位的就借多少位加1位,那么比如-10是1010,就是00001010,借位就得在第9位上借,也就是100000000,结果就是246(11110110)

      借位进行运算:

        1>.100000000(256) - 01111111(127) = 10000001(129)

        2>.100000000(256) = 11111111(255) + 1;

          11111111(255) - 01111111(127) = 10000000(128)

          10000000(128) + 1 = 10000001(129)

      上面就是二进制补码的简单计算过程

    四、二进制补码有哪些好处呢?

      感觉不就是一个负数而已,非要搞的这么弯弯绕,我反正是晕了,那接下来就看下二进制补码的好处

      那我们之前说的判断最高位是1还是0来区分正负,那接下来我们就用两种表示法来计算作比较:

      举例:-10

      表达式:20 + (-10)

      1>.最高位区分正负:-10的二进制数为10001010

        二进制计算:00010100 + 10001010 = 10011110

        10011110转换成十进制是30,根据最高位区分正负,结果就是-30

      2>.再来看看二进制补码的方式进行计算:-10的二进制补码(11110101 + 1 = 11110110(246))

        二进制计算:00010100 + 11110110 = 100001010 

        而咱们刚才已经说了,假设计算机是8位的,那么这个结果超过8位,第九位会被舍弃,也就是00001010,结果就是10

    五、为什么正数加法适用于二进制补码呢?

      接下来我们求证一下X-Y(x + (-Y))这个表达式,相信大家就明白了(8位机)

      Y的二进制补码由上面的讲解大家都知道是:(11111111 - Y) + 1 ,所以也就是X加上Y的二进制补码,表达式可以写成如下格式:X + (11111111 - Y) + 1

      得到这个表达式就好办了,接下来我们分成两种情况来解释:

      1>.那就是X小于Y,那么结果肯定是个负数了,我们采用二进制的补码的逆运算,求出它对应的正绝对值,再在前面加一个负号就可以了

        第一步:计算Z、X、Y的二进制补码的表达式 Z = -((11111111 - Z) + 1);X = (11111111 - X) + 1;Y = (11111111 - Y) + 1;

        第二步:根据表达式X + (11111111 - Y) + 1来替换计算:-( ( ( 11111111 - X) + 1 ) - ( ( 11111111 - Y ) + 1 ) ) = -(11111111 - X + 1 - 11111111 + Y - 1) = -( -X + Y) = X - Y; 

      2>.X大于Y,那结果肯定是正数,那意味着Z肯定大于11111111,那根据8位机,第九位溢出了,就要舍去,表达式为(不太明白...):

        Z = Z - 100000000 = X + (11111111 - Y) + 1 - 100000000 = X - Y;

      文章出自:http://www.ruanyifeng.com/blog/2009/08/twos_complement.htm

  • 相关阅读:
    从aop中获取被拦截方法中的参数
    使用多线程 执行有返回值的方法
    MyBatis中#{}和${}的区别
    Java 调用api,json化结果
    Spring入门
    实用: 将程序的内容写出到excel中
    实用:Java基础流计算
    2020年7月12号笔记
    2020年7月11号笔记
    2020年7月6号笔记
  • 原文地址:https://www.cnblogs.com/zengguowang/p/6074845.html
Copyright © 2011-2022 走看看