Fond memories

Let me tell you about a greeting from the past I recently found…

My first code - found again

When digging through old files, I happened to find a record of the first computer program that I have ever written. This was back in 1973, I believe, but it could also have been 1974; I was 13 or 14 years old back then.

The program ran on a Diehl Combitron S, a very early programmable (of sorts) desk top computer. This machine could do the obvious +, -, ×, and ÷ in fixed point calculation, and calculate square roots.

My home-brew algorithm taught it to calculate (decadic) logarithms. Doing the reverse is my second program ever, written at the same time.

The story

I had done the original coding on paper, without prior contact with the computer I was programming. Then, one glorious Saturday, we went to my dad’s workplace to try out my program.

The time had come. The machine was to calculate log(2) (base 10). It sat there, fan humming, nothing being printed.

Dad became suspicious: “These programs never run that long! Something must surely be wrong!” I went through my code again and found I had indeed gotten one of the conditional jumps wrong. This resulted in an endless loop.

After correction, the same story: Again the computer sat there, humming, printing nothing. Again dad started to voice his doubts. Again I was busy staring at and thinking through my code – when suddenly, the computer’s noisy printer sprang into action, startling us, and giving the correct answer. It just took a while! (Maybe three minutes for one logarithm?)

The record

Here comes my documentation from the 70s. The logarithm part is at the left, the “ten to the power of” at the right. The code must be read in columns rather than rows.

Scan of my original manuscript

A modern port

Some 40+ years later, I remember the simple code well enough to translate it to Python. This code is not intended to be pretty Python, but to reflect the original algorithm faithfully.

The algorithm works by producing a series of numbers with known logarithm in variable k2, the known logarithms in variable k3. This starts with k2 = 10000, its known logarithm being k3 = 4.

In a loop, the next value for k2 is calculated from the previous one by taking a square root, and its known logarithm k3 is divided by 2 at the same time. k2 converges to 1, k3 converges to 0. The algorithm terminates when the representation of k3 collapses to 0, given the limited numerical precision.

We accumulate the logarithm of k1 in the variable k4. For this, we compare k1 with k2 during each loop iteration. If k2 fits into k1, we divide k1 by k2 and add the current value of k3 to k4.

The special case when k1 and k2 are equal is dealt with properly, but in a rather roundabout way. This may be a later addition that has not been present in the original very first version of the program.

#!/usr/bin/env python3

import sys
import math

k5 = 2
k6 = 10000
k7 = 4
k8 = 0
k4 = k8 # Implicit after switch-on of original machine.

# The smallest number that makes a difference when added to 1
# (or to any number - this was fixed decimal point)
# in the original Diehl Combitron S back in 1973
# is substituted by the smallest such number in Python today:
k9 = sys.float_info.epsilon

while True:
    k1 = float(input("log > "))
    print(k1)

    # Invariant A of the algorithm:
    # k2 is some number with known log, and k3 is that log.
    # We'll see to it that k3 becomes closer and closer to 0.
    k2 = k6
    k3 = k7

    while True:
        if 0 <= -k1 + k2 - k9:
            pass
        else:
            # Invariant B of the algorithm:
            # If k1_original is the original value of k1,
            # then log(k1_original) = log(k1) + k4 .
            # We'll see to it that k1 becomes closer and closer to 1,
            # so k4 will become closer and closer to log(k1_original)
            k1 = k1 / k2
            k4 = k3 + k4

        # Keep invariant A,
        # but let k2 converge to 1 and k3 to 0:
        k2 = math.sqrt(k2)
        k3 = k3 / k5

        # This termination condition made sense
        # on the fixed-point machine, but it still works
        # (though it's somewhat wasteful) with today's floats:
        if 0 <= -k3:
            break

    # Print the logarithm
    print(k4)

    # Prepare for next iteration.
    k4 = k8

Some remarks:

  • The slips of paper glued to the page are original Combitron printouts from the 70s. These numbers are what you get when you interpret the program code numerically. They can be used to type in the program quickly.

  • The Python code above is an almost literal translation of the original code, the while and if and else reflecting the original jumps and conditional jumps. (A conditional jump happens if the current value is 0 or larger.)

  • The original machines has variables, 10 of them. It does not have constants. So you tend to grudgingly sacrifice a precious variable for every constant you want to use (or resort to tricks like “divide anything nonzero by itself to obtain 1”).

  • The program was not intended to calculate logarithms of numbers smaller than 1.

  • The original hardware, configured the way we did, supported no numbers beyond or including 10**7. (If I remember correctly, you could shift the location of the decimal point to gain larger numbers at the expense of precision.) The algorithm with the initial values given calculates correct results only for numbers up to 10**8.

  • After calculation of a logarithm, both the original program and the Python code ask for the next input. You have to forcibly terminate both when your logarithmic desires have been satisfied.

Dr. Andreas Krüger, Herweghstr. 13, 12487 Berlin, Germany, andreas.krueger@famsik.de