• 二进制数的有效讨论


    为什么-128的二进制表示是10000000?

    这里面就要讨论到有关于真数在计算机中表示了。

    在计算机内部,所有的信息都是由二进制数串表示的,这其中就分为了无符号有符号。无符号的整数用来表示正数和0,有符号的整数则可以用来表示全体整数。

    由于计算机中的整数全部由二进制表示,所以正负号也全部由0(正)和1(负)表示。一般来讲,将进制中的最高有效位设置为符号位。将一个真值表示成二进制数串的机器数的过程被称为编码。

    而其中,规定真值在计算机中的二进制表示通通由它们的补码表示。为什么要用补码?

    • 因为补码可以将符号位与其他位统一处理,同时减法也可以按加法来运算,即如果是补码表示的数,不管是加减法都直接用加法运算即可实现;
    • 两个用补码表示的数相加时,若果最高位有进位则舍弃进位。

    这样做的好处是:

    1. 是符号位能够与有效值部分一同参加运算,简化运算规律。从而可以简化运算器的结构,提高运算速度;
    2. 加法运算比减法运算更易于实现。进一步简化运算器线路设计

    下面深入分析采用补码的原因:

    用带符号位的原码进行乘除运算时结果正确,而在加减运算的时候就出现了问题 ,如下:

    1D-1D = 1D + (-1D) = 0D
    (00000001)原 + (10000001)原 = (10000010)原 = -2
    

    这显然是错误的。因为在两个整数的加法运算中是没有问题的,于是就发现问题出在带符号的负数上。

    用带符号的反码进行运算,如下:

    1D- 1D = 1D + (-1D) = 0D
    (00000001) 反+ (11111110)反 = (11111111)反 = ( -0 ) 有问题。
    
    1D - 2D= 1D+ -2D = (-1)D
    (00000001) 反+ (11111101)反 = (11111110)反 = ( -1 ) 正确
    

    问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的。

    现在再来看下有符号的补码运算,如下:

    1D- 1D = 1D + (-1D) = 0D
    (00000001)补 + (11111111)补 = (00000000)补 = 0D
    
    1D + 1D = 2D
    (00000001)补 + (00000001)补 = (00000010)补 = 2D
    

    由此可以证明计算机中的带符号运算都是基于补码实现的。

    二进制中的特殊值

    反码表示法规定:正数的反码就是其本身。负数的反码保持符号位不变其他按位取反。
    而8位二进制能表示的反码范围为:-127~127.
    此时-128没有原码和反码。这是因为-0与-128的反码一致,且看:

    -0 = (10000000)原 = (11111111)反
    -128 = (10000000)原 = (11111111)反  [**<span style='color:red'>假设</span>**]
    

    此时,-1与-128的反码冲突,所以当有了-0的原码反码时就不该有-128的原码反码。

    我们再来看一下八位二进制中的原码、反码、补码的范围:

    原码:-127~127
    反码:-127~127
    补码:-128~127

    此时会发现补码比反码多了一个,这是因为0这个因素。

    +0: (00000000)原 (00000000)反 (00000000)补
    -0:  (10000000)原 (11111111)反 (00000000)补 
    

    **需要说明为什么-0的补码还是00000000**

    补码本质是用来构成一个环,以实现一个同余运算。以8位整数为例,取得的结果永远是2^8次方的余数,这与有无符号无关。

    用计算器做加法运算时,实际上做的是同余加法,即:
    1+2 ≡ 1(mod 256)+ 2(mod 256) ≡ 3(mod 256)
    这样做的好处是无论所运算的是否为有符号,都可以使用同样的运算规则。

    256的余数总共就256种,分别是0~255。但是我们希望表示一个负数,那怎么做呢?
    255 ≡ -1(mod 256) ≡ 255(mod 256)
    于是乎就用255来表示了。考虑到取值范围,以及为了方便区分,我们定义有一半的数是正数、一半的数是负数,恰恰就是二进制最高位为1则是负数,最高位为0则表示正数范围,这个就是补码的本质。

    至于补码的计算方法,也就是取反加1,完全是因为:
    x+~x ≡ 255(mod 256)
    这与『符号位』无关,它的逆运算,其实求解的是:
    x+~x+1 ≡ 0(mod 256)
    可以得出:-x ≡ ~x+1(mod 256)

    此时把0代入可得:-0 ≡ ~0+1(mod 256) ≡ 255+1(mod 256) ≡ 0;

    所以,补码能表示的数的个数中,比原码反码少了一个,所以补码可以多表示一个真值为-128的数。
    但是,多表示的这个数-128比较特殊,只有原码和补码,没有反码。
    -128的补码是1000 0000。

    为什么-128的补码是10000000呢?
    可根据上文进行推导:
    -128 ≡ ~128+1(mod 256) ≡ 127+1(mod 256) ≡ 128;
    所以-128的补码与128一致即为10000000。

    本文内容借鉴了一些前辈的观点:

    作者:今天还是要喝水 链接:https://www.cnblogs.com/flowerslip/p/5933833.html

    作者:Coldwings 链接:https://www.zhihu.com/question/21511392/answer/82989720

  • 相关阅读:
    《C++ Primer Plus》15.1 友元 学习笔记
    《C++ Primer Plus》14.4 类模板 学习笔记
    《C++ Primer Plus》14.3 多重继承 学习笔记
    《C++ Primer Plus》14.2 私有继承 学习笔记
    《C++ Primer Plus》第13章 类继承 笔记
    继承和动态内存分配——需要为继承类定义 显式析构函数、复制构造函数和赋值运算符
    C++中的抽象基类示例
    C++ 在继承中使用virtual
    《C++ Primer Plus》第12章 类和动态内存分配 学习笔记
    《C++ Primer Plus》12.7 队列模拟 学习笔记
  • 原文地址:https://www.cnblogs.com/njuptzheng/p/14471357.html
Copyright © 2020-2023  润新知