⚙️

Boolean Algebra & Digital Logic

A Complete 10-Chapter Maths for Programmers Course

Topics covered:
Boolean operators & the laws of Boolean algebra · canonical forms
Simplification & Karnaugh maps · logic gates & combinational circuits
Adders, multiplexers & decoders · sequential logic & memory
Binary, hexadecimal & two's complement

Capstone: designing a real 3-bit adder/subtractor with overflow detection
Exercises: 30 hands-on exercises with worked solutions
Format: A4 · Dark-theme code examples
Philip Osztromok · Generated with Claude

Table of Contents

  1. Why Boolean Algebra & Digital Logic Matters for Programmers
  2. Boolean Values, Operators & Truth Tables
  3. The Laws of Boolean Algebra
  4. Boolean Functions & Canonical Forms
  5. Simplifying Boolean Expressions
  6. Logic Gates & Combinational Circuits
  7. Building Blocks: Adders, Multiplexers & Decoders
  8. Sequential Logic: Latches, Flip-Flops & Memory
  9. Binary, Hexadecimal & Number Representation
  10. Capstone — Designing a Small Digital Circuit
Chapter 1 of 10

Why Boolean Algebra & Digital Logic Matters for Programmers

Boolean Algebra & Digital Logic

Chapter 1 · Why Boolean Algebra & Digital Logic Matters for Programmers

Discrete Mathematics Fundamentals' own Chapter 2 already covered truth tables, AND/OR/NOT, and De Morgan's Laws — as propositional logic: statements that are true or false, connected by logical words. This course reintroduces the exact same truth tables, on purpose, as a genuinely different thing: an algebra — a system of values and operations you can manipulate with algebraic laws, the way ordinary arithmetic lets you manipulate numbers. That shift in framing is what turns "true/false sentences" into "the actual mathematics every logic gate, CPU, and bitwise operator in a running computer is built from."

Same Truth Table, Two Different Framings

Propositional logic asks: is this sentence true? Boolean algebra asks: what does this expression evaluate to? The underlying table never changes — only what the two columns are understood to mean.

Propositional logic (Discrete Math Ch.2)Boolean algebra (this course)
P, Q — statements, each true or falsex, y — variables, each 1 or 0
P ∧ Q (P and Q)x · y or xy (Boolean product)
P ∨ Q (P or Q)x + y (Boolean sum)
¬P (not P)x' or (complement)

The · and + notation isn't decorative — writing Boolean operations as "multiplication" and "addition" is exactly what makes Chapter 3's algebraic laws (distributive, absorption, and the rest) feel like genuine algebra rather than a list of logic rules to memorize separately.

A Real Demonstration: Your Own Code Already Runs on These Laws

A permissions system — READ, WRITE, EXECUTE as individual bits, combined with | (OR) and tested with & (AND) — is Boolean algebra running directly in production code, not an analogy for it.

Verified directly
READ=0b100, WRITE=0b010. Granting both: READ | WRITE = 0b110. Idempotent law (x + x = x): perms | perms == perms — verified True. Absorption law (x + (x · y) = x): perms | (perms & y) == perms — verified True. De Morgan's Law, on real 3-bit values: ~(a & b) and (~a | ~b), both masked to 3 bits, computed to the identical result — verified directly, not assumed.
Why this matters more than it looks like it does
Every one of those laws will be formally proved in Chapter 3 — but they're already true of code you may have written without ever naming them. Boolean algebra isn't a new set of rules to learn from scratch; it's the existing rules bitwise code already obeys, made explicit enough to reason about, simplify, and eventually build actual hardware from.

Five Concrete Connections to Real Code

Boolean algebra topicWhere it actually shows up
Boolean operators (Ch.2-3)Bitwise operators in every language — &, |, ^, ~, <<, >>
Boolean simplification (Ch.5)Simplifying tangled if conditions and short-circuit logic in real code
Flags & bitmasks (Ch.2-3, Ch.9)Permission systems, feature flags, CPU status registers, protocol header fields
Logic gates & circuits (Ch.6-8)What a CPU's ALU, adders, and multiplexers are physically built from
Number representation (Ch.9)Two's complement — why negative numbers behave the way they do in every language

What This Course Won't Cover

Digital logic, taken to its full depth, becomes computer architecture and then chip engineering. This course deliberately stops well before that point:

  • Computer architecture / CPU design — instruction sets, pipelining, cache hierarchies, and how gates assemble into an actual processor stay out of scope; that's its own substantial future topic
  • VLSI / physical circuit engineering — transistor-level design, timing analysis, and fabrication are a genuinely different (and much deeper) discipline than the logical structure this course covers
  • Formal digital design tools — HDLs like Verilog/VHDL, and real synthesis/simulation tooling, aren't covered; this course builds the mathematical foundation those tools are built on top of
Why draw the line at gate-level logic specifically
Boolean algebra, canonical forms, simplification, and the handful of building-block circuits (adders, multiplexers, flip-flops) this course covers are exactly what's needed to understand why a computer's binary logic works the way it does — without requiring the years of additional depth that full processor design or chip fabrication would take.

Where This Course Is Headed

ChapterTopic
2Boolean Values, Operators & Truth Tables
3The Laws of Boolean Algebra
4Boolean Functions & Canonical Forms
5Simplifying Boolean Expressions
6Logic Gates & Combinational Circuits
7Building Blocks: Adders, Multiplexers & Decoders
8Sequential Logic: Latches, Flip-Flops & Memory
9Binary, Hexadecimal & Number Representation
10Capstone — Designing a Small Digital Circuit
This course's throughline
Every chapter answers a version of the same question: given only two values and a handful of operations, what can genuinely be built — a simplified expression, a working circuit, a way to remember one bit of state, a way to represent a negative number? By Chapter 10, the answer is "an actual, working piece of digital hardware," assembled entirely from what came before.

Hands-On Exercises

Exercise 1

Using this chapter's own translation table, rewrite the propositional-logic statement (P ∧ Q) ∨ ¬P in Boolean algebra notation (using ·, +, and ').

📄 View solution
Exercise 2

A feature-flag system uses DARK_MODE=0b1000, BETA=0b0100, ADMIN=0b0010, DEBUG=0b0001. A user has flags enabled = DARK_MODE | BETA. Verify directly (compute the actual bit values) that the idempotent law enabled | enabled == enabled holds for this specific value, and explain in one sentence why this law will always hold for any combination of flags, not just this one.

📄 View solution
Exercise 3

A colleague says "bitwise operators are just a performance trick — they don't have any real mathematical structure behind them." Using this chapter's own flags demonstration, explain specifically why that's wrong, naming at least one Boolean algebra law that real bitwise code already obeys.

📄 View solution

Chapter 1 Quick Reference

  • Boolean algebra is propositional logic's own truth tables, reframed as algebra: · (AND), + (OR), ' (NOT) instead of , , ¬
  • Real bitwise/flags code already obeys Boolean algebra's laws — verified directly on a permissions bitmask (idempotent, absorption, De Morgan's)
  • Five direct connections: bitwise operators, condition simplification, flags/bitmasks, logic gates/circuits, number representation
  • Deliberately out of scope: full computer architecture/CPU design, VLSI/physical circuit engineering, HDL tooling
  • Next chapter: Boolean values, operators, and truth tables — formalized
Chapter 2 of 10

Boolean Values, Operators & Truth Tables

Boolean Algebra & Digital Logic

Chapter 2 · Boolean Values, Operators & Truth Tables

A Boolean value is one of exactly two elements — 0 or 1 (equivalently False/True). A Boolean operator takes one or two Boolean values and produces another. This chapter defines the full working set — including two operators, XOR and NAND/NOR, that Discrete Mathematics Fundamentals' own propositional-logic chapter never needed but digital logic can't do without.

The Core Three: AND, OR, NOT

xyx · y (AND)x + y (OR)
0000
0101
1001
1111

AND is 1 only when both inputs are 1. OR is 1 when at least one input is 1. NOT (x') simply flips: 0' = 1, 1' = 0.

XOR — Exclusive Or

XOR () is 1 exactly when its two inputs differ — true when exactly one input is 1, unlike plain OR which also accepts both.

xyx ⊕ y (XOR)
000
011
101
110
Why XOR gets its own chapter real estate
XOR isn't a minor variant of OR — it's the operator that makes binary addition without carry possible (1⊕1=0, exactly like adding two 1-bits and dropping the carry), which is precisely why Chapter 7's half adder is built directly from it.

NAND & NOR — Derived, and Surprisingly Powerful

NAND (NOT AND) and NOR (NOT OR) are simply AND/OR immediately followed by NOT:

xyNAND(x,y)NOR(x,y)
0011
0110
1010
1100

A Remarkable Verified Fact: NAND Alone Builds Everything

NAND is functionally complete — every other operator in this chapter, including NOT, AND, and OR themselves, can be built using only NAND, wired to itself and to its own inputs.

Verified directly, for every input combination
NOT(x) = NAND(x, x) — verified for both x=0 and x=1. AND(x,y) = NAND(NAND(x,y), NAND(x,y)) — verified for all 4 input pairs, matching real AND exactly. OR(x,y) = NAND(NOT(x), NOT(y)) — verified for all 4 input pairs, matching real OR exactly.
Why this isn't just a curiosity
This is exactly why real chip manufacturing leans so heavily on NAND gates: building one reliable gate design and wiring it in different patterns is far more practical at scale than fabricating several different gate types. Chapter 6 picks this fact up directly when building real circuits.

Real Relevance: Logical vs. Bitwise Operators — a Genuine Trap

Most languages give you two separate operator families for what looks like the same idea: logical operators (and/or/not in Python) working on whole truthy/falsy expressions with short-circuit evaluation, and bitwise operators (&/|/^/~) working on individual bits — this chapter's own AND/OR/NOT/XOR, applied per-bit to an entire number at once.

A real, verified bug: operator precedence
& binds tighter than comparison operators in Python — so temperature > 10 & temperature < 30 silently parses as temperature > (10 & temperature) < 30, not the intended range check. Verified directly: with temperature = 50 (clearly not between 10 and 30), the un-parenthesized version wrongly returns True, while (temperature > 10) & (temperature < 30) correctly returns False. Always parenthesize each side when mixing comparisons with bitwise operators.
A real, verified gotcha: ~True is not False
~True evaluates to -2, not False~ is bitwise complement, not logical negation, and applying it to a boolean silently promotes it to an integer first. This is a genuinely recognized trap: recent Python versions emit a DeprecationWarning specifically for ~ on a bare bool, confirming this is a known real-world footgun, not an edge case invented for this lesson. Use not x for logical negation, ~ only when you deliberately mean bitwise complement.

Operators in Code

def NAND(x, y): return 1 - (x & y) def NOT_from_nand(x): return NAND(x, x) def AND_from_nand(x, y): n = NAND(x, y) return NAND(n, n) def OR_from_nand(x, y): return NAND(NOT_from_nand(x), NOT_from_nand(y)) # verify every combination matches Python's own operators for x in (0, 1): for y in (0, 1): assert AND_from_nand(x, y) == (x & y) assert OR_from_nand(x, y) == (x | y) print("NAND builds AND and OR correctly for all inputs")

Hands-On Exercises

Exercise 1

Write out the full truth table for NOR(x,y) derived entirely from AND, OR, and NOT — that is, show (x + y)' matches the NOR truth table for all 4 input combinations.

📄 View solution
Exercise 2

Using this chapter's own NOT(x) = NAND(x,x) and OR(x,y) = NAND(NOT(x), NOT(y)) identities, trace through the computation of OR(0,1) step by step using only NAND operations, and confirm the final result is 1.

📄 View solution
Exercise 3

A piece of code checks if score > 90 & score < 100: in Python (using bitwise & instead of and). For score = 95, compute what this condition actually evaluates to (showing the precedence-driven parse), and explain why it happens to look correct here even though the operator choice is a real bug. Then show a specific score value where the bug produces a genuinely wrong result.

📄 View solution

Chapter 2 Quick Reference

  • AND (·): 1 only if both inputs are 1. OR (+): 1 if at least one input is 1. NOT ('): flips the value
  • XOR (⊕): 1 exactly when inputs differ — the basis of binary addition without carry (Chapter 7)
  • NAND/NOR: AND/OR immediately followed by NOT
  • NAND alone is functionally complete — verified to build NOT, AND, and OR for every input
  • Logical operators (and/or/not) and bitwise operators (&/|/^/~) are genuinely different — mixing them causes real, verified bugs (precedence, ~True)
  • Next chapter: The laws of Boolean algebra
Chapter 3 of 10

The Laws of Boolean Algebra

Boolean Algebra & Digital Logic

Chapter 3 · The Laws of Boolean Algebra

Chapter 1's own finding-box already showed three of these laws holding on a real permissions bitmask, without naming them formally. This chapter names every law properly, proves each one, and introduces the one proof method that's unique to Boolean algebra: since every variable only has two possible values, an identity in n variables can be proved completely just by checking all 2ⁿ input combinations — no infinite case to worry about, unlike ordinary algebra over the real numbers.

The Standard Laws

LawStatement
Commutativex+y = y+x, xy = yx
Associative(x+y)+z = x+(y+z), (xy)z = x(yz)
Distributivex(y+z) = xy+xz
Identityx+0 = x, x·1 = x
Dominationx+1 = 1, x·0 = 0
Complementx+x' = 1, x·x' = 0
Idempotentx+x = x, x·x = x
Absorptionx+(xy) = x, x(x+y) = x
Verified directly, exhaustively
Complement law, both values of x: x+x'=1 and x·x'=0 in both cases. Absorption law, all 4 combinations of x,y: x+(x·y) equals x in every single case.

A Genuinely Surprising Law: The Second Distributive Law

Ordinary arithmetic distributes multiplication over addition (x(y+z)=xy+xz) — but never the reverse; addition does not distribute over multiplication for real numbers. Boolean algebra is different: OR genuinely does distribute over AND, a law with no counterpart in ordinary arithmetic at all.

Verified directly, for all 8 combinations of x,y,z
x+(y·z) = (x+y)·(x+z) — checked exhaustively, every single one of the 8 possible (x,y,z) combinations matches on both sides.
Confirmed NOT to hold for ordinary numbers
Trying the same shape with real numbers, x=2, y=3, z=4: x+(y×z) = 2+12 = 14, but (x+y)×(x+z) = 5×6 = 30not equal. This law is a genuine property of the two-valued Boolean system, not a fact that happens to carry over from regular arithmetic just because the +/· notation looks the same.

De Morgan's Laws, Proved Algebraically

Discrete Mathematics Fundamentals introduced these as a logical equivalence between statements. Here they're the same two identities, proved the same exhaustive way as every other law in this chapter:

Verified directly, all 4 combinations each
(x+y)' = x'·y' — matches on every input pair. (x·y)' = x'+y' — matches on every input pair. Same theorem, same truth values, now derived as algebra rather than restated as a logic rule.

The Duality Principle

Notice the laws above come in matched pairs. That's not a coincidence: swap every + with ·, and every 0 with 1, and any true Boolean law becomes another true Boolean law — its dual. The two distributive laws are duals of each other; so are the two De Morgan's laws, the two identity laws, and the two domination laws. Once one half of a pair is proved, the other is guaranteed true for free.

Real Relevance: Negating Compound Conditions Correctly

De Morgan's Laws are the exact tool for correctly inverting a compound condition in real code — not (a and b) is not the same as (not a) and (not b), a mistake that's easy to make under pressure. The correct inversion, straight from this chapter's own proof, is (not a) or (not b). Chapter 5 builds on every law in this chapter directly to simplify tangled real conditions down to their shortest equivalent form.

Hands-On Exercises

Exercise 1

Using a full truth table (all 4 combinations of x,y), prove the commutative law for AND: xy = yx.

📄 View solution
Exercise 2

Using this chapter's own duality principle, state the dual of the identity law x·1 = x without checking a truth table first — then verify your answer is actually true for both values of x.

📄 View solution
Exercise 3

A piece of code needs to negate the condition is_admin or is_owner to correctly express "neither an admin nor the owner." Using De Morgan's Law from this chapter, write the correct negated form, and explain specifically what would go wrong if someone incorrectly wrote not is_admin or not is_owner instead.

📄 View solution

Chapter 3 Quick Reference

  • Every Boolean law can be completely proved by checking all 2ⁿ input combinations — a finite, exhaustive proof unique to two-valued algebra
  • Commutative, associative, distributive, identity, domination, complement, idempotent, absorption — the full standard law set, each verified exhaustively
  • The second distributive law (x+(yz)=(x+y)(x+z)) has no counterpart in ordinary arithmetic — confirmed to fail for real numbers
  • De Morgan's Laws, re-proved algebraically — same theorem as Discrete Mathematics Fundamentals Chapter 2, now derived rather than restated
  • Duality: swap +· and 01 in any true law to get another true law, for free
  • Next chapter: Boolean functions and canonical forms
Chapter 4 of 10

Boolean Functions & Canonical Forms

Boolean Algebra & Digital Logic

Chapter 4 · Boolean Functions & Canonical Forms

Chapters 2-3 gave the vocabulary and the laws. This chapter gives the actual, mechanical procedure: given any truth table at all, how do you write down a Boolean expression that produces it? The answer works for every possible function, every time, with no cleverness required.

How Many Boolean Functions Even Exist?

A Boolean function of n variables has 2ⁿ rows in its truth table, and each row's output can independently be 0 or 1 — so there are exactly 2^(2ⁿ) possible functions of n variables.

Verified directly
2 variables: 2^(2²) = 16 possible functions (AND, OR, XOR, NAND, NOR, XNOR, and 10 others, including the two constant functions "always 0" and "always 1"). 3 variables: 2^(2³) = 256 possible functions.

Minterms: A Building Block for Exactly One Row

A minterm is an AND of every variable (each either plain or complemented) that evaluates to 1 for exactly one input combination and 0 everywhere else. For two variables x,y, the minterm for the row x=1,y=0 is xy' — it's only 1 when x=1 and y=0.

Sum-of-Products: Reconstructing Any Truth Table

The mechanical procedure
For every row where the truth table's output is 1, write down that row's own minterm. OR all of them together. The result is guaranteed to reproduce the exact original truth table — this is the sum-of-products (SOP) form, and it works for any Boolean function, not just convenient ones.

Maxterms & Product-of-Sums: The Dual Construction

A maxterm is the dual idea — an OR of every variable that evaluates to 0 for exactly one input combination. Taking the maxterm for every row where the output is 0, and AND-ing them together, gives the product-of-sums (POS) form — the same truth table, built from the opposite direction.

A Real Worked Example: The Majority Function

majority(x,y,z) outputs 1 exactly when at least two of its three inputs are 1 — a genuinely useful function, not a toy: it's the core of triple modular redundancy (TMR), the real fault-tolerance technique used in spacecraft and other safety-critical computers, where three independent copies of a circuit vote and the majority result is trusted even if one copy has been corrupted (by a cosmic ray flipping a bit, for instance).

Verified directly — the full truth table
Output is 1 for exactly 4 rows: (0,1,1), (1,0,1), (1,1,0), (1,1,1). Output is 0 for the other 4: (0,0,0), (0,0,1), (0,1,0), (1,0,0).
Both forms verified directly, all 8 combinations
SOP: x'yz + xy'z + xyz' + xyz (one minterm per 1-row). POS: (x+y+z)(x+y+z')(x+y'+z)(x'+y+z) (one maxterm per 0-row). Both expressions were evaluated against the actual majority() function for all 8 input combinations — every single one matches, both forms and the original function agree perfectly.

Real Relevance: Specifying Business Logic From Test Cases

Anywhere requirements arrive as a table of "given these flags, the system should do X" — SOP construction turns that table directly into a correct, complete Boolean condition, mechanically, without needing to guess a clever simplified form first. Chapter 5 picks up immediately from here: an SOP expression built this way is always correct, but rarely the shortest way to say it — simplification is the next problem.

Canonical Forms in Code

def majority(x, y, z): return 1 if (x + y + z) >= 2 else 0 def sop(x, y, z): # x'yz + xy'z + xyz' + xyz -- one minterm per 1-row return ((1-x)&y&z) | (x&(1-y)&z) | (x&y&(1-z)) | (x&y&z) def pos(x, y, z): # (x+y+z)(x+y+z')(x+y'+z)(x'+y+z) -- one maxterm per 0-row return (x|y|z) & (x|y|(1-z)) & (x|(1-y)|z) & ((1-x)|y|z) from itertools import product assert all(majority(x,y,z) == sop(x,y,z) == pos(x,y,z) for x,y,z in product([0,1], repeat=3)) print("SOP and POS both exactly reproduce majority() for all 8 inputs")

Hands-On Exercises

Exercise 1

A 2-variable function f(x,y) is 1 only when x=0, y=1 or x=1, y=0 (this is XOR). Write out its SOP form using minterms, and verify it matches the actual XOR truth table for all 4 input combinations.

📄 View solution
Exercise 2

Using the same XOR function from Exercise 1, write out its POS form using maxterms (from the rows where the output is 0), and verify it also matches the actual XOR truth table for all 4 combinations.

📄 View solution
Exercise 3

A requirements table says a discount applies (output 1) only when is_member=1, is_holiday=0 or when is_member=0, is_holiday=1 — and never applies in any other combination of the two flags. Using this chapter's own SOP procedure, write the exact Boolean expression this requirements table describes, and name which well-known 2-input function it turns out to be.

📄 View solution

Chapter 4 Quick Reference

  • A function of n variables has exactly 2^(2ⁿ) possible truth tables — 16 for 2 variables, 256 for 3
  • Minterm: an AND term that's 1 for exactly one row. Maxterm: an OR term that's 0 for exactly one row
  • Sum-of-Products (SOP): OR together the minterms of every 1-row — reconstructs any truth table, mechanically
  • Product-of-Sums (POS): AND together the maxterms of every 0-row — the dual construction, same guarantee
  • Verified on a real, useful function (3-input majority, the core of triple modular redundancy) — both forms matched exactly
  • SOP built this way is always correct, but rarely shortest — Chapter 5 covers simplification
  • Next chapter: Simplifying Boolean expressions
Chapter 5 of 10

Simplifying Boolean Expressions

Boolean Algebra & Digital Logic

Chapter 5 · Simplifying Boolean Expressions

Chapter 4 closed with an honest admission: the SOP form it built is always correct, but almost never the shortest way to say the same thing. This chapter delivers two genuinely different tools for shrinking an expression down — algebraic simplification using Chapter 3's own laws, and Karnaugh maps, a visual method that finds the same simplification by spotting patterns instead of manipulating symbols.

Algebraic Simplification: Shrinking Chapter 4's Own Majority Function

Chapter 4's SOP form for the majority function was x'yz + xy'z + xyz' + xyz — 4 terms, 12 literals total. Simplifying it directly:

Step by step, using only Chapter 3's own laws
The idempotent law (A=A+A) allows duplicating the shared xyz term twice, giving x'yz + xy'z + xyz' + xyz + xyz + xyz — still exactly equal to the original, just written with two extra (redundant) copies. Regrouping: (x'yz+xyz) + (xy'z+xyz) + (xyz'+xyz). Factoring each pair (distributive law): yz(x'+x) + xz(y'+y) + xy(z'+z). Applying the complement law (x'+x=1) to each: yz(1) + xz(1) + xy(1). Applying the identity law (x·1=x): yz + xz + xy.
Verified directly against the original function
xy + xz + yz matches majority(x,y,z) exactly, for all 8 input combinations — down from 4 terms / 12 literals to 3 terms / 6 literals, exactly half the size, with zero loss of correctness.

Karnaugh Maps: The Same Simplification, Found Visually

A Karnaugh map (K-map) arranges a truth table in a grid where adjacent cells always differ in exactly one variable — achieved by ordering the column headers in Gray code (00, 01, 11, 10, not the "obvious" 00, 01, 10, 11) so a single-bit change always corresponds to a single step across the grid.

x \ yz00011110
00010
10111
Reading the map: group adjacent 1s in powers of 2
Circling a pair of horizontally- or vertically-adjacent 1-cells eliminates whichever variable changes between them, leaving only the variables that stay fixed across the group. Groups may overlap freely.
Verified directly — the same three groups the algebra found
Cells (x=1,yz=01) and (x=1,yz=11) are adjacent (only y changes) → group gives xz. Cells (x=1,yz=11) and (x=1,yz=10) are adjacent (only z changes) → group gives xy. Cells (x=0,yz=11) and (x=1,yz=11) are adjacent (only x changes) → group gives yz. Together: xz + xy + yzthe exact same result the algebraic method reached, found by pattern-spotting instead of symbol manipulation.

A Second, Simpler Example

A 2-variable function: f(x,y) = xy + xy'.

Verified directly
Algebraically: xy + xy' = x(y+y') = x(1) = x — an entire variable, y, disappears completely. Checked for all 4 inputs: f(x,y) equals plain x in every case. On a K-map, this is exactly a group spanning an entire row — the widest possible group, eliminating the one variable that changes across the whole row.

Real Relevance

Chapter 4's requirements-table-to-SOP procedure is guaranteed correct but routinely produces expressions far longer than necessary — exactly what happened with the majority function's own 12-literal starting point. Whether reached algebraically or visually, a simplified expression means fewer conditions to read in code, and — critically for Chapter 6 onward — fewer physical logic gates to build the same circuit from.

Hands-On Exercises

Exercise 1

Simplify f(x,y) = xy + x'y algebraically, using Chapter 3's own laws, showing each step. Verify your simplified result against the original for all 4 input combinations.

📄 View solution
Exercise 2

Draw the K-map for the function f(x,y) = xy + x'y from Exercise 1 (a 2×2 grid, rows x=0/1, columns y=0/1), identify the group of adjacent 1s, and confirm it produces the same simplified expression you found algebraically.

📄 View solution
Exercise 3

A colleague simplifies xy + xz + yz (this chapter's own majority-function result) down to just xy + xz, claiming the yz term is redundant. Determine whether they're correct by checking all 8 input combinations, and explain your conclusion.

📄 View solution

Chapter 5 Quick Reference

  • Algebraic simplification: apply Chapter 3's own laws (idempotent to duplicate a shared term, distributive to factor, complement + identity to collapse) directly to an SOP expression
  • Chapter 4's majority function shrank from 4 terms/12 literals to 3 terms/6 literals — verified against the original for all 8 inputs
  • Karnaugh map: a grid with Gray-code-ordered headers so adjacent cells differ in exactly one variable; group adjacent 1s to eliminate the variable that changes across the group
  • Both methods, applied to the same function, land on the exact same simplified result — verified directly
  • A group spanning an entire row/column eliminates a whole variable (Exercise-worthy 2-variable example: xy+xy'=x)
  • Next chapter: Logic gates and combinational circuits
Chapter 6 of 10

Logic Gates & Combinational Circuits

Boolean Algebra & Digital Logic

Chapter 6 · Logic Gates & Combinational Circuits

Everything so far has been symbols on a page. This chapter makes it physical: a logic gate is a real electronic component that takes voltage levels standing in for 0 and 1, and produces an output voltage exactly matching one of Chapter 2's own truth tables. Wire gates together, and Chapter 5's simplified expressions become an actual working circuit.

Combinational Circuits: Output Depends Only on Right-Now Inputs

A combinational circuit is built purely from gates with no memory anywhere in it — its output at any instant depends only on its current inputs, never on what happened before. Every circuit in this chapter is combinational. Chapter 8 introduces the genuinely different case — circuits that do remember something — which is a different kind of building block entirely, not just "combinational logic with extra wires."

Building Chapter 5's Own Simplified Circuit

Chapter 5 simplified the majority function down to xy + xz + yz. Wired directly into gates, using only 2-input AND and OR gates:

x, y ──[AND]── A1 ──┐ ├──[OR]── O1 ──┐ x, z ──[AND]── A2 ──┘ ├──[OR]── majority │ y, z ──[AND]── A3 ───────────────────┘
Traced and verified directly — x=1, y=1, z=0
A1 = AND(x=1, y=1) = 1. A2 = AND(x=1, z=0) = 0. A3 = AND(y=1, z=0) = 0. O1 = OR(A1=1, A2=0) = 1. Output = OR(O1=1, A3=0) = 1. Matches majority(1,1,0) = 1 exactly — and the full circuit was verified against majority() for all 8 possible inputs, not just this one trace.

Why Chapter 5's Simplification Mattered Physically

Chapter 4's own unsimplified SOP form (x'yz + xy'z + xyz' + xyz) needs real gates too — and Chapter 5's simplification isn't just a shorter formula, it's a genuinely smaller, cheaper, faster circuit.

VersionNOT gatesAND gatesOR gatesTotal
Chapter 4's unsimplified SOP34 (3-input each)3 (chained 2-input)10
Chapter 5's simplified form03 (2-input each)2 (chained 2-input)5
This is Algorithms & Complexity's own lesson, in hardware
Fewer gates means less silicon area, less power draw, and — critically — less propagation delay: every gate a signal passes through takes real physical time, so a circuit with fewer gates in its longest signal path is a genuinely faster circuit, the exact same "fewer operations, less time" reasoning Algorithms & Complexity applied to code, now applied to voltage instead of instructions.

Real Relevance

This is literally what happens inside an FPGA or ASIC design flow: a Boolean expression gets simplified, then mapped onto real gates, then measured by exactly the gate-count and propagation-delay metrics above. Chapter 2's own NAND-completeness proof is why many real fabrication processes build every gate type shown here — AND, OR, NOT included — out of nothing but wired-together NAND gates, for manufacturing consistency.

Gate Simulation in Code

def AND(a, b): return a & b def OR(a, b): return a | b def majority_circuit(x, y, z): a1 = AND(x, y) a2 = AND(x, z) a3 = AND(y, z) o1 = OR(a1, a2) return OR(o1, a3) def majority(x, y, z): return 1 if (x + y + z) >= 2 else 0 from itertools import product assert all(majority_circuit(x,y,z) == majority(x,y,z) for x,y,z in product([0,1], repeat=3)) print("5-gate circuit exactly matches majority() for all 8 inputs")

Hands-On Exercises

Exercise 1

Using this chapter's own majority circuit, trace the signal through every gate for x=0, y=1, z=1, showing each gate's output, and confirm the final result matches majority(0,1,1).

📄 View solution
Exercise 2

Chapter 5's Exercise 1 simplified xy + x'y down to just y. Draw (describe in words, gate by gate) the circuit for the unsimplified form xy + x'y, count its gates (including any NOT gates needed), and compare that count to the simplified circuit, which needs zero gates at all since the output is just y directly.

📄 View solution
Exercise 3

Explain, using this chapter's own combinational-circuit definition, why a circuit that computes output = A AND (output from one clock cycle ago) could not be a combinational circuit, even though it's built entirely from an AND gate.

📄 View solution

Chapter 6 Quick Reference

  • Logic gate: a physical component realizing one of Chapter 2's own truth tables in real voltage levels
  • Combinational circuit: output depends only on current inputs — no memory anywhere (contrast: Chapter 8's sequential logic)
  • Chapter 5's simplified majority circuit (xy+xz+yz) traced and verified directly, gate by gate, for all 8 inputs
  • Simplification's real payoff: 10 gates down to 5, zero NOT gates needed — smaller, cheaper, and faster (less propagation delay)
  • Fewer gates in a circuit is the exact same "fewer operations, less time" idea as Algorithms & Complexity, applied to hardware instead of code
  • Next chapter: Building blocks — adders, multiplexers, and decoders
Chapter 7 of 10

Building Blocks: Adders, Multiplexers & Decoders

Boolean Algebra & Digital Logic

Chapter 7 · Building Blocks: Adders, Multiplexers & Decoders

Chapter 6 built one specific circuit. This chapter builds three genuinely reusable ones — standard components wired into essentially every real digital system, including the exact logic a CPU uses to add numbers.

The Half Adder: Chapter 2's XOR Promise, Delivered

Chapter 2 called XOR "the basis of binary addition without carry." A half adder adds two single bits and produces exactly that: a SUM bit and a CARRY bit.

The circuit
SUM = x ⊕ y. CARRY = x · y. Two gates, total.
Verified directly against real binary addition
1+1=2, i.e. binary 10: SUM=0, CARRY=1 — matches. 0+1=1, binary 01: SUM=1, CARRY=0 — matches. Every one of the 4 input combinations produces the exact CS (carry, sum) digits of the real binary sum.

The Full Adder — and a Genuine Reuse of Chapters 4-6

A half adder can't be chained — real multi-bit addition needs each column to also accept a carry in from the column before it. A full adder takes three inputs (x, y, cin) and produces SUM and COUT: SUM = x ⊕ y ⊕ cin, COUT = xy + cin(x⊕y).

A genuine finding, verified directly: COUT is exactly the majority function
Checked for all 8 input combinations of (x,y,cin): COUT equals 1 in precisely the same cases as majority(x,y,cin) — because a carry genuinely does occur exactly when at least two of the three bits being added are 1. This isn't a coincidence worth noting in passing: the full adder's carry-out logic is Chapter 5-6's own simplified xy+xz+yz circuit, with the variables simply renamed. The exact 5-gate circuit already built and traced in Chapter 6 is a real full adder's carry logic, reused wholesale.

Chaining Full Adders: A Real Multi-Bit Adder

Wire the COUT of one full adder into the cin of the next, and multi-bit numbers add correctly, column by column, exactly like doing long addition by hand — this is a real ripple-carry adder, and it's genuinely how simple ALU addition works.

Verified directly — a 2-bit ripple-carry adder
11₂ + 10₂ (3+2): first stage adds the low bits with cin=0, its carry feeds the second stage — result 101₂ (5). 10₂ + 10₂ (2+2): result 100₂ (4). 01₂ + 01₂ (1+1): result 010₂ (2). All three verified correct against real binary addition.

Multiplexers: A Selectable Wire

A multiplexer (MUX) routes exactly one of several data inputs through to a single output, chosen by a separate select input. A 2-to-1 MUX: output = sel'·in0 + sel·in1.

Verified directly, all 8 combinations
With sel=0, the output always exactly matches in0, regardless of in1. With sel=1, the output always exactly matches in1, regardless of in0 — confirmed for every combination.

Decoders: Physically Wired Minterms

A decoder takes n select inputs and activates exactly one of 2ⁿ output lines. A 2-to-4 decoder's four outputs are literally Chapter 4's own four possible 2-variable minterms — a'b', a'b, ab', ab — each wired to its own physical output line.

Verified directly — the outputs correspond exactly to the binary input value
ab=00 activates D0. ab=01 activates D1. ab=10 activates D2. ab=11 activates D3 — the active output number always equals the binary value of the select inputs, confirmed for all 4 combinations.

Real Relevance

Ripple-carry addition is the literal mechanism behind a CPU's own integer addition (real ALUs use faster carry-lookahead variants at scale, but the correctness principle is identical). Multiplexers select which data path is active on every clock cycle inside a real processor. Decoders turn a binary address into "activate exactly this one memory location" — the basic mechanism behind RAM addressing itself.

Building Blocks in Code

def half_adder(x, y): return x ^ y, x & y # sum, carry def full_adder(x, y, cin): s = x ^ y ^ cin cout = (x & y) | (cin & (x ^ y)) # == majority(x,y,cin) return s, cout def add_2bit(a1, a0, b1, b0): s0, c0 = full_adder(a0, b0, 0) s1, c1 = full_adder(a1, b1, c0) # carry ripples in return c1, s1, s0 print(add_2bit(1,1,1,0)) # (1, 0, 1) -- 3+2=5, binary 101 def mux2(sel, in0, in1): return ((1-sel) & in0) | (sel & in1) def decoder_2to4(a, b): return ((1-a)&(1-b), (1-a)&b, a&(1-b), a&b)

Hands-On Exercises

Exercise 1

Using this chapter's own full adder, add the 2-bit binary numbers 10 and 11 (decimal 2 and 3) via a ripple-carry chain, showing each full adder's inputs and outputs, and confirm the result equals 101 (decimal 5).

📄 View solution
Exercise 2

Using this chapter's own MUX formula (sel'·in0 + sel·in1), trace the output for sel=1, in0=1, in1=0, and explain in one sentence why the value of in0 doesn't matter at all once sel=1 is fixed.

📄 View solution
Exercise 3

Explain, using this chapter's own finding about the full adder's carry-out logic, why a chip designer who already has a working, well-tested majority-function circuit could reuse it directly as the carry-out logic of a full adder — without redesigning anything from scratch.

📄 View solution

Chapter 7 Quick Reference

  • Half adder: SUM=x⊕y, CARRY=xy — exactly Chapter 2's own XOR promise, delivered
  • Full adder: adds x, y, cin; SUM=x⊕y⊕cin, COUT=majority(x,y,cin) — a genuine, verified reuse of Chapters 4-6's own circuit
  • Ripple-carry adder: chain full adders, COUT of one feeds cin of the next — verified on real 2-bit binary addition
  • Multiplexer: routes exactly one of several inputs to the output based on a select line
  • Decoder: activates exactly one of 2ⁿ outputs — physically wires Chapter 4's own minterms, one per output line
  • Next chapter: Sequential logic — latches, flip-flops, and memory
Chapter 8 of 10

Sequential Logic: Latches, Flip-Flops & Memory

Boolean Algebra & Digital Logic

Chapter 8 · Sequential Logic: Latches, Flip-Flops & Memory

Chapter 6 defined a combinational circuit as one whose output depends only on its current inputs, and named this chapter as the exception. The mechanism behind that exception is simple to state and genuinely powerful: wire a gate's output back into its own input, and the circuit's behavior starts depending on its own history — which is exactly what memory is.

The SR Latch: Two Gates, Wired to Remember

The simplest memory element is two NOR gates, cross-coupled — each gate's output feeds into the other gate's input. It has two inputs, S (set) and R (reset), and two outputs, Q and its complement Q'.

The feedback equations
Q = NOR(R, Q'), Q' = NOR(S, Q) — each output depends on the other gate's own current output, not just on S and R directly.
Verified directly — real memory, across a real time sequence
Starting at Q=0: S=1,R=0 (SET) → Q=1. Then S=0,R=0 (HOLD) → Q stays 1. Another S=0,R=0 → still 1. Then S=0,R=1 (RESET) → Q=0. Then two more S=0,R=0 steps → Q stays 0 both times. The exact same inputs (S=0,R=0) produced different Q values depending on what happened earlier — precisely the history-dependence that disqualifies this circuit from being combinational, now demonstrated with a real simulated gate network rather than asserted.

The Forbidden State

A real, verified limitation — not a simplification
S=1, R=1 simultaneously drives both Q and Q' toward 0 — verified directly: both outputs land on 0, breaking the invariant that Q and Q' must always be complements of each other. Real SR latches genuinely forbid this input combination; it's not a corner case this chapter is glossing over, it's a real constraint every actual circuit using an SR latch has to respect.

The D Latch: A Structural Fix

A D latch adds a data input D and an enable line, deriving S and R automatically: S = D · enable, R = D' · enable.

Verified directly — the forbidden state becomes structurally impossible
Checked for all 4 combinations of D and enable: S and R are never both 1 at the same time — because D and D' can never both be 1, whatever gets AND-ed with enable inherits that same guarantee. The forbidden state isn't avoided by careful usage; it's ruled out by the wiring itself.

Level-Triggered vs. Edge-Triggered: Why Flip-Flops Exist

A D latch is level-triggered — while enable stays high, Q tracks D continuously, which can cause real problems when latches are chained (a change can "race" through several stages within a single enable pulse). A D flip-flop is edge-triggered — it only updates at the exact instant a clock signal transitions (e.g. low-to-high), holding steady the rest of the time. This is the real building block used in registers, counters, and pipeline stages, specifically because it makes multi-stage timing predictable.

Real Relevance: This Is What a Variable Actually Is

A CPU register, one bit of RAM, or the value behind an ordinary variable in running code — all the way down at the hardware level — genuinely is one of these feedback circuits. There's no separate "memory technology" beyond this trick, repeated billions of times: writing a variable sets a flip-flop; reading it later returns whatever that flip-flop has been holding since.

Sequential Logic in Code

def NOR(a, b): return 1 - (a | b) def sr_latch_step(S, R, Q, Qn): # iterate the feedback loop until it settles for _ in range(10): new_Q = NOR(R, Qn) new_Qn = NOR(S, Q) if new_Q == Q and new_Qn == Qn: break Q, Qn = new_Q, new_Qn return Q, Qn Q, Qn = 0, 1 for S, R in [(1,0), (0,0), (0,0), (0,1), (0,0)]: Q, Qn = sr_latch_step(S, R, Q, Qn) print(f"S={S},R={R}: Q={Q}") # Q holds its value through every (0,0) step

Hands-On Exercises

Exercise 1

Starting from Q=1, Q'=0, trace this chapter's own SR latch through the sequence (S=0,R=1), (S=0,R=0), (S=0,R=0), (S=1,R=0), showing Q after each step, and confirm Q genuinely holds its value during both (0,0) steps.

📄 View solution
Exercise 2

Using this chapter's own D latch equations (S=D·enable, R=D'·enable), compute S and R for D=1, enable=0, and explain what this means for Q — does the latch update, or hold its previous value? Connect your answer to what "enable" is actually doing.

📄 View solution
Exercise 3

A colleague argues "a D latch can never reach the SR latch's forbidden state, so it must be strictly better and the plain SR latch is obsolete." Using this chapter's own material, explain what's wrong with dismissing the SR latch entirely — specifically, is the SR latch's own S/R behavior ever still useful on its own terms, separate from the forbidden-state issue?

📄 View solution

Chapter 8 Quick Reference

  • Feedback (a gate's output wired back into its own input) is the mechanism that breaks Chapter 6's own combinational definition and creates memory
  • SR latch: cross-coupled NOR gates — verified directly to genuinely hold its value across identical S=0,R=0 inputs, depending on prior history
  • Forbidden state: S=1,R=1 breaks the Q/Q' complement invariant — verified directly, a real constraint
  • D latch: derives S/R from D and enable so the forbidden state becomes structurally impossible — verified across all 4 combinations
  • D flip-flop: edge-triggered, not level-triggered — the real building block for registers and multi-stage timing
  • A variable's stored value, all the way down, genuinely is one of these feedback circuits
  • Next chapter: Binary, hexadecimal, and number representation
Chapter 9 of 10

Binary, Hexadecimal & Number Representation

Boolean Algebra & Digital Logic

Chapter 9 · Binary, Hexadecimal & Number Representation

Every chapter so far has quietly assumed numbers arrive as bits. This chapter asks the question directly — and answers a mystery Chapter 2 left open along the way: why ~True really does equal -2, not by accident, but by design.

Binary and Hexadecimal: The Same Number, Two Notations

Binary is positional notation base 2. Hexadecimal (base 16) exists because it aligns perfectly with binary in a way decimal never can: each hex digit represents exactly 4 bits, with no remainder.

Verified directly
173 in binary: 10101101. Split into 4-bit groups: 1010 and 1101 — decimal 10 and 13, i.e. hex A and D. Result: 0xAD, confirmed to equal 173 exactly.

Two's Complement: How Negative Numbers Actually Work

A naive "sign bit" scheme (flip the top bit to mean negative) has two real problems: it creates two representations of zero (+0 and -0), and ordinary addition breaks unless the hardware special-cases signs. Two's complement avoids both: to negate a number, invert every bit, then add 1.

Verified directly — 4-bit two's complement encodings
+3 = 0011. Inverting gives 1100; adding 1 gives 1101 — the encoding of -3. +5 → -5 = 1011. There's exactly one encoding of zero (0000), and the 4-bit range is -8 to 7 — deliberately asymmetric, one more negative value than positive, since 0 itself uses up one of the 16 available patterns on the positive side.

The Real Payoff: Chapter 7's Own Adder Needs No Changes at All

This is the entire reason two's complement is universal: a ripple-carry adder built with zero awareness of signs correctly computes negative results, purely because of how the bit patterns are chosen.

Verified directly, using Chapter 7's own unmodified 4-bit adder
Adding 0011 (+3) and 1101 (-3) through the exact same full-adder chain from Chapter 7: result bits 0000, with a discarded final carry-out of 1zero, exactly correct. Adding 0101 (+5) and 1011 (-5): same result, 0000. No special subtraction circuit, no sign-checking logic — the identical hardware from Chapter 7 handles both positive and negative numbers correctly, simply because the encoding was chosen to make that true.

Closing the Loop: Why ~True Really Is -2

Chapter 2 flagged ~True == -2 as a real, verified gotcha without explaining why. In two's complement, bitwise complement and negation are related by a clean identity:

Verified directly — the identity, and Chapter 2's own mystery resolved
~x = -x - 1, for every value checked: ~5=-6 (-5-1=-6), ~10=-11, ~100=-101, all matching exactly. Applied to Chapter 2's own case: True acts as 1, so ~True = -1-1 = -2 — not a quirk of Python's own boolean handling, but two's complement working exactly as designed, on a value that happened to be a boolean.

Arithmetic vs. Logical Right Shift

Right-shifting a negative number needs to decide what to fill the vacated high bits with. Python's >> is an arithmetic shift — it fills with the sign bit, preserving negativity and behaving like floor division by 2.

Verified directly
-8 >> 1 = -4. -7 >> 1 = -4 (floor of -3.5). -1 >> 1 = -1 — stays negative forever under repeated arithmetic shifting, never reaching 0 the way a logical (zero-filling) shift would. Some languages (Java's >>>, for instance) offer a separate logical shift operator specifically because arithmetic and logical shifts genuinely disagree on negative inputs.

Real Relevance

Bitwise operators (&, |, ^, ~, <<, >>) operate directly on these representations — Chapter 2's own flags/bitmasks are binary representation in action, and every value stored anywhere in a running program is, physically, one of the encodings this chapter just formalized.

Number Representation in Code

def to_twos_complement(x, bits): if x < 0: x = (1 << bits) + x return format(x, f"0{bits}b") print(to_twos_complement(-3, 4)) # '1101' # the ~x = -x-1 identity, verified generally for x in [5, 10, 100]: assert ~x == -x - 1 print("~x == -x-1 confirmed")

Hands-On Exercises

Exercise 1

Convert 202 to binary, then group it into 4-bit nibbles and convert each nibble to hexadecimal, confirming your hex result equals 202 when checked directly.

📄 View solution
Exercise 2

Encode +6 and -6 in 4-bit two's complement (showing the invert-then-add-1 process for the negative value), then add the two 4-bit patterns using Chapter 7's own full-adder chain, showing each stage's SUM and COUT, and confirm the result is 0000 with the carry-out discarded.

📄 View solution
Exercise 3

Using this chapter's own ~x = -x-1 identity, predict the value of ~(-5) without computing it directly first, then verify your prediction. Explain in one sentence why applying ~ twice in a row (~~x) always returns the original value x.

📄 View solution

Chapter 9 Quick Reference

  • Hex aligns exactly with binary — each hex digit is 4 bits, no remainder
  • Two's complement: invert all bits, add 1 — fixes sign-magnitude's double-zero and broken-addition problems
  • 4-bit range is -8 to 7 — deliberately asymmetric, exactly one representation of zero
  • Verified directly: Chapter 7's own unmodified adder correctly computes +x + (-x) = 0 — no special subtraction circuitry needed
  • Closed the loop on Chapter 2: ~x = -x-1~True=-2 was two's complement working exactly as designed
  • Arithmetic right shift sign-extends negative numbers; logical shift zero-fills — genuinely different results, real cross-language relevance
  • Next chapter: Capstone — designing a small digital circuit
Chapter 10 of 10

Capstone — Designing a Small Digital Circuit

Boolean Algebra & Digital Logic

Chapter 10 · Capstone — Designing a Small Digital Circuit

One continuous project: a real 3-bit adder/subtractor with overflow detection — the exact same technique a genuine ALU uses to compute both A+B and A-B from a single piece of hardware, touching every chapter of this course in the order a real designer would actually reach for each idea.

StepTaskChapter(s) used
1The core trick: one mode signal, reusing addition to do subtractionCh.9 (two's complement)
2Wire the mode-select logicCh.1-3 (operators, laws), Ch.6 (gates)
3Build the full 3-bit circuitCh.7 (full adders, chained)
4Trace and verify four real casesCh.7, Ch.9
5Derive overflow detection from first principlesCh.4 (canonical form), Ch.5 (simplification)
6Full gate-count accountingCh.6

Step 1 — The Core Trick

Ch.9

Chapter 9 proved that negating a number in two's complement is "invert every bit, then add 1." A single mode signal M can trigger exactly that, on demand: XOR every bit of B with M (inverting B when M=1, leaving it unchanged when M=0), and feed M itself in as the initial carry-in (supplying the "+1"). When M=0: ordinary addition, A+B. When M=1: A + B' + 1 = A + (-B) = A - B.

Step 2 — Wiring the Mode-Select Logic

Ch.1-3, Ch.6

Three XOR gates (one per bit of B), each with M as one input — the smallest possible piece of combinational logic (Chapter 6) doing real, load-bearing work.

Step 3 — The Full 3-Bit Circuit

Ch.7

Three full adders, chained exactly as in Chapter 7's own ripple-carry adder — LSB first, each stage's COUT feeding the next stage's cin — except the chain's very first cin is M instead of a hardwired 0, and each adder's own B input is the XOR-modified bit from Step 2, not the raw bit.

Step 4 — Four Real Cases, Fully Traced

Verified directly — 2 + 1, M=0 (addition)
LSB: full_adder(0,1,cin=0) → SUM=1, COUT=0. Middle: full_adder(1,0,cin=0) → SUM=1, COUT=0. Sign/MSB: full_adder(0,0,cin=0) → SUM=0, COUT=0. Result: 3. Correct.
Verified directly — 3 − 1, M=1 (subtraction)
B XOR M flips 1 (001) to 110. LSB: full_adder(1,0,cin=1) → SUM=0, COUT=1. Middle: full_adder(1,1,cin=1) → SUM=1, COUT=1. Sign/MSB: full_adder(0,1,cin=1) → SUM=0, COUT=1. Result: 2. Correct.
Verified directly — 1 − 3, M=1 (a genuine negative result)
LSB: SUM=0, COUT=1. Middle: SUM=1, COUT=0. Sign/MSB: SUM=1, COUT=0. Result bits 110, decoded as two's complement: −2. Correct — the exact same unmodified circuitry handles a negative result with no special case.
Verified directly — 2 + 2, M=0: a genuine, caught overflow
LSB: SUM=0, COUT=0. Middle: SUM=0, COUT=1. Sign/MSB: SUM=1, COUT=0. Raw result bits 100 decode as −42+2 is not −4. This is a genuine overflow: 4 falls outside the 3-bit signed range (−4 to 3, per Chapter 9). The circuit doesn't know this on its own — Step 5 builds the logic that catches it.

Step 5 — Deriving Overflow Detection From First Principles

Ch.4, Ch.5

Overflow happens exactly when the carry into the sign bit's own full adder disagrees with the carry out of it — one more bit "wanted" to flow in than the sign position can correctly represent. Both signals already exist as real wires in the circuit built in Step 3, so this is genuinely just overflow = carry_in_sign ⊕ carry_out_sign — a single XOR gate, no new adder logic required.

Verified directly against all four cases above
2+1: carry-in-to-sign 0, carry-out-of-sign 0 → overflow 0. 3−1: 1 and 1 → overflow 0. 1−3: 0 and 0 → overflow 0. 2+2: 1 and 0 → overflow 1 — the exact case flagged as suspicious above, now caught mechanically rather than by manual inspection.

Step 6 — Full Gate-Count Accounting

Ch.6

Each full adder needs 2 XOR + 2 AND + 1 OR gates (5 total, per Chapter 7's own SUM=x⊕y⊕cin, COUT=xy+cin(x⊕y) formulas, reusing the shared x⊕y signal). Three full adders: 15 gates. Three mode-select XOR gates: 3 gates. One overflow XOR gate: 1 gate.

Total: 19 gates
A complete, working 3-bit adder and subtractor and overflow detector — sharing almost every piece of hardware between the add and subtract cases, exactly the efficiency argument Chapter 6 made about simplification paying off physically, now demonstrated at the level of a genuinely useful circuit rather than a single function.

What This Course Doesn't Cover

As stated honestly back in Chapter 1: full computer architecture/CPU design, VLSI/physical circuit engineering, and formal HDL tooling were named as deliberately out of scope, and stayed out of scope through all ten chapters. This capstone's own adder/subtractor is a genuine, real ALU building block — but a real ALU is many such blocks, plus instruction decoding, registers, and control logic this course never claimed to cover.

Where This Course Connects

Algorithms & Complexity's own "fewer operations, less time" reasoning reappeared directly in Chapter 6's gate-count argument, now paying off again in this capstone's own 19-gate, three-function circuit. Discrete Mathematics Fundamentals' own propositional logic was this course's own starting point (Chapter 1), and its proof-technique toolkit underwrote Chapter 3's own exhaustive law proofs. Number Theory & Cryptographic Math's own binary/modular reasoning and this course's Chapter 9 cover genuinely adjacent ground — worth revisiting side by side.

Hands-On Exercises

Exercise 1

Using this chapter's own circuit, trace −1 + 1 (M=0) through all three full-adder stages, showing each stage's SUM and COUT, and confirm the result is 0 with no overflow.

📄 View solution
Exercise 2

Using this chapter's own overflow formula, check whether −3 − 2 (M=1) overflows the 3-bit signed range. Trace the circuit fully, compute the carry-into-sign and carry-out-of-sign values, and state whether the result is trustworthy.

📄 View solution
Exercise 3

Explain, using this chapter's own gate-count accounting, why building two separate circuits — one dedicated adder and one dedicated subtractor — would very likely need more than 19 gates combined, even though each one individually might look simpler than the combined adder/subtractor.

📄 View solution

Chapter 10 Quick Reference

  • Full worked project: two's-complement negation via XOR+carry-in (Ch.9) → mode-select gates (Ch.1-3,6) → chained full adders (Ch.7) → four fully traced/verified cases including a caught overflow → overflow formula derived from first principles (Ch.4-5) → full gate count (Ch.6)
  • The exact same unmodified circuitry correctly handles addition, subtraction, and negative results — verified directly, no special-casing anywhere
  • Overflow = carry-into-sign XOR carry-out-of-sign — one extra gate, reusing wires the circuit already has
  • 19 gates total: a real adder, subtractor, and overflow detector, sharing nearly all their hardware
  • Out of scope: full CPU/ALU design, VLSI engineering, HDL tooling
  • Course complete — Boolean Algebra & Digital Logic, 10 chapters, from truth tables to a working adder/subtractor