Martin Richards, the designer of BCPL (based on Algol-60 and CPL, and the predecessor for B and C), had this to say on the motivation for many such decisions:
It was not until July 1967 that a specification of a character set was published that closely resembles the ASCII character set we have today. Prior to that, computers typically had their own character sets and these were often quite limited. For instance, on the first machine on which BCPL ran, namely an IBM 7094 running CTSS, the standard code used 6-bit characters packed in 36-bit words. The characters available were essentially those used in Fortran and did not include square or curly brackets ([ ] { }), semicolon (;), double quote (") or underscore (_) and commonly used terminals such as the Model 35 Teletype only permitted letters in upper case. However, at Cambridge, CPL programs used a much richer character set since they were typically prepared using a Flexowriter which was an electric typewriter that was combined with a 7-track paper tape reader and punch. The available characters included backspace and so overprinting was possible and used to represent symbols such as ≠. System words such as while were underlined to distinguish them from ordinary identifiers. BCPL on the 7094 thus had to represent lexical tokens quite differently.
Most of the commonly-used ASCII representations of operators were codified in either B or C. Many two-character tokens seem to have been chosen based on how some terminals could print one character on top of another. For example, on many paper terminals, ê would have been represented as e
-backspace-^
, which on a terminal that didn’t support overstriking, would display as e^
. When programming languages were transitioning to ASCII in the late ’60s, this seems to have inspired several of the two-character operators familiar to us today. So, !=
would look like a vertical stroke across an equals sign if they were printed on top of each other. Note that =|
was already taken in B for the binary operator that became |=
in C.
Algol and BCPL originally had ≤
(which some machines could represent as an underlined <
, and others replaced with a text mnemonic). This became =<
in B and early C, and <=
in BASIC, C and languages influenced by them. Probably, C reversed all the equals operators at the same time, so that typos such x=-1
for x = -1
would no longer cause so many bugs. This happened to make the existing !=
operator look as though x != 0
should be a synonym for x = !0
, which the syntax of B did not imply. However, perhaps because all C users knew B and !=
is never used in a context where anyone would ever suspect it meant if (x = !0)
, the designers of C saw no need to change it.
Multiplication and Exponentiation
A recent question on LangDev.SX discussed the history of *
. The use of an asterisk for multiplication in printed books goes back at least to Johann Heinrich Rahn in 1659. The first programming language to use it was Fortran. Fortran’s preliminary report, in 1954, proposed using ×
for multiplication and ××
for exponentiation.. By 1956, *
and **
had been chosen instead. MATH-MATIC (deriving from work by Grace Hopper) was being developed at the same time and also settled on *
sometime between 1955 and 1957. John Backus said this was a coincidence, and that he was unaware of much previous work that came to light later. He made this choice because of the very limited 48-character set of the BCD-coded punch cards he needed to support, and even removed comparisons from DO
loops because of the lack of a <
character (giving rise to .LT.
).
The convention of ^
for exponentiation derived from Algol’s choice of ↑
(perhaps because it represents raising the exponent). Dartmouth BASIC in 1964 originally used this symbol as well, despite being primarily based on Fortran. Some early teletypes and computers displayed character 5E as ↑
, but ASCII standardized it as ^
, and BASIC was the first language to officially make exponentiation ^
. This symbol was later adopted by AWK and Donald E. Knuth’s TeX. The ubiquity of TeX in mathematics is probably what led other languages used primarily by mathematicians to follow suit.
Logical Operators
The Medieval Latin abbreviation &
(originally a stylized et) came to be read as and in many languages that use the Latin script. Algol used ⋎
for or in the reference language itself, but the hugely influential ALGOL-60 report also was the first to use BNF grammar. Its section 1.1 introduces the syntax of BNF with:
The marks ::=
and |
(the latter with the meaning of or) are metalinguistic connectives.
Successor languages designed after ASCII had become dominant used |
to mean or within the language itself. B in particular had no short-circuting logical or, only bitwise or, and used |
to mean that. BCPL and B had the optimization that a &
at the top level of a conditional expression, such as if (p & q)
, would short-circuit.
Algol had used the standard symbol ¬
for logical not. Since that did not make it into ASCII and B had only bitwise complement (representing false as 0 and true as ~0, or -1 in two’s-complement), B used the closest available character to ¬
in ASCII, ~
.
Ken Thompson would later call the choice of ^
for exclusive-or in B “a random choice of the characters left,” and say, “if i had it to do over again (which i did) i would use the same operator for xor (^
) and bit complement (~
)” The “(which i did)” is a reference to how he made “the better-known operator” ^
mean both bitwise complement and exclusive-or in Golang.
The &&
and ||
operators first appeared in C. Dennis Ritchie credits Alan Snyder for them.
Rapid changes continued after the language had been named, for example the introduction of the && and || operators. In BCPL and B, the evaluation of expressions depends on context: within if and other conditional statements that compare an expression's value with zero, these languages place a special interpretation on the and (&) and or (|) operators. In ordinary contexts, they operate bitwise, but in the B statement
if (e1 & e2) ...
the compiler must evaluate e1 and if it is non-zero, evaluate e2, and if it too is non-zero, elaborate the statement dependent on the if. The requirement descends recursively on & and | operators within e1 and e2. The short-circuit semantics of the Boolean operators in such `truth-value' context seemed desirable, but the overloading of the operators was difficult to explain and use. At the suggestion of Alan Snyder, I introduced the && and || operators to make the mechanism more explicit.
Speculation
The division sign /
was probably chosen to represent a fraction slash, as in 2/3. The %
symbol for modulus was likely picked as the closest ASCII equivalent of ÷. Its occasional use for cents might have suggested its use for a remainder.