Algol 68 bits
last modified November 13, 2026
The mode BITS holds a fixed-width pattern of bits. A program uses
it for flags, masks, and the low-level representation of numbers, and the
language provides the boolean operations, the shifts, and the conversions
between a pattern and an integer. This article describes those operations and
a procedure that prints a number in binary.
Bit patterns and based denotations
A based denotation writes a number in a base other than ten, and its value has
mode BITS. 2r1010 is a binary pattern,
16rff a hexadecimal one, and 8r777 an octal one.
ABS converts a pattern to the integer it represents.
BEGIN BITS a = 2r1010; BITS b = 16rff; BITS c = 8r777; print((whole(ABS a, 0), " ", whole(ABS b, 0), " ", whole(ABS c, 0), newline)); print((BIN 12, newline)) END
The three patterns represent 10, 255, and 511. BIN goes the other
way and converts an integer to a pattern, and printing that pattern shows one
character per bit: F for a zero and T for a one. The
width belongs to the implementation, and this build prints 32 characters.
$ a68g denot.a68 10 255 511 FFFFFFFFFFFFFFFFFFFFFFFFFFFFTTFF
Printing binary digits
The F and T form is exact but hard to read. A
procedure that divides by two and collects the remainders produces the
familiar binary notation, without leading zeros.
PROC binary = (INT n) STRING:
( STRING s := "";
INT v := n;
WHILE v > 0 DO
s := (IF ODD v THEN "1" ELSE "0" FI) + s;
v OVERAB 2
OD;
IF s = "" THEN "0" ELSE s FI );
BEGIN
print((binary(10), " ", binary(255), " ", binary(0), newline))
END
ODD tests the last bit, the character is added in front of the
result so far, and OVERAB 2 shifts the value right by one place.
The loop ends when the value becomes zero, and the special case prints
0 for the input zero. The function is used in the rest of the
article to show bit patterns in a readable form.
$ a68g binary.a68 1010 11111111 0
Boolean operations on bits
AND, OR, XOR, and NOT work
on bit patterns bit by bit. The result of the first three has mode
BITS, so ABS turns it into an integer for printing.
PROC binary = (INT n) STRING:
( STRING s := "";
INT v := n;
WHILE v > 0 DO
s := (IF ODD v THEN "1" ELSE "0" FI) + s;
v OVERAB 2
OD;
IF s = "" THEN "0" ELSE s FI );
BEGIN
BITS a = 2r1100, b = 2r1010;
print(("and ", binary(ABS (a AND b)), newline));
print(("or ", binary(ABS (a OR b)), newline));
print(("xor ", binary(ABS (a XOR b)), newline))
END
The two patterns share the third bit only, so the conjunction is
1000. The disjunction has every bit that either operand has, and
the exclusive or has the bits that differ. The printed values drop leading
zeros, which is why the last line shows 110 instead of
0110.
$ a68g logic.a68 and 1000 or 1110 xor 110
Masks
A mask is a pattern with ones in the positions of interest. AND
with a mask tests or extracts bits, OR with a mask sets bits, and
AND NOT with a mask clears them.
PROC binary = (INT n) STRING:
( STRING s := "";
INT v := n;
WHILE v > 0 DO
s := (IF ODD v THEN "1" ELSE "0" FI) + s;
v OVERAB 2
OD;
IF s = "" THEN "0" ELSE s FI );
BEGIN
BITS flags := 2r0000;
flags := flags OR 2r0100;
flags := flags OR 2r0001;
print((binary(ABS flags), newline));
IF ABS (flags AND 2r0100) > 0 THEN
print(("read bit set", newline))
FI;
flags := flags AND NOT 2r0100;
print((binary(ABS flags), newline))
END
Two bits are set one at a time, and the pattern becomes 101. The
test isolates the middle bit and compares the result with zero, which is the
usual way to ask whether a flag is on. The last assignment clears that bit
with a mask that has ones everywhere except at the tested position, so only
the lowest bit remains.
$ a68g flags.a68 101 read bit set 1
Shifts
SHL moves the bits of a pattern to the left and SHR
moves them to the right. Both take an integer count and yield a pattern, and
the vacated positions are filled with zeros.
BEGIN BITS b = 2r0001; print((whole(ABS (b SHL 1), 0), " ", whole(ABS (b SHL 4), 0), newline)); print((whole(ABS (2r1000 SHR 2), 0), newline)); BITS c := 2r0011; c := c SHL 2; print((whole(ABS c, 0), newline)) END
One shifted left once is 2 and shifted left four times is 16, which is the same as multiplying by a power of two. Shifting 8 right twice gives 2, the integer division by four. The last part applies the shift to a variable and stores the result back into it.
$ a68g shifts.a68 2 16 2 12
Bits and integers
The bit operations are often used alongside integer arithmetic rather than
instead of it. ODD reads the lowest bit of an integer, and the
binary procedure turns the result into readable output.
PROC binary = (INT n) STRING:
( STRING s := "";
INT v := n;
WHILE v > 0 DO
s := (IF ODD v THEN "1" ELSE "0" FI) + s;
v OVERAB 2
OD;
IF s = "" THEN "0" ELSE s FI );
BEGIN
[]INT numbers = (5, 12, 7, 20);
FOR i TO UPB numbers DO
IF ODD numbers[i] THEN
print((whole(numbers[i], 0), " ", binary(numbers[i]), " odd", newline))
ELSE
print((whole(numbers[i], 0), " ", binary(numbers[i]), " even", newline))
FI
OD
END
An odd number has a one in its lowest bit, and ODD reports that
directly. The same test could be written as
ABS (BIN 1 AND BIN n) > 0, but ODD states the
intent without a conversion. The four values alternate between the two cases,
and the binary text shows the lowest bit that decides them.
$ a68g odd.a68 5 101 odd 12 1100 even 7 111 odd 20 10100 even
Next steps
The literals article covers the based
denotations, and operators explains the
priorities of AND, OR, and the shifts. The
complex numbers article continues with the
other numeric mode that has operations of its own.
Source
Revised Report on the Algorithmic Language Algol 68
In this article we have written bit patterns in binary, hexadecimal, and
octal, converted them to integers and back, printed numbers in binary, applied
AND, OR, XOR, and NOT,
used masks to test, set, and clear bits, shifted patterns left and right, and
tested integers for oddness. The complex numbers
article continues with the arithmetic of the complex mode.
Author
List all Algol 68 tutorials.