补码 符号数的二进制 整数

Blablabla~ 

今天重温了《深入了解计算机系统》关于符号数的bianary表示,弄懂了补码的原理。并写了python脚本验证。当初对这块有疑惑是一上来就告诉你,xxx取反加1就是补码,完全不知道为什么这么做,今天抛开这个说法,从我们想要解决问题入手去思考。

目标

我们想要解的问题是:我们知道计算机都是binary的存储,那么这些binary怎么解释或者对应到 带符号的整数呢?

这是我们想要的解决的问题

解决方案(general)

提供了一种翻译机制,就是一个函数,输入是binary,输出是 符号数

def B2S(binary):

      reutrn sign_integer

具体方案(detail)

  • 一个很正常是思路就是一个bit位符号位,0为正,1为负,其他的n-1 bit照旧。这个方案有一个问题是0有两个表示10000和00000 (这套方案叫 singned magnitude 原码),这个方案正负数相加会有问题哦(不是0)
  • 另外一个思路是负数:保留符号位,其余的数 取反,有一个问题就是+0 = 0000, -0 = 11111,有两个方式(这套方案叫 ones' complement), 两数 x+(-x)会得到1111 (就是-0)
  • 最后看我们计算机中的最终选择的方案吧 (two's complement)

书里的2.2.3章节的这个图比较形象地画出方案细节,具体可以看下1011的例子。-8在左边是灰色的,蓝色的是正的,累加起来。

扫描二维码关注公众号,回复: 14721648 查看本文章

def B2U(b):
    #binary to unsigned
    x=0
    b_str = b[::-1]
    for i,v in enumerate(b_str):
        if int(v)!=0:
            x+= np.power(2,i)
    return x
def test_B2U():
    assert B2U('0001') == 1
    assert B2U('0101') == 5
    assert B2U('1011') == 11
    assert B2U('1111') == 15

def B2T(b):
    #bianry to two's component
    x = 0
    b_str = b[::-1]
    idx = len(b_str)-1
    for i,v in enumerate(b_str):
        if i<idx:
            if int(v)!=0:
                x+= np.power(2,i)
        else:
            x += -int(v)*np.power(2, i)
    return x

def test_B2U():
    assert B2U('0001') == 1
    assert B2U('0101') == 5
    assert B2U('1011') == -5 # -8+2+1
    assert B2U('1111') == -1 # -8+4+2+1

本质上,我们知道符号数的第一位来表示符号,0表示正,1表示负,那么实际的数值就是:

- 最大的值: 0111, 2^n-1

- 最小的值: 1000, - 2^n

- 一般的值:(-v)*2^n+ 其他项

明白了最小的值是1000,结合上面的图,那么任意bit的整数,-1的表示都是0xfffff。。。

补码:对于任意x, 我们用 -2^w+x 来表示 -x的w位表示

           另一个思路是,x+(-x)=0 那么,-x = 0-x = 2^w - x = 10000 -(x) 这个思路很好(但是我们不应该记住结论/公式:负数的binary就是其整数取反再加1,记住过程,我们希望x+(-x)=0,所以-x = 0000- x

总结

这套方案(函数),在计算机里叫做 "补码编码". 一般都使用补码的形式来表示有符号整数。弄明白了计算机使用补码(two's component)的编码方式来表示负数(即符号数)。本质就是制定一个规则,一个bianry怎么serialze 到有符号数,这个规则就是一个函数,就是我上面写的B2T,这个函数叫做补码编码。

unsigned char x=0;

printf("%u", x-1); #255

猜你喜欢

转载自blog.csdn.net/Chunying27/article/details/127809494