1. Introduction

In this tutorial, we’ll discuss the difference between signed and unsigned variables. We know that almost all computers store data in binary. In a specific language, such as C, Java, or Python, variables can be stored in 8, 16, 32, 64, or 128 bit chunks. Furthermore, we’ve all encountered the terms signed or unsigned. These can be a source of confusion for some programmers, so we’ll methodically understand the differences between them.

2.  A Tiny Example

We’ll start with a hypothetical computer that stores variables in 4-bit chunks. Later, we’ll extend this example to more realistic sizes.

Let’s see all the possible values of a 4-bit number:

img 62ff5ea170d23

Since the number of possible values for an n-bit number is {2^n}, the number of possibilities will be {2^4=16} in our tiny example.

If we interpret these values as unsigned, they will range from 0 to {2^n-1}, that is, 0 to 15 in our example, where {n=4}, as shown in the above figure.

3. One’s Complement

We use the leftmost bit as a sign bit in this representation. If this bit is 0, the number is positive and we can find the magnitude of the number by converting the remaining 3 bits from binary to decimal.

For example, 0101 is a positive number with magnitude 5, as shown below:

img 62ff5ea285265

If we encounter a sign bit \mathbf{=1}, we know the number is negative and can find its magnitude by obtaining the one’s complement, which means inverting each bit in the binary representation. For, example 1011 is a negative number with magnitude \mathbf{\bar{1}}\mathbf{\bar{0}}\mathbf{\bar{1}}\mathbf{\bar{1}}=\mathbf{0100}, i.e., -4 decimal.

3.1. A Problem With One’s Complement

We notice something sneaky about one’s complement: there are two zeros, a \mathbf{+0} and a \mathbf{-0}.

This is because 0000=0, as we would expect, but at the same time, 1111 is a negative number with one’s complement {\bar{1}}{\bar{1}}{\bar{1}}{\bar{1}}={0000} that represents -0.

This was a serious problem in the early computers (that used one’s complement) as we had to check for both a \mathbf{+0} and a \mathbf{-0}. One’s complement is rarely used in today’s computers, but it is used in some situations, so we have to watch out for this anomaly.

4. Two’s Complement

There is a subtle difference between one’s and two’s complement. To explain this, we present the corresponding figures side by side, so we can conveniently compare the representations.

img 62ff5ea395d00

4.1. Positive Numbers

The sign bit in two’s complement is the leftmost bit, as in the case of one’s complement. We obtain decimal equivalents of positive two’s complement numbers by straight binary to decimal conversion. Thus 0110 equals 6 decimal.

4.2. Negative Numbers

If the sign bit is 1, we obtain the magnitude using two’s complement. The procedure we follow is to take the one’s complement and add 1.

For example, for 1010, we first take the one’s complement {\bar{1}\bar{0}\bar{1}\bar{0}={0101}}. Adding 1 yields {0101+1={0110}}, which represents -6 decimal.

4.3. Range of Negative Numbers

In two’s complement, the range of negative numbers is -1 to {-{2^n}}. In our 4 bit example the range is from -1 to -8.

This range of negative numbers in two’s complement is one greater than in one’s complement and, as we can see from the figures, it eliminates the -1 problem.

5. A Summary of Results

We’ll now summarize our results using a set of tables, one each for unsigned, one’s complement and two’s complement. In each table, we’ll see the specific values for 8, 16 and 32-bit words and also the general expression for the ranges of values. Let’s keep in mind that one’s and two’s complement both have a sign bit at the leftmost end.

5.1. Unsigned Numbers

Unsigned numbers with n bits range in value from 0 to 2^n-1. These numbers are all positive–no negative numbers are possible. For example, if n=16, the range of numbers is 0 to 2^{16} -1=65535.

>

Bits

Unsigned

8

0
\downarrow
2^8-1=255

00000000
\downarrow
11111111

16

0
\downarrow
2^16-1=65535

00000000\ 00000000
\downarrow
11111111\ 11111111

32

0
\downarrow
2^32-1=4294967295

00000000\ 00000000\ 00000000\ 00000000
\downarrow
11111111\ 11111111\ 11111111\ 11111111

n

0
\downarrow
2^n-1

5.2. One’s Complement Numbers

Let’s have a look at one’s complement. For n bits, these numbers range from -(2^{n-1}-1) to -0 and then from +0 t0 +(2^{n-1}-1).

If we look at the case of n=8, the values range from -(2^7-1)=-127 to -0 and then from +0 to +(2^7-1)=+127.

As we’ve discussed above, there is a \mathbf{-0} as well as a \mathbf{+0}, which can make things complicated for programmers.

Bits

One’s Complement

8

+0
\downarrow
+(2^7-1)=+127
-(2^7-1)=-127
\uparrow
-0

00000000
\downarrow
01111111
10000000
\uparrow
11111111

16

+0
\downarrow
+(2^15-1)=+32767
-(2^15-1)=-32767
\uparrow
-0

00000000\ 00000000
\downarrow
01111111\ 11111111
10000000\ 00000000
\uparrow
11111111\ 11111111

32

+0
\downarrow
+(2^31-1)=+2147483647
-(2^31-1)=-2147483647
\uparrow
-0

00000000\ 00000000\ 00000000\ 00000000
\downarrow
01111111\ 11111111\ 11111111\ 11111111
10000000\ 00000000\ 00000000\ 00000000
\uparrow
11111111\ 11111111\ 11111111\ 11111111

n

+0
\downarrow
+(2^n-1-1)
-(2^n-1-1)
\uparrow
-0

5.3. Two’s Complement Numbers

Finally, we look at the most common signed representation, that is, two’s complement.  In this case the numbers range from -(2^{n-1}) to 0 and then to +(2^{n-1} -1). The magnitude of the most negative number is 1 greater than the most positive number, and there is only one zero.

For example, for n=32, the values range from -(2^{31})=-214748368 to 0 and then to +(2^{31}-1)=+2147483647.

Bits

Two’s Complement

8

+0
\downarrow
+(2^7-1)=+127
-(2^7)=-128
\uparrow
-1

00000000
\downarrow
01111111
10000000
\uparrow
11111111
00000000\ 00000000

16

+0
\downarrow
+(2^15-1)=+32767
-(2^15)=-32768
\uparrow
-1

00000000\ 00000000
\downarrow
01111111\ 11111111
10000000\ 00000000
\uparrow
11111111\ 11111111

32

+0
\downarrow
+(2^31-1)=+2147483647
-(2^31)=-2147483648
\uparrow
-1

00000000\ 00000000\ 00000000\ 00000000
\downarrow
01111111\ 11111111\ 11111111\ 11111111
10000000\ 00000000\ 00000000\ 00000000
\uparrow
11111111\ 11111111\ 11111111\ 11111111

n

+0
\downarrow
+(2^n-1-1)
-(2^n-1)
\uparrow
-1

6. Conclusion

In this article, we’ve presented the concepts of unsigned and signed variables used in computers. We’ve learned that all numbers are represented in binary. A signed number uses a 1 in the leftmost bit position to represent negative numbers.

We’ve also learned that an unsigned variable cannot represent negative numbers, but has a greater range than signed numbers.

One’s complement numbers are symmetric–they have the same magnitude of maximum negative and maximum positive. Unfortunately this leads to a \mathbf{-0} as well as a \mathbf{+0}, which can be a problem for programmers.  One’s complement is rarely used in modern computing.

Two’s complement numbers are widely used in today’s computers. The magnitude of the most negative number is 1 greater than the magnitude of the most positive number. There is only one zero.