C programming
algorithms
probability
biased coin
fair coin

C puzzle Make a fair coin from a biased coin

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The classic puzzle asks how to generate fair coin flips from a biased coin with unknown bias p (where 0 < p < 1). The standard solution is the Von Neumann extractor. It uses pairs of biased flips and only accepts mismatched outcomes. This produces unbiased results without knowing p.

The key idea is symmetry: probability of HT equals probability of TH, even if the coin is biased.

Core Sections

1. Von Neumann method

Procedure:

  1. Flip twice.
  2. If outcomes are HT, return heads.
  3. If outcomes are TH, return tails.
  4. If HH or TT, discard and retry.

Why it works:

  • P(HT) = p(1-p)
  • P(TH) = (1-p)p
  • therefore equal probabilities for accepted outcomes

2. C implementation

c
1#include <stdio.h>
2#include <stdlib.h>
3#include <time.h>
4
5// Placeholder biased coin: returns 1 with probability about 0.7
6int biased_flip(void) {
7    return (rand() % 10) < 7;
8}
9
10int fair_flip(void) {
11    while (1) {
12        int a = biased_flip();
13        int b = biased_flip();
14
15        if (a == 1 && b == 0) return 1; // HT
16        if (a == 0 && b == 1) return 0; // TH
17        // HH or TT -> retry
18    }
19}
20
21int main(void) {
22    srand((unsigned)time(NULL));
23
24    int heads = 0, tails = 0;
25    for (int i = 0; i < 100000; i++) {
26        int x = fair_flip();
27        if (x) heads++; else tails++;
28    }
29
30    printf("heads=%d tails=%d\n", heads, tails);
31    return 0;
32}

3. Efficiency implications

Expected retries depend on bias. Acceptance probability is 2p(1-p), highest at p=0.5 and worst near extremes. If coin is very biased, many pairs are discarded.

4. Testing fairness empirically

Run large simulations and check convergence of heads/tails ratio toward 1:1. Use statistical tests if high confidence is required.

5. Practical constraints

Assumes independent identically distributed flips. If bias changes over time or flips are correlated, fairness guarantee breaks.

Common Pitfalls

  • Mapping HH to heads and TT to tails, which preserves bias.
  • Assuming method still works if successive flips are dependent.
  • Using too few samples and concluding result is biased.
  • Implementing biased source incorrectly and testing wrong property.
  • Ignoring performance degradation when source bias is extreme.

Summary

You can derive a fair coin from an unknown biased coin using the Von Neumann extractor. By discarding matching pairs and mapping HT and TH oppositely, accepted outcomes become unbiased. The approach is simple, mathematically sound, and easy to implement in C. Its main tradeoff is efficiency, especially for strongly biased sources.

A practical way to keep this guidance useful in real projects is to convert it into an executable runbook rather than leaving it as one-time reading. A strong runbook lists exact prerequisites, expected versions, environment assumptions, and a short sequence of checks that confirm healthy behavior. It also records the first one or two failure signatures engineers are most likely to see and maps each signature to the next diagnostic step. This structure reduces ambiguity when incidents happen under time pressure and helps new contributors act with the same consistency as experienced maintainers.

It also helps to keep one minimal reproducible fixture in version control for this exact scenario. The fixture can be a tiny script, API call, YAML manifest, query, or test harness that demonstrates both expected success and a known failure mode. When dependencies, frameworks, or infrastructure versions change, that fixture becomes an early warning system for regressions. Instead of discovering breakage deep in production workflows, teams can run a focused check in minutes and isolate whether the problem is environmental drift, configuration mismatch, or logic change.

For long-term reliability, add one lightweight automated guardrail to CI that targets the most fragile point in the workflow. Good candidates include schema validation, deterministic unit tests, protocol compatibility checks, API contract tests, and startup smoke tests. Keep the guardrail narrow and fast so it runs on every change and produces actionable output when it fails. If the same issue class appears repeatedly, promote the manual troubleshooting step into automation. Over time, this shifts effort from reactive debugging to preventive quality control, and ensures the article stays aligned with how teams actually build, test, and operate software.


Course illustration
Course illustration

All Rights Reserved.