11.001001000011111101101010100010001000 Arithmazium
Home

Pocket Guide to Python for Paranoia

Paranoia is a complex program with a simple structure – a single sequence of computations with results displayed at each step. ParaPy breaks the in-line form of ParaBas into dozens of independent functions, but the flow of execution is the same.

The structure of ParaPy and the clean form of Python make this code as readable as any pseudocode, but this section presents a small number of Python's features you might find helpful. The focus is on what matters for Paranoia, not the juicy details of Python exploited to its fullest.

If you want to learn more about Python, Dive Into Python 3 offers a wonderful tour of the language. Or try the official tutorial for a more thorough treatment.

Values, not types

Python is untyped. Variables arise from use rather than by declaration. Python supports integers of arbitrary size, but ParaPy uses floating point values for its tests. If you're using any conventional computer (or cloud-based server) from the past four decades, you're likely to have IEEE Standard 754 64-bit double values. You can find intimate details of IEEE 754 arithmetic in the Arithmetic room.

Python supports the boolean values True and False, and an intuitive definition of truthiness as anything remotely nonzero.

Strings in ParaPy usually appear in "double quotes", but may also be written with 'single quotes'.

Comments

The hash sign # not embedded in a string introduces a comment that runs to the end of the line.

Python also supports docstrings, triple-quoted comments you'll find as the first line(s) of most functions.

  def print_if_err_cnt_positive():
      '''Print an error message from a global count.'''

Functions

A function can take any number of parameters and return and number of values. This is another example from ParaPy, including the one-line docstring.

  def compute_H_and_inverse():
      """Return min(1/B, 1/2) and reciprocal, noting H is a fraction."""

The return mechanism is coming right up.

Block structure

Python's most remarkable feature is its approach to punctuation. Indented lines of code are blocks, usually introduced with a : character. Here is the body of compute_H_and_inverse() from the last section. It is indented one level in (typically 4 spaces) from the def.

    if B < TWO:
        h_inv = TWO
    else:
        h_inv = B

Locally, the indentation is very readable. When the plot thickens and you find yourself several levels deep in the logic, it takes a steady eye, or a plumb line, to keep oriented. ParaPy reaches its deepest nesting in the examination of underflow, which may not surprise readers who have been down this path before.

Tuples

Part of Python's expressiveness is its ability to manipulate multiple values at a time. The final line of compute_H_and_inverse() is the return of H and its reciprocal:

    return ONE / h_inv, h_inv

You can guess that the invocation assigns two results.

  H, ONE_OVER_H = compute_H_and_inverse()

Python tuples are defined as values grouped by parentheses, but the Pythonic way is to relax the requirement for the punctuation when the context is obvious. Tuples are likewise useful in loops, where two or more values are updated at each pass.

Global variables

Basic on the original IBM Personal Computer was limited by its flat structure and its limited namespace for variables. All variables were global, of the form A or X3, making the glossary at the end of ParaBas essential reading. Reuse of some variables in different sections of the code could complicate things for the reader.

ParaPy uses Python global variables sparingly, always in a way parallel to ParaBas. One class of globals, the flags and counters, are defined and initialized at the beginning of the code.

The other globals are constants, distinguished by their all-caps names. They are assigned once, then used as needed. Two exceptions, radix B and PRECISION, are double-checked and are subject to update.

When a global variable is assigned within a function it must be declared global, otherwise a local variable is created. For example, the pause() function accesses two globals.

  def pause():
      """Wait until the user hits RETURN."""
      global milestone, page_num

Style

ParaPy generally follows the Google style guide. As just noted, constant variables like ONE_HALF are upper case. All other variables and all functions are lower case with underscore dividers, like underflow_threshold.

An idiom for do-while

The Pythonic approach is to support one way, not four, to accomplish a task. Python supports while loops, whose condition is tested at the top of the loop. ParaBas employs the alternative do...while structure heavily, in which the condition is tested at the end of the loop.

ParaPy effects this structure with a mild deviation from the style guide. Bringing the loop break statement up alongside the if test improves readability.

    y = ONE
    while True:
        b = big + y
        y = y + y
        b = b - big
        if b != ZERO: break

Modules and libraries

ParaPy has a simple structure that fits in a single file (module), so there's no need for elaboration. At the top of the code, it imports the math library, giving access to handy functions like math.sqrt and math.pow.

The curious line

  from __future__ import division      # use // for integer division

is a bit of Python custom around the / operator as it applies to integers. We'll do nothing subtle with integer division.

Lists

A Python list is an ordered sequence of values. In ParaPy, we sometimes iterate over a list, as in this case of small odd primes:

    for z in [3, 5, 7, 11, 13, 17, 19, 23]:

Dictionaries

A Python dictionary is a set of key-value pairs. ParaPy has just one dictionary, a global set of test results. This is the start of its defiinition.

  flags = {
      "mult_guard_digit": False,
      "div_guard_digit": False,

The construct flags["mult_guard_digit"] accesses the dictionary element.

Number formatting

If you have formatted floating point numbers in another language, Python will come as no surprise. This is a typical usage.

    print("\tdiffers from z * 1 = {:0.17e}".format(r1))

Format requests in {...} are fulfilled in sequence from the arguments to format. As in C, \t skips to the next tab stop, and \n skips to the next line. The .17e requests 17 significant digits in the exponential format.

Home