Two symbols.
Everything else.
Every photo, song, message and program on every device you've ever touched is, at the lowest level, a sequence of 0s and 1s. This page walks you from "what does that even mean" all the way down to two's complement and IEEE 754, which is the machine's actual view of a number.
What is binary, really?
In 1947, a physicist at Bell Labs made electricity change direction. He called it a transistor.
A transistor is just a switch. It has two states. High voltage or low voltage. On or off. 1 or 0.
That is the entire foundation of every computer ever built. Not because someone chose binary arbitrarily; because physics made it inevitable. A switch with two states is the simplest reliable building block that exists. Everything else is just what you can build when you wire enough of them together.
You already know how to count. When you write 237, you don't think about it, but you're using a system called base-10: ten symbols (0 through 9), and each position is worth ten times more than the one to its right.
237 means 2×100 + 3×10 + 7×1.
Binary is the same idea, but with only two symbols: 0 and 1. Each position is worth twice as much as the one to its right. That's it. That's the whole thing.
Counting the binary way
| position | value | example bit | contributes |
|---|---|---|---|
| 2⁰ | 1 | 1 | 1 |
| 2¹ | 2 | 0 | 0 |
| 2² | 4 | 1 | 4 |
| 2³ | 8 | 1 | 8 |
1101 in binary = 8 + 4 + 0 + 1 = 13 in decimal
Why two symbols?
Computers are built from billions of tiny switches. A switch has two natural states: off (low voltage) and on (high voltage). Map 0 to off, 1 to on, and suddenly numbers, letters, images, and code are all just patterns of switch-states. The switch itself, the transistor, gets its own page later on.
Try it: toggle eight switches
Every transistor in your CPU is one of these switches. Your CPU has about 100 billion of them. ← see: logic gates
Your first program: print a number in binary
fn main() {
let n: u8 = 13;
// {:08b} = 8-digit binary, zero-padded
println!("{} → {:08b}", n, n);
// prints: 13 → 00001101
}#include <stdio.h>
int main(void) {
unsigned char n = 13;
// C has no %b, so print bit by bit
printf("%d → ", n);
for (int i = 7; i >= 0; i--)
putchar((n >> i) & 1 ? '1' : '0');
putchar('\n');
return 0;
}Bitwise operations & signed numbers
Once numbers live as bits, you can do something you can't do as easily in decimal: operate on each bit independently. These are the bitwise operators, and they're shockingly fast because the CPU can do them in a single cycle.
| op | name | does | example |
|---|---|---|---|
& | AND | both bits 1 | 0b1100 & 0b1010 = 0b1000 |
| | OR | either bit 1 | 0b1100 | 0b1010 = 0b1110 |
^ | XOR | bits differ | 0b1100 ^ 0b1010 = 0b0110 |
! / ~ | NOT | flip every bit | ~0b1100 = 0b0011 (in 4 bits) |
<< | shift left | multiply by 2 | 0b0011 << 1 = 0b0110 |
>> | shift right | divide by 2 | 0b0110 >> 1 = 0b0011 |
Negative numbers: two's complement
Computers don't have a "minus sign" wire. So how do they store −5? They use a clever convention called two's complement: take the positive number, flip every bit, then add 1. The leftmost bit becomes a sign bit: 0 for positive, 1 for negative.
5 (8-bit) = 00000101
flip = 11111010
+ 1 = 11111011 ← this is −5
The genius: addition just works. 5 + (−5) as bits is 00000101 + 11111011 = 100000000. The 9th bit overflows out, and you're left with 00000000 = 0. The hardware doesn't need separate adders for signed and unsigned numbers.
SHA-256, the algorithm that secures Bitcoin, is 64 rounds of AND, OR, XOR, NOT, bit rotations and bit shifts. The same six operations in the table above. Logic gates doing mathematics at billions of cycles per second. ← see: hashing
Bit tricks you'll actually use
fn main() {
let x: u8 = 0b0010_1100;
// is bit 3 set?
let bit3 = (x >> 3) & 1; // 1
// set bit 0
let y = x | 1; // 0010_1101
// clear bit 2
let z = x & !(1 << 2); // 0010_1000
// toggle bit 5
let w = x ^ (1 << 5); // 0000_1100
// count ones (population count)
let ones = x.count_ones(); // 3
println!("{} {} {} {} {}", bit3, y, z, w, ones);
}#include <stdio.h>
int main(void) {
unsigned char x = 0b00101100;
// is bit 3 set?
int bit3 = (x >> 3) & 1; // 1
// set bit 0
unsigned char y = x | 1; // 0010_1101
// clear bit 2
unsigned char z = x & ~(1 << 2); // 0010_1000
// toggle bit 5
unsigned char w = x ^ (1 << 5); // 0000_1100
// count ones (gcc/clang builtin)
int ones = __builtin_popcount(x); // 3
printf("%d %u %u %u %d\n", bit3, y, z, w, ones);
return 0;
}&, set with |, clear with & ~, toggle with ^. Memorise this and bit manipulation becomes muscle memory.When the OS marks a file as readable, writable, or executable it sets three bits in a permission byte. chmod 755 is just three octal digits. Each one is three bits. Your entire filesystem security model is bitwise flags. ← see: operating system
Floats, endianness & why 0.1 + 0.2 ≠ 0.3
IEEE 754: how computers store decimals
Integers are easy: a fixed pattern of bits, one fixed value. Decimals are a different story. Computers use a binary version of scientific notation called IEEE 754. A 32-bit float splits into three fields:
The number is reconstructed as (−1)sign × 1.mantissa × 2exp − 127. The catch: most decimal fractions aren't exactly representable in binary. 0.1 in binary is a repeating fraction, just like 1/3 is in decimal. So 0.1 + 0.2 stores as 0.30000000000000004 on virtually every machine.
fn main() {
let a: f32 = 0.1;
let b: f32 = 0.2;
// raw 32-bit pattern of 0.1
println!("0.1 bits = {:032b}", a.to_bits());
println!("0.1+0.2 = {}", a + b);
// 0.30000001
println!("equal? = {}", a + b == 0.3);
// false
}#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(void) {
float a = 0.1f, b = 0.2f;
// reinterpret bits without UB
uint32_t bits;
memcpy(&bits, &a, sizeof(bits));
printf("0.1 bits = 0x%08x\n", bits);
printf("0.1+0.2 = %.10f\n", a + b);
printf("equal? = %d\n", (a + b) == 0.3f);
return 0;
}Endianness: how bytes line up in memory
A 32-bit integer is four bytes. But in what order are those bytes laid out in memory? Two conventions exist: little-endian (least significant byte first, used by x86 and ARM by default) and big-endian (most significant byte first, used by network protocols and older CPUs).
0xDEADBEEF stored in memory:
little-endian: EF BE AD DE ← what your laptop does
big-endian: DE AD BE EF ← what TCP/IP uses
This matters when you read raw bytes from disk, the network, or shared memory between architectures. Forget about it and you get silently corrupted data.
==. Compare with an epsilon: (a − b).abs() < 1e-6. Use integer or fixed-point math when correctness matters (currency, accounting, blockchain consensus).Binary in blockchain
Every concept on this page appears inside a Bitcoin node.
SHA-256 uses bitwise AND, XOR, NOT and bit rotations: the exact operations from the intermediate section above. 64 rounds, billions of times per second.
Bitcoin transaction amounts are 64-bit unsigned integers (u64 in Rust). Stored in little-endian byte order. The same endianness your x86 CPU uses.
The 0.1 + 0.2 problem is why blockchain ledgers never use floats. Every balance is stored as an integer. In Bitcoin, the unit is satoshis. 1 BTC = 100,000,000 satoshis. Integer math, exact, always.
A blockchain private key is 256 bits of random data. 32 bytes. The same bit patterns this page is about, just 256 of them. Chosen once, never shared, never lost.
fn satoshis_to_btc(satoshis: u64) -> f64 {
satoshis as f64 / 100_000_000.0
// note: display only; never use floats
// for actual Bitcoin arithmetic
}
fn main() {
let balance: u64 = 100_000_000; // 1 BTC in satoshis
println!("Balance: {} BTC", satoshis_to_btc(balance));
// Bitcoin amounts as integer bits
println!("As bits: {:064b}", balance);
println!("As hex: {:#018x}", balance);
// 0x0000000005f5e100
}#include <stdio.h>
#include <stdint.h>
int main(void) {
uint64_t balance = 100000000; // 1 BTC in satoshis
printf("Balance: %.8f BTC\n", balance / 100000000.0);
printf("As hex: 0x%016lx\n", balance);
// 0x0000000005f5e100
return 0;
}Where binary appears in BitRoot
This page is the substrate; every other topic on the site rests on it somewhere. The shortest path from any of them back to here:
Where this lands you
You now have the substrate. You know what a bit is, how integers and decimals are encoded, and how the CPU manipulates them. Next: how those bits become letters.