Binary Number System Tutorial
A practical introduction to binary: how computers think in ones and zeros, and why every developer should understand it.
Why Binary?
Every computation your computer performs, every pixel it renders, every packet it sends, ultimately reduces to patterns of ones and zeros. This is not a design choice but a consequence of physics: digital circuits operate with two voltage levels (high and low), making binary (base 2) the natural language of electronic hardware. Understanding binary is not just academic; it is the key to understanding how data is stored, how arithmetic overflows happen, how bitwise operations work, and why certain bugs exist.
This tutorial starts from the ground up. If you already know what a bit is, skip ahead to the sections on arithmetic or two's complement. If you are new to binary, read on; by the end, you will be comfortable reading, writing, and reasoning about binary numbers.
Bits, Nibbles, and Bytes
A bit (binary digit) is the smallest unit of information: it can be either 0 or 1. While a single bit is not very useful on its own, groups of bits can represent increasingly large values:
- 1 bit: 2 possible values (0 or 1)
- 4 bits (nibble): 16 possible values (0 to 15). One nibble maps to exactly one hexadecimal digit.
- 8 bits (byte): 256 possible values (0 to 255). The byte is the fundamental addressable unit in virtually all modern architectures.
- 16 bits (word): 65,536 possible values
- 32 bits (double word): ~4.29 billion possible values
- 64 bits (quad word): ~18.4 quintillion possible values
The pattern is simple: n bits can represent 2n distinct values. This exponential relationship is why adding just one bit doubles the range.
Positional Notation in Binary
Binary uses the same positional notation as decimal, but with base 2 instead of base 10. Each position represents a power of 2, starting from the right:
Example: 11001010 in Binary
| Position | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| Power of 2 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
| Bit | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
| Value | 128 | 64 | 0 | 0 | 8 | 0 | 2 | 0 |
128 + 64 + 8 + 2 = 202 in decimal
To convert any binary number to decimal, simply add up the positional values where the bit is 1. You can practice this interactively with the Bit Layout visualizer in our Base Converter, which lets you click individual bits and see all representations update in real time.
Counting in Binary
Counting in binary follows the same pattern as decimal: when a digit reaches its maximum value, it resets to 0 and the next position increments. In decimal, the maximum digit is 9; in binary, the maximum digit is 1. Here is the pattern:
Decimal Binary
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
10 1010
... ...
15 1111
16 10000Notice how every power of 2 (1, 2, 4, 8, 16) has exactly one bit set, and every number one less than a power of 2 (1, 3, 7, 15) has all lower bits set. This pattern is the foundation of bitmasking, which you will encounter constantly in systems programming.
Binary Arithmetic
Addition
Binary addition follows four simple rules:
- 0 + 0 = 0
- 0 + 1 = 1
- 1 + 0 = 1
- 1 + 1 = 10 (0 with carry 1)
When both bits are 1, the result is 0 with a carry of 1 to the next position, just like carrying in decimal addition when digits sum to 10 or more. For example, adding 1011 (11) and 0110 (6):
1 0 1 1 (11)
+ 0 1 1 0 ( 6)
─────────
1 0 0 0 1 (17)Try this yourself in the Arithmetic Calculator, which shows step-by-step breakdowns for any base.
Overflow
When the result of an addition exceeds the available bit width, an overflow occurs. In an 8-bit unsigned register, 11111111 (255) + 00000001 (1) produces 100000000 (256), but the 9th bit is lost, leaving 00000000 (0). This wraparound behavior is the source of many subtle bugs: counter overflows, timer wraps, and the infamous Y2K-style issues. Understanding why it happens requires understanding binary representation.
Representing Negative Numbers: Two's Complement
Unsigned binary can only represent non-negative numbers. To handle negative values, computers use two's complement, a scheme where the most significant bit (MSB) acts as a sign bit. If the MSB is 0, the number is positive or zero; if 1, it is negative.
To negate a number in two's complement, invert all the bits (bitwise NOT) and add 1. For example, to represent -5 in 8-bit two's complement:
- Start with 5:
00000101 - Invert all bits:
11111010 - Add 1:
11111011
So -5 is 11111011 (or 0xFB) in 8-bit two's complement. The beauty of this representation is that addition works identically for signed and unsigned numbers, meaning the CPU needs only one adder circuit.
The range of an n-bit two's complement integer is -2n-1 to 2n-1 - 1. For 8 bits: -128 to 127. For 32 bits: -2,147,483,648 to 2,147,483,647. You can explore these boundaries in the Reference tab of our converter.
Binary in Real-World Programming
Flags and Bit Fields
Operating systems and protocols pack multiple boolean values into a single integer using bit flags. Unix file permissions use 9 bits (three groups of rwx), TCP flags occupy 6 bits in the header, and CPU status registers encode conditions (carry, zero, overflow, sign) as individual bits. Reading and manipulating these flags requires thinking in binary. See our Bitwise Operations guide for the operators used to work with flags.
Alignment and Padding
Memory alignment rules require data to be placed at addresses that are multiples of the data size (typically powers of 2). A 4-byte integer must sit at an address divisible by 4, meaning the last two bits of the address are always 00. Compilers insert padding bytes between struct fields to maintain alignment. Understanding binary makes these rules intuitive rather than mysterious.
Floating-Point Representation
IEEE 754 floating-point numbers (float, double) are encoded as three binary fields: a sign bit, an exponent (biased binary), and a mantissa (fractional binary). The infamous 0.1 + 0.2 != 0.3 anomaly exists because 0.1 cannot be represented exactly in binary, just as 1/3 cannot be represented exactly in decimal. Understanding the binary layout helps debug precision issues.
Converting Between Binary and Other Bases
Binary has an elegant relationship with octal and hexadecimal. Each octal digit corresponds to exactly 3 binary bits, and each hex digit corresponds to exactly 4 binary bits. This means you can convert between binary and hex (or octal) by simply grouping bits:
Binary: 1100 1010
Hex: C A → 0xCA
Binary: 001 100 101 010
Octal: 1 4 5 2 → 0o1452This grouping property is why hex is preferred over decimal in low-level programming: it preserves the binary structure visually. Our Base Converter updates all bases simultaneously, making these relationships immediately visible.
Try It Yourself
The interactive Bit Layout in our Base Converter lets you click individual bits to toggle them and watch the decimal, hex, and octal values update in real time. Start with an 8-bit width, set a few bits, and observe the patterns. Then try the Arithmetic Calculator to add and subtract binary values and see the step-by-step carry propagation.
Further Reading
- Binary number — Wikipedia
Overview of the binary number system, its history, and mathematical properties.
- Two's complement — Wikipedia
Detailed explanation of how modern computers represent negative integers.
- IEEE 754 Floating-Point — Wikipedia
The floating-point standard that defines how decimals are stored in binary.
- Bit manipulation — Algorithms for Competitive Programming
Practical bit manipulation techniques commonly used in competitive programming.
- Khan Academy — Binary and Data
Interactive introduction to bits, binary counting, and data representation.