Algol 68 complex numbers
last modified November 13, 2026
The mode COMPL holds a complex number, a pair of reals that the
language treats as one value. The arithmetic operators are defined for it,
and the prelude adds the procedures that read the two parts and the
properties of the number. This article describes how a complex value is
built, printed, and used in calculations.
Building a complex value
A complex value is written as a display of two reals, in the order real part
and imaginary part. The display may be prefixed with COMPL, and a
plain real widens to a complex number with a zero imaginary part.
BEGIN COMPL z = COMPL(3.0, 4.0); print((z, newline)); print((fixed(re OF z, 0, 1), " ", fixed(im OF z, 0, 1), newline)); print((fixed(ABS z, 0, 1), newline)); print((fixed(ARG z, 0, 3), newline)) END
The first line shows the default output of a complex value, which prints each
part in the default real format, so the article uses the parts instead.
re OF and im OF select the real and imaginary parts,
ABS gives the modulus, and ARG gives the argument in
radians. For 3 and 4 the modulus is 5 and the argument is about 0.927.
$ a68g basic.a68 +3.00000000000000e +0+4.00000000000000e +0 3.0 4.0 5.0 .927
A printing procedure
Because the default form is hard to read, a program that prints complex
numbers usually writes a small procedure. The parts are printed with
fixed, which gives a uniform number of decimals.
PROC show = (COMPL z) VOID:
print(("(", fixed(re OF z, 0, 2), ", ", fixed(im OF z, 0, 2), ")", newline));
BEGIN
show(COMPL(3.0, 4.0));
show(COMPL(0.0, -1.5))
END
The procedure prints the pair in parentheses, in the same order in which the
display is written. The second call shows a negative imaginary part, and the
zero real part is printed as .00, because a field of zero
characters before the point drops the leading zero.
$ a68g show.a68 (3.00, 4.00) (.00, -1.50)
Arithmetic
The four operators +, -, *, and
/ work on complex numbers with the usual rules, and a real
operand may be mixed with a complex one. The result always has mode
COMPL.
PROC show = (COMPL z) VOID:
print(("(", fixed(re OF z, 0, 2), ", ", fixed(im OF z, 0, 2), ")", newline));
BEGIN
COMPL a = COMPL(1.0, 2.0), b = COMPL(3.0, -1.0);
show(a + b);
show(a - b);
show(a * b);
show(a / b)
END
Addition and subtraction work on the two parts separately, giving
(4, 1) and (-2, 3). Multiplication multiplies the
parts in the way that produces -1 from i * i, and
the product here is (5, 5). Division multiplies both parts by the
conjugate of the divisor, which gives (0.1, 0.7).
$ a68g arith.a68 (4.00, 1.00) (-2.00, 3.00) (5.00, 5.00) (.10, .70)
Powers and real operands
The power operator accepts an integer exponent, and a real may take part in a formula with a complex value. The real is widened before the operation, so the imaginary part of the result follows from the arithmetic.
PROC show = (COMPL z) VOID:
print(("(", fixed(re OF z, 0, 2), ", ", fixed(im OF z, 0, 2), ")", newline));
BEGIN
COMPL z = COMPL(1.0, 1.0);
show(z ** 2);
show(z + 1.0)
END
Squaring 1 + i gives 2i, because the two imaginary
products contribute -1 and the real parts contribute 1. Adding
the real 1 changes only the real part, which becomes 2. The same widening
happens in a comparison, in an argument, and in an initialiser.
$ a68g pow.a68 (.00, 2.00) (2.00, 1.00)
The conjugate
CONJ returns the complex conjugate, which has the same real part
and the negated imaginary part. Multiplying a number by its conjugate gives a
real value, the square of the modulus.
PROC show = (COMPL z) VOID:
print(("(", fixed(re OF z, 0, 2), ", ", fixed(im OF z, 0, 2), ")", newline));
BEGIN
COMPL z = COMPL(3.0, 4.0);
show(CONJ z);
show(z * CONJ z)
END
The conjugate of 3 + 4i is 3 - 4i, and the product
is 25 with no imaginary part. CONJ is a monadic operator, so it
applies to the following operand; the call passes the whole result to
show. The modulus printed earlier was the square root of this
product.
$ a68g conj.a68 (3.00, -4.00) (25.00, .00)
Equality
Complex numbers compare with = and /=, and both
parts have to be equal. There is no ordering, because the complex numbers have
no natural order that the comparison could follow.
BEGIN COMPL a = COMPL(1.0, 2.0), b = COMPL(1.0, 2.0), c = COMPL(2.0, 1.0); print((a = b, " ", a = c, " ", a /= c, newline)) END
The first two values have the same parts in the same order and compare equal,
while c has them swapped and compares different. Writing
a < c is a compile error about an undeclared operator, which
is how the language keeps the comparison honest.
$ a68g equal.a68 T F T
Rows of complex numbers
COMPL is an ordinary mode for a row, so a row may hold a sequence
of complex values. The elements are multiplied and printed with the procedure
from the previous sections.
PROC show = (COMPL z) VOID:
print(("(", fixed(re OF z, 0, 2), ", ", fixed(im OF z, 0, 2), ")", newline));
BEGIN
[]COMPL corners = (COMPL(1.0, 1.0), COMPL(-1.0, 1.0), COMPL(-1.0, -1.0), COMPL(1.0, -1.0));
FOR i TO UPB corners DO
show(corners[i] * corners[i])
OD
END
The four values are the corners of the unit square in the complex plane, and squaring each one gives a value on the imaginary axis. The loop walks the row with the bounds read from the row itself, so the same code works for a longer sequence.
$ a68g row.a68 (.00, 2.00) (.00, -2.00) (.00, 2.00) (.00, -2.00)
Next steps
The modes article lists COMPL with
the other numeric modes, and
coercions explains the widening from
REAL to COMPL. The bits
article describes the other non-decimal mode, and
strings shows how numbers become text.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have built complex values from two reals, read their parts
with re OF and im OF, computed the modulus and the
argument, printed the values with a procedure, added, subtracted, multiplied
and divided them, raised one to a power, mixed a real into the arithmetic,
taken a conjugate, compared complex values, and stored them in a row. The
bits article continues with bit patterns.
Author
List all Algol 68 tutorials.