Signed Integers
Signed integers represent both positive and negative whole numbers, most often using two's complement.
Representing a sign
A signed integer must encode negatives as well as positives within a fixed number of bits. Three classic schemes exist: sign-magnitude, one's complement, and two's complement. Modern hardware uses two's complement almost universally.
Range
With n bits, a two's complement signed integer spans −2ⁿ⁻¹ to 2ⁿ⁻¹−1. An 8-bit signed byte covers −128 to 127. The range is asymmetric: there is one more negative value than positive.
Why two's complement won
In two's complement, addition and subtraction use the same circuitry as unsigned arithmetic, and there is a single representation of zero. Sign-magnitude and one's complement both have two zeros and need special-case adders.
Interpreting the top bit
The most significant bit acts as a sign indicator: 0 for non-negative, 1 for negative. But in two's complement it is not merely a flag; it carries a negative place value of −2ⁿ⁻¹.
Sign extension
Widening a signed value to more bits requires copying the sign bit into the new high bits, preserving the value. Copying zeros instead would corrupt negative numbers.
def as_signed(bits, n):
if bits & (1 << (n-1)):
return bits - (1 << n)
return bits
print(as_signed(0b11111111, 8)) # -1