Why prefer two's complement over sign-and-magn

2019-01-03 18:58发布

I'm just curious if there's a reason why in order to represent -1 in binary, two's complement is used: flipping the bits and adding 1?

-1 is represented by 11111111 (two's complement) rather than (to me more intuitive) 10000001 which is binary 1 with first bit as negative flag.

Disclaimer: I don't rely on binary arithmetic for my job!

18条回答
啃猪蹄的小仙女
2楼-- · 2019-01-03 19:38

The usual implementation of the operation is "flip the bits and add 1", but there's another way of defining it that probably makes the rationale clearer. 2's complement is the form you get if you take the usual unsigned representation where each bit controls the next power of 2, and just make the most significant term negative.

Taking an 8-bit value a7 a6 a5 a4 a3 a2 a1 a0

The usual unsigned binary interpretation is:
27*a7 + 26*a6 + 25*a5 + 24*a4 + 23*a3 + 22*a2 + 21*a1 + 20*a0
11111111 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255

The two's complement interpretation is:
-27*a7 + 26*a6 + 25*a5 + 24*a4 + 23*a3 + 22*a2 + 21*a1 + 20*a0
11111111 = -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = -1

None of the other bits change meaning at all, and carrying into a7 is "overflow" and not expected to work, so pretty much all of the arithmetic operations work without modification (as others have noted). Sign-magnitude generally inspect the sign bit and use different logic.

查看更多
Juvenile、少年°
3楼-- · 2019-01-03 19:40

To expand on others answers:

In two's complement

  • Adding is the same mechanism as plain positive integers adding.
  • Subtracting doesn't change too
  • Multiplication too!

Division does require a different mechanism.

All these are true because two's complement is just normal modular arithmetic, where we choose to look at some numbers as negative by subtracting the modulo.

查看更多
够拽才男人
4楼-- · 2019-01-03 19:43

One satisfactory answer of why Two2's Complement is used to represent negative numbers rather than One's Complement system is that Two's Complement system solves the problem of multiple representations of 0 and the need for end-around-carry which exist in the One's complement system of representing negative numbers.

For more information Visit https://en.wikipedia.org/wiki/Signed_number_representations

For End-around-carry Visit https://en.wikipedia.org/wiki/End-around_carry

查看更多
爷、活的狠高调
5楼-- · 2019-01-03 19:44

A major advantage of two's-complement representation which hasn't yet been mentioned here is that the lower bits of a two's-complement sum, difference, or product are dependent only upon the corresponding bits of the operands. The reason that the 8 bit signed value for -1 is 11111111 is that subtracting any integer whose lowest 8 bits are 00000001 from any other integer whose lowest 8 bits are 0000000 will yield an integer whose lowest 8 bits are 11111111. Mathematically, the value -1 would be an infinite string of 1's, but all values within the range of a particular integer type will either be all 1's or all 0's past a certain point, so it's convenient for computers to "sign-extend" the most significant bit of a number as though it represented an infinite number of 1's or 0's.

Two's-complement is just about the only signed-number representation that works well when dealing with types larger than a binary machine's natural word size, since when performing addition or subtraction, code can fetch the lowest chunk of each operand, compute the lowest chunk of the result, and store that, then load the next chunk of each operand, compute the next chunk of the result, and store that, etc. Thus, even a processor which requires all additions and subtractions to go through a single 8-bit register can handle 32-bit signed numbers reasonably efficiently (slower than with a 32-bit register, of course, but still workable).

When using of the any other signed representations allowed by the C Standard, every bit of the result could potentially be affected by any bit of the operands, making it necessary to either hold an entire value in registers at once or else follow computations with an extra step that would, in at least some cases, require reading, modifying, and rewriting each chunk of the result.

查看更多
【Aperson】
6楼-- · 2019-01-03 19:45

Reading the answers to this question, I came across this comment [edited].

2's complement of 0100(4) will be 1100. Now 1100 is 12 if I say normally. So, when I say normal 1100 then it is 12, but when I say 2's complement 1100 then it is -4? Also, in Java when 1100 (lets assume 4 bits for now) is stored then how it is determined if it is +12 or -4 ?? – hagrawal Jul 2 at 16:53

In my opinion, the question asked in this comment is quite interesting and so I'd like first of all to rephrase it and then to provide an answer and an example.

QUESTION – How can the system establish how one or more adjacent bytes have to be interpreted? In particular, how can the system establish whether a given sequence of bytes is a plain binary number or a 2's complement number?

ANSWER – The system establishes how to interpret a sequence of bytes through types. Types define

  • how many bytes have to be considered
  • how those bytes have to be interpreted

EXAMPLE – Below we assume that

  • char's are 1 byte long
  • short's are 2 bytes long
  • int's and float's are 4 bytes long

Please note that these sizes are specific to my system. Although pretty common, they can be different from system to system. If you're curious of what they are on your system, use the sizeof operator.

First of all we define an array containing 4 bytes and initialize all of them to the binary number 10111101, corresponding to the hexadecimal number BD.

// BD(hexadecimal) = 10111101 (binary)
unsigned char   l_Just4Bytes[ 4 ]   =   { 0xBD, 0xBD, 0xBD, 0xBD };

Then we read the array content using different types.

unsigned char and signed char

// 10111101 as a PLAIN BINARY number equals 189
printf( "l_Just4Bytes as unsigned char  -> %hi\n", *( ( unsigned char* )l_Just4Bytes ) );

// 10111101 as a 2'S COMPLEMENT number equals -67
printf( "l_Just4Bytes as signed char    -> %i\n", *( ( signed char* )l_Just4Bytes ) );

unsigned short and short

// 1011110110111101 as a PLAIN BINARY number equals 48573
printf( "l_Just4Bytes as unsigned short -> %hu\n", *( ( unsigned short* )l_Just4Bytes ) );

// 1011110110111101 as a 2'S COMPLEMENT number equals -16963
printf( "l_Just4Bytes as short          -> %hi\n", *( ( short* )l_Just4Bytes ) );

unsigned int, int and float

// 10111101101111011011110110111101 as a PLAIN BINARY number equals 3183328701
printf( "l_Just4Bytes as unsigned int   -> %u\n", *( ( unsigned int* )l_Just4Bytes ) );

// 10111101101111011011110110111101 as a 2'S COMPLEMENT number equals -1111638595
printf( "l_Just4Bytes as int            -> %i\n", *( ( int* )l_Just4Bytes ) );

// 10111101101111011011110110111101 as a IEEE 754 SINGLE-PRECISION number equals -0.092647
printf( "l_Just4Bytes as float          -> %f\n", *( ( float* )l_Just4Bytes ) );

The 4 bytes in RAM (l_Just4Bytes[ 0..3 ]) always remain exactly the same. The only thing that changes is how we interpret them.

Again, we tell the system how to interpret them through types.

For instance, above we have used the following types to interpret the contents of the l_Just4Bytes array

  • unsigned char: 1 byte in plain binary
  • signed char: 1 byte in 2's complement
  • unsigned short: 2 bytes in plain binary notation
  • short: 2 bytes in 2's complement
  • unsigned int: 4 bytes in plain binary notation
  • int: 4 bytes in 2's complement
  • float: 4 bytes in IEEE 754 single-precision notation

[EDIT] This post has been edited after the comment by user4581301. Thank you for taking the time to drop those few helpful lines!

查看更多
看我几分像从前
7楼-- · 2019-01-03 19:46

Two's complement allows negative and positive numbers to be added together without any special logic.

If you tried to add 1 and -1 using your method
10000001 (-1)
+00000001 (1)
you get
10000010 (-2)

Instead, by using two's complement, we can add

11111111 (-1)
+00000001 (1) you get
00000000 (0)

The same is true for subtraction.

Also, if you try to subtract 4 from 6 (two positive numbers) you can 2's complement 4 and add the two together 6 + (-4) = 6 - 4 = 2

This means that subtraction and addition of both positive and negative numbers can all be done by the same circuit in the cpu.

查看更多
登录 后发表回答