7

I still haven't found a reason why the lowest signed negative number doesn't have an equivalent signed positive number? I mean in a 3 digit binary number for simplicity 100 is -4? but we can't have a positive 4 in signed format because we can't. It overflows. So how do we know two's complement 1000 is -4 1000 0000 is -128 and so on? We have no original positive number

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Lews Therin
  • 10,907
  • 4
  • 48
  • 72
  • 4
    Because you have to count 0. [-4,-1] contains 4 numbers and [0,3] contains 4 numbers, for a total of 8, and 3 digit binary numbers have 2 to the power of 3 (=8) possible combinations. – André Caron Jan 18 '12 at 20:56
  • What? Sorry I don't understand anything you wrote before the 2^3 = 8 possible combinations. – Lews Therin Jan 18 '12 at 20:58
  • 2
    You have 4 negative numbers, 3 positive numbers, and 1 zero. Total 8! – Mr Lister Jan 18 '12 at 21:01
  • 2
    [-4,-1] is the set of numbers -4, -3, -2 and -1. [0,+3] is the set of numbers 0, 1, 2 and 3. Each of those halves of your total interval have 4 numbers, that's all 8 slots allocated to your 3-bit representation. – André Caron Jan 18 '12 at 21:02
  • For the record this was also discussed in chat: http://chat.stackoverflow.com/transcript/message/2401301#2401301 – Flexo Jan 18 '12 at 22:55

10 Answers10

19

One way to think about it is that signed, two's complement format works by assigning each bit a power of two, then flipping the sign of the last power of two. Let's look at -4, for example, which is represented as 100. This means that the value is

-1 x 2^2 + 0 x 2^1 + 0 x 2^0

If we want to get the positive version of this value, we'd have to negate it to get

 1 x 2^2 - 0 x 2^1 - 0 x 2^0

Notice that this value is equal to

 1 x 2^2 + 0 x 2^1 + 0 x 2^0

In other words, the normal binary representation of this value is 100. However, we're in trouble here, because we're using a signed two's complement representation, which means that we have specifically reserved the 4's bit as the sign bit. Consequently, when we try to interpret the bit pattern 100 as a signed, three-bit, two's complement value, it comes back out identically to what we started with. The shortage of bits is what's hurting here.

More generally, given n bits, of which the first is the sign bit in a two's complement representation, trying to compute -1000...00 will give back the same value, because the bit needed to store the large positive value has the special meaning assigned to it.

So why do this at all? The reason for this is that if you have only n bits, you cannot store the values -2n - 1 through 2n - 1, because there are 2n + 1 different numbers here and only 2^n different bit patterns. Excluding the largest positive number thus makes it possible to hold all the different numbers in the bit pattern specified.

But why drop the high value and not the low value? This is in order to preserve binary compatibility with unsigned integers. In an unsigned integer, the values 0 through 2n-1 - 1 are all encoded using the standard base-two representation. Consequently, for unsigned and signed integers to agree at all, the unsigned integers are designed so that they are bit-for-bit equivalent with the first 2n - 1 unsigned integers, which range from 0 to 2n - 1 - 1, inclusive. After this, the unsigned values need the most significant bit to encode numbers, but the signed values are using this as the sign bit.

Hope this helps!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
15

-INT_MIN is an integer overflow and is undefined behavior in C.

-INT_MIN is guaranteed to be equal to INT_MIN only when signed integer overflows wrap. This can be enabled with gcc for example with -fwrapv option.

Compiler usually take advantage of the fact that integer overflow is undefined behavior in C to perform some optimizations. Relying on signed integer overflows that wrap is unsafe.

A well known example of compiler optimization is the following

#define ABS(x) ((x) > 0 ? (x) : -(x)) 

void foo(int x){  
    if (ABS(x) >= 0) {
        // some code
    }
}

most of the compilers today (gcc, icc) with the optimizations options enabled would optimize out the test relying on the fact that -INT_MIN is undefined behavior.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • To be precise `-fwrapv` is the correct flag to ensure modulo wraparound for signed integers. `-fno-strict-overflow` prevents the optimizer from assuming that integer overflows never happen. – nucleon Mar 09 '16 at 17:24
  • @nucleon `-fwrapv` is the correct option here, thanks I edited my answer. – ouah Mar 09 '16 at 20:42
3

A. There is an even number of possibilities to n-digit binary number, so we can't represent the same range for positive and negative numbers.

B. We want that every number that begin with 1 will be negative, and every number begin with 0 will be no-negative. (not the opposite, because we want same represent to positive and zero in signed and unsinged. Because of that, 0 is in the half of the positives, so them have one place less.

asaelr
  • 5,438
  • 1
  • 16
  • 22
3

The alternative to two's complement has such a property, it's known as one's complement.
In one's complement form, the lowest possible value also has a valid positive form.


One's complement works by simply inverting all the bits in the number itself.
For example, we know that 0110 == 6 and in one's complement 1001 == -6. Using one's complement, we have just as many positive numbers as we do negative numbers.

But what about the bit representation 1111? Just by looking at it, we can tell that it's the "negative" form of zero (0000 = 0; 1111 = -0), but such a number doesn't make any sense and is somewhat wasteful.

Instead, we use two's complement, which is similar to one's complement, but after inverting the bits, we add one. So if we know that 0110 = 6, then the one's complement is 1001 and the two's complement is 1001 + 1 == 1010. Using two's complement, we don't have a "negative zero" because it causes an overflow.

A different way of looking at it is "if the highest bit is set, then the number is negative". That means that the positive range is [0 .. 2^(bits - 1)] and the negative range is everything else. There's the same number of positive numbers as there are negative numbers, but because (in this format) zero is considered positive, the negative range gets shifted one to [-1 .. (neg) 2^(bits - 1)].


Lets assume we're dealing with a 3-bit signed number in two's complement. That'd give us the following table:

BITS  VALUE
000       0
001       1
010       2
011       3

100      -4
101      -3
110      -2
111      -1

You can see that there's the same quantity of positive numbers as negative numbers, it's just that the negative numbers don't start from 0 like the positive set does.

Mr. Llama
  • 20,202
  • 2
  • 62
  • 115
  • Two's-complement integers regard the leftmost bit as yielding a value which should be copied to all bits to its left [for any N, subtract 1 from a value whose rightmost N bits are 0, and the rightmost N bits of the result will be 1's], so -1 is equivalent to an infinite sequence of 1's. For ones' complement, the same value is used to pad the left and right sides. The values 0.1111... and ...111.0 [infinitely many 1's in either case] are equivalent to 1.0 and ...110.111..., respectively [infinitely many ones on both sides in the latter case] but only the latter two forms are normalized. – supercat May 18 '16 at 21:17
2

The missing digit is 0. In a mathematical sense, 0 is neither positive nor negative. But in a binary sense, since 0 has no negative bit, it's considered positive. In other words, if you wanted -128 to 128, there couldn't be a 0.

Chris Eberle
  • 47,994
  • 12
  • 82
  • 119
  • But we have 0 which is 000 -3 digit representation. Where does -4 come from? Since we can't represent 4 as signed – Lews Therin Jan 18 '12 at 21:00
  • Count with me: 3 bits = 2^3 choices = 8 possible combinations. Here they are: -4, -3, -2, -1, 0, 1, 2, 3. As per my answer, there are 4 positive numbers, and 4 negative numbers here. -4 in this case would be `111`, and 3 would be `011`. – Chris Eberle Jan 18 '12 at 21:04
  • Yeah that's right, I see that. However how does 128 ensure we have no 0? I know we can't have 128 because it is -128 due to the MSB acting as a negative sign. – Lews Therin Jan 18 '12 at 21:07
  • @LewsTherin: you can't do that in two's complement representation. You could come up with another representation which had no 0. – André Caron Jan 18 '12 at 21:09
  • @LewsTherin -- I think the problem here is that you're thinking about numbers as a human (i.e. how can I represent the "concept" of -10 if I don't have a +10). Computers don't see it this way. The binary mapping to base 10 signed is PURELY CONVENTION. I could just as easily say that 000110111000 maps to 42, and then make a whole system around that. The negative sign and the decimal numbers are only added back after translation. – Chris Eberle Jan 18 '12 at 21:12
  • Damn, I'm really confused now. 111 is not -4.. which case are you talking about Chris? @AndréCaron I guess you can do that, but there'd be no point, would there? I'm trying to understand Chris' answer as to how having -128 to 128 removes the 0. – Lews Therin Jan 18 '12 at 21:12
  • @Chris just saw your reply - so it is like how we choose to represent 0 or 1 - as either true or false. – Lews Therin Jan 18 '12 at 21:14
  • @LewsTherin- The idea here is that in the range -128 to 128 there are 257 numbers, which can't fit into eight bits (there are only 256 different bit patterns). Consequently, some number in that range has to be taken out. The signed two's-complement representation chooses to remove the largest possible value (128) in order to get a simple implementation. – templatetypedef Jan 18 '12 at 21:14
  • Try this as a thought experiment: you have 3 bits, which means you have 8 choices. Practically speaking, you could represent 8 of whatever number you wanted. So I could say 000 = 56, 001 = 2, 010 = -83, 011 = 99, 100 = -422, 101 = 101, 110 = 23, and 111 = 10000. The computer itself doesn't need to conceptualize what the final "meaning" of these 8 bits really means. That's up to the programmer. It's the same with binary. At the CPU level, it's all just bits. The fact that it happens to map very nicely back to base 10 numbers later on is due to some very careful planning. – Chris Eberle Jan 18 '12 at 21:14
  • @Chris I understand all the basic points now. That it is just convention - how the programmer chooses to define the meaning.. but your statement "if you wanted -128 to 128, there couldn't be a 0." baffles me. If you could clarify that I'd appreciate it, thanks. EDIT: Seriously wish I could pick more than one accepted answer :( – Lews Therin Jan 18 '12 at 21:20
  • 2
    @LewsTherin my statement was a bit hasty. A more accurate statement would be, if there WAS a +128, you'd need to drop a number elsewhere. I chose 0 because it seemed absurd. More realistically you'd probably drop -128. – Chris Eberle Jan 18 '12 at 21:33
  • So what you are saying is, I'd have to drop a number to keep the number of signs symmetric 4 positive and negative numbers? – Lews Therin Jan 18 '12 at 21:56
  • Sorry again, this symmetrical property is required for arithmetic purposes? – Lews Therin Jan 19 '12 at 11:26
1

Because you have to count 0. The integer range [-4,-1] (or, equivalently -4,-3,-2 and -1) contains 4 numbers and the rest of the range [0,3] (or, equivalently 0, 1, 2 and 3) contains 4 numbers, for a total of 8, and 3 digit binary numbers have 2 to the power of 3 (=8) possible combinations.

Think of it this way. Any integer range of the form [-n,+n] necessarily has an odd size (2*n+1 integers). Whatever integer binary representation you use will have a different number of negative and positive numbers because the number of combinations is always even (powers of 2).

André Caron
  • 44,541
  • 12
  • 67
  • 125
0

This answer is just a summary.

In N bit 2's complement:

  • The negative range is [-2^{N-1}, -1] which has cardinality 2^{N}/2.
  • The positive range is [0, 2^{N-1}-1] which again has cardinality 2^{N}/2.

and the overall range [-2^{N-1}, 2^{N-1}-1] must have the cardinality 2^{N}. Performing N bit operations on any number out of this range will cause an overflow.

And notice that when all the number in this signed range is added with a bias 2^{N-1} we get an unsigned range [0, 2^{N-1}].

0

Two's complement represents negative numbers by reserving the highest bit as negative. This means you can't use the highest bit as positive anymore.

All the other (lower) bits are positive but no matter how you add them up, the sum can never reach the highest bit because it's seen as negative.

Humpity
  • 152
  • 1
  • 9
0

We should know how we manage to make x to -x:

  1. Flip all bits in x. Like 5 is 0101, and we get 1010 in this step;
  2. Add 1 to what we get in last step. This time we get 1010 + 1 = 1011.

And in the real machine, negative ones are always shown in 2's complement format, so 1011 presents -5(which is -8 + 2 + 1 = -5).

Now back to the question, INT_MIN in the real machine is 1 with 31 consecutive 0.

So after the first step, you will get a number which is 0 with 31 consecutive 1 and it is INT_MAX in C language.

In the second step, add 1 to what we get from the last step, and the result is 1 with 31 consecutive 0, which is also INT_MIN.

So INT_MIN = -INT_MIN

0

So how do we know two's complement 1000 is -4 1000 0000 is -128 and so on? We have no original positive number

Your mistake is thinking that we need a two's complement representation of the positive number in order to compute the two's complement representation of the negative number.

The process for finding the two's complement of a negative number is:

Start out with the normal, non-two's complement representation of the absolute value of the number to be represented. So for -4, take the non-two's complement representation of |-4|, 100.

Flip all the bits: 100 -> 011 (or ...11111011 with the ones continuing indefinitely to the left).

Add one: 011 -> 100 (or ...11111100)

Now truncate to the number of bits you're using (this eliminates the carry bit or the infinite string of 1s). As a result, 100 is the 3-bit, two's complement representation of -4.

To go the other way, take the two's complement representation (100) flip the bits (011) and add one (100) you now have the non-two's complement representation of |-4|. 1*2^2 + 0*2^1 + 0*2^0 = 4. Therefore we know that representation we started off with, 100, is the 3-bit, two's complement representation of -4.

NullUserException
  • 83,810
  • 28
  • 209
  • 234
bames53
  • 86,085
  • 15
  • 179
  • 244