dc: The 1971 RPN Calculator That Predates C and Still Fits in a Pipeline

2026-09-03

Everyone knows bc. Almost nobody remembers that bc was originally a front-end that compiled to dc bytecode — the "d" and "c" both stand for calculator, and dc is the older one. It shipped in Unix v1. It predates C. And it's still sitting in /usr/bin on every Linux and BSD box you touch, quietly guaranteed by POSIX.

Under the hood it's a reverse Polish notation calculator with arbitrary precision arithmetic, 256 named registers (each of which is itself a stack), macros, and conditional execution. Which is a fancy way of saying dc is Turing complete — the smallest programmable language POSIX guarantees on your system.

The basics that bite people

Push operands, then the operator. p prints the top of stack without popping. k sets decimal precision. i and o set input and output base.

$ echo '2 3 + p' | dc
5

$ echo '20 k 22 7 / p' | dc
3.14285714285714285714

$ echo '2 1000 ^ p' | dc
10715086071862673209484250490600018105614...   # 302 digits, no bignum library needed

Base conversion without leaving the shell

Every developer eventually needs to turn 0xDEADBEEF into decimal, or a decimal into binary. Most reach for Python. dc does it in one pipe:

$ echo '16 i DEADBEEF p' | dc
3735928559

$ echo '16 o 3735928559 p' | dc
DEADBEEF

$ echo '2 o 255 p' | dc
11111111

Set the input base first (16 i). After you change it, following digits are parsed in the new base — including any digits meant to set the output base afterward. That subtlety is where every first-time user eats it.

Macros: where dc stops being a calculator

Anything between [ and ] is a string. Store in register S with sS, load with lS, execute with x.

# Define "square" as dup-multiply, apply to 7
$ dc -e '[d*]sS 7 lSx p'
49

# Compose it: fourth power = square of square
$ dc -e '[d*]sS 3 lSx lSx p'
81

Conditional operators (=r, <r, >r) pop two values and run register r's macro if the relation holds. Combine that with a macro that reloads itself and you have loops. That is genuinely all you need to write real programs — Rosetta Code has full dc implementations of factorial, Fibonacci, primality, and RPN evaluators, most under 100 bytes.

Why reach for dc when bc, python, or a browser tab exists?

The one real gotcha is that RPN gets unforgiving once expressions nest. Past three operators, break into newlines and use # comments (GNU extension) or write the intent above the invocation. Otherwise you will be debugging stack order at 2am, and that is not what a wizard-tier tool should be reduced to.

Key Takeaway: dc is the smallest Turing-complete language POSIX guarantees on your system — reach for it when you want arbitrary precision arithmetic or base conversion in a pipeline without paying the startup cost of a real interpreter.

All newsletters