ALGOL 60 - Josephus problem

For our ALGOL 60 sample program we’ll have a quick look at implementing a solution to the Josephus problem.

The problem

Imagine n prisoners standing in a circle, numbered sequentially from 0 to n-1. An executioner walks around the circle, starting at prisoner 0, and kills every kth prisoner, removing them from the circle. As this continues, the circle becomes smaller and smaller; the last prisoner remaining is freed.

An example for n=11 prisoners and k=3. Prisoners 2, 5 and 8 will be killed on the first trip round the circle. On the second trip, it’s goodbye to prisoners 0, 4 and 9. Continuing this leaves prisoner 6 as the survivor.

The task, given any n and k (both which should be greater than zero), find the prisoner who is freed.

See Rosetta Code for a full description and sample code in other languages.

Solution

There’s a fairly simple iterative solution to the main function to determine the last survivor:

    'COMMENT' Find surviving prisoner from circle of N;
    'COMMENT' after killing each Kth prisoner;
    'INTEGER' 'PROCEDURE' JOSEPHUS(N, K);
    'VALUE' N, K;
    'INTEGER' N, K;
    'BEGIN'
        'INTEGER' INDEX, PRISONER;
         PRISONER := 0;
        'FOR' INDEX := 1 'STEP' 1 'UNTIL' N 'DO'
        'BEGIN'
            JOSEPHUS := PRISONER := MODULUS(PRISONER + K, INDEX);
        'END'
    'END'

It would seem that we could just use JOSEPHUS as the variable and not need PRISONER but ALGOL only allows return value variables to appear on the left hand side of an expression.

Next, we need to define the MODULUS function to give the remainder after dividing two integers

    'COMMENT' Finds the remainder of X and Y for positive values;
    'INTEGER' 'PROCEDURE' MODULUS(X, Y);
    'VALUE' X, Y;
    'INTEGER' X, Y;
    'BEGIN'
        MODULUS := X - (Y * (X '/' Y));
    'END'

Note that we use the integer division operator รท (written as '/' in the IBM hardware representation) as the regular division operator / on integers will round either up or down depending on the value.

Finally, for the main program we can call the JOSEPHUS function and output the integer result: we use 41 prisoners and k=3:

'BEGIN'
    'COMMENT' Main program;
    OUTINTEGER(1, JOSEPHUS(41, 3));
'END'

So writing this was fairly easy. Quoting all keywords still feels unnatural so I normally put them in after writing out the program in full. I had to look up the difference between the two division operators but expressing the main flow was simple. What tripped me up on first compile was the comment syntax: I was using COMMENT abc which the compiler appeared to accept but would sometimes swallow the next line. Fixing this to quote the COMMENT and terminate the line with a semicolon fixed this (eg 'COMMENT' abc;).

Running the solution

Let’s see how this looks when we compile and run the program. Don’t forger to destroy or empty the output object file first otherwise you will get strange results after each recompile.

# $destroy -load
 File "-LOAD" has been destroyed.

# $run *algol scards=josephus.al spunch=-load
Execution begins   21:39:02
 i
  LEVEL 1JUL67                            OS ALGOL F                       DATE  FEB 05 1915
                                       SOURCE PROGRAM                               PAGE 001
   SC     SOURCE STATEMENT
  00000   'BEGIN'
  00000       'COMMENT' Finds the remainder of X and Y for positive values;
  00000       'INTEGER' 'PROCEDURE' MODULUS(X, Y);
  00001       'VALUE' X, Y;
  00002       'INTEGER' X, Y;
  00003       'BEGIN'
  00003           MODULUS := X - (Y * (X '/' Y));
  00004       'END'
  00004
  00004       'COMMENT' Find surviving prisoner from circle of N;
  00005       'COMMENT' after killing each Kth prisoner;
  00005       'INTEGER' 'PROCEDURE' JOSEPHUS(N, K);
  00006       'VALUE' N, K;
  00007       'INTEGER' N, K;
  00008       'BEGIN'
  00008           'INTEGER' INDEX, PRISONER;
  00009            PRISONER := 0;
  00010           'FOR' INDEX := 1 'STEP' 1 'UNTIL' N 'DO'
  00010           'BEGIN'
  00010               JOSEPHUS := PRISONER := MODULUS(PRISONER + K, INDEX);
  00011           'END'
  00011       'END'
  00011
  00011       'COMMENT' Main program;
  00012       OUTINTEGER(1, JOSEPHUS(41, 3));
  00013   'END'
 i
                                       IDENTIFIER TABLE                             PAGE 002
  PBN SC    PBN      NAME   TYPE  DM DSP       NAME   TYPE  DM DSP       NAME   TYPE  DM DSP
            SURR                  PR LN                     PR LN                     PR LN

  001 00000 000      JOSEPH I P   02 074       MODULU I P   02 070

  002 00000 001      MODULU I P   02 070       X      I  V     020       Y      I  V     028

  003 00005 001      INDEX  I        030       JOSEPH I P   02 074       K      I  V     028
                     N      I  V     020       PRISON I        034
 i
                                   STORAGE REQUIREMENTS (DECIMAL)                   PAGE 003

  OBJECT MODULE SIZE 840 BYTES.
  DATA STORAGE AREA SIZES
    PBN   BYTES       PBN   BYTES       PBN   BYTES       PBN   BYTES       PBN   BYTES
    001      36       002      48       003      68
Execution terminated   21:39:02  T=0.016

# $run -load+*algollib
Execution begins   21:39:10
         +30



 END OF ALGOL PROGRAM EXECUTION

Execution terminated   21:39:10  T=0.003

We can see in the compiler identifier table output that although we can use long identifiers they are truncated to six characters.

Final thoughts on ALGOL 60

There’s a lot to like in ALGOL 60: the language definition is more precise than the informal descriptions used before; the block structure and variable scoping; the powerful control statements. As a programmer with a C background it appears much more familiar then FORTRAN.

However it does feel like an interim release rather than a fully developed language; I think this is partially due to its academic origins rather than from a computer company looking to sell its hardware. The different language representations and call-by-name are a bit too clever and the emphasis on machine independence went too far - the lack of any I/O means that no useful program could be portable. Another factor not evident when running MTS today is that the FORTRAN development environment and compilers are much more advanced so for any computationally expensive workload you would have been better off with FORTRAN.

With the experience of implementing compilers in ALGOL 60, the group responsible for the original report looked at what changes should be made for the next version of ALGOL. In the next post I’ll look at one of these, ALGOL W.

Further information

Full source code for this program is on github.

Comments

comments powered by Disqus