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.
On page one you learned that a single number can wear many costumes.
Binary is the only one the machine actually wears.
Two symbols. 0 and 1. Thats the entire alphabet. Every photo youve saved, every song youve streamed, every message youve ever sent is spelled with just those two letters.
The obvious question is why.
Why two? Why not ten, like your fingers? Why not something richer and more expressive?
The answer isnt engineering. It isnt convention. Its physics.
In 1947, three physicists at Bell Labs built the first transistor. A switch with no moving parts. And a switch can do exactly one reliable thing. It can be on, or it can be off.
Not on-ish. Not seventy percent on. On or off. A voltage above the line, or below it.
Try to store ten distinct levels in that switch and noise destroys you. The real world smears your values together until you cant tell them apart. But two states? Two states are almost impossible to confuse.
So the machine doesnt speak binary because someone chose it.
It speaks binary because thats the only language that survives contact with a noisy electrical world.
Everything above this page, every number system, every program, every blockchain, is a tower built on these two symbols.
This is the bedrock.
Lets learn to read it.
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 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.
Binary across ScrapyBytes
The same ideas surface all over ScrapyBytes. Here is where this page connects to the rest of the curriculum, and how to follow each thread.
Every bit is a voltage held by a transistor, and logic gates are the switches that store and combine those bits. Binary is the language; gates are the hardware that speaks it.
scrapybytes.vercel.app/logic-gates →Number SystemsBinary is base two. The number systems page covers every base; binary is the one with two symbols, the only base the hardware understands natively.
scrapybytes.vercel.app/number-systems →ASCIIASCII is binary with a meaning attached. 0100 0001 is the bits; A is what we agree they spell. Encoding is binary plus a convention.
The CPU is binary in motion: registers hold bits, the ALU adds them, instructions are bit patterns. Everything on the CPU page is the binary on this one, clocked.
scrapybytes.vercel.app/cpu →MemoryMemory is addressable binary. Every byte is eight bits at a numbered location. The memory page is where the bits from this page actually live.
scrapybytes.vercel.app/memory →VariablesThe type decides how a variable's bits are read. The same 32 bits are an i32 or an f32. Two's complement and IEEE 754 from this page are why.
SHA-256 turns bytes into exactly 256 bits, and flipping one input bit flips about half the output bits. Hashing is binary arithmetic at its most violent.
scrapybytes.vercel.app/hashing →NetworkingEvery packet is binary and every IP address is 32 bits of it. The networking page is binary at planet scale.
scrapybytes.vercel.app/networking →BlockchainBitcoin private keys are 256 random bits and amounts are 64-bit integers. The blockchain page is hashes of hashes of hashes, all of it binary, all of it integer math.
scrapybytes.vercel.app/blockchain →