
I did not go straight to university after high school.
Life, as it often does for many people, took a less cinematic route.
Instead, life took me to a technical school, where I studied Computer Systems Design. One of the courses in the program was Structure of Programming Languages, and somewhere in that class, while wrestling with FORTRAN, of all things, we ran into a topic that both boggled and bothered me:
random number generators.
We had a book called Advanced Problem Solving with FORTRAN 77 by Stacey L. Edgar. I still remember it because, even then, FORTRAN already felt old. Not vintage in the fashionable sense, more like something previous generations had already suffered through and quietly left behind.
And strangely enough, I liked it.
Not necessarily FORTRAN itself, good grief, no, but what it forced one to understand.
The machine expected precision, and the mathematics expected you to know what you were doing.
There was very little room for bluffing.
If your logic broke, the program broke.
If your assumptions were wrong, the compiler had an efficient way of humiliating you without raising its voice.
Somewhere between loops, arrays, and FORTRAN’s occasional attempts to destroy my confidence, we encountered something fascinating:
random number generators.
Which, when one pauses to think about it, is an absurd phrase.
There is nothing remotely random about a computer.
A computer is obedience mechanized.
Give it the same input and it will faithfully produce the same output forever.
Which created an interesting problem:
How exactly do you persuade a deterministic machine to behave unpredictably?
The answer was mathematics.
Clever mathematics.
Sometimes elegant.
Sometimes fragile.
And occasionally held together by optimism.
What fascinated me then, and still does now, was that I actually understood the math behind it.
The seeds.
The modular arithmetic.
Why periods mattered.
Why tiny parameter choices quietly ruined everything while pretending to work perfectly.
Which, come to think of it, describes an alarming number of systems in life.
The Mid-Square Method: Hope, Squared
One of the earliest methods we learned was the mid-square method, often associated with computing pioneer John von Neumann (Knuth, 1981).
The implementation sounded suspiciously simple.
Take a seed number.
Square it.
Extract the middle digits.
Repeat.
Suppose we start with:
1234
Square it:
1234² = 1522756
Take the middle four digits:
2275
Repeat:
2275² = 5175625
Middle digits:
7562
And continue.
In FORTRAN, implementation was straightforward enough. Square the value, pad the result if necessary, extract the middle digits, then reuse the output as the next seed.
It was fast, compact, and economical, qualities that mattered back when computers had memory constraints severe enough to make modern software developers faint dramatically.
The flaw?
The method occasionally gave up.
The mid-square generator suffers from degeneration, meaning randomness slowly leaks away (Knuth, 1981).
Some sequences collapse into short loops.
Others drift toward fixed values.
The worst outcome is zero.
Once the sequence reaches zero:
0000 → 0000 → 0000
Forever.
Your random number generator has effectively retired.
No notice.
No explanation.
Just quiet mathematical resignation.
The method was brilliant in the way early computing often was: clever, efficient, slightly unstable, and held together by equal parts mathematics and optimism.
It worked.
Until it did not.
The Additive and Midproduct Methods: Trying to Improve the Lie
The additive method tried to improve matters by introducing memory into the process (Fishman, 1986).
Instead of relying only on the current value, it combined earlier values to generate the next number.
The formula:
Xₙ = (Xₙ₋ⱼ + Xₙ₋ₖ) mod m
Suppose:
X₁ = 15
X₂ = 28
Then:
X₃ = (15 + 28) mod 100 = 43
And onward it goes.
Its biggest advantage was longer periods, meaning the sequence took longer to repeat.
Because pseudo-random generators eventually repeat.
Machines, after all, enjoy routine.
The downside was that poor seed choices could still create hidden patterns and correlations (Fishman, 1986).
Things looked random enough, until somebody statistically competent arrived and ruined everybody’s confidence.
Then there was the midproduct generator, which expanded on the mid-square idea.
Instead of squaring one number, it multiplied two seed values and extracted the middle digits.
Example:
1234 × 5678 = 7006652
Middle digits:
0665
Continue.
The theory was sensible.
Surely two numbers ought to create more variability than one.
Unfortunately, theory and reality occasionally maintain a difficult relationship.
Sometimes it worked.
Sometimes poor seeds quietly wandered into repetitive cycles anyway (Knuth, 1981).
Computing history contains an alarming number of success stories built on the phrase:
“Well, it works well enough.”
The Multiplicative Generator: Minimalism with Consequences
The multiplicative generator simplified things considerably.
The formula:
Xₙ₊₁ = (aXₙ) mod m
Start with a seed.
Multiply by a constant.
Apply a modulus.
Repeat.
Example:
a = 5
m = 16
X₀ = 3
Then:
X₁ = (5 × 3) mod 16 = 15
X₂ = (5 × 15) mod 16 = 11
Continue.
Its strengths were obvious:
- Fast
- Simple
- Efficient
- Easy to implement
Its weakness, however, was parameter sensitivity.
Choose poor constants and everything quietly deteriorates (Knuth, 1981).
Periods become embarrassingly short.
Patterns quietly emerge where none were supposed to exist.
Choose the wrong multiplier and your magnificent pseudo-random generator suddenly behaves like office bureaucracy: predictable, repetitive, and quietly allergic to surprises.
Mathematics, unlike motivational speakers, actually cares about details.
The Linear Congruential Generator: The Reliable Workhorse
Eventually came the Linear Congruential Generator (LCG), arguably the workhorse of classical pseudo-random generation.
The formula:
Xₙ₊₁ = (aXₙ + c) mod m
Compared with multiplicative generators, LCGs added one ingredient:
an increment (c).
Small change.
Meaningful improvement.
Example:
a = 5
c = 3
m = 16
X₀ = 7
Then:
X₁ = (5 × 7 + 3) mod 16 = 6
X₂ = (5 × 6 + 3) mod 16 = 1
Continue.
LCGs became popular because they balanced speed, simplicity, efficiency, and reasonably acceptable randomness.
For FORTRAN programs, simulations, and numerical models, this mattered enormously.
Still, flaws remained.
Poor parameter choices could create hidden patterns and serial correlation, where values quietly influenced future outputs (Knuth, 1981).
Which is awkward, considering unpredictability was the whole point.
Testing the Lie: How Random Is Random Enough?
Generating numbers was only half the problem.
The other half involved figuring out whether the generator was actually random, or merely pretending convincingly.
Because pseudo-random sequences have a troubling habit of looking perfectly respectable right until somebody competent inspects them.
Humans, incidentally, are terrible at recognizing randomness.
We see patterns where none exist and miss patterns sitting directly in front of us.
Ask people to “make something random,” and they often become suspiciously orderly. We instinctively avoid repetition because repetition feels un-random, even though genuine randomness occasionally produces streaks that seem absurd.
Flip a coin enough times and eventually you will get several heads in a row.
People become suspicious.
The coin, meanwhile, remains emotionally uninvolved.
Which is why random number generators get tested in the first place.
Frequency Test: Is One Number Showing Off Too Much?
The frequency test checks whether numbers appear roughly as often as expected (Knuth, 1981).
Suppose a generator produces digits from 0 to 9.
Over enough runs, each digit should appear roughly the same number of times.
Not exactly.
Randomness has no obligation to be tidy.
But close enough.
If one number keeps appearing suspiciously often, something may be wrong.
Imagine if every supposedly random sequence somehow favored the number 7.
At some point one begins asking difficult questions.
That is not randomness.
That is favoritism.
Runs Test: Does Randomness Have Strange Habits?
The runs test examines streaks in a sequence (Fishman, 1986).
Suppose numbers continuously rise:
2, 4, 5, 7, 9
Or continuously fall:
8, 6, 3, 1
Random sequences naturally contain runs.
The question is whether there are too many or too few.
Too orderly?
Suspicious.
Too chaotic?
Also suspicious.
People expect randomness to spread itself politely and evenly.
Actual randomness occasionally behaves like it forgot the assignment.
Serial Correlation Test: Is Yesterday Quietly Controlling Tomorrow?
The serial correlation test checks whether earlier values influence later values too strongly.
In good randomness, one number should not secretly control the next.
This mattered especially in multiplicative and linear congruential generators, where poor parameter choices sometimes introduced hidden patterns (Knuth, 1981).
Everything looked respectable.
Then statistics arrived and ruined everybody’s confidence.
Chi-Square Test: Mathematics Starts Asking Awkward Questions
The chi-square test compares what should happen with what actually happened.
Suppose every digit should appear about 10% of the time.
But suddenly digit 3 appears 25% of the time while digit 9 barely appears at all.
Now things feel suspicious.
Mathematics quietly raises an eyebrow.
Not dramatically.
Mathematics is far too dignified for drama.
But the message is unmistakable:
“Something here looks questionable.”
Poker Test: Yes, Someone Borrowed from Gambling
Then there is the wonderfully named poker test.
Numbers are grouped into combinations resembling poker hands, pairs, triples, repeated values, and compared against expected probabilities (Knuth, 1981).
Apparently even mathematics occasionally borrows ideas from casinos.
One assumes statisticians occasionally required entertainment.
The lesson became simple:
Never trust randomness merely because it looks messy.
Test it.
Measure it.
Distrust it professionally.
Frankly, that advice applies to considerably more than computers.
What Stayed With Me
Looking back now, what stayed with me was not merely the mathematics.
It was the audacity of the whole enterprise.
Human beings built machines obsessed with order and immediately demanded disorder from them.
We created deterministic systems and then acted vaguely offended when they behaved deterministically.
So naturally, we invented mathematical tricks to persuade machines to pretend otherwise.
The mid-square method.
Additive generators.
Midproduct generators.
Multiplicative generators.
Linear congruential generators.
All slightly imperfect schemes trying to persuade obedient machines to misbehave in statistically acceptable ways.
And somehow, improbably, they worked.
Not perfectly.
But well enough.
I think that was the lesson I carried from those classes.
I liked understanding the machinery underneath, why things worked, why they failed, and how tiny assumptions occasionally collapsed spectacularly.
And perhaps that is why I still remember random number generators all these years later.
Because somewhere along the way, one realizes randomness is not merely a problem in computing.
It is suspiciously close to life.
Life, after all, rarely behaves according to elegant formulas.
Certainly not mine.
I did not take the cinematic route.
No smooth march from youth to adulthood.
No carefully plotted sequence where everything unfolded exactly as planned.
Life wandered, sometimes awkwardly, sometimes unexpectedly, and occasionally with all the elegance of a random number generator quietly going off the rails.
Yet somehow, things still worked out.
Not perfectly.
But well enough.
Which, come to think of it, sounds suspiciously similar to those old random number generators.
You start with a seed.
You make decisions.
Some good.
Some mathematically questionable.
Sometimes things collapse spectacularly.
Sometimes you start over.
And somehow the sequence keeps going.
Truthfully, most of us are probably just figuring things out as we go, pretending we understand the algorithm while quietly hoping the math somehow works out.
Which, admittedly, sounds far more philosophical than anyone expected from an old FORTRAN class.
References
Edgar, S. L. (1987). Advanced problem solving with FORTRAN 77. McGraw-Hill.
Fishman, G. S. (1986). A first course in Monte Carlo. Brooks/Cole.
Hull, T. E., & Dobell, A. R. (1962). Random number generators. SIAM Review, 4(3), 230–254.
Knuth, D. E. (1981). The Art of Computer Programming, Volume 2: Seminumerical Algorithms (2nd ed.). Addison-Wesley.
Schrage, L. (1979). A more portable FORTRAN random number generator. ACM Transactions on Mathematical Software, 5(2), 132–138.