Understanding two’s complement2 min read

Have you ever wondered why, in Java and other languages, one byte can only represent -2^7 to 2^7-1 as the maximum value and why cannot we have 2^7. There is indeed a reason for that, in Java, some primitive types (int, short, long, byte) are signed two’s complement. In this article, we will learn how two’s complement can be used to represent both positive and negative decimal values in the binary representation.

Given a positive number, two’s complement is an operation to reverse this number into a negative number, and the most significant bit (the leftmost one) indicates whether this number is positive or negative (0 means positive, and 1 means negative). For example, I have the number 7 and want to find the binary representation of its negative, i.e. -7. Here is the general procedure (to make it less verbose, we only use 4 bits to represent our binary number):

  • Get the binary representation of the number 7 => 0111_2
  • Flip all the bits (0 becomes 1 and 1 becomes 0) => 1000_2
  • Add 1 to the flipped value => 1001_2

That’s how you get the number -7 in its binary form. Along the way, we have the number 7 with the binary value of 0111_2 since it’s two’s complement value, we need to add an extra 0 at the most significant bit to signify it’s a positive value.

Here, to verify that 1001 is indeed -7 in the decimal format, we don’t calculate the decimal representation as we usually do, but instead, we will add all the bits up but subtract the most significant bit:

-2^3 * 1 + 2^2 * 0 + 2^1 * 0 + 2^0 * 1 = -8 + 1 = -7

Now we have some knowledge of how two’s complement works, we can come back to the initial question of why Java can only represent 127 as the maximum value instead of 128 for the byte data type. Because each byte contains 8 bits and bytes in Java are two’s complements, meaning that we have to reserve 1 bit for the sign, and the rest 7 bits represent the magnitude, here 11111111_2 will represent -1, not 128. Going backward, we can still represent -128 as the lower bound as we know 10000000_2 is indeed -128.

To find the decimal representation of any two’s complement value, we can use this general formula:

w = -a_{N-1} 2^{N-1} + \sum_{i=0}^{N-2} a_i 2^i

Or if the formula above looks complicated, we also can use this procedure to compute the decimal value for a two’s complement; let’s say we want to convert 1100_2 to decimal:

  • First, we find the complement of 1100_2 by flipping all the bits, which is 0011_2
  • Add one to it, 0100_2
  • Convert 0100 to decimal, which is 4
  • Apply the sign that we have at the beginning; the result we get is -4.
Previous Article
Next Article
Every support is much appreciated ❤️

Buy Me a Coffee