C语言学习之补码的深刻理解

1 篇文章 0 订阅
1 篇文章 0 订阅
学到C语言的本质之补码时( http://learn.akae.cn/media/ch14s03.html)。发现不是很理解,特别是这段描述。

如果8个bit采用2'sComplement表示法,

负数的取值范围是从10000000到11111111(-128~-1),

正数是从00000000到01111111(0~127)。

      于是搜索了不少资料,总算理清了这一点。

首先,原码,反码,补码是一个真值用二进制表示的的不同方式。将一个真值表示成二进制字串的机器数的过程就称为编码。无符号数没有原码、反码和补码一说。只有带符号数才存在不同的编码方式。

    至于为什么计算机最终选择补码来表示呢?具体看这里

http://sharecourse.upln.cn/courses/c_809_04/theory/module_2/pdf/whybm.pdf

    从原码转成补码也看上面的文章。

    这里有一点很重要的,就是从补码怎么转为原码或者真值呢?

    其实这个过程跟从原码转成补码是一样的。这一点很多学习资料都没提到。我是在

http://wenwen.soso.com/z/q110390792.htm这里看到的。

        

         具备了以上知识后,现在来解释一下补码的范围是怎么回事。

1 先从简单的开始,正数的范围,明显补码的二进制范围是从00000000到01111111。那么取几个特殊的值来看看,

0000,0000

0111,1111

这两个二进制的数是谁的补码呢?

也就是(0000,0000)的真值是?

(0111,1111)的真值是?

由于正数的补码跟真值是一样的,

所以(0000,0000)的真值是0,(0111,1111)的真值是127。

由此可见,用补码来表示正数,取值范围是0-127。

2 负数的范围,明显补码的二进制范围是从10000000到11111111。再取几个特殊值来看看,

那么10000000的真值是?

10000001的真值是?

11111111的真值是?

上面有说过如何从补码转为真值。

计算后,发现

10000000的真值是(-1000,0000)=-128

10000001的真值是(-111,1111)=-127

11111111的真值是(-000,0001)=-1。

所以用补码表示负数,范围是-128到-1。

这里,特地,演算一下。(采取先不管符号位的做法)

10000001(这是补码)

取反,得 (111,1110)

+1,得(111,1111)

加上符号位(-111,1111)即-127

(1000,0000)(这是补码)

取反,得(111,1111)

+1,得(1000,0000)

加上符号位,得 –1000,0000,即是-128。

那么我们验证一下真值-127的补码形式是不是(1000,0001)。

-127这是真值,即(-111,1111)

转为原码(1111,1111)

取反,转为反码(1000,0000)(符号位不变)

+1,(1000,0001)(符号位不变)

再验证一下真值-128的补码形式是不是(1000,0000)。

-128(-1000,0000)显然原码表示不了。

只能这么理解法,

先不管符号位,得(1000,0000)。

取反,得(0111,1111)

+1,得(1000,0000),7位溢出了,去掉进位得(000,0000)

补上符号位得(1000,0000)。

其实,我们只要记住真值-128的补码形式是(1000,0000)就好了。

其实,求反加1的方法是有缺陷的,并不是补码的定义,了解了补码的定义,才可以真正了解补码与真值的转换。

就是利用同余。http://sharecourse.upln.cn/courses/c_809_04/theory/module_2/pdf/whybm.pdf

在数学中,用“同余”概念描述上述关系,即两整数 A、B 用同一个正整数 M (M 称为

模)去除而余数相等,则称 A、B 对 M 同余,记作:

A=B (MOD M)

具有同余关系的两个数为互补关系,其中一个称为另一个的补码。当 M=12 时,-

5 和+7,-4 和+8,-3 和+9 就是同余的,它们互为补码。

从同余的概念和上述时钟的例子,不难得出结论:对于某一确定的模,用某数减去

小于模的另一个数,总可以用加上“模减去该数绝对值的差”来代替。因此,在有

模运算中,减法就可以化作加法来做。

可以发现,有个技巧,互为补码的两个数加起来刚好等于模。

对于8位得二进制数,模等于2的8次方=256。

真值-127的补码是谁呢?

-127等价于 加上模减去127的差,即加上 129(1000,0001)。

因此-127与129(1000,0001)互补。

即真值-127的补码为(1000,0001),这个补码看起来是正数,其实表示的是负数。

现在再来看看真值-128的补码形式是不是(1000,0000)。

显然,-128等价于加上 256-128=128,即(1000,0000)。

触类旁通,真值-126的补码是?

-126等价于加上256-126=130,即(1000,0010)。

上面是,由真值求补码。

那么怎么由补码求真值呢?

比如补码(1000,0010)的真值是?

显然(1000,0010)=130,符号位是1,表示的真值是负数,

130-256=-126。

补码(1000,0000)的真值是?

显然,(1000,0000)=128,符号位是1,表示的真值是负数,

128-256=-128。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中,负数的原码、补码和反码用于表示负数的二进制形式。下面是关于负数的原码、补码和反码的解释: 1. 原码(Sign-Magnitude):负数的原码是将其绝对值转换为二进制形式,然后在最高位加上符号位(0表示正数,1表示负数)。例如,-5的原码是10000101(假设使用8位二进制表示)。 2. 反码(Ones' Complement):负数的反码是将其原码的除符号位外的所有位取反。例如,-5的反码是11111010。 3. 补码(Two's Complement):负数的补码是将其反码加1。例如,-5的补码是11111011。 以下是一个示例代码,用于获取负数的原码、反码和补码: ```c #include <stdio.h> void printBinary(int num) { unsigned int mask = 1 << (sizeof(int) * 8 - 1); // 使用无符号整数来避免右移时引入符号位 printf("原码:"); for (int i = 0; i < sizeof(int) * 8; i++) { if (num & mask) { printf("1"); } else { printf("0"); } mask >>= 1; } printf("\n"); printf("反码:"); if (num < 0) { num = ~num; } for (int i = 0; i < sizeof(int) * 8; i++) { if (num & mask) { printf("1"); } else { printf("0"); } mask >>= 1; } printf("\n"); printf("补码:"); if (num < 0) { num = ~num + 1; } for (int i = 0; i < sizeof(int) * 8; i++) { if (num & mask) { printf("1"); } else { printf("0"); } mask >>= 1; } printf("\n"); } int main() { int negativeNum = -5; printBinary(negativeNum); return 0; } ``` 在上述示例代码中,负数 `-5` 的原码是 `10000101`,反码是 `11111010`,补码是 `11111011`。该代码通过位操作和循环打印出了负数的原码、反码和补码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值