
The most important thing that we need to understand is that the computer’s works only with 1 and 0, and this information is known how bits.
So when we stored a number, in specific an integer in a program wroten in a language how to C is typically 1, 2, 4 or 8 bytes in length, or 8, 16, 32, or 64 bits in length.
The integer types can be:
- Unsigned: that can store values from 0 to 2^n -1, as simple binary numbers.
- Signed: that can store values from -(2^(n-1)) to 2^(n-1), as two’s complement binary format. Values greater than or equal to zer0 are stored with same bit values as unsigned numbers.
The size of bits int this case n depends on the bits in the machine ( 32 bits or 64 bits).
If 64bits are there to store number then the maximum value you can store in it is (2 ⁶³) -1 which takes 63 bits in its representation. It means MSB is always zero for a positive number. If all the bits are 1s the number is -1.

Two’s complement
The representation of signed integers that I showed above is the representation used by modern processors. It is called “two’s complement” because to negate an integer, you subtract it from 2N. For example, to get the representation of –2 in 3-bit arithmetic, you can compute 8–2 = 6, and so –2 is represented in two’s complement as 6 in binary: 110.
This is another way to compute two’s complement, which is easier to imagine implemented in hardware:
- Start with a binary representation of the number you need to negate
- Flip all bits
- Add one
The reason why this works is that flipping bits is equivalent to subtracting the number from (2N — 1). We actually need to subtract the number from 2N, and step 3 compensates for that — 1.
Decoding 2’s Complement Numbers
For positive values, if the leftmost (sign) bit is zero, the value is positive so simply do a binary to decimal conversion.

This example was run on a 64-bit machine so there are about 57 zeros before this number so the number is positive and the rest we calculate right to left as powers of two starting at zero and then multiplied by the bit at that power.
So going right to left we have;
0*²⁰ + 0*²¹ + 1*²² + 0*²³ + 1*²⁴ + 0*²⁵ + 1*²⁶
= 0 + 0 + 4 + 0 + 16 + 0 + 64 = 84
Negative number example:

Let’s use -84 since we already used it above.
Step 1. 84 = 0…000…0001010100
Step 2. 1…111…1110101011
Step 3. add 1 so we get 1…111…1110101100
So we have 1…111…1110101100 just like in screenshot above
The interesting consequence in 2’s complement arithmetic
In unsigned arithmetic, a carry of the most significant digit means that there has been an overflow, but in signed arithmetic, an overflow is not so easy to detect. In fact, signed arithmetic overflows are detected by checking the consistency of the signs of the operands and the final answer.
A signed overflow can occur in an addition or subtraction if:
- the sum of two positive numbers is negative
- the sum of two negative numbers is non-negative
- subtracting a positive number from a negative one yields a positive result
- subtracting a negative number from a non-negative one yields a negative result

The CPU doesn’t know if a number is signed or unsigned when it moves it from one place to another. When the compiler creates the machine language file, it chooses the correct operation to be executed to make a math operation with that number. If you declared your variable to be of the signed type, for instance, than the operation to be executed in machine language will be one that treats that memory position as a signed value.
In any software of any kind, it is always when you interpret the data that you give it meaning. A byte in memory can be a signed or unsigned number, or a character, or a part of a music file, or a pixel in a picture, etc. What gives it meaning is how you use that byte.
So in summary the number is only signed or unsigned based on your interpretation of it, the CPU gives you the tools necessary to distinguish between them, but doesn’t distinguish on its own.
