dc
The oldest surviving Unix language — a stack-based, arbitrary-precision desk calculator using reverse Polish notation, first shipped with Version 1 AT&T Unix in 1971.
Created by Robert Morris and Lorinda Cherry
dc (desk calculator) holds a singular place in computing history: it is the oldest surviving Unix language program. First shipped with Version 1 AT&T Unix on November 3, 1971, dc predates the C programming language, the Bourne shell, and nearly every other tool still in common use on Unix-like systems. More than fifty years later, dc remains available on virtually every Unix, Linux, and macOS installation.
History & Origins
dc was created by Robert Morris and Lorinda Cherry at AT&T Bell Laboratories. Morris, an American cryptographer and mathematician who joined Bell Labs in 1960, contributed several foundational Unix components including the math library, the crypt program, and the Unix password encryption scheme. Cherry joined Bell Labs’ Computing Science Research Center in 1971 and collaborated with Morris on dc.
The original implementation of dc was written in B, the programming language that preceded C at Bell Labs. According to Ken Thompson, dc was reportedly the first program to run on Bell Labs’ PDP-11 — even before an assembler was available for the machine. Later versions of dc were rewritten, first in PDP-11 assembly language (as seen in the Version 6 Unix source tree), and eventually in C.
The Birth of bc
In 1975, Lorinda Cherry created bc (bench calculator) as a front-end to dc. Where dc uses reverse Polish notation, bc provides a more conventional infix syntax resembling the C programming language. The original bc was literally a preprocessor: it compiled its C-like input into dc commands and piped the results through dc for execution. This architectural relationship persisted for many years, though modern implementations (such as GNU bc and Gavin Howard’s implementation) have reversed or eliminated this dependency.
Design Philosophy
dc embodies the Unix philosophy of small, sharp tools. Its interface is minimal — most commands are single characters — and it communicates through standard input and output, making it composable with other Unix utilities via pipes.
The core design is built on three concepts:
- Reverse Polish Notation (RPN): Operators follow their operands, eliminating the need for parentheses and operator precedence rules
- Stack-based computation: All values are pushed onto a stack; operations consume values from the stack and push results back
- Arbitrary precision: dc supports unlimited precision arithmetic, with the number of fractional digits controlled by the user
This design makes dc simultaneously powerful and cryptic. A simple addition looks like:
3 4 + p
This pushes 3 and 4 onto the stack, adds them, and prints the result (7). The p command prints the top of the stack without removing it.
Key Features
Arbitrary-Precision Arithmetic
dc performs arithmetic to arbitrary precision. The k command sets the number of fractional digits maintained during computation. By default, precision is zero, meaning dc performs integer arithmetic:
10 k
1 3 / p
This sets precision to 10 decimal places, divides 1 by 3, and prints .3333333333.
Registers and Storage
dc provides at least 256 named registers, each identified by a single character. Each register maintains its own stack, allowing values to be stored and retrieved:
5 sa # Store 5 in register 'a'
la p # Load from register 'a' and print
Strings and Macros
dc can manipulate strings as well as numbers. Strings are enclosed in square brackets and can be printed or — crucially — executed as macros. This capability transforms dc from a simple calculator into a programmable system:
[Hello, World!] p
Conditional Execution
dc supports conditional execution by comparing the top two stack values and executing a macro stored in a register if the condition is met:
# Print "yes" if 5 > 3
5 3 [yes] sa >a
The >a command pops two values, compares them, and executes the macro in register a if the first is greater than the second.
Base Conversion
dc supports separate input and output radices, making base conversion straightforward:
16 o 255 p # Set output radix to 16, print 255 → FF
16 i FF p # Set input radix to 16, print FF → 255
Looping via Recursion
Since dc has no built-in loop constructs, loops are implemented through recursive macros:
# Count from 1 to 10
[p 1 + d 10 !<a] sa 1 la x
This stores a macro in register a that prints the top of the stack, increments it, duplicates it, and recursively calls itself while the value is not greater than 10.
Implementations
dc has been independently implemented multiple times over its long history:
| Implementation | Platform | Notes |
|---|---|---|
| GNU dc | Linux, cross-platform | Part of the GNU bc package; latest version 1.5.2 (2025) |
| OpenBSD dc | OpenBSD | Complete rewrite by Otto Moerbeek (2003, OpenBSD 3.3) using big number routines |
| Gavin Howard’s dc | macOS, FreeBSD, Android | Modern BSD-licensed implementation; default on macOS since Ventura (2022) |
| Plan 9 dc | Plan 9 | Maintained as part of the Plan 9 operating system |
Installing dc
On most Unix-like systems, dc is already installed. If not:
| |
Current Relevance
Despite its age and terse syntax, dc remains relevant for several reasons:
- Ubiquity: dc is available on essentially every Unix-like system, making it one of the most portable tools for arithmetic in shell scripts
- Arbitrary precision: Unlike most shell arithmetic (which is limited to integer or floating-point precision), dc handles numbers of any size with any desired precision
- No dependencies: dc requires nothing beyond a basic Unix installation, making it valuable for minimal environments, containers, and recovery scenarios
- Pipeline integration: dc reads from standard input, making it trivially composable with other Unix tools
POSIX Status
Notably, dc is not part of the POSIX standard. When POSIX standardized bc in 1992 (IEEE Std 1003.2), dc was deliberately excluded because bc was considered to have “a more intuitive programmatic interface.” Despite this, dc is shipped on virtually every Unix-like system in practice.
Why It Matters
dc’s significance extends beyond its utility as a calculator. As the oldest surviving Unix language program, it represents the dawn of the Unix tool philosophy — small programs that do one thing well, communicate through text streams, and compose together into larger solutions.
The dc-to-bc relationship also demonstrates an important pattern in language design: building a more user-friendly language as a front-end to a more powerful but less accessible one. This architectural approach — where a high-level language compiles down to a lower-level execution engine — anticipates patterns seen throughout computing, from compiled languages targeting virtual machines to modern transpilers.
dc is a living artifact of Unix history, still doing exactly what it was designed to do more than fifty years ago.
Timeline
Notable Uses & Legacy
Unix Shell Scripting
dc is commonly used in shell scripts for arbitrary-precision arithmetic and base conversions, especially on minimal systems where more complex tools may not be available
System Administration
Used for quick command-line calculations, hexadecimal/octal/decimal conversions, and computing network addresses or file sizes
Code Golf
dc's extremely terse single-character command syntax makes it a popular choice in code golf competitions and programming puzzles
Portable Scripting
dc is available on virtually every Unix-like system, making it a reliable tool for arithmetic in scripts that must run across diverse environments
Language Influence
Influenced By
Influenced
Running Today
Run examples using the official Docker image:
docker pull alpine:latestExample usage:
echo '2 3 + p' | docker run --rm -i alpine:latest sh -c 'apk add --quiet bc > /dev/null && dc'