one's complemen:即将每位二进制求反即反码。
000...00001 = +1 000...00000 = +0 111...11111 = -0
问题出现在(+0)和(-0)上,在人们的计算概念中零是没有正负之分的.这种简单的机制会产生-1 + 2 = +0,为避免这种情况,引入twos-complement.
binary decimal 11111110 -1 + 00000010 +2 ............ ... 1 00000000 0 <-- not the correct answer 1 +1 <-- add carry ............ ... 00000001 1 <-- correct answer
two complement: 是将二进制求反加一,忽略溢出。
这就避免了对0的两种表示。
000...00001 = +1 000...00000 = 0 111...11111 = -1
注意:111...11111,111...11111在不同规则下表示的是不同的值。Sign-and-magnitude表示原码。
在two complement 下1000 0000b表示是多少?
分析:首先它是负数,所以取反加一得到他相对应的正数的补码,而正数的补码为其本身,所以1000 0000b就表示为2的8次方即为-128,故而8为补码所表示的范围为-128----127(1111 1111)。
故而two complement表示的范围是:
sign bit | |||||||||
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | = | 127 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | = | 2 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | = | 1 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | = | 0 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | = | −1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | = | −2 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | = | −127 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | = | −128 |
而源码,反码的范围都是-127-127.
|
Note that according to our negation rule, . Logically, what has happened is that the result has ``overflowed'' and ``wrapped around'' back to itself. Note that
also. In other words, if you compute 4 somehow, since there is no bit-pattern assigned to 4, you get -4, because -4 is assigned the bit pattern that would be assigned to 4 if
were larger. Note that numerical overflows naturally result in ``wrap around'' from positive to negative numbers (or from negative numbers to positive numbers). Computers normally ``trap'' overflows as an ``exception.'' The exceptions are usually handled by a software ``interrupt handler,'' and this can greatly slow down the processing by the computer (one numerical calculation is being replaced by a rather sizable program).
Note that temporary overflows are ok in two's complement; that is, if you add to
to get
, adding
to
will give
again. This is why two's complement is a nice choice: it can be thought of as placing all the numbers on a ``ring,'' allowing temporary overflows of intermediate results in a long string of additions and/or subtractions. All that matters is that the final sum lie within the supported dynamic range。
mov al,27h
mov bl,73h
add al,bl
27h 00100111
73h 01110011
如果是无符号数al的结果为10011010(9A),如果是有符号数结果是什么?
如果是有符号数,结果依然是10011010(9A)。注意,此时溢出标志置位。表明这个加法如果是作为有符号数的加法时,结果是不能用的。当然,如果你把这个加法作为无符号数的加法来看,结果则是可用的(虽然此时仍有溢出,但它是无意义的。溢出只针对有符号数而言的)。
这是个特例。因为无符号数的加减法与有符号数的补码的加减法是恰巧是一致的。因此有符号数与无符号数可以使用同一指令,得到同一结果。而这一结果是作为有符号数还是无符号数,是由程序员来定义的:如果程序员认为是有符号数的加减法,则他将关心运算结果的溢出标志,以判别结果是否可用;如果程序员认为是无符号数的加减法,则他将关心运算结果的进位标志,看运算结果是否有进(借)位。
正是基于这样的原因,计算机的有符号数才采用补码表示。
例如:
al=1001 1100(9C),bl=1110 0111(E7),则
add al,bl
运算结果是:
al=1000 0011(83) 且进位标志CY=1,溢出标志OV=0.
对于这个结果,你可以把它作为无符号数运算,即有:
al=9Ch=156d,bl=E7h=231d,运算结果al=83h=131d,考虑到进位,运算结果应为131+256=387,而al+bl=156+231=387.正确。
同样对于这个结果,你也可以把它作为有符号数的运算,即有:
al=9Ch=-100d,bl=E7h=-25d,(注意有符号数均看成补码,9Ch是-100的补码,下同)。
而运算结果al=83h= -125d,因为没有溢出(有符号数是不考虑进位的),运算结果可用。
而al+bl=9Ch+E7h=(-100)+(-25)=-125.可见结果亦完全正确。
由上例可见,无符号数的加法与有符号数的补码加法是完全一致的。CPU没有必要去区分。关键在于程序员如何去看待。CPU的运算结果将同时影响进位标志与溢出标志。如果程序员认为这是无符号数运算,则只考虑进位标志而忽略溢出标志。反之,如果程序员认为这是有符号数运算,则只考虑溢出标志而忽略进位标志。
Both Csharp and Visual Basic uses twos complement representations of numbers. Understanding twos complement isn't strictly necessary for most applications but it sometimes comes in handy. With a little thought, you can discover the value of every bit in a number whether it is positive or negative.
Bitwise operators in c# OR(|), XOR(^), AND(&), NOT(~)
参考:http://en.wikipedia.org/wiki/Two's_complement
http://ccrma.stanford.edu/~jos/mdft/Two_s_Complement_Fixed_Point_Format.html
http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html
http://topic.youkuaiyun.com/t/20030913/20/2256856.html#