关于补码,反码的学习

as we know, char has 8 bits.

char b = 128;
printf("%d", b); // print -128

that's overflow, so why print -128?

128 的二进制形式 1000 0000

char是有符号的,所以第一位是符号位且为1,那就认为这个数是负数。然后负数都是用补码表示,计算机认为这就是一个负数的补码

原码被计算出来为 1000 0000(0 1000 0000 -> 0 0111 1111(减1) -> 0 1000 0000(取反))取后8 bits 就是1000 0000也就是2^7 = 128???

这个很特殊,看一下其他的比如130 二进制为:1000 0010

原码被计算出来为1111 1110(1000 0010 -> 1000 0001(减1) -> 1111 1110(取反)) 第一位是符号位,后7位111 1110 = 126, 加上符号位就是-126了

。。。


Inverse code/one's complement  [计] 二进制反码

Complement code/two's complement [计] 二进制补码

There are no inverse or compliment for positive.

Binary code is the binary representation of unsigned integers. If we're talking about computers, there is a certain number of bits used to represent the number. So, the total range which n-bits can represent is 2^n.

Inverse code or one's complement is inverted binary code of a number. That is, all zeroes become ones and all ones become zeroes.

Complement code or two's complement is inverse code plus one

These codes were invented to make sign operations more comfortable (for machines).


Let's assume we have a computer with 4-bits binary numbers. A total range, which 4-bits can represent, is 0, 1, ... 15.

But these are unsigned numbers and are not of much use. We need to introduce a sign. So, half of the range is taken for positive numbers (eight, including zero), and half of the range - for negative (also eight). Note that the machine considers zero as a positive number, unlike usual math.

So, our positives are 0,...,7, and negatives are -1,...,-8.

To distinguish positive and negative numbers, we assign the left-most bit as sign bit. Zero in sign bit tells as that this is a positive number and one - negative.

Positive numbers are represented by plain binary code
 

0 - 0000
1 - 0001
...
7 - 0111

But how can negative numbers be represented? Here comes the complement code. That is, -7 complement is

binary 7 = 0111
inverse 7 = 1000
complement 7 = 1001

Note that binary 1001 is 9, which differs from -7 by 16, or 2^4. Or, which is the same, complement code "complements" binary code to 2^n, i.e. 7+9=16.

This proved to be very useful for machine computation - usage of complement code to represent negatives allows engineers to use an addition scheme for both addition and subtraction, thus simplifying the design of ALU (arithmetic and logical unit - part of the processor). This representation easily detects overflow, and then there are not enough bits to represent the given number.

Several examples

7-3=4
0111 binary 7
1101 two's complement of 3
0100 result of addition 4


-1+7=6
1111 two's complement of 1
0111 binary 7
0110 result of addition 6

Overflow is detected by looking at the two last carries, including carrying beyond the right-most bit. If carry bits are 11 or 00, there is no overflow; if carry bits are 01 or 10, there is overflow. And, if there is no overflow, carry beyond the right-most bit can be safely ignored.

Some examples with carries and a fifth bit (a bit beyond right-most bit)

7+1=8

// 因为要看最后两位进位,所以需要多一位二进制表示(5位
00111 binary 7
00001 binary 1
01110 carries // 每位对应的进位
01000 result of addition 8 - overflow
// The two last carries are 01. This gives a signal of overflow.
// carry beyond the right-most bit can not be safely ignored.

-7+7=0

00111 binary 7
01001 two's complement of 7
11110 carries
10000 result of addition 16 - but fifth bit can be ignored; the real result is 0.
// The two last carries are 11. There is no overflow, so the correct result is zero.
// There is no overflow, carry beyond the right-most bit can be safely ignored.

Overflow check can be done by simple XOR-ing two last carry bits.(不明白这句话是什么意思??

Because of these convenient properties, two's complement is the most common method to represent negative numbers on computers.

P.S. Inverse code, "complements" binary code to 2^n - 1, (all ones). It also can be used to represent negatives, but the addition scheme should employ cyclic carry and is more complex. The range, which n-bits can represent, is reduced by 1 since 1111 is busy as inverted 0000 - negative zero. So, it is less convenient.(反码也可以代表负数,但是加法需要采用循环进位,而且比较复杂,所以balabala)


计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行。
即:减去某个数字(或者说加上某个负数)的运算,都应该研究如何用加法来完成。

模、补数
在日常生活当中,可以看到很多这样的事情:
把某物体左转 90 度,和右转 270 度,在不考虑圈数的条件下,最终的效果是相同的;
把数字 87,减去 25,和加上 75,在不考虑百位数的条件下,效果也是相同的;
上述几组数字,有这样的关系:
90 + 270 = 360
25 + 75 = 100
式中的 360, 100,就是“模”。
式中的 90 和 270、以及 25 和 75,就是一对对“互补”的数字。
知道了模,求补码,就是轻而易举的了:
补码就是按照这个要求来定义的:正数不变,负数即用模减去绝对值。

二进制数的模
前面说过的十进制数 25 和 75,它们是 2 位数的运算,模是 100,即 1 的后面加上 2 个 0。
如果有 3 位数参加运算,模就是 1000,即 1 的后面加上 3 个 0。
这里的 1000,是十进制数的一千,可以写成 10^3,即 10 的 3 次方。
推论:有多少位数参加运算,模就是在 1 的后面加上多少个 0。
对于二进制数字,模也是这样推算。
如果是 3 位二进制数参加运算,模就是 1000,即 1 的后面加上 3 个 0;
那么当 8 位二进制数参加运算,模就是 1 0000 0000,即 1 的后面加上 8 个 0。
16 位二进制数参加运算,模可就大了,是 1 的后面加上 16 个 0。
注意:这里提到的 1、0,都是二进制数。
8 位二进制数的模可以按照十进制写成 2^8,即 256。
16 位数二进制数的模,就是 2^16,按照十进制,它就是 65536。

二进制数的补码
求二进制数的补数,目的是往计算机里面存放。
二进制补码是这么求的:正数不变,负数即用模减去绝对值。(注意,正数不变,即正数没有补码和反码也可认为正数的反码补码就是其本身!)

--符号位


从这个表格中,可以看出特点:正数的最高位都是0,负数的最高位都是1。
这样一来,有人就把最高位理解成了符号位。说什么是规定的用0代表正号,......。并且郑重其事的补充说明:“符号位也参加运算”。真能忽悠!卖拐、卖车的都甘拜下风。
其实,前面说过的 补数 和 补码的定义式 里面,根本就没有什么符号位。这最高位的1、0是自然出现的,并不是由人来规定的。

--原码和反码
由于使用“求反加一”来求取补码,顺便又引出了 原码 和 反码 两个垃圾概念。

其实,“求反加一”的计算方法只是适用于计算二进制形式的补数,它并不是通用的。
并且把“求反加一”用于求-128的补码,有个溢出的现象,很多人都在这里被弄瘸了很长时间。
原码和反码也只不过是“人工”进行“求反加一”时的中间过程,在计算机里面根本是不存在的,它们也就没有丝毫用处。

做而论道的建议
求取补码,就按照定义的规定,负数采用“模减去绝对值”的方法来求,这是求补数的通用方法,适合于各种进制、各种大小的数字。
不要用求反加一的方法,也就不用理会原码和反码了,也不牵涉符号位的问题。
以后的计算,也就没有必要特殊说明:“符号位一起参加运算...”,因为根本就没有什么符号位。

如果把原码和反码、符号位等等垃圾概念,从计算机的书中删减掉,学习补码将会省力不少。感觉这句话说法太极端,并不好,因为计算机判断一个正负数就是利用第一个bit的值来判断一个数是正数还是负数,可以说是计算机利用了上面的 ''巧合''来判断的正负数,而不是因为为了判断正负数而设置的第1bit用来表示一个数的符号.

最终问题,那书和老师为什么要用原码,反码来讲补码 ?
空穴来风,未必无因
那是因为计算机就是这样求负数的补码的,我们在键盘上敲一个负数的时候,计算机要把它用补码的形式存储下来,还记得上面我们讲的补码是怎么来的吗?
模-绝对值,这是不是个减法公式?但计算机没有减法逻辑,我们费了那么大的劲搞了一套补码的规则就是为了用加法来替代减法,但为了实现这么套规则,却跨不过一个坎,就是把负数计算成补码仍然是需要减法逻辑的。怎么办呢,那些伟大的先贤们 (膜拜)就想出了这么个办法:
首位不变,其余位取反后,再加一


V
下面是吐槽
不知道是哪个书呆子教书,照搬了机器的逻辑,把取反加一的方法当做补码的计算逻辑就这么教下来了。搞笑的是,还保留了补码这个名字,照理说这种教法应该叫 取反加一码 更合理,你还补什么啊?
不仅如此,还搞出了个首位符号位的说法,弄出了个正0负0,还用负0来充当-128,真是不把人弄疯不罢休啊!!
int a = -2056;
Binary of 2056 will be calculated which is:
00000000000000000000100000001000 (32 bit representation, according of storage of int in C)
2’s complement of the above binary is:
11111111111111111111011111111000.
So finally the above binary will be stored at memory allocated for variable a.


Check for Integer Overflow

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值